Skip to content

[extension type] Analyzer has incorrect constant identity for type literals of nested extension types. #54057

Closed
Listed in
@lrhn

Description

@lrhn

Example:

void main() {
  // Base case.
  const Chk(ExInt, id: int);
  // Generics.
  const Chk(ExList<int>, id: List<int>);
  const Chk(List<ExInt>, id: List<int>);
  const Chk(ExList<ExInt>, id: List<int>); // Fails
  // Multiple arguments.
  const Chk(Map<ExInt, String>, id: Map<int, String>);
  const Chk(Map<ExInt, ExString>, id: Map<int, String>);
  const Chk(ExMap<int, String>, id: Map<int, String>);
  const Chk(ExMap<ExInt, String>, id: Map<int, String>); // Fails
  const Chk(ExMap<ExInt, ExString>, id: Map<int, String>); // Fails
  // Generic twice.
  const Chk(List<List<ExInt>>, id: List<List<int>>);
  const Chk(List<ExList<int>>, id: List<List<int>>);
  const Chk(ExList<List<int>>, id: List<List<int>>);
  const Chk(ExList<List<ExInt>>, id: List<List<int>>); // Fails
  const Chk(List<ExList<ExInt>>, id: List<List<int>>); // Fails
  const Chk(ExList<ExList<int>>, id: List<List<int>>); // Fails
  const Chk(ExList<ExList<ExInt>>, id: List<List<int>>); // Fails
}

extension type const Chk._(Object? _) {
  const Chk(Object? object, {required Object? id}) :
      assert(identical(object, id)), _ = object;
}

extension type const ExInt(int value) implements int {}
extension type const ExString(String value) implements String {}
extension type const ExList<T>(List<T> value) implements List<T> {}
extension type const ExMap<K, V>(Map<K, V> value) implements Map<K, V> {}

Analyzing this with a freshly built analyzer (updated some time today) gives the following errors:

Analyzing ana-const-type-err.dart...

  error - ana-const-type-err.dart:7:3 - Evaluation of this constant expression throws an exception. - const_eval_throws_exception
           - The exception is 'The assertion in this constant expression failed.' and occurs here at ana-const-type-err.dart:26:7.
  error - ana-const-type-err.dart:12:3 - Evaluation of this constant expression throws an exception. - const_eval_throws_exception
           - The exception is 'The assertion in this constant expression failed.' and occurs here at ana-const-type-err.dart:26:7.
  error - ana-const-type-err.dart:13:3 - Evaluation of this constant expression throws an exception. - const_eval_throws_exception
           - The exception is 'The assertion in this constant expression failed.' and occurs here at ana-const-type-err.dart:26:7.
  error - ana-const-type-err.dart:18:3 - Evaluation of this constant expression throws an exception. - const_eval_throws_exception
           - The exception is 'The assertion in this constant expression failed.' and occurs here at ana-const-type-err.dart:26:7.
  error - ana-const-type-err.dart:19:3 - Evaluation of this constant expression throws an exception. - const_eval_throws_exception
           - The exception is 'The assertion in this constant expression failed.' and occurs here at ana-const-type-err.dart:26:7.
  error - ana-const-type-err.dart:20:3 - Evaluation of this constant expression throws an exception. - const_eval_throws_exception
           - The exception is 'The assertion in this constant expression failed.' and occurs here at ana-const-type-err.dart:26:7.
  error - ana-const-type-err.dart:21:3 - Evaluation of this constant expression throws an exception. - const_eval_throws_exception
           - The exception is 'The assertion in this constant expression failed.' and occurs here at ana-const-type-err.dart:26:7.

The error seems to only occur when there are extension types nested inside composite extension types.
(I have a bigger test combining this with things like T?, FutureOr<T> and function types. Seems to be consistent, but hard to say exactly.)

The identity is consistent, if I check const Chk(ExList<ExInt>, id: ExList<ExInt>);, it gives no error,
same if I try to put two types that are considered distinct into the same constant set.

The error message doesn't say what the actual Type objects are, just that they're not identical to to the expected constant type literal. Which is reasonable, the assert just saw a false value, it didn't know why. (Also doesn't look at the message.)

(Haven't found a way to make the analyzer print constant Type objects. If I add "${(object, id: id)}" as a message to the assert, the CFE compiler helpfully shows a useful "toString" of the Type object that it won't allow me to convert to a string.)

Activity

eernstg

eernstg commented on Nov 15, 2023

@eernstg
Member

Cool! Function types?

added
P1A high priority bug; for example, a single project is unusable or has many test failures
on Nov 20, 2023
self-assigned this
on Nov 20, 2023
scheglov

scheglov commented on Nov 20, 2023

@scheglov
Contributor

Yes, I failed to apply the representation type erasure recursively, when it is instantiated.
https://dart-review.googlesource.com/c/sdk/+/337261 should help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P1A high priority bug; for example, a single project is unusable or has many test failuresfeature-extension-typesImplementation of the extension type featurelegacy-area-analyzerUse area-devexp instead.type-bugIncorrect behavior (everything from a crash to more subtle misbehavior)

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

    Development

    No branches or pull requests

      Participants

      @srawlins@scheglov@lrhn@eernstg

      Issue actions

        [extension type] Analyzer has incorrect constant identity for type literals of nested extension types. · Issue #54057 · dart-lang/sdk