Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CFE and analyzer: constant error when casting null to nullable extension type. #53751

Closed
Tracked by #49732
lrhn opened this issue Oct 13, 2023 · 3 comments
Closed
Tracked by #49732
Assignees
Labels
cfe-feature-extension-types Implement extension types feature in the CFE feature-extension-types Implementation of the extension type feature legacy-area-fe-analyzer-shared Legacy: Use area-dart-model instead. type-bug Incorrect behavior (everything from a crash to more subtle misbehavior)

Comments

@lrhn
Copy link
Member

lrhn commented Oct 13, 2023

Example:

extension type const E(int? n) {}
const E e = null as E;

This errs in both CFE and Analyzer (DartPad, master branch).
Analyze:

error
line 2 • Evaluation of this constant expression throws an exception.

CFE:

lib/main.dart:2:18:
Error: Constant evaluation error:
const E e = null as E;
                 ^
lib/main.dart:2:18:
Info: Expected constant 'null' to be of type 'E', but was of type 'Null'.
const E e = null as E;
                 ^

Guessing this is constant evaluation not being extension-type aware again, like #53610, which is why I tried this workaround.
There is currently no way (that I have found) to create a constant which has an extension type and a representation object of null.

If I change the code to:

extension type const E(int? n) {}
const E e = null as dynamic;

the analyzer error changes to:

error
line 2 • A value of type 'Null' can't be assigned to a const variable of type 'E'. (view docs)
Try using a subtype, or removing the 'const' keyword

CFE/Dart2JS is pretty much the same:

lib/main.dart:2:18:
Error: Constant evaluation error:
const E e = null as dynamic;
                 ^
lib/main.dart:2:18:
Info: Expected constant 'null' to be of type 'E', but was of type 'Null'.
const E e = null as dynamic;
                 ^

In any case, all of these should be allowed, since null is castable to int? at runtime, and therefore null as E, explicitly or implicitly by downcast, should succeed with runtime-type null and static type E.

@lrhn lrhn added type-bug Incorrect behavior (everything from a crash to more subtle misbehavior) legacy-area-fe-analyzer-shared Legacy: Use area-dart-model instead. feature-extension-types Implementation of the extension type feature labels Oct 13, 2023
@johnniwinther johnniwinther added the cfe-feature-extension-types Implement extension types feature in the CFE label Oct 13, 2023
@eernstg
Copy link
Member

eernstg commented Oct 13, 2023

The main thing seems to be that the CFE and the analyzer both predict that null as E would throw at run time, and as you mention here this is probably fixed by ensuring that this prediction checks the actual value of the expression against the representation type of E, not against E.

However, I noted one more thing:

There is currently no way (that I have found) to create a constant which has an extension type and a representation object of null.

The analyzer at least accepts this one:

extension type const E<X extends Object>(X? it) {
  const E.fromNull(): it = null;
}

void main() {
  const e = E<int>.fromNull();
  print(e == null);
}

However, this also demonstrates an issue with the CFE:

Error compiling to JavaScript:
lib/main.dart:6:13:
Error: Constant evaluation error:
  const e = E<int>.fromNull();
            ^
lib/main.dart:2:19:
Info: Expected constant 'null' to be of type 'E<X>', but was of type 'Null'.
  const E.fromNull(): it = null;
                  ^
lib/main.dart:6:9:
Info: While analyzing:
  const e = E<int>.fromNull();
        ^
Error: Compilation failed.

Here the CFE reports an 'Info' on the constructor declaration, implying that something has type Null where E<X> is expected (again, this shows that it is about the constructor, not the invocation E<int>.fromNull(), because it considers the type argument to be X rather than int).

But a (generative) constructor invocation does not return an object, it just performs primitive initialization of a freshly allocated area of memory and then runs user-code to perform further initialization.

It looks like the constructor is treated like a regular function that returns the value of the representation variable. This is not surprising (because that's pretty much what it is and does), but it could be a source of further confusion if the same perspective is used with other diagnostic messages.

@eernstg
Copy link
Member

eernstg commented Oct 13, 2023

Trying the same example on the bleeding edge dart, commit f87142f, and the CFE no longer reports any errors. So it must have been fixed very recently.

In other words, it is possible to create a constant expression whose type is an extension type with a nullable representation type and whose value is null. ;-)

@scheglov
Copy link
Contributor

scheglov commented Nov 8, 2023

With https://dart-review.googlesource.com/c/sdk/+/334862 this code seems to work in the analyzer.

@johnniwinther johnniwinther self-assigned this Nov 9, 2023
copybara-service bot pushed a commit that referenced this issue Nov 9, 2023
Bug: #53935
Bug: #53751
Change-Id: I514c79c79c9229b7fed313712b8f1d7a3ed91ca7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/334862
Reviewed-by: Kallen Tu <kallentu@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cfe-feature-extension-types Implement extension types feature in the CFE feature-extension-types Implementation of the extension type feature legacy-area-fe-analyzer-shared Legacy: Use area-dart-model instead. type-bug Incorrect behavior (everything from a crash to more subtle misbehavior)
Projects
None yet
Development

No branches or pull requests

4 participants