From 34561fac0a0d13947c7a5bb3930b331858e342e6 Mon Sep 17 00:00:00 2001 From: Paul Berry Date: Thu, 4 Apr 2024 21:24:34 +0000 Subject: [PATCH] Additional improvements to `inference-update-3` tests. This CL makes the following improvements (suggested in the code review of https://dart-review.googlesource.com/c/sdk/+/356303): - Add parenthetical comment "(Testing this case here. Otherwise continued below.)", to reduce confusion for a reader reading the tests for the first time. - In all test cases using a promotable variable `o`, declare `Object? o;` first, then assign `o = ... as Object?;`. This makes the test cases more symmetrical, since `o = ... as Object?;` now appears in every test case, rather than getting coalesced with the variable declaration in some test cases but not others. - Consistently use `e` rather than `E` to refer to the whole expression being tested. - Expand on the explanation for how each test case matches up to the type metavariables K, T1, T2, etc., and why the expected result occurs. - Remove tickmarks around type metavariables. - Clarify that the type S is chosen, rather than T, only when the feature is enabled. Change-Id: I149b323daeac9fc44104681370cea33ee010faa4 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/357204 Reviewed-by: Lasse Nielsen Commit-Queue: Paul Berry --- .../conditional_expression_disabled_test.dart | 116 +++++-- .../conditional_expression_test.dart | 140 +++++++-- ...ension_index_expression_disabled_test.dart | 229 ++++++++++---- ...licit_extension_index_expression_test.dart | 253 ++++++++++++---- ..._aware_index_expression_disabled_test.dart | 248 ++++++++++----- ...sion_null_aware_index_expression_test.dart | 276 ++++++++++++----- ...ion_null_aware_property_disabled_test.dart | 248 ++++++++++----- ...it_extension_null_aware_property_test.dart | 276 ++++++++++++----- ...icit_extension_property_disabled_test.dart | 229 ++++++++++---- ...ment_explicit_extension_property_test.dart | 253 ++++++++++++---- ...extension_this_property_disabled_test.dart | 220 ++++++++++---- ...explicit_extension_this_property_test.dart | 244 +++++++++++---- ..._explicit_this_property_disabled_test.dart | 220 ++++++++++---- ...ssignment_explicit_this_property_test.dart | 244 +++++++++++---- ..._explicit_this_property_disabled_test.dart | 220 ++++++++++---- ...extension_explicit_this_property_test.dart | 244 +++++++++++---- ..._implicit_this_property_disabled_test.dart | 220 ++++++++++---- ...extension_implicit_this_property_test.dart | 244 +++++++++++---- ...ension_index_expression_disabled_test.dart | 229 ++++++++++---- ...licit_extension_index_expression_test.dart | 253 ++++++++++++---- ..._aware_index_expression_disabled_test.dart | 248 ++++++++++----- ...sion_null_aware_index_expression_test.dart | 276 ++++++++++++----- ...ion_null_aware_property_disabled_test.dart | 248 ++++++++++----- ...it_extension_null_aware_property_test.dart | 276 ++++++++++++----- ...icit_extension_property_disabled_test.dart | 229 ++++++++++---- ...ment_implicit_extension_property_test.dart | 253 ++++++++++++---- ..._implicit_this_property_disabled_test.dart | 220 ++++++++++---- ...ssignment_implicit_this_property_test.dart | 244 +++++++++++---- ...gnment_index_expression_disabled_test.dart | 229 ++++++++++---- ...null_assignment_index_expression_test.dart | 253 ++++++++++++---- ...f_null_assignment_local_disabled_test.dart | 260 +++++++++++----- .../if_null_assignment_local_test.dart | 284 +++++++++++++----- ..._aware_index_expression_disabled_test.dart | 248 ++++++++++----- ...ment_null_aware_index_expression_test.dart | 276 ++++++++++++----- ...ent_null_aware_property_disabled_test.dart | 248 ++++++++++----- ...l_assignment_null_aware_property_test.dart | 276 ++++++++++++----- ...ull_assignment_property_disabled_test.dart | 229 ++++++++++---- .../if_null_assignment_property_test.dart | 253 ++++++++++++---- ...ignment_static_property_disabled_test.dart | 229 ++++++++++---- ..._null_assignment_static_property_test.dart | 253 ++++++++++++---- ..._super_index_expression_disabled_test.dart | 240 +++++++++++---- ...ssignment_super_index_expression_test.dart | 261 +++++++++++----- ...signment_super_property_disabled_test.dart | 220 ++++++++++---- ...f_null_assignment_super_property_test.dart | 244 +++++++++++---- ...t_this_index_expression_disabled_test.dart | 240 +++++++++++---- ...assignment_this_index_expression_test.dart | 261 +++++++++++----- ...ment_top_level_property_disabled_test.dart | 229 ++++++++++---- ...ll_assignment_top_level_property_test.dart | 253 ++++++++++++---- .../if_null_disabled_test.dart | 120 ++++++-- .../inference_update_3/if_null_test.dart | 145 ++++++--- .../switch_expression_disabled_test.dart | 115 +++++-- .../switch_expression_test.dart | 139 +++++++-- 52 files changed, 8915 insertions(+), 3190 deletions(-) diff --git a/tests/language/inference_update_3/conditional_expression_disabled_test.dart b/tests/language/inference_update_3/conditional_expression_disabled_test.dart index 18879243247..0ec56e6e2b4 100644 --- a/tests/language/inference_update_3/conditional_expression_disabled_test.dart +++ b/tests/language/inference_update_3/conditional_expression_disabled_test.dart @@ -16,11 +16,11 @@ import '../static_type_helper.dart'; Object? contextIterable(Iterable x) => x; test(bool b) { - // - A conditional expression `E` of the form `b ? e1 : e2` with context type - // `K` is analyzed as follows: + // - A conditional expression `e` of the form `b ? e1 : e2` with context type + // K is analyzed as follows: // - // - Let `T1` be the type of `e1` inferred with context type `K`. - // - Let `T2` be the type of `e2` inferred with context type `K`. + // - Let T1 be the type of `e1` inferred with context type K. + // - Let T2 be the type of `e2` inferred with context type K. { // Check the context type of `e1` and `e2`: // - Where the context is established using a function call argument. @@ -29,7 +29,8 @@ test(bool b) { : (contextType('')..expectStaticType>())); // - Where the context is established using local variable promotion. - var o = '' as Object?; + Object? o; + o = '' as Object?; if (o is String) { o = b ? (contextType('')..expectStaticType>()) @@ -37,62 +38,123 @@ test(bool b) { } } - // - Let `T` be `UP(T1, T2)`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(T1, T2). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int, and T2=double, therefore T=num and S=Object, so T <: S, - // and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int + // - T2 = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var i = 1; var d = 2.0; context((b ? i : d)..expectStaticType>()); - // K=Iterable<_>, T1=Iterable, and T2=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable + // - T2 = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableInt = [] as Iterable; var iterableDouble = [] as Iterable; contextIterable((b ? iterableInt : iterableDouble) ..expectStaticType>>()); } - // - Otherwise, if `T1 <: S` and `T2 <: S`, then the type of `E` is `S` if - // `inference-update-3` is enabled, else the type of `E` is `T`. + // - Otherwise, if T1 <: S and T2 <: S, and `inference-update-3` is enabled, + // then the type of `e` is S. { - // K=Iterable, T1=Iterable, and T2=List, therefore T=Object - // and S=Iterable, so T is not <: S, but T1 <: S and T2 <: S, hence the - // type of E is Object. + // This example has: + // - K = Iterable + // - T1 = Iterable + // - T2 = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T [] as Iterable; var listNum = []; - var o = [0] as Object?; + Object? o; + o = [0] as Object?; if (o is Iterable) { // We avoid having a compile-time error because `o` can be demoted. o = (b ? iterableInt : listNum)..expectStaticType>(); } } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var i = 1; - var o = '' as Object?; + Object? o; var d = 2.0; + o = '' as Object?; if (o is String?) { - // K=String?, T1=Null, and T2=int, therefore T=int? and S=String?, so T is - // not <: S. T1 <: S, but T2 is not <: S. Hence the type of E is int?. + // This example has: + // - K = String? + // - T1 = Null + // - T2 = int + // Which implies: + // - T = int? + // - S = String? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int, and T2=Null, therefore T=int? and S=String?, so T is - // not <: S. T2 <: S, but T1 is not <: S. Hence the type of E is int?. + // This example has: + // - K = String? + // - T1 = int + // - T2 = Null + // Which implies: + // - T = int? + // - S = String? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int, and T2=double, therefore T=num and S=String?, so - // none of T, T1, nor T2 are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int + // - T2 = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } diff --git a/tests/language/inference_update_3/conditional_expression_test.dart b/tests/language/inference_update_3/conditional_expression_test.dart index edcfe6e4835..7bd58ba21a4 100644 --- a/tests/language/inference_update_3/conditional_expression_test.dart +++ b/tests/language/inference_update_3/conditional_expression_test.dart @@ -29,11 +29,11 @@ class C2 implements B1, B2 {} Object? contextB1(B1 x) => x; test(bool b) { - // - A conditional expression `E` of the form `b ? e1 : e2` with context type - // `K` is analyzed as follows: + // - A conditional expression `e` of the form `b ? e1 : e2` with context type + // K is analyzed as follows: // - // - Let `T1` be the type of `e1` inferred with context type `K`. - // - Let `T2` be the type of `e2` inferred with context type `K`. + // - Let T1 be the type of `e1` inferred with context type K. + // - Let T2 be the type of `e2` inferred with context type K. { // Check the context type of `e1` and `e2`: // - Where the context is established using a function call argument. @@ -42,7 +42,8 @@ test(bool b) { : (contextType('')..expectStaticType>())); // - Where the context is established using local variable promotion. - var o = '' as Object?; + Object? o; + o = '' as Object?; if (o is String) { o = b ? (contextType('')..expectStaticType>()) @@ -50,71 +51,148 @@ test(bool b) { } } - // - Let `T` be `UP(T1, T2)`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(T1, T2). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int, and T2=double, therefore T=num and S=Object, so T <: S, - // and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int + // - T2 = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var i = 1; var d = 2.0; context((b ? i : d)..expectStaticType>()); - // K=Iterable<_>, T1=Iterable, and T2=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable + // - T2 = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableInt = [] as Iterable; var iterableDouble = [] as Iterable; contextIterable((b ? iterableInt : iterableDouble) ..expectStaticType>>()); } - // - Otherwise, if `T1 <: S` and `T2 <: S`, then the type of `E` is `S`. + // - Otherwise, if T1 <: S and T2 <: S, then the type of `e` is S. { - // K=B1<_>, T1=C1, and T2=C2, therefore T=A and S=B1, - // so T is not <: S, but T1 <: S and T2 <: S, hence the type of E is - // B1. + // This example has: + // - K = B1<_> + // - T1 = C1 + // - T2 = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . var c1Int = C1(); var c2Double = C2(); contextB1((b ? c1Int : c2Double)..expectStaticType>>()); - // K=B1, T1=C1, and T2=C2, therefore T=A and - // S=B1, so T is not <: S, but T1 <: S and T2 <: S, hence the type - // of E is B1. + // This example has: + // - K = B1 + // - T1 = C1 + // - T2 = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . contextB1( (b ? c1Int : c2Double)..expectStaticType>>()); - // K=Iterable, T1=Iterable, and T2=List, therefore T=Object - // and S=Iterable, so T is not <: S, but T1 <: S and T2 <: S, hence the - // type of E is Iterable. + // This example has: + // - K = Iterable + // - T1 = Iterable + // - T2 = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T . var iterableInt = [] as Iterable; var listNum = []; context>((b ? iterableInt : listNum) ..expectStaticType>>()); } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var i = 1; - var o = '' as Object?; + Object? o; var d = 2.0; + o = '' as Object?; if (o is String?) { - // K=String?, T1=Null, and T2=int, therefore T=int? and S=String?, so T is - // not <: S. T1 <: S, but T2 is not <: S. Hence the type of E is int?. + // This example has: + // - K = String? + // - T1 = Null + // - T2 = int + // Which implies: + // - T = int? + // - S = String? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int, and T2=Null, therefore T=int? and S=String?, so T is - // not <: S. T2 <: S, but T1 is not <: S. Hence the type of E is int?. + // This example has: + // - K = String? + // - T1 = int + // - T2 = Null + // Which implies: + // - T = int? + // - S = String? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int, and T2=double, therefore T=num and S=String?, so - // none of T, T1, nor T2 are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int + // - T2 = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } diff --git a/tests/language/inference_update_3/if_null_assignment_explicit_extension_index_expression_disabled_test.dart b/tests/language/inference_update_3/if_null_assignment_explicit_extension_index_expression_disabled_test.dart index f8f1121d2c2..6d4f3226c49 100644 --- a/tests/language/inference_update_3/if_null_assignment_explicit_extension_index_expression_disabled_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_explicit_extension_index_expression_disabled_test.dart @@ -48,18 +48,18 @@ extension Extension on Indexable { } main() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -70,62 +70,106 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T <: - // S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context((Extension(Indexable(null))[0] ??= d) ..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((Extension(Indexable?, Object?>(null))[0] ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((Extension(Indexable(null))[0] ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S` if `inference-update-3` is enabled, else the type of `E` is `T`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, and `inference-update-3` + // is enabled, then the type of `e` is S. { - // K=Iterable, T1=Iterable?, and T2'=List, therefore T=Object - // and S=Iterable, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is Object. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T []; - var o = [0] as Object?; + Object? o; + o = [0] as Object?; if (o is Iterable) { // We avoid having a compile-time error because `o` can be demoted. o = (Extension(Indexable?, Object?>(null))[0] ??= listNum) ..expectStaticType>(); } - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function(), so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is A Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T >(); o = (() => B1()) as Object?; if (o is B1 Function()) { @@ -136,32 +180,65 @@ main() { } } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T (null))[0] ??= d) ..expectStaticType>(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T (null))[0] ??= intQuestion) ..expectStaticType>(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T (null))[0] ??= d) ..expectStaticType>(); @@ -170,10 +247,20 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T Function()?, Function?>(null))[0] ??= callableClassC2Int) @@ -182,10 +269,20 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T Function()?, Function?>(null))[0] ??= callableClassC2Int) @@ -194,10 +291,20 @@ main() { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced from - // T2=CallableClass>), therefore T=A Function() and S=int, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T Function()?, Function?>(null))[0] ??= callableClassC2Int) diff --git a/tests/language/inference_update_3/if_null_assignment_explicit_extension_index_expression_test.dart b/tests/language/inference_update_3/if_null_assignment_explicit_extension_index_expression_test.dart index 869b6fe1efb..a7f41e09870 100644 --- a/tests/language/inference_update_3/if_null_assignment_explicit_extension_index_expression_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_explicit_extension_index_expression_test.dart @@ -51,18 +51,18 @@ extension Extension on Indexable { } main() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -73,73 +73,131 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T <: - // S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context((Extension(Indexable(null))[0] ??= d) ..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((Extension(Indexable?, Object?>(null))[0] ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((Extension(Indexable(null))[0] ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, then the type of `e` is S. { - // K=B1<_>, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1. + // This example has: + // - K = B1<_> + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . var c2Double = C2(); contextB1((Extension(Indexable?, Object?>(null))[0] ??= c2Double) ..expectStaticType>>()); - // K=B1, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1. + // This example has: + // - K = B1 + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . contextB1((Extension(Indexable?, Object?>(null))[0] ??= c2Double) ..expectStaticType>>()); - // K=Iterable, T1=Iterable?, and T2'=List, therefore T=Object - // and S=Iterable, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is Iterable. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T . var listNum = []; context>( (Extension(Indexable?, Object?>(null))[0] ??= listNum) ..expectStaticType>>()); - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function(), so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is B1 Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T Function(). var callableClassC2Int = CallableClass>(); context Function()>( (Extension(Indexable Function()?, Function?>(null))[0] ??= @@ -147,32 +205,65 @@ main() { ..expectStaticType Function()>>()); } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T (null))[0] ??= d) ..expectStaticType>(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T (null))[0] ??= intQuestion) ..expectStaticType>(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T (null))[0] ??= d) ..expectStaticType>(); @@ -181,10 +272,20 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T Function()?, Function?>(null))[0] ??= callableClassC2Int) @@ -193,10 +294,20 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T Function()?, Function?>(null))[0] ??= callableClassC2Int) @@ -205,10 +316,20 @@ main() { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced from - // T2=CallableClass>), therefore T=A Function() and S=int, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T Function()?, Function?>(null))[0] ??= callableClassC2Int) diff --git a/tests/language/inference_update_3/if_null_assignment_explicit_extension_null_aware_index_expression_disabled_test.dart b/tests/language/inference_update_3/if_null_assignment_explicit_extension_null_aware_index_expression_disabled_test.dart index 223eeb02a57..8e7b318d058 100644 --- a/tests/language/inference_update_3/if_null_assignment_explicit_extension_null_aware_index_expression_disabled_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_explicit_extension_null_aware_index_expression_disabled_test.dart @@ -52,18 +52,18 @@ Indexable? maybeIndexable( Indexable(value); main() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -74,42 +74,65 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object?, T1=int?, and T2'=double, therefore T=num and S=Object?, so T - // <: S, and hence the type of E is num (which becomes num? after null - // shorting completes). + // This example has: + // - K = Object? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object? + // We have: + // - T <: S + // Therefore the type of `e` is T = num. + // (Which becomes num? after null shorting completes.) var d = 2.0; context((Extension(maybeIndexable(null))?[0] ??= d) ..expectStaticType>()); - // K=Iterable<_>?, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable?, so T <: S, and hence the type - // of E is Iterable (which becomes Iterable? after null shorting - // completes). + // This example has: + // - K = Iterable<_>? + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable? + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. + // (Which becomes Iterable? after null shorting completes.) var iterableDouble = [] as Iterable; contextIterableQuestion( (Extension(maybeIndexable?, Object?>(null))?[0] ??= iterableDouble) ..expectStaticType?>>()); - // K=Function?, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function?, so T <: S, - // and hence the type of E is Function (which becomes Function? after null - // shorting completes). + // This example has: + // - K = Function? + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function? + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. + // (Which becomes Function? after null shorting completes.) var callableClassInt = CallableClass(); context( (Extension(maybeIndexable(null))?[0] ??= @@ -117,15 +140,26 @@ main() { ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S` if `inference-update-3` is enabled, else the type of `E` is `T`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, and `inference-update-3` + // is enabled, then the type of `e` is S. { - // K=Iterable?, T1=Iterable?, and T2'=List, therefore - // T=Object and S=Iterable?, so T is not <: S, but NonNull(T1) <: S and - // T2' <: S, hence the type of E is Object (which becomes Object? after null - // shorting completes). + // This example has: + // - K = Iterable? + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable? + // We have: + // - T []; - var o = [0] as Object?; + Object? o; + o = [0] as Object?; if (o is Iterable?) { // We avoid having a compile-time error because `o` can be demoted. o = (Extension(maybeIndexable?, Object?>(null))?[0] ??= @@ -133,11 +167,21 @@ main() { ..expectStaticType>(); } - // K=B1 Function()?, T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function()?, so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is A Function() (which becomes A Function()? after - // null shorting completes). + // This example has: + // - K = B1 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function()? + // We have: + // - T >(); o = (() => B1()) as Object?; if (o is B1 Function()?) { @@ -148,24 +192,46 @@ main() { } } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num (which becomes num? after null shorting completes). + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T (null))?[0] ??= d) ..expectStaticType>(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T (null))?[0] ??= intQuestion) @@ -173,9 +239,21 @@ main() { } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num - // (which becomes num? after null shorting completes). + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T (null))?[0] ??= d) ..expectStaticType>(); @@ -184,11 +262,21 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()?) { - // K=C1 Function()?, T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function()?, so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function() (which - // becomes A Function()? after null shorting completes). + // This example has: + // - K = C1 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function()? + // We have: + // - T Function()?, Function?>(null))?[ 0] ??= callableClassC2Int) @@ -197,11 +285,21 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()?) { - // K=C2 Function()?, T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function()?, so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function() (which - // becomes A Function()? after null shorting completes). + // This example has: + // - K = C2 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function()? + // We have: + // - T Function()?, Function?>(null))?[ 0] ??= callableClassC2Int) @@ -210,11 +308,21 @@ main() { o = 0 as Object?; if (o is int?) { - // K=int?, T1=C1 Function()?, and T2'=C2 Function() (coerced - // from T2=CallableClass>), therefore T=A Function() and S=int?, - // so T is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type - // of E is A Function() (which becomes A Function()? after null shorting - // completes). + // This example has: + // - K = int? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int? + // We have: + // - T Function()?, Function?>(null))?[ 0] ??= callableClassC2Int) diff --git a/tests/language/inference_update_3/if_null_assignment_explicit_extension_null_aware_index_expression_test.dart b/tests/language/inference_update_3/if_null_assignment_explicit_extension_null_aware_index_expression_test.dart index 73738340615..e86077eff4d 100644 --- a/tests/language/inference_update_3/if_null_assignment_explicit_extension_null_aware_index_expression_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_explicit_extension_null_aware_index_expression_test.dart @@ -55,18 +55,18 @@ Indexable? maybeIndexable( Indexable(value); main() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -77,42 +77,65 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object?, T1=int?, and T2'=double, therefore T=num and S=Object?, so T - // <: S, and hence the type of E is num (which becomes num? after null - // shorting completes). + // This example has: + // - K = Object? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object? + // We have: + // - T <: S + // Therefore the type of `e` is T = num. + // (Which becomes num? after null shorting completes.) var d = 2.0; context((Extension(maybeIndexable(null))?[0] ??= d) ..expectStaticType>()); - // K=Iterable<_>?, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable?, so T <: S, and hence the type - // of E is Iterable (which becomes Iterable? after null shorting - // completes). + // This example has: + // - K = Iterable<_>? + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable? + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. + // (Which becomes Iterable? after null shorting completes.) var iterableDouble = [] as Iterable; contextIterableQuestion( (Extension(maybeIndexable?, Object?>(null))?[0] ??= iterableDouble) ..expectStaticType?>>()); - // K=Function?, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function?, so T <: S, - // and hence the type of E is Function (which becomes Function? after null - // shorting completes). + // This example has: + // - K = Function? + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function? + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. + // (Which becomes Function? after null shorting completes.) var callableClassInt = CallableClass(); context( (Extension(maybeIndexable(null))?[0] ??= @@ -120,41 +143,76 @@ main() { ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, then the type of `e` is S. { - // K=B1<_>?, T1=C1?, and T2'=C2, therefore T=A and - // S=B1?, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is B1 (which becomes B1? after null - // shorting completes). + // This example has: + // - K = B1<_>? + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1? + // We have: + // - T . + // (Which becomes B1? after null shorting completes.) var c2Double = C2(); contextB1Question( (Extension(maybeIndexable?, Object?>(null))?[0] ??= c2Double) ..expectStaticType?>>()); - // K=B1?, T1=C1?, and T2'=C2, therefore T=A and - // S=B1?, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1 (which becomes B1? after null - // shorting completes). + // This example has: + // - K = B1? + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1? + // We have: + // - T . + // (Which becomes B1? after null shorting completes.) contextB1Question( (Extension(maybeIndexable?, Object?>(null))?[0] ??= c2Double) ..expectStaticType?>>()); - // K=Iterable?, T1=Iterable?, and T2'=List, therefore - // T=Object and S=Iterable?, so T is not <: S, but NonNull(T1) <: S and - // T2' <: S, hence the type of E is Iterable (which becomes - // Iterable? after null shorting completes). + // This example has: + // - K = Iterable? + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable? + // We have: + // - T . + // (Which becomes Iterable? after null shorting completes.) var listNum = []; context?>( (Extension(maybeIndexable?, Object?>(null))?[0] ??= listNum) ..expectStaticType?>>()); - // K=B1 Function()?, T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function()?, so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is B1 Function() (which becomes B1 - // Function()? after null shorting completes). + // This example has: + // - K = B1 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function()? + // We have: + // - T Function(). + // (Which becomes B1 Function()? after null shorting completes.) var callableClassC2Int = CallableClass>(); context Function()?>( (Extension(maybeIndexable Function()?, Function?>(null))?[0] ??= @@ -162,24 +220,46 @@ main() { ..expectStaticType Function()?>>()); } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num (which becomes num? after null shorting completes). + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T (null))?[0] ??= d) ..expectStaticType>(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T (null))?[0] ??= intQuestion) @@ -187,9 +267,21 @@ main() { } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num - // (which becomes num? after null shorting completes). + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T (null))?[0] ??= d) ..expectStaticType>(); @@ -198,11 +290,21 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()?) { - // K=C1 Function()?, T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function()?, so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function() (which - // becomes A Function()? after null shorting completes). + // This example has: + // - K = C1 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function()? + // We have: + // - T Function()?, Function?>(null))?[ 0] ??= callableClassC2Int) @@ -211,11 +313,21 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()?) { - // K=C2 Function()?, T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function()?, so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function() (which - // becomes A Function()? after null shorting completes). + // This example has: + // - K = C2 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function()? + // We have: + // - T Function()?, Function?>(null))?[ 0] ??= callableClassC2Int) @@ -224,11 +336,21 @@ main() { o = 0 as Object?; if (o is int?) { - // K=int?, T1=C1 Function()?, and T2'=C2 Function() (coerced - // from T2=CallableClass>), therefore T=A Function() and S=int?, - // so T is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type - // of E is A Function() (which becomes A Function()? after null shorting - // completes). + // This example has: + // - K = int? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int? + // We have: + // - T Function()?, Function?>(null))?[ 0] ??= callableClassC2Int) diff --git a/tests/language/inference_update_3/if_null_assignment_explicit_extension_null_aware_property_disabled_test.dart b/tests/language/inference_update_3/if_null_assignment_explicit_extension_null_aware_property_disabled_test.dart index db6289fdfb7..8ccc86a401d 100644 --- a/tests/language/inference_update_3/if_null_assignment_explicit_extension_null_aware_property_disabled_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_explicit_extension_null_aware_property_disabled_test.dart @@ -56,18 +56,18 @@ extension Extension on String { main() { var s = '' as String?; - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -78,66 +78,110 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object?, T1=int?, and T2'=double, therefore T=num and S=Object?, so T - // <: S, and hence the type of E is num (which becomes num? after null - // shorting completes). + // This example has: + // - K = Object? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object? + // We have: + // - T <: S + // Therefore the type of `e` is T = num. + // (Which becomes num? after null shorting completes.) var d = 2.0; context( (Extension(s)?.pIntQuestion ??= d)..expectStaticType>()); - // K=Iterable<_>?, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable?, so T <: S, and hence the type - // of E is Iterable (which becomes Iterable? after null shorting - // completes). + // This example has: + // - K = Iterable<_>? + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable? + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. + // (Which becomes Iterable? after null shorting completes.) var iterableDouble = [] as Iterable; contextIterableQuestion((Extension(s)?.pIterableIntQuestion ??= iterableDouble) ..expectStaticType?>>()); - // K=Function?, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function?, so T <: S, - // and hence the type of E is Function (which becomes Function? after null - // shorting completes). + // This example has: + // - K = Function? + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function? + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. + // (Which becomes Function? after null shorting completes.) var callableClassInt = CallableClass(); context((Extension(s)?.pFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S` if `inference-update-3` is enabled, else the type of `E` is `T`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, and `inference-update-3` + // is enabled, then the type of `e` is S. { - // K=Iterable?, T1=Iterable?, and T2'=List, therefore - // T=Object and S=Iterable?, so T is not <: S, but NonNull(T1) <: S and - // T2' <: S, hence the type of E is Object (which becomes Object? after null - // shorting completes). + // This example has: + // - K = Iterable? + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable? + // We have: + // - T []; - var o = [0] as Object?; + Object? o; + o = [0] as Object?; if (o is Iterable?) { // We avoid having a compile-time error because `o` can be demoted. o = (Extension(s)?.pIterableIntQuestion ??= listNum) ..expectStaticType>(); } - // K=B1 Function()?, T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function()?, so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is A Function() (which becomes A Function()? after - // null shorting completes). + // This example has: + // - K = B1 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function()? + // We have: + // - T >(); o = (() => B1()) as Object?; if (o is B1 Function()?) { @@ -147,32 +191,66 @@ main() { } } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num (which becomes num? after null shorting completes). + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num - // (which becomes num? after null shorting completes). + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -180,11 +258,21 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()?) { - // K=C1 Function()?, T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function()?, so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function() (which - // becomes A Function()? after null shorting completes). + // This example has: + // - K = C1 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function()? + // We have: + // - T >(); @@ -192,11 +280,21 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()?) { - // K=C2 Function()?, T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function()?, so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function() (which - // becomes A Function()? after null shorting completes). + // This example has: + // - K = C2 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function()? + // We have: + // - T >(); @@ -204,11 +302,21 @@ main() { o = 0 as Object?; if (o is int?) { - // K=int?, T1=C1 Function()?, and T2'=C2 Function() (coerced - // from T2=CallableClass>), therefore T=A Function() and S=int?, - // so T is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type - // of E is A Function() (which becomes A Function()? after null shorting - // completes). + // This example has: + // - K = int? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int? + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_explicit_extension_null_aware_property_test.dart b/tests/language/inference_update_3/if_null_assignment_explicit_extension_null_aware_property_test.dart index ac11279db92..b4210b8cf7d 100644 --- a/tests/language/inference_update_3/if_null_assignment_explicit_extension_null_aware_property_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_explicit_extension_null_aware_property_test.dart @@ -61,18 +61,18 @@ extension Extension on String { main() { var s = '' as String?; - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -83,109 +83,201 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object?, T1=int?, and T2'=double, therefore T=num and S=Object?, so T - // <: S, and hence the type of E is num (which becomes num? after null - // shorting completes). + // This example has: + // - K = Object? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object? + // We have: + // - T <: S + // Therefore the type of `e` is T = num. + // (Which becomes num? after null shorting completes.) var d = 2.0; context( (Extension(s)?.pIntQuestion ??= d)..expectStaticType>()); - // K=Iterable<_>?, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable?, so T <: S, and hence the type - // of E is Iterable (which becomes Iterable? after null shorting - // completes). + // This example has: + // - K = Iterable<_>? + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable? + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. + // (Which becomes Iterable? after null shorting completes.) var iterableDouble = [] as Iterable; contextIterableQuestion((Extension(s)?.pIterableIntQuestion ??= iterableDouble) ..expectStaticType?>>()); - // K=Function?, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function?, so T <: S, - // and hence the type of E is Function (which becomes Function? after null - // shorting completes). + // This example has: + // - K = Function? + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function? + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. + // (Which becomes Function? after null shorting completes.) var callableClassInt = CallableClass(); context((Extension(s)?.pFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, then the type of `e` is S. { - // K=B1<_>?, T1=C1?, and T2'=C2, therefore T=A and - // S=B1?, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is B1 (which becomes B1? after null - // shorting completes). + // This example has: + // - K = B1<_>? + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1? + // We have: + // - T . + // (Which becomes B1? after null shorting completes.) var c2Double = C2(); contextB1Question((Extension(s)?.pC1IntQuestion ??= c2Double) ..expectStaticType?>>()); - // K=B1?, T1=C1?, and T2'=C2, therefore T=A and - // S=B1?, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1 (which becomes B1? after null - // shorting completes). + // This example has: + // - K = B1? + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1? + // We have: + // - T . + // (Which becomes B1? after null shorting completes.) contextB1Question((Extension(s)?.pC1IntQuestion ??= c2Double) ..expectStaticType?>>()); - // K=Iterable?, T1=Iterable?, and T2'=List, therefore - // T=Object and S=Iterable?, so T is not <: S, but NonNull(T1) <: S and - // T2' <: S, hence the type of E is Iterable (which becomes - // Iterable? after null shorting completes). + // This example has: + // - K = Iterable? + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable? + // We have: + // - T . + // (Which becomes Iterable? after null shorting completes.) var listNum = []; context?>((Extension(s)?.pIterableIntQuestion ??= listNum) ..expectStaticType?>>()); - // K=B1 Function()?, T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function()?, so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is B1 Function() (which becomes B1 - // Function()? after null shorting completes). + // This example has: + // - K = B1 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function()? + // We have: + // - T Function(). + // (Which becomes B1 Function()? after null shorting completes.) var callableClassC2Int = CallableClass>(); context Function()?>((Extension(s)?.pC1IntFunctionQuestion ??= callableClassC2Int) ..expectStaticType Function()?>>()); } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num (which becomes num? after null shorting completes). + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num - // (which becomes num? after null shorting completes). + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -193,11 +285,21 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()?) { - // K=C1 Function()?, T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function()?, so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function() (which - // becomes A Function()? after null shorting completes). + // This example has: + // - K = C1 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function()? + // We have: + // - T >(); @@ -205,11 +307,21 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()?) { - // K=C2 Function()?, T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function()?, so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function() (which - // becomes A Function()? after null shorting completes). + // This example has: + // - K = C2 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function()? + // We have: + // - T >(); @@ -217,11 +329,21 @@ main() { o = 0 as Object?; if (o is int?) { - // K=int?, T1=C1 Function()?, and T2'=C2 Function() (coerced - // from T2=CallableClass>), therefore T=A Function() and S=int?, - // so T is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type - // of E is A Function() (which becomes A Function()? after null shorting - // completes). + // This example has: + // - K = int? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int? + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_explicit_extension_property_disabled_test.dart b/tests/language/inference_update_3/if_null_assignment_explicit_extension_property_disabled_test.dart index 165c700f75a..bdb78ccba9a 100644 --- a/tests/language/inference_update_3/if_null_assignment_explicit_extension_property_disabled_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_explicit_extension_property_disabled_test.dart @@ -54,18 +54,18 @@ extension Extension on String { } main() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -76,60 +76,104 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T <: - // S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context( (Extension('').pIntQuestion ??= d)..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((Extension('').pIterableIntQuestion ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((Extension('').pFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S` if `inference-update-3` is enabled, else the type of `E` is `T`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, and `inference-update-3` + // is enabled, then the type of `e` is S. { - // K=Iterable, T1=Iterable?, and T2'=List, therefore T=Object - // and S=Iterable, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is Object. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T []; - var o = [0] as Object?; + Object? o; + o = [0] as Object?; if (o is Iterable) { // We avoid having a compile-time error because `o` can be demoted. o = (Extension('').pIterableIntQuestion ??= listNum) ..expectStaticType>(); } - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function(), so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is A Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T >(); o = (() => B1()) as Object?; if (o is B1 Function()) { @@ -139,31 +183,64 @@ main() { } } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -171,10 +248,20 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T >(); @@ -182,10 +269,20 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T >(); @@ -193,10 +290,20 @@ main() { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced from - // T2=CallableClass>), therefore T=A Function() and S=int, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_explicit_extension_property_test.dart b/tests/language/inference_update_3/if_null_assignment_explicit_extension_property_test.dart index 475055be400..950afbde759 100644 --- a/tests/language/inference_update_3/if_null_assignment_explicit_extension_property_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_explicit_extension_property_test.dart @@ -59,18 +59,18 @@ extension Extension on String { } main() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -81,100 +81,191 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T <: - // S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context( (Extension('').pIntQuestion ??= d)..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((Extension('').pIterableIntQuestion ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((Extension('').pFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, then the type of `e` is S. { - // K=B1<_>, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1. + // This example has: + // - K = B1<_> + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . var c2Double = C2(); contextB1((Extension('').pC1IntQuestion ??= c2Double) ..expectStaticType>>()); - // K=B1, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1. + // This example has: + // - K = B1 + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . contextB1((Extension('').pC1IntQuestion ??= c2Double) ..expectStaticType>>()); - // K=Iterable, T1=Iterable?, and T2'=List, therefore T=Object - // and S=Iterable, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is Iterable. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T . var listNum = []; context>((Extension('').pIterableIntQuestion ??= listNum) ..expectStaticType>>()); - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function(), so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is B1 Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T Function(). var callableClassC2Int = CallableClass>(); context Function()>((Extension('').pC1IntFunctionQuestion ??= callableClassC2Int) ..expectStaticType Function()>>()); } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -182,10 +273,20 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T >(); @@ -193,10 +294,20 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T >(); @@ -204,10 +315,20 @@ main() { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced from - // T2=CallableClass>), therefore T=A Function() and S=int, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_explicit_extension_this_property_disabled_test.dart b/tests/language/inference_update_3/if_null_assignment_explicit_extension_this_property_disabled_test.dart index 078f3dece53..843664e0654 100644 --- a/tests/language/inference_update_3/if_null_assignment_explicit_extension_this_property_disabled_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_explicit_extension_this_property_disabled_test.dart @@ -53,15 +53,15 @@ extension Extension on String { set pStringQuestion(String? value) {} test() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K // is analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that + // - Otherwise, J is the write type `e1`. This is the type schema that // the setter associated with `e1` imposes on its single argument (or, // for the case of indexed assignment, the type schema that // `operator[]=` imposes on its second argument). @@ -75,61 +75,104 @@ extension Extension on String { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T - // <: S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context((Extension(this).pIntQuestion ??= d) ..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type - // of E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((Extension(this).pIterableIntQuestion ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((Extension(this).pFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S` if `inference-update-3` is enabled, else the type of `E` is - // `T`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, and `inference-update-3` + // is enabled, then the type of `e` is S. { - // K=Iterable, T1=Iterable?, and T2'=List, therefore - // T=Object and S=Iterable, so T is not <: S, but NonNull(T1) <: S - // and T2' <: S, hence the type of E is Object. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T []; - var o = [0] as Object?; + Object? o; + o = [0] as Object?; if (o is Iterable) { // We avoid having a compile-time error because `o` can be demoted. o = (Extension(this).pIterableIntQuestion ??= listNum) ..expectStaticType>(); } - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=B1 Function(), so T is not <: S, but NonNull(T1) - // <: S and T2' <: S, hence the type of E is A Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T >(); o = (() => B1()) as Object?; if (o is B1 Function()) { @@ -139,32 +182,65 @@ extension Extension on String { } } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E - // is num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T - // is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of - // E is num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); @@ -173,10 +249,20 @@ extension Extension on String { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T >(); @@ -184,10 +270,20 @@ extension Extension on String { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T >(); @@ -195,10 +291,20 @@ extension Extension on String { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced - // from T2=CallableClass>), therefore T=A Function() and S=int, - // so T is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the - // type of E is A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_explicit_extension_this_property_test.dart b/tests/language/inference_update_3/if_null_assignment_explicit_extension_this_property_test.dart index e0c7de16bb5..33d7e78e6b0 100644 --- a/tests/language/inference_update_3/if_null_assignment_explicit_extension_this_property_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_explicit_extension_this_property_test.dart @@ -58,15 +58,15 @@ extension Extension on String { set pStringQuestion(String? value) {} test() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K // is analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that + // - Otherwise, J is the write type `e1`. This is the type schema that // the setter associated with `e1` imposes on its single argument (or, // for the case of indexed assignment, the type schema that // `operator[]=` imposes on its second argument). @@ -80,101 +80,193 @@ extension Extension on String { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T - // <: S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context((Extension(this).pIntQuestion ??= d) ..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type - // of E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((Extension(this).pIterableIntQuestion ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((Extension(this).pFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, then the type of `e` is + // S. { - // K=B1<_>, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is B1. + // This example has: + // - K = B1<_> + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . var c2Double = C2(); contextB1((Extension(this).pC1IntQuestion ??= c2Double) ..expectStaticType>>()); - // K=B1, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is B1. + // This example has: + // - K = B1 + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . contextB1((Extension(this).pC1IntQuestion ??= c2Double) ..expectStaticType>>()); - // K=Iterable, T1=Iterable?, and T2'=List, therefore - // T=Object and S=Iterable, so T is not <: S, but NonNull(T1) <: S - // and T2' <: S, hence the type of E is Iterable. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T . var listNum = []; context>((Extension(this).pIterableIntQuestion ??= listNum) ..expectStaticType>>()); - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=B1 Function(), so T is not <: S, but NonNull(T1) - // <: S and T2' <: S, hence the type of E is B1 Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T Function(). var callableClassC2Int = CallableClass>(); context Function()>((Extension(this).pC1IntFunctionQuestion ??= callableClassC2Int) ..expectStaticType Function()>>()); } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E - // is num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T - // is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of - // E is num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); @@ -183,10 +275,20 @@ extension Extension on String { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T >(); @@ -194,10 +296,20 @@ extension Extension on String { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T >(); @@ -205,10 +317,20 @@ extension Extension on String { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced - // from T2=CallableClass>), therefore T=A Function() and S=int, - // so T is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the - // type of E is A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_explicit_this_property_disabled_test.dart b/tests/language/inference_update_3/if_null_assignment_explicit_this_property_disabled_test.dart index 7d3c01d60d2..3ca3d0136e1 100644 --- a/tests/language/inference_update_3/if_null_assignment_explicit_this_property_disabled_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_explicit_this_property_disabled_test.dart @@ -53,15 +53,15 @@ class Test { set pStringQuestion(String? value) {} test() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K // is analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that + // - Otherwise, J is the write type `e1`. This is the type schema that // the setter associated with `e1` imposes on its single argument (or, // for the case of indexed assignment, the type schema that // `operator[]=` imposes on its second argument). @@ -74,61 +74,104 @@ class Test { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T - // <: S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context( (this.pIntQuestion ??= d)..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type - // of E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((this.pIterableIntQuestion ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((this.pFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S` if `inference-update-3` is enabled, else the type of `E` is - // `T`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, and `inference-update-3` + // is enabled, then the type of `e` is S. { - // K=Iterable, T1=Iterable?, and T2'=List, therefore - // T=Object and S=Iterable, so T is not <: S, but NonNull(T1) <: S - // and T2' <: S, hence the type of E is Object. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T []; - var o = [0] as Object?; + Object? o; + o = [0] as Object?; if (o is Iterable) { // We avoid having a compile-time error because `o` can be demoted. o = (this.pIterableIntQuestion ??= listNum) ..expectStaticType>(); } - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=B1 Function(), so T is not <: S, but NonNull(T1) - // <: S and T2' <: S, hence the type of E is A Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T >(); o = (() => B1()) as Object?; if (o is B1 Function()) { @@ -138,31 +181,64 @@ class Test { } } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E - // is num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T - // is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of - // E is num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -170,10 +246,20 @@ class Test { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T >(); @@ -181,10 +267,20 @@ class Test { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T >(); @@ -192,10 +288,20 @@ class Test { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced - // from T2=CallableClass>), therefore T=A Function() and S=int, - // so T is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the - // type of E is A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_explicit_this_property_test.dart b/tests/language/inference_update_3/if_null_assignment_explicit_this_property_test.dart index 149fb89d59f..b119156911a 100644 --- a/tests/language/inference_update_3/if_null_assignment_explicit_this_property_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_explicit_this_property_test.dart @@ -58,15 +58,15 @@ class Test { set pStringQuestion(String? value) {} test() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K // is analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that + // - Otherwise, J is the write type `e1`. This is the type schema that // the setter associated with `e1` imposes on its single argument (or, // for the case of indexed assignment, the type schema that // `operator[]=` imposes on its second argument). @@ -79,100 +79,192 @@ class Test { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T - // <: S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context( (this.pIntQuestion ??= d)..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type - // of E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((this.pIterableIntQuestion ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((this.pFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, then the type of `e` is + // S. { - // K=B1<_>, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is B1. + // This example has: + // - K = B1<_> + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . var c2Double = C2(); contextB1((this.pC1IntQuestion ??= c2Double) ..expectStaticType>>()); - // K=B1, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is B1. + // This example has: + // - K = B1 + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . contextB1((this.pC1IntQuestion ??= c2Double) ..expectStaticType>>()); - // K=Iterable, T1=Iterable?, and T2'=List, therefore - // T=Object and S=Iterable, so T is not <: S, but NonNull(T1) <: S - // and T2' <: S, hence the type of E is Iterable. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T . var listNum = []; context>((this.pIterableIntQuestion ??= listNum) ..expectStaticType>>()); - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=B1 Function(), so T is not <: S, but NonNull(T1) - // <: S and T2' <: S, hence the type of E is B1 Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T Function(). var callableClassC2Int = CallableClass>(); context Function()>((this.pC1IntFunctionQuestion ??= callableClassC2Int) ..expectStaticType Function()>>()); } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E - // is num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T - // is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of - // E is num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -180,10 +272,20 @@ class Test { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T >(); @@ -191,10 +293,20 @@ class Test { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T >(); @@ -202,10 +314,20 @@ class Test { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced - // from T2=CallableClass>), therefore T=A Function() and S=int, - // so T is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the - // type of E is A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_implicit_extension_explicit_this_property_disabled_test.dart b/tests/language/inference_update_3/if_null_assignment_implicit_extension_explicit_this_property_disabled_test.dart index bc84c2a954d..bd523d18569 100644 --- a/tests/language/inference_update_3/if_null_assignment_implicit_extension_explicit_this_property_disabled_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_implicit_extension_explicit_this_property_disabled_test.dart @@ -53,15 +53,15 @@ extension on String { set pStringQuestion(String? value) {} test() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K // is analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that + // - Otherwise, J is the write type `e1`. This is the type schema that // the setter associated with `e1` imposes on its single argument (or, // for the case of indexed assignment, the type schema that // `operator[]=` imposes on its second argument). @@ -74,61 +74,104 @@ extension on String { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T - // <: S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context( (this.pIntQuestion ??= d)..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type - // of E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((this.pIterableIntQuestion ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((this.pFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S` if `inference-update-3` is enabled, else the type of `E` is - // `T`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, and `inference-update-3` + // is enabled, then the type of `e` is S. { - // K=Iterable, T1=Iterable?, and T2'=List, therefore - // T=Object and S=Iterable, so T is not <: S, but NonNull(T1) <: S - // and T2' <: S, hence the type of E is Object. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T []; - var o = [0] as Object?; + Object? o; + o = [0] as Object?; if (o is Iterable) { // We avoid having a compile-time error because `o` can be demoted. o = (this.pIterableIntQuestion ??= listNum) ..expectStaticType>(); } - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=B1 Function(), so T is not <: S, but NonNull(T1) - // <: S and T2' <: S, hence the type of E is A Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T >(); o = (() => B1()) as Object?; if (o is B1 Function()) { @@ -138,31 +181,64 @@ extension on String { } } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E - // is num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T - // is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of - // E is num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -170,10 +246,20 @@ extension on String { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T >(); @@ -181,10 +267,20 @@ extension on String { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T >(); @@ -192,10 +288,20 @@ extension on String { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced - // from T2=CallableClass>), therefore T=A Function() and S=int, - // so T is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the - // type of E is A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_implicit_extension_explicit_this_property_test.dart b/tests/language/inference_update_3/if_null_assignment_implicit_extension_explicit_this_property_test.dart index d1eca47c0c0..5c7c016a085 100644 --- a/tests/language/inference_update_3/if_null_assignment_implicit_extension_explicit_this_property_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_implicit_extension_explicit_this_property_test.dart @@ -58,15 +58,15 @@ extension on String { set pStringQuestion(String? value) {} test() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K // is analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that + // - Otherwise, J is the write type `e1`. This is the type schema that // the setter associated with `e1` imposes on its single argument (or, // for the case of indexed assignment, the type schema that // `operator[]=` imposes on its second argument). @@ -79,100 +79,192 @@ extension on String { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T - // <: S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context( (this.pIntQuestion ??= d)..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type - // of E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((this.pIterableIntQuestion ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((this.pFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, then the type of `e` is + // S. { - // K=B1<_>, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is B1. + // This example has: + // - K = B1<_> + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . var c2Double = C2(); contextB1((this.pC1IntQuestion ??= c2Double) ..expectStaticType>>()); - // K=B1, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is B1. + // This example has: + // - K = B1 + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . contextB1((this.pC1IntQuestion ??= c2Double) ..expectStaticType>>()); - // K=Iterable, T1=Iterable?, and T2'=List, therefore - // T=Object and S=Iterable, so T is not <: S, but NonNull(T1) <: S - // and T2' <: S, hence the type of E is Iterable. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T . var listNum = []; context>((this.pIterableIntQuestion ??= listNum) ..expectStaticType>>()); - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=B1 Function(), so T is not <: S, but NonNull(T1) - // <: S and T2' <: S, hence the type of E is B1 Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T Function(). var callableClassC2Int = CallableClass>(); context Function()>((this.pC1IntFunctionQuestion ??= callableClassC2Int) ..expectStaticType Function()>>()); } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E - // is num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T - // is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of - // E is num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -180,10 +272,20 @@ extension on String { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T >(); @@ -191,10 +293,20 @@ extension on String { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T >(); @@ -202,10 +314,20 @@ extension on String { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced - // from T2=CallableClass>), therefore T=A Function() and S=int, - // so T is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the - // type of E is A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_implicit_extension_implicit_this_property_disabled_test.dart b/tests/language/inference_update_3/if_null_assignment_implicit_extension_implicit_this_property_disabled_test.dart index c2217218347..7c0586065c7 100644 --- a/tests/language/inference_update_3/if_null_assignment_implicit_extension_implicit_this_property_disabled_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_implicit_extension_implicit_this_property_disabled_test.dart @@ -53,15 +53,15 @@ extension on String { set pStringQuestion(String? value) {} test() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K // is analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that + // - Otherwise, J is the write type `e1`. This is the type schema that // the setter associated with `e1` imposes on its single argument (or, // for the case of indexed assignment, the type schema that // `operator[]=` imposes on its second argument). @@ -73,60 +73,103 @@ extension on String { pStringQuestion ??= contextType('')..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T - // <: S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context((pIntQuestion ??= d)..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type - // of E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((pIterableIntQuestion ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((pFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S` if `inference-update-3` is enabled, else the type of `E` is - // `T`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, and `inference-update-3` + // is enabled, then the type of `e` is S. { - // K=Iterable, T1=Iterable?, and T2'=List, therefore - // T=Object and S=Iterable, so T is not <: S, but NonNull(T1) <: S - // and T2' <: S, hence the type of E is Object. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T []; - var o = [0] as Object?; + Object? o; + o = [0] as Object?; if (o is Iterable) { // We avoid having a compile-time error because `o` can be demoted. o = (pIterableIntQuestion ??= listNum) ..expectStaticType>(); } - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=B1 Function(), so T is not <: S, but NonNull(T1) - // <: S and T2' <: S, hence the type of E is A Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T >(); o = (() => B1()) as Object?; if (o is B1 Function()) { @@ -136,31 +179,64 @@ extension on String { } } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E - // is num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T - // is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of - // E is num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -168,10 +244,20 @@ extension on String { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T >(); @@ -179,10 +265,20 @@ extension on String { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T >(); @@ -190,10 +286,20 @@ extension on String { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced - // from T2=CallableClass>), therefore T=A Function() and S=int, - // so T is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the - // type of E is A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_implicit_extension_implicit_this_property_test.dart b/tests/language/inference_update_3/if_null_assignment_implicit_extension_implicit_this_property_test.dart index 515399f6983..69eaf2796f3 100644 --- a/tests/language/inference_update_3/if_null_assignment_implicit_extension_implicit_this_property_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_implicit_extension_implicit_this_property_test.dart @@ -58,15 +58,15 @@ extension on String { set pStringQuestion(String? value) {} test() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K // is analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that + // - Otherwise, J is the write type `e1`. This is the type schema that // the setter associated with `e1` imposes on its single argument (or, // for the case of indexed assignment, the type schema that // `operator[]=` imposes on its second argument). @@ -78,99 +78,191 @@ extension on String { pStringQuestion ??= contextType('')..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T - // <: S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context((pIntQuestion ??= d)..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type - // of E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((pIterableIntQuestion ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((pFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, then the type of `e` is + // S. { - // K=B1<_>, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is B1. + // This example has: + // - K = B1<_> + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . var c2Double = C2(); contextB1((pC1IntQuestion ??= c2Double) ..expectStaticType>>()); - // K=B1, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is B1. + // This example has: + // - K = B1 + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . contextB1((pC1IntQuestion ??= c2Double) ..expectStaticType>>()); - // K=Iterable, T1=Iterable?, and T2'=List, therefore - // T=Object and S=Iterable, so T is not <: S, but NonNull(T1) <: S - // and T2' <: S, hence the type of E is Iterable. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T . var listNum = []; context>((pIterableIntQuestion ??= listNum) ..expectStaticType>>()); - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=B1 Function(), so T is not <: S, but NonNull(T1) - // <: S and T2' <: S, hence the type of E is B1 Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T Function(). var callableClassC2Int = CallableClass>(); context Function()>((pC1IntFunctionQuestion ??= callableClassC2Int) ..expectStaticType Function()>>()); } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E - // is num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T - // is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of - // E is num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -178,10 +270,20 @@ extension on String { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T >(); @@ -189,10 +291,20 @@ extension on String { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T >(); @@ -200,10 +312,20 @@ extension on String { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced - // from T2=CallableClass>), therefore T=A Function() and S=int, - // so T is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the - // type of E is A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_implicit_extension_index_expression_disabled_test.dart b/tests/language/inference_update_3/if_null_assignment_implicit_extension_index_expression_disabled_test.dart index f9e93c44e28..5e9dbaa77be 100644 --- a/tests/language/inference_update_3/if_null_assignment_implicit_extension_index_expression_disabled_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_implicit_extension_index_expression_disabled_test.dart @@ -48,18 +48,18 @@ extension on Indexable { } main() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -70,62 +70,106 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T <: - // S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context((Indexable(null)[0] ??= d) ..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((Indexable?, Object?>(null)[0] ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((Indexable(null)[0] ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S` if `inference-update-3` is enabled, else the type of `E` is `T`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, and `inference-update-3` + // is enabled, then the type of `e` is S. { - // K=Iterable, T1=Iterable?, and T2'=List, therefore T=Object - // and S=Iterable, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is Object. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T []; - var o = [0] as Object?; + Object? o; + o = [0] as Object?; if (o is Iterable) { // We avoid having a compile-time error because `o` can be demoted. o = (Indexable?, Object?>(null)[0] ??= listNum) ..expectStaticType>(); } - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function(), so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is A Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T >(); o = (() => B1()) as Object?; if (o is B1 Function()) { @@ -136,32 +180,65 @@ main() { } } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T (null)[0] ??= d) ..expectStaticType>(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T (null)[0] ??= intQuestion) ..expectStaticType>(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T (null)[0] ??= d) ..expectStaticType>(); @@ -170,10 +247,20 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T Function()?, Function?>(null)[0] ??= callableClassC2Int) @@ -182,10 +269,20 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T Function()?, Function?>(null)[0] ??= callableClassC2Int) @@ -194,10 +291,20 @@ main() { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced from - // T2=CallableClass>), therefore T=A Function() and S=int, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T Function()?, Function?>(null)[0] ??= callableClassC2Int) diff --git a/tests/language/inference_update_3/if_null_assignment_implicit_extension_index_expression_test.dart b/tests/language/inference_update_3/if_null_assignment_implicit_extension_index_expression_test.dart index b393dfd7cd0..b3315514943 100644 --- a/tests/language/inference_update_3/if_null_assignment_implicit_extension_index_expression_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_implicit_extension_index_expression_test.dart @@ -51,18 +51,18 @@ extension on Indexable { } main() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -73,72 +73,130 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T <: - // S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context((Indexable(null)[0] ??= d) ..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((Indexable?, Object?>(null)[0] ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((Indexable(null)[0] ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, then the type of `e` is S. { - // K=B1<_>, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1. + // This example has: + // - K = B1<_> + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . var c2Double = C2(); contextB1((Indexable?, Object?>(null)[0] ??= c2Double) ..expectStaticType>>()); - // K=B1, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1. + // This example has: + // - K = B1 + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . contextB1((Indexable?, Object?>(null)[0] ??= c2Double) ..expectStaticType>>()); - // K=Iterable, T1=Iterable?, and T2'=List, therefore T=Object - // and S=Iterable, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is Iterable. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T . var listNum = []; context>((Indexable?, Object?>(null)[0] ??= listNum) ..expectStaticType>>()); - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function(), so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is B1 Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T Function(). var callableClassC2Int = CallableClass>(); context Function()>( (Indexable Function()?, Function?>(null)[0] ??= @@ -146,32 +204,65 @@ main() { ..expectStaticType Function()>>()); } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T (null)[0] ??= d) ..expectStaticType>(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T (null)[0] ??= intQuestion) ..expectStaticType>(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T (null)[0] ??= d) ..expectStaticType>(); @@ -180,10 +271,20 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T Function()?, Function?>(null)[0] ??= callableClassC2Int) @@ -192,10 +293,20 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T Function()?, Function?>(null)[0] ??= callableClassC2Int) @@ -204,10 +315,20 @@ main() { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced from - // T2=CallableClass>), therefore T=A Function() and S=int, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T Function()?, Function?>(null)[0] ??= callableClassC2Int) diff --git a/tests/language/inference_update_3/if_null_assignment_implicit_extension_null_aware_index_expression_disabled_test.dart b/tests/language/inference_update_3/if_null_assignment_implicit_extension_null_aware_index_expression_disabled_test.dart index be97afa2430..9f3f788fef9 100644 --- a/tests/language/inference_update_3/if_null_assignment_implicit_extension_null_aware_index_expression_disabled_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_implicit_extension_null_aware_index_expression_disabled_test.dart @@ -52,18 +52,18 @@ Indexable? maybeIndexable( Indexable(value); main() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -74,67 +74,111 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object?, T1=int?, and T2'=double, therefore T=num and S=Object?, so T - // <: S, and hence the type of E is num (which becomes num? after null - // shorting completes). + // This example has: + // - K = Object? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object? + // We have: + // - T <: S + // Therefore the type of `e` is T = num. + // (Which becomes num? after null shorting completes.) var d = 2.0; context((maybeIndexable(null)?[0] ??= d) ..expectStaticType>()); - // K=Iterable<_>?, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable?, so T <: S, and hence the type - // of E is Iterable (which becomes Iterable? after null shorting - // completes). + // This example has: + // - K = Iterable<_>? + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable? + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. + // (Which becomes Iterable? after null shorting completes.) var iterableDouble = [] as Iterable; contextIterableQuestion( (maybeIndexable?, Object?>(null)?[0] ??= iterableDouble) ..expectStaticType?>>()); - // K=Function?, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function?, so T <: S, - // and hence the type of E is Function (which becomes Function? after null - // shorting completes). + // This example has: + // - K = Function? + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function? + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. + // (Which becomes Function? after null shorting completes.) var callableClassInt = CallableClass(); context((maybeIndexable(null)?[0] ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S` if `inference-update-3` is enabled, else the type of `E` is `T`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, and `inference-update-3` + // is enabled, then the type of `e` is S. { - // K=Iterable?, T1=Iterable?, and T2'=List, therefore - // T=Object and S=Iterable?, so T is not <: S, but NonNull(T1) <: S and - // T2' <: S, hence the type of E is Object (which becomes Object? after null - // shorting completes). + // This example has: + // - K = Iterable? + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable? + // We have: + // - T []; - var o = [0] as Object?; + Object? o; + o = [0] as Object?; if (o is Iterable?) { // We avoid having a compile-time error because `o` can be demoted. o = (maybeIndexable?, Object?>(null)?[0] ??= listNum) ..expectStaticType>(); } - // K=B1 Function()?, T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function()?, so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is A Function() (which becomes A Function()? after - // null shorting completes). + // This example has: + // - K = B1 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function()? + // We have: + // - T >(); o = (() => B1()) as Object?; if (o is B1 Function()?) { @@ -145,33 +189,67 @@ main() { } } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num (which becomes num? after null shorting completes). + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T (null)?[0] ??= d) ..expectStaticType>(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T (null)?[0] ??= intQuestion) ..expectStaticType>(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num - // (which becomes num? after null shorting completes). + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T (null)?[0] ??= d) ..expectStaticType>(); @@ -180,11 +258,21 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()?) { - // K=C1 Function()?, T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function()?, so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function() (which - // becomes A Function()? after null shorting completes). + // This example has: + // - K = C1 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function()? + // We have: + // - T Function()?, Function?>(null)?[0] ??= callableClassC2Int) @@ -193,11 +281,21 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()?) { - // K=C2 Function()?, T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function()?, so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function() (which - // becomes A Function()? after null shorting completes). + // This example has: + // - K = C2 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function()? + // We have: + // - T Function()?, Function?>(null)?[0] ??= callableClassC2Int) @@ -206,11 +304,21 @@ main() { o = 0 as Object?; if (o is int?) { - // K=int?, T1=C1 Function()?, and T2'=C2 Function() (coerced - // from T2=CallableClass>), therefore T=A Function() and S=int?, - // so T is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type - // of E is A Function() (which becomes A Function()? after null shorting - // completes). + // This example has: + // - K = int? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int? + // We have: + // - T Function()?, Function?>(null)?[0] ??= callableClassC2Int) diff --git a/tests/language/inference_update_3/if_null_assignment_implicit_extension_null_aware_index_expression_test.dart b/tests/language/inference_update_3/if_null_assignment_implicit_extension_null_aware_index_expression_test.dart index a1beb092238..fd16a7700c8 100644 --- a/tests/language/inference_update_3/if_null_assignment_implicit_extension_null_aware_index_expression_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_implicit_extension_null_aware_index_expression_test.dart @@ -55,18 +55,18 @@ Indexable? maybeIndexable( Indexable(value); main() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -77,80 +77,138 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object?, T1=int?, and T2'=double, therefore T=num and S=Object?, so T - // <: S, and hence the type of E is num (which becomes num? after null - // shorting completes). + // This example has: + // - K = Object? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object? + // We have: + // - T <: S + // Therefore the type of `e` is T = num. + // (Which becomes num? after null shorting completes.) var d = 2.0; context((maybeIndexable(null)?[0] ??= d) ..expectStaticType>()); - // K=Iterable<_>?, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable?, so T <: S, and hence the type - // of E is Iterable (which becomes Iterable? after null shorting - // completes). + // This example has: + // - K = Iterable<_>? + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable? + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. + // (Which becomes Iterable? after null shorting completes.) var iterableDouble = [] as Iterable; contextIterableQuestion( (maybeIndexable?, Object?>(null)?[0] ??= iterableDouble) ..expectStaticType?>>()); - // K=Function?, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function?, so T <: S, - // and hence the type of E is Function (which becomes Function? after null - // shorting completes). + // This example has: + // - K = Function? + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function? + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. + // (Which becomes Function? after null shorting completes.) var callableClassInt = CallableClass(); context((maybeIndexable(null)?[0] ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, then the type of `e` is S. { - // K=B1<_>?, T1=C1?, and T2'=C2, therefore T=A and - // S=B1?, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is B1 (which becomes B1? after null - // shorting completes). + // This example has: + // - K = B1<_>? + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1? + // We have: + // - T . + // (Which becomes B1? after null shorting completes.) var c2Double = C2(); contextB1Question((maybeIndexable?, Object?>(null)?[0] ??= c2Double) ..expectStaticType?>>()); - // K=B1?, T1=C1?, and T2'=C2, therefore T=A and - // S=B1?, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1 (which becomes B1? after null - // shorting completes). + // This example has: + // - K = B1? + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1? + // We have: + // - T . + // (Which becomes B1? after null shorting completes.) contextB1Question((maybeIndexable?, Object?>(null)?[0] ??= c2Double) ..expectStaticType?>>()); - // K=Iterable?, T1=Iterable?, and T2'=List, therefore - // T=Object and S=Iterable?, so T is not <: S, but NonNull(T1) <: S and - // T2' <: S, hence the type of E is Iterable (which becomes - // Iterable? after null shorting completes). + // This example has: + // - K = Iterable? + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable? + // We have: + // - T . + // (Which becomes Iterable? after null shorting completes.) var listNum = []; context?>( (maybeIndexable?, Object?>(null)?[0] ??= listNum) ..expectStaticType?>>()); - // K=B1 Function()?, T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function()?, so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is B1 Function() (which becomes B1 - // Function()? after null shorting completes). + // This example has: + // - K = B1 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function()? + // We have: + // - T Function(). + // (Which becomes B1 Function()? after null shorting completes.) var callableClassC2Int = CallableClass>(); context Function()?>( (maybeIndexable Function()?, Function?>(null)?[0] ??= @@ -158,33 +216,67 @@ main() { ..expectStaticType Function()?>>()); } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num (which becomes num? after null shorting completes). + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T (null)?[0] ??= d) ..expectStaticType>(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T (null)?[0] ??= intQuestion) ..expectStaticType>(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num - // (which becomes num? after null shorting completes). + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T (null)?[0] ??= d) ..expectStaticType>(); @@ -193,11 +285,21 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()?) { - // K=C1 Function()?, T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function()?, so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function() (which - // becomes A Function()? after null shorting completes). + // This example has: + // - K = C1 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function()? + // We have: + // - T Function()?, Function?>(null)?[0] ??= callableClassC2Int) @@ -206,11 +308,21 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()?) { - // K=C2 Function()?, T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function()?, so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function() (which - // becomes A Function()? after null shorting completes). + // This example has: + // - K = C2 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function()? + // We have: + // - T Function()?, Function?>(null)?[0] ??= callableClassC2Int) @@ -219,11 +331,21 @@ main() { o = 0 as Object?; if (o is int?) { - // K=int?, T1=C1 Function()?, and T2'=C2 Function() (coerced - // from T2=CallableClass>), therefore T=A Function() and S=int?, - // so T is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type - // of E is A Function() (which becomes A Function()? after null shorting - // completes). + // This example has: + // - K = int? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int? + // We have: + // - T Function()?, Function?>(null)?[0] ??= callableClassC2Int) diff --git a/tests/language/inference_update_3/if_null_assignment_implicit_extension_null_aware_property_disabled_test.dart b/tests/language/inference_update_3/if_null_assignment_implicit_extension_null_aware_property_disabled_test.dart index 97cc8fed4a5..018312aedaf 100644 --- a/tests/language/inference_update_3/if_null_assignment_implicit_extension_null_aware_property_disabled_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_implicit_extension_null_aware_property_disabled_test.dart @@ -55,18 +55,18 @@ extension on String { main() { var s = '' as String?; - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -76,65 +76,109 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object?, T1=int?, and T2'=double, therefore T=num and S=Object?, so T - // <: S, and hence the type of E is num (which becomes num? after null - // shorting completes). + // This example has: + // - K = Object? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object? + // We have: + // - T <: S + // Therefore the type of `e` is T = num. + // (Which becomes num? after null shorting completes.) var d = 2.0; context( (s?.pIntQuestion ??= d)..expectStaticType>()); - // K=Iterable<_>?, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable?, so T <: S, and hence the type - // of E is Iterable (which becomes Iterable? after null shorting - // completes). + // This example has: + // - K = Iterable<_>? + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable? + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. + // (Which becomes Iterable? after null shorting completes.) var iterableDouble = [] as Iterable; contextIterableQuestion((s?.pIterableIntQuestion ??= iterableDouble) ..expectStaticType?>>()); - // K=Function?, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function?, so T <: S, - // and hence the type of E is Function (which becomes Function? after null - // shorting completes). + // This example has: + // - K = Function? + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function? + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. + // (Which becomes Function? after null shorting completes.) var callableClassInt = CallableClass(); context((s?.pFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S` if `inference-update-3` is enabled, else the type of `E` is `T`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, and `inference-update-3` + // is enabled, then the type of `e` is S. { - // K=Iterable?, T1=Iterable?, and T2'=List, therefore - // T=Object and S=Iterable?, so T is not <: S, but NonNull(T1) <: S and - // T2' <: S, hence the type of E is Object (which becomes Object? after null - // shorting completes). + // This example has: + // - K = Iterable? + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable? + // We have: + // - T []; - var o = [0] as Object?; + Object? o; + o = [0] as Object?; if (o is Iterable?) { // We avoid having a compile-time error because `o` can be demoted. o = (s?.pIterableIntQuestion ??= listNum) ..expectStaticType>(); } - // K=B1 Function()?, T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function()?, so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is A Function() (which becomes A Function()? after - // null shorting completes). + // This example has: + // - K = B1 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function()? + // We have: + // - T >(); o = (() => B1()) as Object?; if (o is B1 Function()?) { @@ -144,32 +188,66 @@ main() { } } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num (which becomes num? after null shorting completes). + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num - // (which becomes num? after null shorting completes). + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -177,11 +255,21 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()?) { - // K=C1 Function()?, T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function()?, so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function() (which - // becomes A Function()? after null shorting completes). + // This example has: + // - K = C1 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function()? + // We have: + // - T >(); @@ -189,11 +277,21 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()?) { - // K=C2 Function()?, T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function()?, so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function() (which - // becomes A Function()? after null shorting completes). + // This example has: + // - K = C2 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function()? + // We have: + // - T >(); @@ -201,11 +299,21 @@ main() { o = 0 as Object?; if (o is int?) { - // K=int?, T1=C1 Function()?, and T2'=C2 Function() (coerced - // from T2=CallableClass>), therefore T=A Function() and S=int?, - // so T is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type - // of E is A Function() (which becomes A Function()? after null shorting - // completes). + // This example has: + // - K = int? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int? + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_implicit_extension_null_aware_property_test.dart b/tests/language/inference_update_3/if_null_assignment_implicit_extension_null_aware_property_test.dart index d850a646e36..0420c090dbf 100644 --- a/tests/language/inference_update_3/if_null_assignment_implicit_extension_null_aware_property_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_implicit_extension_null_aware_property_test.dart @@ -61,18 +61,18 @@ extension on String { main() { var s = '' as String?; - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -82,108 +82,200 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object?, T1=int?, and T2'=double, therefore T=num and S=Object?, so T - // <: S, and hence the type of E is num (which becomes num? after null - // shorting completes). + // This example has: + // - K = Object? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object? + // We have: + // - T <: S + // Therefore the type of `e` is T = num. + // (Which becomes num? after null shorting completes.) var d = 2.0; context( (s?.pIntQuestion ??= d)..expectStaticType>()); - // K=Iterable<_>?, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable?, so T <: S, and hence the type - // of E is Iterable (which becomes Iterable? after null shorting - // completes). + // This example has: + // - K = Iterable<_>? + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable? + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. + // (Which becomes Iterable? after null shorting completes.) var iterableDouble = [] as Iterable; contextIterableQuestion((s?.pIterableIntQuestion ??= iterableDouble) ..expectStaticType?>>()); - // K=Function?, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function?, so T <: S, - // and hence the type of E is Function (which becomes Function? after null - // shorting completes). + // This example has: + // - K = Function? + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function? + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. + // (Which becomes Function? after null shorting completes.) var callableClassInt = CallableClass(); context((s?.pFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, then the type of `e` is S. { - // K=B1<_>?, T1=C1?, and T2'=C2, therefore T=A and - // S=B1?, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is B1 (which becomes B1? after null - // shorting completes). + // This example has: + // - K = B1<_>? + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1? + // We have: + // - T . + // (Which becomes B1? after null shorting completes.) var c2Double = C2(); contextB1Question((s?.pC1IntQuestion ??= c2Double) ..expectStaticType?>>()); - // K=B1?, T1=C1?, and T2'=C2, therefore T=A and - // S=B1?, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1 (which becomes B1? after null - // shorting completes). + // This example has: + // - K = B1? + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1? + // We have: + // - T . + // (Which becomes B1? after null shorting completes.) contextB1Question((s?.pC1IntQuestion ??= c2Double) ..expectStaticType?>>()); - // K=Iterable?, T1=Iterable?, and T2'=List, therefore - // T=Object and S=Iterable?, so T is not <: S, but NonNull(T1) <: S and - // T2' <: S, hence the type of E is Iterable (which becomes - // Iterable? after null shorting completes). + // This example has: + // - K = Iterable? + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable? + // We have: + // - T . + // (Which becomes Iterable? after null shorting completes.) var listNum = []; context?>((s?.pIterableIntQuestion ??= listNum) ..expectStaticType?>>()); - // K=B1 Function()?, T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function()?, so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is B1 Function() (which becomes B1 - // Function()? after null shorting completes). + // This example has: + // - K = B1 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function()? + // We have: + // - T Function(). + // (Which becomes B1 Function()? after null shorting completes.) var callableClassC2Int = CallableClass>(); context Function()?>((s?.pC1IntFunctionQuestion ??= callableClassC2Int) ..expectStaticType Function()?>>()); } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num (which becomes num? after null shorting completes). + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num - // (which becomes num? after null shorting completes). + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -191,11 +283,21 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()?) { - // K=C1 Function()?, T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function()?, so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function() (which - // becomes A Function()? after null shorting completes). + // This example has: + // - K = C1 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function()? + // We have: + // - T >(); @@ -203,11 +305,21 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()?) { - // K=C2 Function()?, T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function()?, so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function() (which - // becomes A Function()? after null shorting completes). + // This example has: + // - K = C2 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function()? + // We have: + // - T >(); @@ -215,11 +327,21 @@ main() { o = 0 as Object?; if (o is int?) { - // K=int?, T1=C1 Function()?, and T2'=C2 Function() (coerced - // from T2=CallableClass>), therefore T=A Function() and S=int?, - // so T is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type - // of E is A Function() (which becomes A Function()? after null shorting - // completes). + // This example has: + // - K = int? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int? + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_implicit_extension_property_disabled_test.dart b/tests/language/inference_update_3/if_null_assignment_implicit_extension_property_disabled_test.dart index 5d3755f3e42..123361bc54a 100644 --- a/tests/language/inference_update_3/if_null_assignment_implicit_extension_property_disabled_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_implicit_extension_property_disabled_test.dart @@ -53,18 +53,18 @@ extension on String { } main() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -74,59 +74,103 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T <: - // S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context((''.pIntQuestion ??= d)..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((''.pIterableIntQuestion ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((''.pFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S` if `inference-update-3` is enabled, else the type of `E` is `T`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, and `inference-update-3` + // is enabled, then the type of `e` is S. { - // K=Iterable, T1=Iterable?, and T2'=List, therefore T=Object - // and S=Iterable, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is Object. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T []; - var o = [0] as Object?; + Object? o; + o = [0] as Object?; if (o is Iterable) { // We avoid having a compile-time error because `o` can be demoted. o = (''.pIterableIntQuestion ??= listNum) ..expectStaticType>(); } - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function(), so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is A Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T >(); o = (() => B1()) as Object?; if (o is B1 Function()) { @@ -136,31 +180,64 @@ main() { } } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -168,10 +245,20 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T >(); @@ -179,10 +266,20 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T >(); @@ -190,10 +287,20 @@ main() { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced from - // T2=CallableClass>), therefore T=A Function() and S=int, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_implicit_extension_property_test.dart b/tests/language/inference_update_3/if_null_assignment_implicit_extension_property_test.dart index 04317cf558e..43d41cf126a 100644 --- a/tests/language/inference_update_3/if_null_assignment_implicit_extension_property_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_implicit_extension_property_test.dart @@ -58,18 +58,18 @@ extension on String { } main() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -79,99 +79,190 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T <: - // S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context((''.pIntQuestion ??= d)..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((''.pIterableIntQuestion ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((''.pFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, then the type of `e` is S. { - // K=B1<_>, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1. + // This example has: + // - K = B1<_> + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . var c2Double = C2(); contextB1((''.pC1IntQuestion ??= c2Double) ..expectStaticType>>()); - // K=B1, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1. + // This example has: + // - K = B1 + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . contextB1((''.pC1IntQuestion ??= c2Double) ..expectStaticType>>()); - // K=Iterable, T1=Iterable?, and T2'=List, therefore T=Object - // and S=Iterable, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is Iterable. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T . var listNum = []; context>((''.pIterableIntQuestion ??= listNum) ..expectStaticType>>()); - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function(), so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is B1 Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T Function(). var callableClassC2Int = CallableClass>(); context Function()>((''.pC1IntFunctionQuestion ??= callableClassC2Int) ..expectStaticType Function()>>()); } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -179,10 +270,20 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T >(); @@ -190,10 +291,20 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T >(); @@ -201,10 +312,20 @@ main() { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced from - // T2=CallableClass>), therefore T=A Function() and S=int, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_implicit_this_property_disabled_test.dart b/tests/language/inference_update_3/if_null_assignment_implicit_this_property_disabled_test.dart index 9785583142e..9a8166877ad 100644 --- a/tests/language/inference_update_3/if_null_assignment_implicit_this_property_disabled_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_implicit_this_property_disabled_test.dart @@ -53,15 +53,15 @@ class Test { set pStringQuestion(String? value) {} test() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K // is analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that + // - Otherwise, J is the write type `e1`. This is the type schema that // the setter associated with `e1` imposes on its single argument (or, // for the case of indexed assignment, the type schema that // `operator[]=` imposes on its second argument). @@ -73,60 +73,103 @@ class Test { pStringQuestion ??= contextType('')..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T - // <: S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context((pIntQuestion ??= d)..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type - // of E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((pIterableIntQuestion ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((pFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S` if `inference-update-3` is enabled, else the type of `E` is - // `T`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, and `inference-update-3` + // is enabled, then the type of `e` is S. { - // K=Iterable, T1=Iterable?, and T2'=List, therefore - // T=Object and S=Iterable, so T is not <: S, but NonNull(T1) <: S - // and T2' <: S, hence the type of E is Object. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T []; - var o = [0] as Object?; + Object? o; + o = [0] as Object?; if (o is Iterable) { // We avoid having a compile-time error because `o` can be demoted. o = (pIterableIntQuestion ??= listNum) ..expectStaticType>(); } - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=B1 Function(), so T is not <: S, but NonNull(T1) - // <: S and T2' <: S, hence the type of E is A Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T >(); o = (() => B1()) as Object?; if (o is B1 Function()) { @@ -136,31 +179,64 @@ class Test { } } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E - // is num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T - // is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of - // E is num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -168,10 +244,20 @@ class Test { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T >(); @@ -179,10 +265,20 @@ class Test { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T >(); @@ -190,10 +286,20 @@ class Test { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced - // from T2=CallableClass>), therefore T=A Function() and S=int, - // so T is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the - // type of E is A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_implicit_this_property_test.dart b/tests/language/inference_update_3/if_null_assignment_implicit_this_property_test.dart index 80a9ddf62f7..8700575c715 100644 --- a/tests/language/inference_update_3/if_null_assignment_implicit_this_property_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_implicit_this_property_test.dart @@ -58,15 +58,15 @@ class Test { set pStringQuestion(String? value) {} test() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K // is analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that + // - Otherwise, J is the write type `e1`. This is the type schema that // the setter associated with `e1` imposes on its single argument (or, // for the case of indexed assignment, the type schema that // `operator[]=` imposes on its second argument). @@ -78,99 +78,191 @@ class Test { pStringQuestion ??= contextType('')..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T - // <: S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context((pIntQuestion ??= d)..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type - // of E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((pIterableIntQuestion ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((pFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, then the type of `e` is + // S. { - // K=B1<_>, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is B1. + // This example has: + // - K = B1<_> + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . var c2Double = C2(); contextB1((pC1IntQuestion ??= c2Double) ..expectStaticType>>()); - // K=B1, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is B1. + // This example has: + // - K = B1 + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . contextB1((pC1IntQuestion ??= c2Double) ..expectStaticType>>()); - // K=Iterable, T1=Iterable?, and T2'=List, therefore - // T=Object and S=Iterable, so T is not <: S, but NonNull(T1) <: S - // and T2' <: S, hence the type of E is Iterable. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T . var listNum = []; context>((pIterableIntQuestion ??= listNum) ..expectStaticType>>()); - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=B1 Function(), so T is not <: S, but NonNull(T1) - // <: S and T2' <: S, hence the type of E is B1 Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T Function(). var callableClassC2Int = CallableClass>(); context Function()>((pC1IntFunctionQuestion ??= callableClassC2Int) ..expectStaticType Function()>>()); } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E - // is num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T - // is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of - // E is num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -178,10 +270,20 @@ class Test { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T >(); @@ -189,10 +291,20 @@ class Test { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T >(); @@ -200,10 +312,20 @@ class Test { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced - // from T2=CallableClass>), therefore T=A Function() and S=int, - // so T is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the - // type of E is A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_index_expression_disabled_test.dart b/tests/language/inference_update_3/if_null_assignment_index_expression_disabled_test.dart index d23b321b340..dc89c3f707d 100644 --- a/tests/language/inference_update_3/if_null_assignment_index_expression_disabled_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_index_expression_disabled_test.dart @@ -43,18 +43,18 @@ class Indexable { } main() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -65,62 +65,106 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T <: - // S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context((Indexable(null)[0] ??= d) ..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((Indexable?, Object?>(null)[0] ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((Indexable(null)[0] ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S` if `inference-update-3` is enabled, else the type of `E` is `T`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, and `inference-update-3` + // is enabled, then the type of `e` is S. { - // K=Iterable, T1=Iterable?, and T2'=List, therefore T=Object - // and S=Iterable, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is Object. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T []; - var o = [0] as Object?; + Object? o; + o = [0] as Object?; if (o is Iterable) { // We avoid having a compile-time error because `o` can be demoted. o = (Indexable?, Object?>(null)[0] ??= listNum) ..expectStaticType>(); } - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function(), so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is A Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T >(); o = (() => B1()) as Object?; if (o is B1 Function()) { @@ -131,32 +175,65 @@ main() { } } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T (null)[0] ??= d) ..expectStaticType>(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T (null)[0] ??= intQuestion) ..expectStaticType>(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T (null)[0] ??= d) ..expectStaticType>(); @@ -165,10 +242,20 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T Function()?, Function?>(null)[0] ??= callableClassC2Int) @@ -177,10 +264,20 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T Function()?, Function?>(null)[0] ??= callableClassC2Int) @@ -189,10 +286,20 @@ main() { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced from - // T2=CallableClass>), therefore T=A Function() and S=int, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T Function()?, Function?>(null)[0] ??= callableClassC2Int) diff --git a/tests/language/inference_update_3/if_null_assignment_index_expression_test.dart b/tests/language/inference_update_3/if_null_assignment_index_expression_test.dart index c317821e172..da7e67b8520 100644 --- a/tests/language/inference_update_3/if_null_assignment_index_expression_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_index_expression_test.dart @@ -46,18 +46,18 @@ class Indexable { } main() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -68,72 +68,130 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T <: - // S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context((Indexable(null)[0] ??= d) ..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((Indexable?, Object?>(null)[0] ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((Indexable(null)[0] ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, then the type of `e` is S. { - // K=B1<_>, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1. + // This example has: + // - K = B1<_> + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . var c2Double = C2(); contextB1((Indexable?, Object?>(null)[0] ??= c2Double) ..expectStaticType>>()); - // K=B1, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1. + // This example has: + // - K = B1 + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . contextB1((Indexable?, Object?>(null)[0] ??= c2Double) ..expectStaticType>>()); - // K=Iterable, T1=Iterable?, and T2'=List, therefore T=Object - // and S=Iterable, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is Iterable. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T . var listNum = []; context>((Indexable?, Object?>(null)[0] ??= listNum) ..expectStaticType>>()); - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function(), so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is B1 Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T Function(). var callableClassC2Int = CallableClass>(); context Function()>( (Indexable Function()?, Function?>(null)[0] ??= @@ -141,32 +199,65 @@ main() { ..expectStaticType Function()>>()); } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T (null)[0] ??= d) ..expectStaticType>(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T (null)[0] ??= intQuestion) ..expectStaticType>(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T (null)[0] ??= d) ..expectStaticType>(); @@ -175,10 +266,20 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T Function()?, Function?>(null)[0] ??= callableClassC2Int) @@ -187,10 +288,20 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T Function()?, Function?>(null)[0] ??= callableClassC2Int) @@ -199,10 +310,20 @@ main() { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced from - // T2=CallableClass>), therefore T=A Function() and S=int, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T Function()?, Function?>(null)[0] ??= callableClassC2Int) diff --git a/tests/language/inference_update_3/if_null_assignment_local_disabled_test.dart b/tests/language/inference_update_3/if_null_assignment_local_disabled_test.dart index 0401df19c76..7bd822afaf3 100644 --- a/tests/language/inference_update_3/if_null_assignment_local_disabled_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_local_disabled_test.dart @@ -30,18 +30,18 @@ class CallableClass { } main() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. var string = ''; @@ -51,39 +51,54 @@ main() { var numQuestion = null as num?; numQuestion ??= contextType(0)..expectStaticType>(); - numQuestion = null as num?; if (numQuestion is int?) { numQuestion ??= contextType(0)..expectStaticType>(); } } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T <: - // S, and hence the type of E is num. - var local1 = null as Object?; + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. + Object? local1; var d = 2.0; + local1 = null as Object?; if (local1 is int?) { // We avoid having a compile-time error because `local1` can be demoted. context((local1 ??= d)..expectStaticType>()); } - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; local1 = null as Object?; if (local1 is Iterable?) { @@ -92,17 +107,34 @@ main() { ..expectStaticType>>()); } - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. - var local2 = null as Function?; + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. + Function? local2; var callableClassInt = CallableClass(); + local2 = null as Function?; context( (local2 ??= callableClassInt)..expectStaticType>()); // Verify that the RHS is not coerced to the promoted type. - // K=Object, T1=Function?, and T2'=CallableClass, therefore T=Object - // and S=Object, so T <: S, and hence the type of E is Object. + // This example has: + // - K = Object + // - T1 = Function? + // - T2' = CallableClass + // Which implies: + // - T = Object + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = Object. local1 = null as Object?; if (local1 is Function?) { // We avoid having a compile-time error because `local1` can be demoted. @@ -111,27 +143,50 @@ main() { } } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S` if `inference-update-3` is enabled, else the type of `E` is `T`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, and `inference-update-3` + // is enabled, then the type of `e` is S. { - // K=Iterable, T1=Iterable?, and T2'=List, therefore T=Object - // and S=Iterable, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is Object. - var local1 = null as Object?; + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T []; - var o = [0] as Object?; + Object? o; + local1 = null as Object?; + o = [0] as Object?; if (local1 is Iterable? && o is Iterable) { // We avoid having a compile-time error because `local1` and `o` can be // demoted. o = (local1 ??= listNum)..expectStaticType>(); } - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function(), so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is A Function(). - var local2 = null as Function?; + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T >(); + local2 = null as Function?; o = (() => B1()) as Object?; if (local2 is C1 Function()? && o is B1 Function()) { // We avoid having a compile-time error because `local2` and `o` can be @@ -141,16 +196,28 @@ main() { } } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { - var local1 = null as Object?; + Object? local1; var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + local1 = null as Object?; + o = 0 as Object?; if (local1 is int? && o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); @@ -158,9 +225,19 @@ main() { local1 = null as Object?; o = 0 as Object?; if (local1 is double? && o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); @@ -168,21 +245,44 @@ main() { local1 = null as Object?; o = '' as Object?; if (local1 is int? && o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } - var local2 = null as Function?; + Function? local2; var callableClassC2Int = CallableClass>(); + local2 = null as Function?; o = (() => C1()) as Object?; if (local2 is C1 Function()? && o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T C2()) as Object?; if (local2 is C1 Function()? && o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T Function()? && o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced from - // T2=CallableClass>), therefore T=A Function() and S=int, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T { Object? contextB1(B1 x) => x; main() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. var string = ''; @@ -54,39 +54,54 @@ main() { var numQuestion = null as num?; numQuestion ??= contextType(0)..expectStaticType>(); - numQuestion = null as num?; if (numQuestion is int?) { numQuestion ??= contextType(0)..expectStaticType>(); } } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T <: - // S, and hence the type of E is num. - var local1 = null as Object?; + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. + Object? local1; var d = 2.0; + local1 = null as Object?; if (local1 is int?) { // We avoid having a compile-time error because `local1` can be demoted. context((local1 ??= d)..expectStaticType>()); } - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; local1 = null as Object?; if (local1 is Iterable?) { @@ -95,17 +110,34 @@ main() { ..expectStaticType>>()); } - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. - var local2 = null as Function?; + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. + Function? local2; var callableClassInt = CallableClass(); + local2 = null as Function?; context( (local2 ??= callableClassInt)..expectStaticType>()); // Verify that the RHS is not coerced to the promoted type. - // K=Object, T1=Function?, and T2'=CallableClass, therefore T=Object - // and S=Object, so T <: S, and hence the type of E is Object. + // This example has: + // - K = Object + // - T1 = Function? + // - T2' = CallableClass + // Which implies: + // - T = Object + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = Object. local1 = null as Object?; if (local1 is Function?) { // We avoid having a compile-time error because `local1` can be demoted. @@ -114,23 +146,41 @@ main() { } } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, then the type of `e` is S. { - // K=B1<_>, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1. - var local1 = null as Object?; + // This example has: + // - K = B1<_> + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . + Object? local1; var c2Double = C2(); + local1 = null as Object?; if (local1 is C1?) { // We avoid having a compile-time error because `local1` can be demoted. contextB1( (local1 ??= c2Double)..expectStaticType>>()); } - // K=B1, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1. + // This example has: + // - K = B1 + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . local1 = null as Object?; if (local1 is C1?) { // We avoid having a compile-time error because `local1` can be demoted. @@ -138,9 +188,18 @@ main() { (local1 ??= c2Double)..expectStaticType>>()); } - // K=Iterable, T1=Iterable?, and T2'=List, therefore T=Object - // and S=Iterable, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is Iterable. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T . var listNum = []; local1 = null as Object?; if (local1 is Iterable?) { @@ -149,12 +208,22 @@ main() { (local1 ??= listNum)..expectStaticType>>()); } - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function(), so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is B1 Function(). - var local2 = null as Function?; + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T Function(). + Function? local2; var callableClassC2Int = CallableClass>(); + local2 = null as Function?; if (local2 is C1 Function()?) { // We avoid having a compile-time error because `local2` can be demoted. context Function()>((local2 ??= callableClassC2Int) @@ -162,16 +231,28 @@ main() { } } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { - var local1 = null as Object?; + Object? local1; var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + local1 = null as Object?; + o = 0 as Object?; if (local1 is int? && o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); @@ -179,9 +260,19 @@ main() { local1 = null as Object?; o = 0 as Object?; if (local1 is double? && o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); @@ -189,21 +280,44 @@ main() { local1 = null as Object?; o = '' as Object?; if (local1 is int? && o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } - var local2 = null as Function?; + Function? local2; var callableClassC2Int = CallableClass>(); + local2 = null as Function?; o = (() => C1()) as Object?; if (local2 is C1 Function()? && o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T C2()) as Object?; if (local2 is C1 Function()? && o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T Function()? && o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced from - // T2=CallableClass>), therefore T=A Function() and S=int, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T ? maybeIndexable( Indexable(value); main() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -69,67 +69,111 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object?, T1=int?, and T2'=double, therefore T=num and S=Object?, so T - // <: S, and hence the type of E is num (which becomes num? after null - // shorting completes). + // This example has: + // - K = Object? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object? + // We have: + // - T <: S + // Therefore the type of `e` is T = num. + // (Which becomes num? after null shorting completes.) var d = 2.0; context((maybeIndexable(null)?[0] ??= d) ..expectStaticType>()); - // K=Iterable<_>?, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable?, so T <: S, and hence the type - // of E is Iterable (which becomes Iterable? after null shorting - // completes). + // This example has: + // - K = Iterable<_>? + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable? + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. + // (Which becomes Iterable? after null shorting completes.) var iterableDouble = [] as Iterable; contextIterableQuestion( (maybeIndexable?, Object?>(null)?[0] ??= iterableDouble) ..expectStaticType?>>()); - // K=Function?, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function?, so T <: S, - // and hence the type of E is Function (which becomes Function? after null - // shorting completes). + // This example has: + // - K = Function? + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function? + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. + // (Which becomes Function? after null shorting completes.) var callableClassInt = CallableClass(); context((maybeIndexable(null)?[0] ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S` if `inference-update-3` is enabled, else the type of `E` is `T`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, and `inference-update-3` + // is enabled, then the type of `e` is S. { - // K=Iterable?, T1=Iterable?, and T2'=List, therefore - // T=Object and S=Iterable?, so T is not <: S, but NonNull(T1) <: S and - // T2' <: S, hence the type of E is Object (which becomes Object? after null - // shorting completes). + // This example has: + // - K = Iterable? + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable? + // We have: + // - T []; - var o = [0] as Object?; + Object? o; + o = [0] as Object?; if (o is Iterable?) { // We avoid having a compile-time error because `o` can be demoted. o = (maybeIndexable?, Object?>(null)?[0] ??= listNum) ..expectStaticType>(); } - // K=B1 Function()?, T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function()?, so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is A Function() (which becomes A Function()? after - // null shorting completes). + // This example has: + // - K = B1 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function()? + // We have: + // - T >(); o = (() => B1()) as Object?; if (o is B1 Function()?) { @@ -140,33 +184,67 @@ main() { } } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num (which becomes num? after null shorting completes). + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T (null)?[0] ??= d) ..expectStaticType>(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T (null)?[0] ??= intQuestion) ..expectStaticType>(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num - // (which becomes num? after null shorting completes). + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T (null)?[0] ??= d) ..expectStaticType>(); @@ -175,11 +253,21 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()?) { - // K=C1 Function()?, T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function()?, so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function() (which - // becomes A Function()? after null shorting completes). + // This example has: + // - K = C1 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function()? + // We have: + // - T Function()?, Function?>(null)?[0] ??= callableClassC2Int) @@ -188,11 +276,21 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()?) { - // K=C2 Function()?, T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function()?, so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function() (which - // becomes A Function()? after null shorting completes). + // This example has: + // - K = C2 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function()? + // We have: + // - T Function()?, Function?>(null)?[0] ??= callableClassC2Int) @@ -201,11 +299,21 @@ main() { o = 0 as Object?; if (o is int?) { - // K=int?, T1=C1 Function()?, and T2'=C2 Function() (coerced - // from T2=CallableClass>), therefore T=A Function() and S=int?, - // so T is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type - // of E is A Function() (which becomes A Function()? after null shorting - // completes). + // This example has: + // - K = int? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int? + // We have: + // - T Function()?, Function?>(null)?[0] ??= callableClassC2Int) diff --git a/tests/language/inference_update_3/if_null_assignment_null_aware_index_expression_test.dart b/tests/language/inference_update_3/if_null_assignment_null_aware_index_expression_test.dart index 96ef25bcc76..cc72f707aff 100644 --- a/tests/language/inference_update_3/if_null_assignment_null_aware_index_expression_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_null_aware_index_expression_test.dart @@ -50,18 +50,18 @@ Indexable? maybeIndexable( Indexable(value); main() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -72,80 +72,138 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object?, T1=int?, and T2'=double, therefore T=num and S=Object?, so T - // <: S, and hence the type of E is num (which becomes num? after null - // shorting completes). + // This example has: + // - K = Object? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object? + // We have: + // - T <: S + // Therefore the type of `e` is T = num. + // (Which becomes num? after null shorting completes.) var d = 2.0; context((maybeIndexable(null)?[0] ??= d) ..expectStaticType>()); - // K=Iterable<_>?, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable?, so T <: S, and hence the type - // of E is Iterable (which becomes Iterable? after null shorting - // completes). + // This example has: + // - K = Iterable<_>? + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable? + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. + // (Which becomes Iterable? after null shorting completes.) var iterableDouble = [] as Iterable; contextIterableQuestion( (maybeIndexable?, Object?>(null)?[0] ??= iterableDouble) ..expectStaticType?>>()); - // K=Function?, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function?, so T <: S, - // and hence the type of E is Function (which becomes Function? after null - // shorting completes). + // This example has: + // - K = Function? + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function? + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. + // (Which becomes Function? after null shorting completes.) var callableClassInt = CallableClass(); context((maybeIndexable(null)?[0] ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, then the type of `e` is S. { - // K=B1<_>?, T1=C1?, and T2'=C2, therefore T=A and - // S=B1?, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is B1 (which becomes B1? after null - // shorting completes). + // This example has: + // - K = B1<_>? + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1? + // We have: + // - T . + // (Which becomes B1? after null shorting completes.) var c2Double = C2(); contextB1Question((maybeIndexable?, Object?>(null)?[0] ??= c2Double) ..expectStaticType?>>()); - // K=B1?, T1=C1?, and T2'=C2, therefore T=A and - // S=B1?, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1 (which becomes B1? after null - // shorting completes). + // This example has: + // - K = B1? + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1? + // We have: + // - T . + // (Which becomes B1? after null shorting completes.) contextB1Question((maybeIndexable?, Object?>(null)?[0] ??= c2Double) ..expectStaticType?>>()); - // K=Iterable?, T1=Iterable?, and T2'=List, therefore - // T=Object and S=Iterable?, so T is not <: S, but NonNull(T1) <: S and - // T2' <: S, hence the type of E is Iterable (which becomes - // Iterable? after null shorting completes). + // This example has: + // - K = Iterable? + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable? + // We have: + // - T . + // (Which becomes Iterable? after null shorting completes.) var listNum = []; context?>( (maybeIndexable?, Object?>(null)?[0] ??= listNum) ..expectStaticType?>>()); - // K=B1 Function()?, T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function()?, so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is B1 Function() (which becomes B1 - // Function()? after null shorting completes). + // This example has: + // - K = B1 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function()? + // We have: + // - T Function(). + // (Which becomes B1 Function()? after null shorting completes.) var callableClassC2Int = CallableClass>(); context Function()?>( (maybeIndexable Function()?, Function?>(null)?[0] ??= @@ -153,33 +211,67 @@ main() { ..expectStaticType Function()?>>()); } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num (which becomes num? after null shorting completes). + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T (null)?[0] ??= d) ..expectStaticType>(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T (null)?[0] ??= intQuestion) ..expectStaticType>(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num - // (which becomes num? after null shorting completes). + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T (null)?[0] ??= d) ..expectStaticType>(); @@ -188,11 +280,21 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()?) { - // K=C1 Function()?, T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function()?, so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function() (which - // becomes A Function()? after null shorting completes). + // This example has: + // - K = C1 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function()? + // We have: + // - T Function()?, Function?>(null)?[0] ??= callableClassC2Int) @@ -201,11 +303,21 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()?) { - // K=C2 Function()?, T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function()?, so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function() (which - // becomes A Function()? after null shorting completes). + // This example has: + // - K = C2 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function()? + // We have: + // - T Function()?, Function?>(null)?[0] ??= callableClassC2Int) @@ -214,11 +326,21 @@ main() { o = 0 as Object?; if (o is int?) { - // K=int?, T1=C1 Function()?, and T2'=C2 Function() (coerced - // from T2=CallableClass>), therefore T=A Function() and S=int?, - // so T is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type - // of E is A Function() (which becomes A Function()? after null shorting - // completes). + // This example has: + // - K = int? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int? + // We have: + // - T Function()?, Function?>(null)?[0] ??= callableClassC2Int) diff --git a/tests/language/inference_update_3/if_null_assignment_null_aware_property_disabled_test.dart b/tests/language/inference_update_3/if_null_assignment_null_aware_property_disabled_test.dart index 7abb4d3ab5a..9e69f7a6518 100644 --- a/tests/language/inference_update_3/if_null_assignment_null_aware_property_disabled_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_null_aware_property_disabled_test.dart @@ -55,18 +55,18 @@ class Test { main() { var test = Test() as Test?; - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -76,65 +76,109 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object?, T1=int?, and T2'=double, therefore T=num and S=Object?, so T - // <: S, and hence the type of E is num (which becomes num? after null - // shorting completes). + // This example has: + // - K = Object? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object? + // We have: + // - T <: S + // Therefore the type of `e` is T = num. + // (Which becomes num? after null shorting completes.) var d = 2.0; context( (test?.pIntQuestion ??= d)..expectStaticType>()); - // K=Iterable<_>?, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable?, so T <: S, and hence the type - // of E is Iterable (which becomes Iterable? after null shorting - // completes). + // This example has: + // - K = Iterable<_>? + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable? + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. + // (Which becomes Iterable? after null shorting completes.) var iterableDouble = [] as Iterable; contextIterableQuestion((test?.pIterableIntQuestion ??= iterableDouble) ..expectStaticType?>>()); - // K=Function?, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function?, so T <: S, - // and hence the type of E is Function (which becomes Function? after null - // shorting completes). + // This example has: + // - K = Function? + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function? + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. + // (Which becomes Function? after null shorting completes.) var callableClassInt = CallableClass(); context((test?.pFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S` if `inference-update-3` is enabled, else the type of `E` is `T`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, and `inference-update-3` + // is enabled, then the type of `e` is S. { - // K=Iterable?, T1=Iterable?, and T2'=List, therefore - // T=Object and S=Iterable?, so T is not <: S, but NonNull(T1) <: S and - // T2' <: S, hence the type of E is Object (which becomes Object? after null - // shorting completes). + // This example has: + // - K = Iterable? + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable? + // We have: + // - T []; - var o = [0] as Object?; + Object? o; + o = [0] as Object?; if (o is Iterable?) { // We avoid having a compile-time error because `o` can be demoted. o = (test?.pIterableIntQuestion ??= listNum) ..expectStaticType>(); } - // K=B1 Function()?, T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function()?, so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is A Function() (which becomes A Function()? after - // null shorting completes). + // This example has: + // - K = B1 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function()? + // We have: + // - T >(); o = (() => B1()) as Object?; if (o is B1 Function()?) { @@ -144,32 +188,66 @@ main() { } } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num (which becomes num? after null shorting completes). + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num - // (which becomes num? after null shorting completes). + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -177,11 +255,21 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()?) { - // K=C1 Function()?, T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function()?, so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function() (which - // becomes A Function()? after null shorting completes). + // This example has: + // - K = C1 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function()? + // We have: + // - T >(); @@ -189,11 +277,21 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()?) { - // K=C2 Function()?, T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function()?, so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function() (which - // becomes A Function()? after null shorting completes). + // This example has: + // - K = C2 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function()? + // We have: + // - T >(); @@ -201,11 +299,21 @@ main() { o = 0 as Object?; if (o is int?) { - // K=int?, T1=C1 Function()?, and T2'=C2 Function() (coerced - // from T2=CallableClass>), therefore T=A Function() and S=int?, - // so T is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type - // of E is A Function() (which becomes A Function()? after null shorting - // completes). + // This example has: + // - K = int? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int? + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_null_aware_property_test.dart b/tests/language/inference_update_3/if_null_assignment_null_aware_property_test.dart index 0f463092625..a18601bb7a0 100644 --- a/tests/language/inference_update_3/if_null_assignment_null_aware_property_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_null_aware_property_test.dart @@ -60,18 +60,18 @@ class Test { main() { var test = Test() as Test?; - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -81,108 +81,200 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object?, T1=int?, and T2'=double, therefore T=num and S=Object?, so T - // <: S, and hence the type of E is num (which becomes num? after null - // shorting completes). + // This example has: + // - K = Object? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object? + // We have: + // - T <: S + // Therefore the type of `e` is T = num. + // (Which becomes num? after null shorting completes.) var d = 2.0; context( (test?.pIntQuestion ??= d)..expectStaticType>()); - // K=Iterable<_>?, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable?, so T <: S, and hence the type - // of E is Iterable (which becomes Iterable? after null shorting - // completes). + // This example has: + // - K = Iterable<_>? + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable? + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. + // (Which becomes Iterable? after null shorting completes.) var iterableDouble = [] as Iterable; contextIterableQuestion((test?.pIterableIntQuestion ??= iterableDouble) ..expectStaticType?>>()); - // K=Function?, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function?, so T <: S, - // and hence the type of E is Function (which becomes Function? after null - // shorting completes). + // This example has: + // - K = Function? + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function? + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. + // (Which becomes Function? after null shorting completes.) var callableClassInt = CallableClass(); context((test?.pFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, then the type of `e` is S. { - // K=B1<_>?, T1=C1?, and T2'=C2, therefore T=A and - // S=B1?, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is B1 (which becomes B1? after null - // shorting completes). + // This example has: + // - K = B1<_>? + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1? + // We have: + // - T . + // (Which becomes B1? after null shorting completes.) var c2Double = C2(); contextB1Question((test?.pC1IntQuestion ??= c2Double) ..expectStaticType?>>()); - // K=B1?, T1=C1?, and T2'=C2, therefore T=A and - // S=B1?, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1 (which becomes B1? after null - // shorting completes). + // This example has: + // - K = B1? + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1? + // We have: + // - T . + // (Which becomes B1? after null shorting completes.) contextB1Question((test?.pC1IntQuestion ??= c2Double) ..expectStaticType?>>()); - // K=Iterable?, T1=Iterable?, and T2'=List, therefore - // T=Object and S=Iterable?, so T is not <: S, but NonNull(T1) <: S and - // T2' <: S, hence the type of E is Iterable (which becomes - // Iterable? after null shorting completes). + // This example has: + // - K = Iterable? + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable? + // We have: + // - T . + // (Which becomes Iterable? after null shorting completes.) var listNum = []; context?>((test?.pIterableIntQuestion ??= listNum) ..expectStaticType?>>()); - // K=B1 Function()?, T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function()?, so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is B1 Function() (which becomes B1 - // Function()? after null shorting completes). + // This example has: + // - K = B1 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function()? + // We have: + // - T Function(). + // (Which becomes B1 Function()? after null shorting completes.) var callableClassC2Int = CallableClass>(); context Function()?>((test?.pC1IntFunctionQuestion ??= callableClassC2Int) ..expectStaticType Function()?>>()); } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num (which becomes num? after null shorting completes). + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num - // (which becomes num? after null shorting completes). + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -190,11 +282,21 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()?) { - // K=C1 Function()?, T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function()?, so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function() (which - // becomes A Function()? after null shorting completes). + // This example has: + // - K = C1 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function()? + // We have: + // - T >(); @@ -202,11 +304,21 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()?) { - // K=C2 Function()?, T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function()?, so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function() (which - // becomes A Function()? after null shorting completes). + // This example has: + // - K = C2 Function()? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function()? + // We have: + // - T >(); @@ -214,11 +326,21 @@ main() { o = 0 as Object?; if (o is int?) { - // K=int?, T1=C1 Function()?, and T2'=C2 Function() (coerced - // from T2=CallableClass>), therefore T=A Function() and S=int?, - // so T is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type - // of E is A Function() (which becomes A Function()? after null shorting - // completes). + // This example has: + // - K = int? + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int? + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_property_disabled_test.dart b/tests/language/inference_update_3/if_null_assignment_property_disabled_test.dart index 46c018b1dfa..fb4c0ff6e02 100644 --- a/tests/language/inference_update_3/if_null_assignment_property_disabled_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_property_disabled_test.dart @@ -55,18 +55,18 @@ class Test { main() { var test = Test(); - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -76,60 +76,104 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T <: - // S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context( (test.pIntQuestion ??= d)..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((test.pIterableIntQuestion ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((test.pFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S` if `inference-update-3` is enabled, else the type of `E` is `T`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, and `inference-update-3` + // is enabled, then the type of `e` is S. { - // K=Iterable, T1=Iterable?, and T2'=List, therefore T=Object - // and S=Iterable, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is Object. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T []; - var o = [0] as Object?; + Object? o; + o = [0] as Object?; if (o is Iterable) { // We avoid having a compile-time error because `o` can be demoted. o = (test.pIterableIntQuestion ??= listNum) ..expectStaticType>(); } - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function(), so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is A Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T >(); o = (() => B1()) as Object?; if (o is B1 Function()) { @@ -139,31 +183,64 @@ main() { } } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -171,10 +248,20 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T >(); @@ -182,10 +269,20 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T >(); @@ -193,10 +290,20 @@ main() { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced from - // T2=CallableClass>), therefore T=A Function() and S=int, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_property_test.dart b/tests/language/inference_update_3/if_null_assignment_property_test.dart index 6d636ab6634..7f172c19ab8 100644 --- a/tests/language/inference_update_3/if_null_assignment_property_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_property_test.dart @@ -60,18 +60,18 @@ class Test { main() { var test = Test(); - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -81,100 +81,191 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T <: - // S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context( (test.pIntQuestion ??= d)..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((test.pIterableIntQuestion ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((test.pFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, then the type of `e` is S. { - // K=B1<_>, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1. + // This example has: + // - K = B1<_> + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . var c2Double = C2(); contextB1((test.pC1IntQuestion ??= c2Double) ..expectStaticType>>()); - // K=B1, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1. + // This example has: + // - K = B1 + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . contextB1((test.pC1IntQuestion ??= c2Double) ..expectStaticType>>()); - // K=Iterable, T1=Iterable?, and T2'=List, therefore T=Object - // and S=Iterable, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is Iterable. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T . var listNum = []; context>((test.pIterableIntQuestion ??= listNum) ..expectStaticType>>()); - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function(), so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is B1 Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T Function(). var callableClassC2Int = CallableClass>(); context Function()>((test.pC1IntFunctionQuestion ??= callableClassC2Int) ..expectStaticType Function()>>()); } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -182,10 +273,20 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T >(); @@ -193,10 +294,20 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T >(); @@ -204,10 +315,20 @@ main() { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced from - // T2=CallableClass>), therefore T=A Function() and S=int, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_static_property_disabled_test.dart b/tests/language/inference_update_3/if_null_assignment_static_property_disabled_test.dart index 7f1a7968f04..90466a901b6 100644 --- a/tests/language/inference_update_3/if_null_assignment_static_property_disabled_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_static_property_disabled_test.dart @@ -53,18 +53,18 @@ class Test { } main() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -74,60 +74,104 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T <: - // S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context( (Test.staticIntQuestion ??= d)..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((Test.staticIterableIntQuestion ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((Test.staticFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S` if `inference-update-3` is enabled, else the type of `E` is `T`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, and `inference-update-3` + // is enabled, then the type of `e` is S. { - // K=Iterable, T1=Iterable?, and T2'=List, therefore T=Object - // and S=Iterable, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is Object. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T []; - var o = [0] as Object?; + Object? o; + o = [0] as Object?; if (o is Iterable) { // We avoid having a compile-time error because `o` can be demoted. o = (Test.staticIterableIntQuestion ??= listNum) ..expectStaticType>(); } - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function(), so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is A Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T >(); o = (() => B1()) as Object?; if (o is B1 Function()) { @@ -137,31 +181,64 @@ main() { } } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -169,10 +246,20 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T >(); @@ -180,10 +267,20 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T >(); @@ -191,10 +288,20 @@ main() { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced from - // T2=CallableClass>), therefore T=A Function() and S=int, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_static_property_test.dart b/tests/language/inference_update_3/if_null_assignment_static_property_test.dart index ff18c4f4b1d..7fce7c4f7d7 100644 --- a/tests/language/inference_update_3/if_null_assignment_static_property_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_static_property_test.dart @@ -58,18 +58,18 @@ class Test { } main() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -79,100 +79,191 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T <: - // S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context( (Test.staticIntQuestion ??= d)..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((Test.staticIterableIntQuestion ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((Test.staticFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, then the type of `e` is S. { - // K=B1<_>, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1. + // This example has: + // - K = B1<_> + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . var c2Double = C2(); contextB1((Test.staticC1IntQuestion ??= c2Double) ..expectStaticType>>()); - // K=B1, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1. + // This example has: + // - K = B1 + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . contextB1((Test.staticC1IntQuestion ??= c2Double) ..expectStaticType>>()); - // K=Iterable, T1=Iterable?, and T2'=List, therefore T=Object - // and S=Iterable, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is Iterable. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T . var listNum = []; context>((Test.staticIterableIntQuestion ??= listNum) ..expectStaticType>>()); - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function(), so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is B1 Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T Function(). var callableClassC2Int = CallableClass>(); context Function()>((Test.staticC1IntFunctionQuestion ??= callableClassC2Int) ..expectStaticType Function()>>()); } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -180,10 +271,20 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T >(); @@ -191,10 +292,20 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T >(); @@ -202,10 +313,20 @@ main() { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced from - // T2=CallableClass>), therefore T=A Function() and S=int, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_super_index_expression_disabled_test.dart b/tests/language/inference_update_3/if_null_assignment_super_index_expression_disabled_test.dart index c398730b8bf..947dbd1c186 100644 --- a/tests/language/inference_update_3/if_null_assignment_super_index_expression_disabled_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_super_index_expression_disabled_test.dart @@ -42,15 +42,15 @@ class Indexable { operator []=(int index, WriteType value) {} } -// - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` is +// - An if-null assignment `e` of the form `e1 ??= e2` with context type K is // analyzed as follows: // -// - Let `T1` be the read type of `e1`. This is the static type that `e1` -// would have as an expression with a context type schema of `_`. -// - Let `T2` be the type of `e2` inferred with context type `J`, where: -// - If the lvalue is a local variable, `J` is the current (possibly -// promoted) type of the variable. -// - Otherwise, `J` is the write type `e1`. This is the type schema that the +// - Let T1 be the read type of `e1`. This is the static type that `e1` would +// have as an expression with a context type schema of `_`. +// - Let T2 be the type of `e2` inferred with context type J, where: +// - If the lvalue is a local variable, J is the current (possibly promoted) +// type of the variable. +// - Otherwise, J is the write type `e1`. This is the type schema that the // setter associated with `e1` imposes on its single argument (or, for the // case of indexed assignment, the type schema that `operator[]=` imposes // on its second argument). @@ -71,24 +71,33 @@ class Test2 extends Indexable { } } -// - Let `J'` be the unpromoted write type of `e1`, defined as follows: -// - If `e1` is a local variable, `J'` is the declared (unpromoted) type of +// - Let J' be the unpromoted write type of `e1`, defined as follows: +// - If `e1` is a local variable, J' is the declared (unpromoted) type of // `e1`. -// - Otherwise `J' = J`. -// - Let `T2'` be the coerced type of `e2`, defined as follows: -// - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is needed). -// - Otherwise, if `T2` can be coerced to a some other type which *is* a -// subtype of `J'`, then apply that coercion and let `T2'` be the type +// - Otherwise J' = J. +// - Let T2' be the coerced type of `e2`, defined as follows: +// - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). +// - Otherwise, if T2 can be coerced to a some other type which *is* a +// subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. -// - Let `T` be `UP(NonNull(T1), T2')`. -// - Let `S` be the greatest closure of `K`. -// - If `T <: S`, then the type of `E` is `T`. +// - Let T be UP(NonNull(T1), T2'). +// - Let S be the greatest closure of K. +// - If T <: S, then the type of `e` is T. +// (Testing this case here. Otherwise continued below.) class Test3 extends Indexable { Test3() : super(null); test() { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T <: - // S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context((super[0] ??= d)..expectStaticType>()); } @@ -97,9 +106,16 @@ class Test3 extends Indexable { class Test4 extends Indexable?, Object?> { Test4() : super(null); test() { - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((super[0] ??= iterableDouble) ..expectStaticType>>()); @@ -109,25 +125,44 @@ class Test4 extends Indexable?, Object?> { class Test5 extends Indexable { Test5() : super(null); test() { - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context( (super[0] ??= callableClassInt)..expectStaticType>()); } } -// - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` is -// `S` if `inference-update-3` is enabled, else the type of `E` is `T`. +// - Otherwise, if NonNull(T1) <: S and T2' <: S, and `inference-update-3` is +// enabled, then the type of `e` is S. class Test6 extends Indexable?, Object?> { Test6() : super(null); test() { - // K=Iterable, T1=Iterable?, and T2'=List, therefore T=Object - // and S=Iterable, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is Object. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T []; - var o = [0] as Object?; + Object? o; + o = [0] as Object?; if (o is Iterable) { // We avoid having a compile-time error because `o` can be demoted. o = (super[0] ??= listNum)..expectStaticType>(); @@ -138,12 +173,23 @@ class Test6 extends Indexable?, Object?> { class Test7 extends Indexable Function()?, Function?> { Test7() : super(null); test() { - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function(), so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is A Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T >(); - var o = (() => B1()) as Object?; + Object? o; + o = (() => B1()) as Object?; if (o is B1 Function()) { // We avoid having a compile-time error because `o` can be demoted. o = (super[0] ??= callableClassC2Int) @@ -152,16 +198,27 @@ class Test7 extends Indexable Function()?, Function?> { } } -// - Otherwise, the type of `E` is `T`. +// - Otherwise, the type of `e` is T. class Test8 extends Indexable { Test8() : super(null); test() { var d = 2.0; - var o = 0 as Object?; + Object? o; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } @@ -172,11 +229,22 @@ class Test9 extends Indexable { Test9() : super(null); test() { var intQuestion = null as int?; - var o = 0 as Object?; + Object? o; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } @@ -187,10 +255,23 @@ class Test10 extends Indexable { Test10() : super(null); test() { var d = 2.0; - var o = '' as Object?; + Object? o; + o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -201,12 +282,23 @@ class Test11 extends Indexable Function()?, Function?> { Test11() : super(null); test() { var callableClassC2Int = CallableClass>(); - var o = (() => C1()) as Object?; + Object? o; + o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T >(); @@ -218,12 +310,23 @@ class Test12 extends Indexable Function()?, Function?> { Test12() : super(null); test() { var callableClassC2Int = CallableClass>(); - var o = (() => C2()) as Object?; + Object? o; + o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T >(); @@ -235,12 +338,23 @@ class Test13 extends Indexable Function()?, Function?> { Test13() : super(null); test() { var callableClassC2Int = CallableClass>(); - var o = 0 as Object?; + Object? o; + o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced from - // T2=CallableClass>), therefore T=A Function() and S=int, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_super_index_expression_test.dart b/tests/language/inference_update_3/if_null_assignment_super_index_expression_test.dart index 4a20e5b71e9..4d6fbcb591d 100644 --- a/tests/language/inference_update_3/if_null_assignment_super_index_expression_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_super_index_expression_test.dart @@ -46,15 +46,15 @@ class Indexable { operator []=(int index, WriteType value) {} } -// - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` is +// - An if-null assignment `e` of the form `e1 ??= e2` with context type K is // analyzed as follows: // -// - Let `T1` be the read type of `e1`. This is the static type that `e1` -// would have as an expression with a context type schema of `_`. -// - Let `T2` be the type of `e2` inferred with context type `J`, where: -// - If the lvalue is a local variable, `J` is the current (possibly -// promoted) type of the variable. -// - Otherwise, `J` is the write type `e1`. This is the type schema that the +// - Let T1 be the read type of `e1`. This is the static type that `e1` would +// have as an expression with a context type schema of `_`. +// - Let T2 be the type of `e2` inferred with context type J, where: +// - If the lvalue is a local variable, J is the current (possibly promoted) +// type of the variable. +// - Otherwise, J is the write type `e1`. This is the type schema that the // setter associated with `e1` imposes on its single argument (or, for the // case of indexed assignment, the type schema that `operator[]=` imposes // on its second argument). @@ -75,24 +75,33 @@ class Test2 extends Indexable { } } -// - Let `J'` be the unpromoted write type of `e1`, defined as follows: -// - If `e1` is a local variable, `J'` is the declared (unpromoted) type of +// - Let J' be the unpromoted write type of `e1`, defined as follows: +// - If `e1` is a local variable, J' is the declared (unpromoted) type of // `e1`. -// - Otherwise `J' = J`. -// - Let `T2'` be the coerced type of `e2`, defined as follows: -// - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is needed). -// - Otherwise, if `T2` can be coerced to a some other type which *is* a -// subtype of `J'`, then apply that coercion and let `T2'` be the type +// - Otherwise J' = J. +// - Let T2' be the coerced type of `e2`, defined as follows: +// - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). +// - Otherwise, if T2 can be coerced to a some other type which *is* a +// subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. -// - Let `T` be `UP(NonNull(T1), T2')`. -// - Let `S` be the greatest closure of `K`. -// - If `T <: S`, then the type of `E` is `T`. +// - Let T be UP(NonNull(T1), T2'). +// - Let S be the greatest closure of K. +// - If T <: S, then the type of `e` is T. +// (Testing this case here. Otherwise continued below.) class Test3 extends Indexable { Test3() : super(null); test() { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T <: - // S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context((super[0] ??= d)..expectStaticType>()); } @@ -101,9 +110,16 @@ class Test3 extends Indexable { class Test4 extends Indexable?, Object?> { Test4() : super(null); test() { - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((super[0] ??= iterableDouble) ..expectStaticType>>()); @@ -113,23 +129,39 @@ class Test4 extends Indexable?, Object?> { class Test5 extends Indexable { Test5() : super(null); test() { - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context( (super[0] ??= callableClassInt)..expectStaticType>()); } } -// - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` is -// `S`. +// - Otherwise, if NonNull(T1) <: S and T2' <: S, then the type of `e` is S. class Test6 extends Indexable?, Object?> { Test6() : super(null); test() { - // K=B1<_>, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1. + // This example has: + // - K = B1<_> + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . var c2Double = C2(); contextB1( (super[0] ??= c2Double)..expectStaticType>>()); @@ -139,9 +171,18 @@ class Test6 extends Indexable?, Object?> { class Test7 extends Indexable?, Object?> { Test7() : super(null); test() { - // K=B1, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1. + // This example has: + // - K = B1 + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . var c2Double = C2(); contextB1( (super[0] ??= c2Double)..expectStaticType>>()); @@ -151,9 +192,18 @@ class Test7 extends Indexable?, Object?> { class Test8 extends Indexable?, Object?> { Test8() : super(null); test() { - // K=Iterable, T1=Iterable?, and T2'=List, therefore T=Object - // and S=Iterable, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is Iterable. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T . var listNum = []; context>( (super[0] ??= listNum)..expectStaticType>>()); @@ -163,26 +213,46 @@ class Test8 extends Indexable?, Object?> { class Test9 extends Indexable Function()?, Function?> { Test9() : super(null); test() { - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function(), so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is B1 Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T Function(). var callableClassC2Int = CallableClass>(); context Function()>((super[0] ??= callableClassC2Int) ..expectStaticType Function()>>()); } } -// - Otherwise, the type of `E` is `T`. +// - Otherwise, the type of `e` is T. class Test10 extends Indexable { Test10() : super(null); test() { var d = 2.0; - var o = 0 as Object?; + Object? o; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } @@ -193,11 +263,22 @@ class Test11 extends Indexable { Test11() : super(null); test() { var intQuestion = null as int?; - var o = 0 as Object?; + Object? o; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } @@ -208,10 +289,23 @@ class Test12 extends Indexable { Test12() : super(null); test() { var d = 2.0; - var o = '' as Object?; + Object? o; + o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -222,12 +316,23 @@ class Test13 extends Indexable Function()?, Function?> { Test13() : super(null); test() { var callableClassC2Int = CallableClass>(); - var o = (() => C1()) as Object?; + Object? o; + o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T >(); @@ -239,12 +344,23 @@ class Test14 extends Indexable Function()?, Function?> { Test14() : super(null); test() { var callableClassC2Int = CallableClass>(); - var o = (() => C2()) as Object?; + Object? o; + o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T >(); @@ -256,12 +372,23 @@ class Test15 extends Indexable Function()?, Function?> { Test15() : super(null); test() { var callableClassC2Int = CallableClass>(); - var o = 0 as Object?; + Object? o; + o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced from - // T2=CallableClass>), therefore T=A Function() and S=int, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_super_property_disabled_test.dart b/tests/language/inference_update_3/if_null_assignment_super_property_disabled_test.dart index c04566c3790..c496aceb7c5 100644 --- a/tests/language/inference_update_3/if_null_assignment_super_property_disabled_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_super_property_disabled_test.dart @@ -55,15 +55,15 @@ class Base { class Test extends Base { test() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K // is analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that + // - Otherwise, J is the write type `e1`. This is the type schema that // the setter associated with `e1` imposes on its single argument (or, // for the case of indexed assignment, the type schema that // `operator[]=` imposes on its second argument). @@ -76,61 +76,104 @@ class Test extends Base { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T - // <: S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context( (super.pIntQuestion ??= d)..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type - // of E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((super.pIterableIntQuestion ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((super.pFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S` if `inference-update-3` is enabled, else the type of `E` is - // `T`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, and `inference-update-3` + // is enabled, then the type of `e` is S. { - // K=Iterable, T1=Iterable?, and T2'=List, therefore - // T=Object and S=Iterable, so T is not <: S, but NonNull(T1) <: S - // and T2' <: S, hence the type of E is Object. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T []; - var o = [0] as Object?; + Object? o; + o = [0] as Object?; if (o is Iterable) { // We avoid having a compile-time error because `o` can be demoted. o = (super.pIterableIntQuestion ??= listNum) ..expectStaticType>(); } - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=B1 Function(), so T is not <: S, but NonNull(T1) - // <: S and T2' <: S, hence the type of E is A Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T >(); o = (() => B1()) as Object?; if (o is B1 Function()) { @@ -140,31 +183,64 @@ class Test extends Base { } } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E - // is num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T - // is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of - // E is num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -172,10 +248,20 @@ class Test extends Base { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T >(); @@ -183,10 +269,20 @@ class Test extends Base { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T >(); @@ -194,10 +290,20 @@ class Test extends Base { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced - // from T2=CallableClass>), therefore T=A Function() and S=int, - // so T is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the - // type of E is A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_super_property_test.dart b/tests/language/inference_update_3/if_null_assignment_super_property_test.dart index 99738d9355c..9986d752694 100644 --- a/tests/language/inference_update_3/if_null_assignment_super_property_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_super_property_test.dart @@ -60,15 +60,15 @@ class Base { class Test extends Base { test() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K // is analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that + // - Otherwise, J is the write type `e1`. This is the type schema that // the setter associated with `e1` imposes on its single argument (or, // for the case of indexed assignment, the type schema that // `operator[]=` imposes on its second argument). @@ -81,100 +81,192 @@ class Test extends Base { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T - // <: S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context( (super.pIntQuestion ??= d)..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type - // of E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((super.pIterableIntQuestion ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((super.pFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, then the type of `e` is + // S. { - // K=B1<_>, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is B1. + // This example has: + // - K = B1<_> + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . var c2Double = C2(); contextB1((super.pC1IntQuestion ??= c2Double) ..expectStaticType>>()); - // K=B1, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is B1. + // This example has: + // - K = B1 + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . contextB1((super.pC1IntQuestion ??= c2Double) ..expectStaticType>>()); - // K=Iterable, T1=Iterable?, and T2'=List, therefore - // T=Object and S=Iterable, so T is not <: S, but NonNull(T1) <: S - // and T2' <: S, hence the type of E is Iterable. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T . var listNum = []; context>((super.pIterableIntQuestion ??= listNum) ..expectStaticType>>()); - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=B1 Function(), so T is not <: S, but NonNull(T1) - // <: S and T2' <: S, hence the type of E is B1 Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T Function(). var callableClassC2Int = CallableClass>(); context Function()>((super.pC1IntFunctionQuestion ??= callableClassC2Int) ..expectStaticType Function()>>()); } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E - // is num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T - // is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of - // E is num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -182,10 +274,20 @@ class Test extends Base { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T >(); @@ -193,10 +295,20 @@ class Test extends Base { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T >(); @@ -204,10 +316,20 @@ class Test extends Base { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced - // from T2=CallableClass>), therefore T=A Function() and S=int, - // so T is not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the - // type of E is A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_this_index_expression_disabled_test.dart b/tests/language/inference_update_3/if_null_assignment_this_index_expression_disabled_test.dart index ec9e85950be..c628d4c62ed 100644 --- a/tests/language/inference_update_3/if_null_assignment_this_index_expression_disabled_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_this_index_expression_disabled_test.dart @@ -42,15 +42,15 @@ class Indexable { operator []=(int index, WriteType value) {} } -// - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` is +// - An if-null assignment `e` of the form `e1 ??= e2` with context type K is // analyzed as follows: // -// - Let `T1` be the read type of `e1`. This is the static type that `e1` -// would have as an expression with a context type schema of `_`. -// - Let `T2` be the type of `e2` inferred with context type `J`, where: -// - If the lvalue is a local variable, `J` is the current (possibly -// promoted) type of the variable. -// - Otherwise, `J` is the write type `e1`. This is the type schema that the +// - Let T1 be the read type of `e1`. This is the static type that `e1` would +// have as an expression with a context type schema of `_`. +// - Let T2 be the type of `e2` inferred with context type J, where: +// - If the lvalue is a local variable, J is the current (possibly promoted) +// type of the variable. +// - Otherwise, J is the write type `e1`. This is the type schema that the // setter associated with `e1` imposes on its single argument (or, for the // case of indexed assignment, the type schema that `operator[]=` imposes // on its second argument). @@ -71,24 +71,33 @@ class Test2 extends Indexable { } } -// - Let `J'` be the unpromoted write type of `e1`, defined as follows: -// - If `e1` is a local variable, `J'` is the declared (unpromoted) type of +// - Let J' be the unpromoted write type of `e1`, defined as follows: +// - If `e1` is a local variable, J' is the declared (unpromoted) type of // `e1`. -// - Otherwise `J' = J`. -// - Let `T2'` be the coerced type of `e2`, defined as follows: -// - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is needed). -// - Otherwise, if `T2` can be coerced to a some other type which *is* a -// subtype of `J'`, then apply that coercion and let `T2'` be the type +// - Otherwise J' = J. +// - Let T2' be the coerced type of `e2`, defined as follows: +// - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). +// - Otherwise, if T2 can be coerced to a some other type which *is* a +// subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. -// - Let `T` be `UP(NonNull(T1), T2')`. -// - Let `S` be the greatest closure of `K`. -// - If `T <: S`, then the type of `E` is `T`. +// - Let T be UP(NonNull(T1), T2'). +// - Let S be the greatest closure of K. +// - If T <: S, then the type of `e` is T. +// (Testing this case here. Otherwise continued below.) class Test3 extends Indexable { Test3() : super(null); test() { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T <: - // S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context((this[0] ??= d)..expectStaticType>()); } @@ -97,9 +106,16 @@ class Test3 extends Indexable { class Test4 extends Indexable?, Object?> { Test4() : super(null); test() { - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((this[0] ??= iterableDouble) ..expectStaticType>>()); @@ -109,25 +125,44 @@ class Test4 extends Indexable?, Object?> { class Test5 extends Indexable { Test5() : super(null); test() { - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context( (this[0] ??= callableClassInt)..expectStaticType>()); } } -// - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` is -// `S` if `inference-update-3` is enabled, else the type of `E` is `T`. +// - Otherwise, if NonNull(T1) <: S and T2' <: S, and `inference-update-3` is +// enabled, then the type of `e` is S. class Test6 extends Indexable?, Object?> { Test6() : super(null); test() { - // K=Iterable, T1=Iterable?, and T2'=List, therefore T=Object - // and S=Iterable, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is Object. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T []; - var o = [0] as Object?; + Object? o; + o = [0] as Object?; if (o is Iterable) { // We avoid having a compile-time error because `o` can be demoted. o = (this[0] ??= listNum)..expectStaticType>(); @@ -138,12 +173,23 @@ class Test6 extends Indexable?, Object?> { class Test7 extends Indexable Function()?, Function?> { Test7() : super(null); test() { - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function(), so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is A Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T >(); - var o = (() => B1()) as Object?; + Object? o; + o = (() => B1()) as Object?; if (o is B1 Function()) { // We avoid having a compile-time error because `o` can be demoted. o = (this[0] ??= callableClassC2Int) @@ -152,16 +198,27 @@ class Test7 extends Indexable Function()?, Function?> { } } -// - Otherwise, the type of `E` is `T`. +// - Otherwise, the type of `e` is T. class Test8 extends Indexable { Test8() : super(null); test() { var d = 2.0; - var o = 0 as Object?; + Object? o; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } @@ -172,11 +229,22 @@ class Test9 extends Indexable { Test9() : super(null); test() { var intQuestion = null as int?; - var o = 0 as Object?; + Object? o; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } @@ -187,10 +255,23 @@ class Test10 extends Indexable { Test10() : super(null); test() { var d = 2.0; - var o = '' as Object?; + Object? o; + o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -201,12 +282,23 @@ class Test11 extends Indexable Function()?, Function?> { Test11() : super(null); test() { var callableClassC2Int = CallableClass>(); - var o = (() => C1()) as Object?; + Object? o; + o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T >(); @@ -218,12 +310,23 @@ class Test12 extends Indexable Function()?, Function?> { Test12() : super(null); test() { var callableClassC2Int = CallableClass>(); - var o = (() => C2()) as Object?; + Object? o; + o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T >(); @@ -235,12 +338,23 @@ class Test13 extends Indexable Function()?, Function?> { Test13() : super(null); test() { var callableClassC2Int = CallableClass>(); - var o = 0 as Object?; + Object? o; + o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced from - // T2=CallableClass>), therefore T=A Function() and S=int, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_this_index_expression_test.dart b/tests/language/inference_update_3/if_null_assignment_this_index_expression_test.dart index 06e181e1735..2cd5e83f7d8 100644 --- a/tests/language/inference_update_3/if_null_assignment_this_index_expression_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_this_index_expression_test.dart @@ -46,15 +46,15 @@ class Indexable { operator []=(int index, WriteType value) {} } -// - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` is +// - An if-null assignment `e` of the form `e1 ??= e2` with context type K is // analyzed as follows: // -// - Let `T1` be the read type of `e1`. This is the static type that `e1` -// would have as an expression with a context type schema of `_`. -// - Let `T2` be the type of `e2` inferred with context type `J`, where: -// - If the lvalue is a local variable, `J` is the current (possibly -// promoted) type of the variable. -// - Otherwise, `J` is the write type `e1`. This is the type schema that the +// - Let T1 be the read type of `e1`. This is the static type that `e1` would +// have as an expression with a context type schema of `_`. +// - Let T2 be the type of `e2` inferred with context type J, where: +// - If the lvalue is a local variable, J is the current (possibly promoted) +// type of the variable. +// - Otherwise, J is the write type `e1`. This is the type schema that the // setter associated with `e1` imposes on its single argument (or, for the // case of indexed assignment, the type schema that `operator[]=` imposes // on its second argument). @@ -75,24 +75,33 @@ class Test2 extends Indexable { } } -// - Let `J'` be the unpromoted write type of `e1`, defined as follows: -// - If `e1` is a local variable, `J'` is the declared (unpromoted) type of +// - Let J' be the unpromoted write type of `e1`, defined as follows: +// - If `e1` is a local variable, J' is the declared (unpromoted) type of // `e1`. -// - Otherwise `J' = J`. -// - Let `T2'` be the coerced type of `e2`, defined as follows: -// - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is needed). -// - Otherwise, if `T2` can be coerced to a some other type which *is* a -// subtype of `J'`, then apply that coercion and let `T2'` be the type +// - Otherwise J' = J. +// - Let T2' be the coerced type of `e2`, defined as follows: +// - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). +// - Otherwise, if T2 can be coerced to a some other type which *is* a +// subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. -// - Let `T` be `UP(NonNull(T1), T2')`. -// - Let `S` be the greatest closure of `K`. -// - If `T <: S`, then the type of `E` is `T`. +// - Let T be UP(NonNull(T1), T2'). +// - Let S be the greatest closure of K. +// - If T <: S, then the type of `e` is T. +// (Testing this case here. Otherwise continued below.) class Test3 extends Indexable { Test3() : super(null); test() { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T <: - // S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context((this[0] ??= d)..expectStaticType>()); } @@ -101,9 +110,16 @@ class Test3 extends Indexable { class Test4 extends Indexable?, Object?> { Test4() : super(null); test() { - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((this[0] ??= iterableDouble) ..expectStaticType>>()); @@ -113,23 +129,39 @@ class Test4 extends Indexable?, Object?> { class Test5 extends Indexable { Test5() : super(null); test() { - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context( (this[0] ??= callableClassInt)..expectStaticType>()); } } -// - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` is -// `S`. +// - Otherwise, if NonNull(T1) <: S and T2' <: S, then the type of `e` is S. class Test6 extends Indexable?, Object?> { Test6() : super(null); test() { - // K=B1<_>, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1. + // This example has: + // - K = B1<_> + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . var c2Double = C2(); contextB1((this[0] ??= c2Double)..expectStaticType>>()); } @@ -138,9 +170,18 @@ class Test6 extends Indexable?, Object?> { class Test7 extends Indexable?, Object?> { Test7() : super(null); test() { - // K=B1, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1. + // This example has: + // - K = B1 + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . var c2Double = C2(); contextB1( (this[0] ??= c2Double)..expectStaticType>>()); @@ -150,9 +191,18 @@ class Test7 extends Indexable?, Object?> { class Test8 extends Indexable?, Object?> { Test8() : super(null); test() { - // K=Iterable, T1=Iterable?, and T2'=List, therefore T=Object - // and S=Iterable, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is Iterable. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T . var listNum = []; context>( (this[0] ??= listNum)..expectStaticType>>()); @@ -162,26 +212,46 @@ class Test8 extends Indexable?, Object?> { class Test9 extends Indexable Function()?, Function?> { Test9() : super(null); test() { - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function(), so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is B1 Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T Function(). var callableClassC2Int = CallableClass>(); context Function()>((this[0] ??= callableClassC2Int) ..expectStaticType Function()>>()); } } -// - Otherwise, the type of `E` is `T`. +// - Otherwise, the type of `e` is T. class Test10 extends Indexable { Test10() : super(null); test() { var d = 2.0; - var o = 0 as Object?; + Object? o; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } @@ -192,11 +262,22 @@ class Test11 extends Indexable { Test11() : super(null); test() { var intQuestion = null as int?; - var o = 0 as Object?; + Object? o; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } @@ -207,10 +288,23 @@ class Test12 extends Indexable { Test12() : super(null); test() { var d = 2.0; - var o = '' as Object?; + Object? o; + o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -221,12 +315,23 @@ class Test13 extends Indexable Function()?, Function?> { Test13() : super(null); test() { var callableClassC2Int = CallableClass>(); - var o = (() => C1()) as Object?; + Object? o; + o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T >(); @@ -238,12 +343,23 @@ class Test14 extends Indexable Function()?, Function?> { Test14() : super(null); test() { var callableClassC2Int = CallableClass>(); - var o = (() => C2()) as Object?; + Object? o; + o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T >(); @@ -255,12 +371,23 @@ class Test15 extends Indexable Function()?, Function?> { Test15() : super(null); test() { var callableClassC2Int = CallableClass>(); - var o = 0 as Object?; + Object? o; + o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced from - // T2=CallableClass>), therefore T=A Function() and S=int, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_top_level_property_disabled_test.dart b/tests/language/inference_update_3/if_null_assignment_top_level_property_disabled_test.dart index 63ba40a9eae..741314f7c17 100644 --- a/tests/language/inference_update_3/if_null_assignment_top_level_property_disabled_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_top_level_property_disabled_test.dart @@ -50,18 +50,18 @@ String? get topLevelStringQuestion => null; set topLevelStringQuestion(String? value) {} main() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -71,60 +71,104 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T <: - // S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context( (topLevelIntQuestion ??= d)..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((topLevelIterableIntQuestion ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((topLevelFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S` if `inference-update-3` is enabled, else the type of `E` is `T`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, and `inference-update-3` + // is enabled, then the type of `e` is S. { - // K=Iterable, T1=Iterable?, and T2'=List, therefore T=Object - // and S=Iterable, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is Object. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T []; - var o = [0] as Object?; + Object? o; + o = [0] as Object?; if (o is Iterable) { // We avoid having a compile-time error because `o` can be demoted. o = (topLevelIterableIntQuestion ??= listNum) ..expectStaticType>(); } - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function(), so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is A Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T >(); o = (() => B1()) as Object?; if (o is B1 Function()) { @@ -134,31 +178,64 @@ main() { } } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -166,10 +243,20 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T >(); @@ -177,10 +264,20 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T >(); @@ -188,10 +285,20 @@ main() { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced from - // T2=CallableClass>), therefore T=A Function() and S=int, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_assignment_top_level_property_test.dart b/tests/language/inference_update_3/if_null_assignment_top_level_property_test.dart index 7dfaaa20c81..bb46abd3466 100644 --- a/tests/language/inference_update_3/if_null_assignment_top_level_property_test.dart +++ b/tests/language/inference_update_3/if_null_assignment_top_level_property_test.dart @@ -54,18 +54,18 @@ String? get topLevelStringQuestion => null; set topLevelStringQuestion(String? value) {} main() { - // - An if-null assignment `E` of the form `e1 ??= e2` with context type `K` - // is analyzed as follows: + // - An if-null assignment `e` of the form `e1 ??= e2` with context type K is + // analyzed as follows: // - // - Let `T1` be the read type of `e1`. This is the static type that `e1` + // - Let T1 be the read type of `e1`. This is the static type that `e1` // would have as an expression with a context type schema of `_`. - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If the lvalue is a local variable, `J` is the current (possibly + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If the lvalue is a local variable, J is the current (possibly // promoted) type of the variable. - // - Otherwise, `J` is the write type `e1`. This is the type schema that - // the setter associated with `e1` imposes on its single argument (or, - // for the case of indexed assignment, the type schema that - // `operator[]=` imposes on its second argument). + // - Otherwise, J is the write type `e1`. This is the type schema that the + // setter associated with `e1` imposes on its single argument (or, for + // the case of indexed assignment, the type schema that `operator[]=` + // imposes on its second argument). { // Check the context type of `e`. // ignore: dead_null_aware_expression @@ -75,100 +75,191 @@ main() { ..expectStaticType>(); } - // - Let `J'` be the unpromoted write type of `e1`, defined as follows: - // - If `e1` is a local variable, `J'` is the declared (unpromoted) type - // of `e1`. - // - Otherwise `J' = J`. - // - Let `T2'` be the coerced type of `e2`, defined as follows: - // - If `T2` is a subtype of `J'`, then `T2' = T2` (no coercion is - // needed). - // - Otherwise, if `T2` can be coerced to a some other type which *is* a - // subtype of `J'`, then apply that coercion and let `T2'` be the type + // - Let J' be the unpromoted write type of `e1`, defined as follows: + // - If `e1` is a local variable, J' is the declared (unpromoted) type of + // `e1`. + // - Otherwise J' = J. + // - Let T2' be the coerced type of `e2`, defined as follows: + // - If T2 is a subtype of J', then T2' = T2 (no coercion is needed). + // - Otherwise, if T2 can be coerced to a some other type which *is* a + // subtype of J', then apply that coercion and let T2' be the type // resulting from the coercion. // - Otherwise, it is a compile-time error. - // - Let `T` be `UP(NonNull(T1), T2')`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2'). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2'=double, therefore T=num and S=Object, so T <: - // S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context( (topLevelIntQuestion ??= d)..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2'=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2' = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableDouble = [] as Iterable; contextIterable((topLevelIterableIntQuestion ??= iterableDouble) ..expectStaticType>>()); - // K=Function, T1=Function?, and T2'=int Function() (coerced from - // T2=CallableClass), therefore T=Function and S=Function, so T <: S, - // and hence the type of E is Function. + // This example has: + // - K = Function + // - T1 = Function? + // - T2' = int Function() + // (coerced from T2=CallableClass) + // Which implies: + // - T = Function + // - S = Function + // We have: + // - T <: S + // Therefore the type of `e` is T = Function. var callableClassInt = CallableClass(); context((topLevelFunctionQuestion ??= callableClassInt) ..expectStaticType>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2' <: S`, then the type of `E` - // is `S`. + // - Otherwise, if NonNull(T1) <: S and T2' <: S, then the type of `e` is S. { - // K=B1<_>, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1. + // This example has: + // - K = B1<_> + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . var c2Double = C2(); contextB1((topLevelC1IntQuestion ??= c2Double) ..expectStaticType>>()); - // K=B1, T1=C1?, and T2'=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2' <: S, hence - // the type of E is B1. + // This example has: + // - K = B1 + // - T1 = C1? + // - T2' = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . contextB1((topLevelC1IntQuestion ??= c2Double) ..expectStaticType>>()); - // K=Iterable, T1=Iterable?, and T2'=List, therefore T=Object - // and S=Iterable, so T is not <: S, but NonNull(T1) <: S and T2' <: S, - // hence the type of E is Iterable. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2' = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T . var listNum = []; context>((topLevelIterableIntQuestion ??= listNum) ..expectStaticType>>()); - // K=B1 Function(), T1=C1 Function()?, and T2'=C2 Function() - // (coerced from T2=CallableClass>), therefore T=A Function() and - // S=B1 Function(), so T is not <: S, but NonNull(T1) <: S and T2' <: - // S, hence the type of E is B1 Function(). + // This example has: + // - K = B1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = B1 Function() + // We have: + // - T Function(). var callableClassC2Int = CallableClass>(); context Function()>((topLevelC1IntFunctionQuestion ??= callableClassC2Int) ..expectStaticType Function()>>()); } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var d = 2.0; - var o = 0 as Object?; + Object? o; var intQuestion = null as int?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2'=double, therefore T=num and S=int?, so T is - // not <: S. NonNull(T1) <: S, but T2' is not <: S. Hence the type of E is - // num. + // This example has: + // - K = int? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2'=int?, therefore T=num? and S=int?, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2' = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2'=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2' are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2' = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } @@ -176,10 +267,20 @@ main() { var callableClassC2Int = CallableClass>(); o = (() => C1()) as Object?; if (o is C1 Function()) { - // K=C1 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C1 Function(), so T is not <: S. NonNull(T1) <: - // S, but T2' is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C1 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C1 Function() + // We have: + // - T >(); @@ -187,10 +288,20 @@ main() { o = (() => C2()) as Object?; if (o is C2 Function()) { - // K=C2 Function(), T1=C1 Function()?, and T2'=C2 - // Function() (coerced from T2=CallableClass>), therefore T=A - // Function() and S=C2 Function(), so T is not <: S. T2' <: S, but - // NonNull(T1) is not <: S. Hence the type of E is A Function(). + // This example has: + // - K = C2 Function() + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = C2 Function() + // We have: + // - T >(); @@ -198,10 +309,20 @@ main() { o = 0 as Object?; if (o is int) { - // K=int, T1=C1 Function()?, and T2'=C2 Function() (coerced from - // T2=CallableClass>), therefore T=A Function() and S=int, so T is - // not <: S. T2' <: S, but NonNull(T1) is not <: S. Hence the type of E is - // A Function(). + // This example has: + // - K = int + // - T1 = C1 Function()? + // - T2' = C2 Function() + // (coerced from T2=CallableClass>) + // Which implies: + // - T = A Function() + // - S = int + // We have: + // - T >(); diff --git a/tests/language/inference_update_3/if_null_disabled_test.dart b/tests/language/inference_update_3/if_null_disabled_test.dart index 57a9c67de73..a51fc99ddc1 100644 --- a/tests/language/inference_update_3/if_null_disabled_test.dart +++ b/tests/language/inference_update_3/if_null_disabled_test.dart @@ -20,10 +20,10 @@ Object? contextUnknown(T x) => x; Object? contextIterable(Iterable x) => x; main() { - // - An if-null expression `E` of the form `e1 ?? e2` with context type `K` is + // - An if-null expression `e` of the form `e1 ?? e2` with context type K is // analyzed as follows: // - // - Let `T1` be the type of `e1` inferred with context type `K?`. + // - Let T1 be the type of `e1` inferred with context type K?. { // Check the context type of `e1`: // - Where the context is established using a function call argument. @@ -31,7 +31,8 @@ main() { context((contextType(1)..expectStaticType>()) ?? 2); // - Where the context is established using local variable promotion. - var o = 0 as Object?; + Object? o; + o = 0 as Object?; if (o is num?) { o = (contextType(1)..expectStaticType>()) ?? 2; } @@ -41,8 +42,8 @@ main() { } } - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If `K` is `_`, `J = T1`. + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If K is `_`, J = T1. { // Check the context type of `e2`. var string = ''; @@ -54,7 +55,7 @@ main() { (contextType('')..expectStaticType>())); } - // - Otherwise, `J = K`. + // - Otherwise, J = K. { var intQuestion = null as int?; context( @@ -63,64 +64,125 @@ main() { intQuestion ?? (contextType(2)..expectStaticType>())); } - // - Let `T` be `UP(NonNull(T1), T2)`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2=double, therefore T=num and S=Object, so T <: - // S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2 = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var intQuestion = null as int?; var d = 2.0; context((intQuestion ?? d)..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2 = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableIntQuestion = null as Iterable?; var iterableDouble = [] as Iterable; contextIterable((iterableIntQuestion ?? iterableDouble) ..expectStaticType>>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2 <: S`, then the type of `E` is - // `S` if `inference-update-3` is enabled, else the type of `E` is `T`. + // - Otherwise, if NonNull(T1) <: S and T2 <: S, and `inference-update-3` is + // enabled, then the type of `e` is S. { - // K=Iterable, T1=Iterable?, and T2=List, therefore T=Object - // and S=Iterable, so T is not <: S, but NonNull(T1) <: S and T2 <: S, - // hence the type of E is Object. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2 = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T ?; var listNum = []; - var o = [0] as Object?; + Object? o; + o = [0] as Object?; if (o is Iterable) { // We avoid having a compile-time error because `o` can be demoted. o = (iterableIntQuestion ?? listNum)..expectStaticType>(); } } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var intQuestion = null as int?; var d = 2.0; - var o = 0 as Object?; + Object? o; var doubleQuestion = null as double?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2=double, therefore T=num and S=int?, so T is not - // <: S. NonNull(T1) <: S, but T2 is not <: S. Hence the type of E is num. + // This example has: + // - K = int? + // - T1 = int? + // - T2 = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2=int?, therefore T=num? and S=int?, so T is - // not <: S. T2 <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2 = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2 are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2 = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } diff --git a/tests/language/inference_update_3/if_null_test.dart b/tests/language/inference_update_3/if_null_test.dart index ab022423d64..71f67e49bee 100644 --- a/tests/language/inference_update_3/if_null_test.dart +++ b/tests/language/inference_update_3/if_null_test.dart @@ -33,10 +33,10 @@ class C2 implements B1, B2 {} Object? contextB1(B1 x) => x; main() { - // - An if-null expression `E` of the form `e1 ?? e2` with context type `K` is + // - An if-null expression `e` of the form `e1 ?? e2` with context type K is // analyzed as follows: // - // - Let `T1` be the type of `e1` inferred with context type `K?`. + // - Let T1 be the type of `e1` inferred with context type K?. { // Check the context type of `e1`: // - Where the context is established using a function call argument. @@ -44,7 +44,8 @@ main() { context((contextType(1)..expectStaticType>()) ?? 2); // - Where the context is established using local variable promotion. - var o = 0 as Object?; + Object? o; + o = 0 as Object?; if (o is num?) { o = (contextType(1)..expectStaticType>()) ?? 2; } @@ -54,8 +55,8 @@ main() { } } - // - Let `T2` be the type of `e2` inferred with context type `J`, where: - // - If `K` is `_`, `J = T1`. + // - Let T2 be the type of `e2` inferred with context type J, where: + // - If K is `_`, J = T1. { // Check the context type of `e2`. var string = ''; @@ -67,7 +68,7 @@ main() { (contextType('')..expectStaticType>())); } - // - Otherwise, `J = K`. + // - Otherwise, J = K. { var intQuestion = null as int?; context( @@ -76,75 +77,151 @@ main() { intQuestion ?? (contextType(2)..expectStaticType>())); } - // - Let `T` be `UP(NonNull(T1), T2)`. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let T be UP(NonNull(T1), T2). + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. + // (Testing this case here. Otherwise continued below.) { - // K=Object, T1=int?, and T2=double, therefore T=num and S=Object, so T <: - // S, and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int? + // - T2 = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var intQuestion = null as int?; var d = 2.0; context((intQuestion ?? d)..expectStaticType>()); - // K=Iterable<_>, T1=Iterable?, and T2=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable? + // - T2 = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableIntQuestion = null as Iterable?; var iterableDouble = [] as Iterable; contextIterable((iterableIntQuestion ?? iterableDouble) ..expectStaticType>>()); } - // - Otherwise, if `NonNull(T1) <: S` and `T2 <: S`, then the type of `E` is - // `S`. + // - Otherwise, if NonNull(T1) <: S and T2 <: S, then the type of `e` is S. { - // K=B1<_>, T1=C1?, and T2=C2, therefore T=A and S=B1, - // so T is not <: S, but NonNull(T1) <: S and T2 <: S, hence the type of E - // is B1. + // This example has: + // - K = B1<_> + // - T1 = C1? + // - T2 = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . var c1IntQuestion = null as C1?; var c2Double = C2(); contextB1( (c1IntQuestion ?? c2Double)..expectStaticType>>()); - // K=B1, T1=C1?, and T2=C2, therefore T=A and - // S=B1, so T is not <: S, but NonNull(T1) <: S and T2 <: S, hence - // the type of E is B1. + // This example has: + // - K = B1 + // - T1 = C1? + // - T2 = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . contextB1( (c1IntQuestion ?? c2Double)..expectStaticType>>()); - // K=Iterable, T1=Iterable?, and T2=List, therefore T=Object - // and S=Iterable, so T is not <: S, but NonNull(T1) <: S and T2 <: S, - // hence the type of E is Iterable. + // This example has: + // - K = Iterable + // - T1 = Iterable? + // - T2 = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T . var iterableIntQuestion = null as Iterable?; var listNum = []; context>((iterableIntQuestion ?? listNum) ..expectStaticType>>()); } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { var intQuestion = null as int?; var d = 2.0; - var o = 0 as Object?; + Object? o; var doubleQuestion = null as double?; + o = 0 as Object?; if (o is int?) { - // K=int?, T1=int?, and T2=double, therefore T=num and S=int?, so T is not - // <: S. NonNull(T1) <: S, but T2 is not <: S. Hence the type of E is num. + // This example has: + // - K = int? + // - T1 = int? + // - T2 = double + // Which implies: + // - T = num + // - S = int? + // We have: + // - T >(); } o = 0 as Object?; if (o is int?) { - // K=int?, T1=double?, and T2=int?, therefore T=num? and S=int?, so T is - // not <: S. T2 <: S, but NonNull(T1) is not <: S. Hence the type of E is - // num?. + // This example has: + // - K = int? + // - T1 = double? + // - T2 = int? + // Which implies: + // - T = num? + // - S = int? + // We have: + // - T >(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int?, and T2=double, therefore T=num and S=String?, so - // none of T, NonNull(T1), nor T2 are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int? + // - T2 = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T >(); } diff --git a/tests/language/inference_update_3/switch_expression_disabled_test.dart b/tests/language/inference_update_3/switch_expression_disabled_test.dart index fde9641c270..23c0d22d651 100644 --- a/tests/language/inference_update_3/switch_expression_disabled_test.dart +++ b/tests/language/inference_update_3/switch_expression_disabled_test.dart @@ -16,13 +16,13 @@ import '../static_type_helper.dart'; Object? contextIterable(Iterable x) => x; test(int i) { - // The static type of a switch expression `E` of the form `switch (e0) { p1 => - // e1, p2 => e2, ... pn => en }` with context type `K` is computed as follows: + // The static type of a switch expression `e` of the form `switch (e0) { p1 => + // e1, p2 => e2, ... pn => en }` with context type K is computed as follows: // // - The scrutinee (`e0`) is first analyzed with context type `_`. // - If the switch expression has no cases, its static type is `Never`. - // - Otherwise, for each case `pi => ei`, let `Ti` be the type of `ei` - // inferred with context type `K`. + // - Otherwise, for each case `pi => ei`, let Ti be the type of `ei` inferred + // with context type K. { // Check the context type of each `ei`: // - Where the context is established using a function call argument. @@ -33,7 +33,8 @@ test(int i) { }); // - Where the context is established using local variable promotion. - var o = '' as Object?; + Object? o; + o = '' as Object?; if (o is String) { o = switch (i) { 0 => (contextType('')..expectStaticType>()), @@ -43,35 +44,61 @@ test(int i) { } } - // - Let `T` be the least upper bound of the static types of all the case + // - Let T be the least upper bound of the static types of all the case // expressions. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. { - // K=Object, T1=int, and T2=double, therefore T=num and S=Object, so T <: S, - // and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int + // - T2 = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context( (switch (i) { 0 => i, _ => d })..expectStaticType>()); - // K=Iterable<_>, T1=Iterable, and T2=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable + // - T2 = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableInt = [] as Iterable; var iterableDouble = [] as Iterable; contextIterable((switch (i) { 0 => iterableInt, _ => iterableDouble }) ..expectStaticType>>()); } - // - Otherwise, if `Ti <: S` for all `i`, then the type of `E` is `S` if - // `inference-update-3` is enabled, else the type of `E` is `T`. + // - Otherwise, if Ti <: S for all i, and `inference-update-3` is enabled, + // then the type of `e` is S. { - // K=Iterable, T1=Iterable, and T2=List, therefore T=Object - // and S=Iterable, so T is not <: S, but T1 <: S and T2 <: S, hence the - // type of E is Object. + // This example has: + // - K = Iterable + // - T1 = Iterable + // - T2 = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T [] as Iterable; var listNum = []; - var o = [0] as Object?; + Object? o; + o = [0] as Object?; if (o is Iterable) { // We avoid having a compile-time error because `o` can be demoted. o = (switch (i) { 0 => iterableInt, _ => listNum }) @@ -79,27 +106,61 @@ test(int i) { } } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { - var o = '' as Object?; + Object? o; var d = 2.0; + o = '' as Object?; if (o is String?) { - // K=String?, T1=Null, and T2=int, therefore T=int? and S=String?, so T is - // not <: S. T1 <: S, but T2 is not <: S. Hence the type of E is int?. + // This example has: + // - K = String? + // - T1 = Null + // - T2 = int + // Which implies: + // - T = int? + // - S = String? + // We have: + // - T null, _ => i })..expectStaticType>(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int, and T2=Null, therefore T=int? and S=String?, so T is - // not <: S. T2 <: S, but T1 is not <: S. Hence the type of E is int?. + // This example has: + // - K = String? + // - T1 = int + // - T2 = Null + // Which implies: + // - T = int? + // - S = String? + // We have: + // - T i, _ => null })..expectStaticType>(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int, and T2=double, therefore T=num and S=String?, so - // none of T, T1, nor T2 are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int + // - T2 = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T i, _ => d })..expectStaticType>(); } diff --git a/tests/language/inference_update_3/switch_expression_test.dart b/tests/language/inference_update_3/switch_expression_test.dart index 2c7057e068a..2744f665dfb 100644 --- a/tests/language/inference_update_3/switch_expression_test.dart +++ b/tests/language/inference_update_3/switch_expression_test.dart @@ -29,13 +29,13 @@ class C2 implements B1, B2 {} Object? contextB1(B1 x) => x; test(int i) { - // The static type of a switch expression `E` of the form `switch (e0) { p1 => - // e1, p2 => e2, ... pn => en }` with context type `K` is computed as follows: + // The static type of a switch expression `e` of the form `switch (e0) { p1 => + // e1, p2 => e2, ... pn => en }` with context type K is computed as follows: // // - The scrutinee (`e0`) is first analyzed with context type `_`. // - If the switch expression has no cases, its static type is `Never`. - // - Otherwise, for each case `pi => ei`, let `Ti` be the type of `ei` - // inferred with context type `K`. + // - Otherwise, for each case `pi => ei`, let Ti be the type of `ei` inferred + // with context type K. { // Check the context type of each `ei`: // - Where the context is established using a function call argument. @@ -46,7 +46,8 @@ test(int i) { }); // - Where the context is established using local variable promotion. - var o = '' as Object?; + Object? o; + o = '' as Object?; if (o is String) { o = switch (i) { 0 => (contextType('')..expectStaticType>()), @@ -56,72 +57,148 @@ test(int i) { } } - // - Let `T` be the least upper bound of the static types of all the case + // - Let T be the least upper bound of the static types of all the case // expressions. - // - Let `S` be the greatest closure of `K`. - // - If `T <: S`, then the type of `E` is `T`. + // - Let S be the greatest closure of K. + // - If T <: S, then the type of `e` is T. { - // K=Object, T1=int, and T2=double, therefore T=num and S=Object, so T <: S, - // and hence the type of E is num. + // This example has: + // - K = Object + // - T1 = int + // - T2 = double + // Which implies: + // - T = num + // - S = Object + // We have: + // - T <: S + // Therefore the type of `e` is T = num. var d = 2.0; context( (switch (i) { 0 => i, _ => d })..expectStaticType>()); - // K=Iterable<_>, T1=Iterable, and T2=Iterable, therefore - // T=Iterable and S=Iterable, so T <: S, and hence the type of - // E is Iterable. + // This example has: + // - K = Iterable<_> + // - T1 = Iterable + // - T2 = Iterable + // Which implies: + // - T = Iterable + // - S = Iterable + // We have: + // - T <: S + // Therefore the type of `e` is T = Iterable. var iterableInt = [] as Iterable; var iterableDouble = [] as Iterable; contextIterable((switch (i) { 0 => iterableInt, _ => iterableDouble }) ..expectStaticType>>()); } - // - Otherwise, if `Ti <: S` for all `i`, then the type of `E` is `S`. + // - Otherwise, if Ti <: S for all i, then the type of `e` is S. { - // K=B1<_>, T1=C1, and T2=C2, therefore T=A and S=B1, - // so T is not <: S, but T1 <: S and T2 <: S, hence the type of E is - // B1. + // This example has: + // - K = B1<_> + // - T1 = C1 + // - T2 = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . var c1Int = C1(); var c2Double = C2(); contextB1((switch (i) { 0 => c1Int, _ => c2Double }) ..expectStaticType>>()); - // K=B1, T1=C1, and T2=C2, therefore T=A and - // S=B1, so T is not <: S, but T1 <: S and T2 <: S, hence the type - // of E is B1. + // This example has: + // - K = B1 + // - T1 = C1 + // - T2 = C2 + // Which implies: + // - T = A + // - S = B1 + // We have: + // - T . contextB1((switch (i) { 0 => c1Int, _ => c2Double }) ..expectStaticType>>()); - // K=Iterable, T1=Iterable, and T2=List, therefore T=Object - // and S=Iterable, so T is not <: S, but T1 <: S and T2 <: S, hence the - // type of E is Iterable. + // This example has: + // - K = Iterable + // - T1 = Iterable + // - T2 = List + // Which implies: + // - T = Object + // - S = Iterable + // We have: + // - T . var iterableInt = [] as Iterable; var listNum = []; context>((switch (i) { 0 => iterableInt, _ => listNum }) ..expectStaticType>>()); } - // - Otherwise, the type of `E` is `T`. + // - Otherwise, the type of `e` is T. { - var o = '' as Object?; + Object? o; var d = 2.0; + o = '' as Object?; if (o is String?) { - // K=String?, T1=Null, and T2=int, therefore T=int? and S=String?, so T is - // not <: S. T1 <: S, but T2 is not <: S. Hence the type of E is int?. + // This example has: + // - K = String? + // - T1 = Null + // - T2 = int + // Which implies: + // - T = int? + // - S = String? + // We have: + // - T null, _ => i })..expectStaticType>(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int, and T2=Null, therefore T=int? and S=String?, so T is - // not <: S. T2 <: S, but T1 is not <: S. Hence the type of E is int?. + // This example has: + // - K = String? + // - T1 = int + // - T2 = Null + // Which implies: + // - T = int? + // - S = String? + // We have: + // - T i, _ => null })..expectStaticType>(); } o = '' as Object?; if (o is String?) { - // K=String?, T1=int, and T2=double, therefore T=num and S=String?, so - // none of T, T1, nor T2 are <: S. Hence the type of E is num. + // This example has: + // - K = String? + // - T1 = int + // - T2 = double + // Which implies: + // - T = num + // - S = String? + // We have: + // - T i, _ => d })..expectStaticType>(); }