Skip to content

Issues in the CFE related to pattern schemas in type inference #51587

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

Closed
chloestefantsova opened this issue Mar 1, 2023 · 6 comments
Closed
Assignees
Labels
legacy-area-front-end Legacy: Use area-dart-model instead.

Comments

@chloestefantsova
Copy link
Contributor

chloestefantsova commented Mar 1, 2023

As mentioned in #51585, the context type schema should be the shape, not the type in the record patterns.

Affected test: https://github.com/dart-lang/co19/blob/7b4f3e723211011878e185db6fa57fbafabd6bb7/LanguageFeatures/Patterns/type_inference_A26_t01.dart#L34-L37

@chloestefantsova chloestefantsova added the legacy-area-front-end Legacy: Use area-dart-model instead. label Mar 1, 2023
@chloestefantsova chloestefantsova self-assigned this Mar 1, 2023
@eernstg
Copy link
Member

eernstg commented Mar 1, 2023

Oh, this is tricky! ;-)

I think I should comment on the terminology, just to make sure we're in sync. Also, I'm tempted to say something about a different topic, namely list patterns, and then return to records later on.


A pattern in an irrefutable context is used to compute a type schema P; P is then provided to the initializing expression (of a pattern declaration) respectively the right hand side (of a pattern assignment) and used as the context type during type inference.

The resulting type after type inference is some type T. T is then used to type check and finalize the pattern. The actual type argument of a list pattern is filled in at this point (if it isn't given explicitly).

This means that we can have a context type schema where the type argument is int, say, and this could be used and ignored during type inference, and the type argument of the pattern will then be filled in with the type argument taken from the initializing expression / right hand side.

void main() {
  var [int i] = <dynamic>[1];
}

In this example, the context type schema is List<int>, the initializing expression has type List<dynamic>, and the pattern is then finalized to be <dynamic>[int i]. The 'required type' of the pattern is then List<dynamic>, and the assignability check at the top level succeeds because List<dynamic> is assignable to List<dynamic>, and the nested check succeeds because dynamic is assignable to int.

With this in mind, the phrase

the expected type of the pattern schema

seems to refer to both the context type schema (which is obtained at first from the pattern), and the required type of the pattern (which is obtained by finalizing the pattern after we've found the static type of the initializing expression / right hand side).

The problem is that it is dangerous to imply that the type argument is the same both times, so it's dangerous to use a terminology that seems to consider those two things to be the same: In the example above, the context type schema has type argument int, and the type argument of the required type of the pattern is dynamic.


Returning to records, and the concrete example for this issue:

In the example, the pattern is (3.14,), the type schema is (int), and the required type is (Object?).

We don't have any type arguments for a record type, but the matched value type for each field pattern is used to perform the type check and finalization of each field (possibly adding coercions/demotions first, and then checking assignability).

In this case we don't have anything which makes the distinction between the (early) type schema and the (late) required type as clear as it is with the list pattern, but we do get the same issues in some cases. For instance, we could have a record pattern where one field pattern is a list pattern, and that list pattern would then be treated in the same way as the list pattern at the top level which was considered in the example above. So we have to be equally strict on the terminology with record patterns.

@chloestefantsova
Copy link
Contributor Author

Thank you for the clarification, Erik! I updated the phrasing in my original message to use "the context type schema".

@chloestefantsova
Copy link
Contributor Author

The underlying issue appears to be fixed.

@nshahan
Copy link
Contributor

nshahan commented Mar 16, 2023

I'm still seeing a compile time error in

co19/LanguageFeatures/Patterns/type_inference_A26_t01

In this code

var (num b,) = (0,);
b as int;
b.isEven;
(b,) = (3.14,);
org-dartlang-app:/tests/co19/src/LanguageFeatures/Patterns/type_inference_A26_t01.dart:37:11: Error: A value of type 'double' can't be assigned to a variable of type 'int'.
  (b,) = (3.14,);
          ^

@chloestefantsova
Copy link
Contributor Author

Thanks for noticing, @nshahan! There are a few interconnected issues, and I was too excited about fixing one of them and closed this issue prematurely. I reopened it and will work on making the CFE passing the test.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
legacy-area-front-end Legacy: Use area-dart-model instead.
Projects
None yet
Development

No branches or pull requests

3 participants