-
Notifications
You must be signed in to change notification settings - Fork 196
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
Use separate grammar rules for null-aware elements. #3812
Conversation
Stuffing the `?` directly inside `expressionElement` and `mapEntryElement` lets us reuse some existing specification around leaf elements, but is otherwise confusing because it makes the case analysis for the different kinds of elements non-disjoint. This fixes that by defining entirely separate rules for null-aware elements.
@@ -466,24 +499,24 @@ add two new cases to that procedure: | |||
|
|||
[unified-dynamic-element]: https://github.com/dart-lang/language/blob/main/accepted/2.3/unified-collections/feature-specification.md#to-evaluate-a-collection-element | |||
|
|||
* If `element` is a null-aware `expressionElement` with expression `e`: | |||
* If `element` is a `nullAwareExpressionElement` with expression `e`: | |||
|
|||
* Evaluate `e` to `v`. | |||
|
|||
* If `v` is not `null` then append it to *result*. *Else the `null` is | |||
discarded.* | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to do something special for coercions here, or will the value be coerced before the null
check?
void main() {
// True, but compiler doesn't know that.
var b = DateTime.now().millisecondsSinceEpoch > 0;
var l1 = <Function>[?(b ? CallableObject() : null)];
var l2 = <int Function(int)>[?(b ? id : null)];
}
T id<T>(T value) => value;
class CallableObject {
void call() {}
}
Will these list literals work or fail to compile?
If we coerce before null-checking, then we coerce CallableObject?
to Function?
which is not supported, so it's a compile-time error. Same for coercing T Function<T>(T)?
to int Function(int)?
. Neither of these are allowed:
Function? v1 = (b ? CallableObject() : null);
int Function(int) v2 = (b ? id : null);
If we coerce after null-checking, the code should works. And it's probably what the author wanted.
So should we?
That would either mean being explicit about where we do coercion, or somehow suggest to inference that the null check is not a coercion-point (a concept we haven't specified other than by the algorithm used.)
WDYT? @stereotype441
The static semantics with a context element type E
would be (paraphrased):
Let
S
be the static type ofe
in contextE?
. LetS'
be NonNull(S
).
It's a compile-time error ifS'
is not assignable to the greatest closure ofE
.
and runtime semantics of executing ?e
would be:
Evaluate
e
to a value v.
If v is not the valuenull
, then
- if the runtime type of v is a subtype of E, let w be v, otherwise coerce v from type
S'
to a value w of typeE
. (Which is always possible becauseS'
is assignable toE
.)- Then append w to result.
(Not sure dynamic
has an issue, downcasting before or after both work.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question! I filed a bug so we can discuss this more: #3821
* If `element` is a value null-aware element and `vv` is `null`, then | ||
stop. Else continue... | ||
* If `element` has a null-aware value and `vv` is `null`, then stop. Else | ||
continue... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we probably want to coerce both after the null
check, although it's probably usually the value where it makes sense (functions are bad keys).
Stuffing the
?
directly insideexpressionElement
andmapEntryElement
lets us reuse some existing specification around leaf elements, but is otherwise confusing because it makes the case analysis for the different kinds of elements non-disjoint.This fixes that by defining entirely separate rules for null-aware elements.