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

Use separate grammar rules for null-aware elements. #3812

Merged
merged 1 commit into from
May 20, 2024

Conversation

munificent
Copy link
Member

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.

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.*

Copy link
Member

@lrhn lrhn May 16, 2024

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 of e in context E?. Let S' be NonNull(S).
It's a compile-time error if S' is not assignable to the greatest closure of E.

and runtime semantics of executing ?e would be:

Evaluate e to a value v.
If v is not the value null, 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 type E. (Which is always possible because S' is assignable to E.)
  • Then append w to result.

(Not sure dynamic has an issue, downcasting before or after both work.)

Copy link
Member Author

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...
Copy link
Member

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).

@munificent munificent merged commit f4f7fd6 into main May 20, 2024
3 checks passed
@munificent munificent deleted the null-aware-element-grammar branch May 20, 2024 17:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants