[cfe] Add implicit cast to relational pattern Closes #51789 Change-Id: I6c3e512b58f0216e0ba1c01812c92c2d1d9dbeaa Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/289824 Commit-Queue: Johnni Winther <johnniwinther@google.com> Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
diff --git a/pkg/front_end/lib/src/fasta/type_inference/delayed_expressions.dart b/pkg/front_end/lib/src/fasta/type_inference/delayed_expressions.dart index 56fc31e..af3cc55 100644 --- a/pkg/front_end/lib/src/fasta/type_inference/delayed_expressions.dart +++ b/pkg/front_end/lib/src/fasta/type_inference/delayed_expressions.dart
@@ -346,14 +346,25 @@ final DelayedExpression _operand; final DartType _type; final bool isUnchecked; + final bool isImplicit; final int fileOffset; DelayedAsExpression(this._operand, this._type, - {this.isUnchecked = false, required this.fileOffset}); + {this.isUnchecked = false, + this.isImplicit = false, + required this.fileOffset}); @override Expression createExpression(TypeEnvironment typeEnvironment) { - return createAsExpression(_operand.createExpression(typeEnvironment), _type, + Expression operand = _operand.createExpression(typeEnvironment); + if (isImplicit) { + DartType operandType = _operand.getType(typeEnvironment); + if (typeEnvironment.isSubtypeOf( + operandType, _type, SubtypeCheckMode.withNullabilities)) { + return operand; + } + } + return createAsExpression(operand, _type, forNonNullableByDefault: true, isUnchecked: isUnchecked, fileOffset: fileOffset);
diff --git a/pkg/front_end/lib/src/fasta/type_inference/matching_expressions.dart b/pkg/front_end/lib/src/fasta/type_inference/matching_expressions.dart index f6ff5a9..070f6c5 100644 --- a/pkg/front_end/lib/src/fasta/type_inference/matching_expressions.dart +++ b/pkg/front_end/lib/src/fasta/type_inference/matching_expressions.dart
@@ -596,16 +596,30 @@ Member? staticTarget; switch (node.accessKind) { case RelationalAccessKind.Instance: + FunctionType functionType = node.functionType!; + DartType argumentType = functionType.positionalParameters.single; expression = new DelayedInstanceInvocation( - matchedExpression, node.target!, node.functionType!, [constant], + matchedExpression, + node.target!, + functionType, + [ + new DelayedAsExpression(constant, argumentType, + isImplicit: true, fileOffset: node.fileOffset) + ], fileOffset: node.fileOffset); break; case RelationalAccessKind.Static: + FunctionType functionType = node.functionType!; + DartType argumentType = functionType.positionalParameters[1]; expression = new DelayedExtensionInvocation( node.target!, - [matchedExpression, constant], + [ + matchedExpression, + new DelayedAsExpression(constant, argumentType, + isImplicit: true, fileOffset: node.fileOffset) + ], node.typeArguments!, - node.functionType!, + functionType, fileOffset: node.fileOffset); staticTarget = node.target; break;
diff --git a/pkg/front_end/testcases/patterns/pattern_types.dart.strong.expect b/pkg/front_end/testcases/patterns/pattern_types.dart.strong.expect index b019bfa..a5ee8e4 100644 --- a/pkg/front_end/testcases/patterns/pattern_types.dart.strong.expect +++ b/pkg/front_end/testcases/patterns/pattern_types.dart.strong.expect
@@ -388,7 +388,7 @@ } { final synthesized self::Class #17#0 = cls; - if(self::_extension#0|<=(#17#0, #C2)) { + if(self::_extension#0|<=(#17#0, #C2 as{ForNonNullableByDefault} core::int)) { } } {
diff --git a/pkg/front_end/testcases/patterns/pattern_types.dart.weak.expect b/pkg/front_end/testcases/patterns/pattern_types.dart.weak.expect index f29e4d0..42ddd8d 100644 --- a/pkg/front_end/testcases/patterns/pattern_types.dart.weak.expect +++ b/pkg/front_end/testcases/patterns/pattern_types.dart.weak.expect
@@ -389,7 +389,7 @@ } { final synthesized self::Class #17#0 = cls; - if(self::_extension#0|<=(#17#0, #C2)) { + if(self::_extension#0|<=(#17#0, #C2 as{ForNonNullableByDefault} core::int)) { } } {
diff --git a/pkg/front_end/testcases/patterns/pattern_types.dart.weak.modular.expect b/pkg/front_end/testcases/patterns/pattern_types.dart.weak.modular.expect index f29e4d0..42ddd8d 100644 --- a/pkg/front_end/testcases/patterns/pattern_types.dart.weak.modular.expect +++ b/pkg/front_end/testcases/patterns/pattern_types.dart.weak.modular.expect
@@ -389,7 +389,7 @@ } { final synthesized self::Class #17#0 = cls; - if(self::_extension#0|<=(#17#0, #C2)) { + if(self::_extension#0|<=(#17#0, #C2 as{ForNonNullableByDefault} core::int)) { } } {
diff --git a/pkg/front_end/testcases/patterns/relational_assignable.dart b/pkg/front_end/testcases/patterns/relational_assignable.dart new file mode 100644 index 0000000..7453c61 --- /dev/null +++ b/pkg/front_end/testcases/patterns/relational_assignable.dart
@@ -0,0 +1,13 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +method(int i) { + const dynamic d = 0; + const dynamic s = ''; + return switch (i) { + < d => 0, + > s => 1, + _ => 2, + }; +}
diff --git a/pkg/front_end/testcases/patterns/relational_assignable.dart.strong.expect b/pkg/front_end/testcases/patterns/relational_assignable.dart.strong.expect new file mode 100644 index 0000000..03a8a31 --- /dev/null +++ b/pkg/front_end/testcases/patterns/relational_assignable.dart.strong.expect
@@ -0,0 +1,36 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; + +static method method(core::int i) → dynamic { + return block { + core::int #t1; + final synthesized core::int #0#0 = i; + #L1: + { + { + if(#0#0.{core::num::<}(#C1 as{ForNonNullableByDefault} core::num){(core::num) → core::bool}) { + #t1 = 0; + break #L1; + } + } + { + if(#0#0.{core::num::>}(#C2 as{ForNonNullableByDefault} core::num){(core::num) → core::bool}) { + #t1 = 1; + break #L1; + } + } + { + if(true) { + #t1 = 2; + break #L1; + } + } + } + } =>#t1; +} + +constants { + #C1 = 0 + #C2 = "" +}
diff --git a/pkg/front_end/testcases/patterns/relational_assignable.dart.strong.transformed.expect b/pkg/front_end/testcases/patterns/relational_assignable.dart.strong.transformed.expect new file mode 100644 index 0000000..8da7e0a --- /dev/null +++ b/pkg/front_end/testcases/patterns/relational_assignable.dart.strong.transformed.expect
@@ -0,0 +1,40 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; + +static method method(core::int i) → dynamic { + return block { + core::int #t1; + final synthesized core::int #0#0 = i; + #L1: + { + { + if(#0#0.{core::num::<}(#C1 as{ForNonNullableByDefault} core::num){(core::num) → core::bool}) { + #t1 = 0; + break #L1; + } + } + { + if(#0#0.{core::num::>}(#C2 as{ForNonNullableByDefault} core::num){(core::num) → core::bool}) { + #t1 = 1; + break #L1; + } + } + { + if(true) { + #t1 = 2; + break #L1; + } + } + } + } =>#t1; +} + +constants { + #C1 = 0 + #C2 = "" +} + +Extra constant evaluation status: +Evaluated: AsExpression @ org-dartlang-testcase:///relational_assignable.dart:9:5 -> IntConstant(0) +Extra constant evaluation: evaluated: 12, effectively constant: 1
diff --git a/pkg/front_end/testcases/patterns/relational_assignable.dart.textual_outline.expect b/pkg/front_end/testcases/patterns/relational_assignable.dart.textual_outline.expect new file mode 100644 index 0000000..63be012 --- /dev/null +++ b/pkg/front_end/testcases/patterns/relational_assignable.dart.textual_outline.expect
@@ -0,0 +1 @@ +method(int i) {}
diff --git a/pkg/front_end/testcases/patterns/relational_assignable.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/patterns/relational_assignable.dart.textual_outline_modelled.expect new file mode 100644 index 0000000..63be012 --- /dev/null +++ b/pkg/front_end/testcases/patterns/relational_assignable.dart.textual_outline_modelled.expect
@@ -0,0 +1 @@ +method(int i) {}
diff --git a/pkg/front_end/testcases/patterns/relational_assignable.dart.weak.expect b/pkg/front_end/testcases/patterns/relational_assignable.dart.weak.expect new file mode 100644 index 0000000..03a8a31 --- /dev/null +++ b/pkg/front_end/testcases/patterns/relational_assignable.dart.weak.expect
@@ -0,0 +1,36 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; + +static method method(core::int i) → dynamic { + return block { + core::int #t1; + final synthesized core::int #0#0 = i; + #L1: + { + { + if(#0#0.{core::num::<}(#C1 as{ForNonNullableByDefault} core::num){(core::num) → core::bool}) { + #t1 = 0; + break #L1; + } + } + { + if(#0#0.{core::num::>}(#C2 as{ForNonNullableByDefault} core::num){(core::num) → core::bool}) { + #t1 = 1; + break #L1; + } + } + { + if(true) { + #t1 = 2; + break #L1; + } + } + } + } =>#t1; +} + +constants { + #C1 = 0 + #C2 = "" +}
diff --git a/pkg/front_end/testcases/patterns/relational_assignable.dart.weak.modular.expect b/pkg/front_end/testcases/patterns/relational_assignable.dart.weak.modular.expect new file mode 100644 index 0000000..03a8a31 --- /dev/null +++ b/pkg/front_end/testcases/patterns/relational_assignable.dart.weak.modular.expect
@@ -0,0 +1,36 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; + +static method method(core::int i) → dynamic { + return block { + core::int #t1; + final synthesized core::int #0#0 = i; + #L1: + { + { + if(#0#0.{core::num::<}(#C1 as{ForNonNullableByDefault} core::num){(core::num) → core::bool}) { + #t1 = 0; + break #L1; + } + } + { + if(#0#0.{core::num::>}(#C2 as{ForNonNullableByDefault} core::num){(core::num) → core::bool}) { + #t1 = 1; + break #L1; + } + } + { + if(true) { + #t1 = 2; + break #L1; + } + } + } + } =>#t1; +} + +constants { + #C1 = 0 + #C2 = "" +}
diff --git a/pkg/front_end/testcases/patterns/relational_assignable.dart.weak.outline.expect b/pkg/front_end/testcases/patterns/relational_assignable.dart.weak.outline.expect new file mode 100644 index 0000000..eb9ee10 --- /dev/null +++ b/pkg/front_end/testcases/patterns/relational_assignable.dart.weak.outline.expect
@@ -0,0 +1,6 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; + +static method method(core::int i) → dynamic + ;
diff --git a/pkg/front_end/testcases/patterns/relational_assignable.dart.weak.transformed.expect b/pkg/front_end/testcases/patterns/relational_assignable.dart.weak.transformed.expect new file mode 100644 index 0000000..8da7e0a --- /dev/null +++ b/pkg/front_end/testcases/patterns/relational_assignable.dart.weak.transformed.expect
@@ -0,0 +1,40 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; + +static method method(core::int i) → dynamic { + return block { + core::int #t1; + final synthesized core::int #0#0 = i; + #L1: + { + { + if(#0#0.{core::num::<}(#C1 as{ForNonNullableByDefault} core::num){(core::num) → core::bool}) { + #t1 = 0; + break #L1; + } + } + { + if(#0#0.{core::num::>}(#C2 as{ForNonNullableByDefault} core::num){(core::num) → core::bool}) { + #t1 = 1; + break #L1; + } + } + { + if(true) { + #t1 = 2; + break #L1; + } + } + } + } =>#t1; +} + +constants { + #C1 = 0 + #C2 = "" +} + +Extra constant evaluation status: +Evaluated: AsExpression @ org-dartlang-testcase:///relational_assignable.dart:9:5 -> IntConstant(0) +Extra constant evaluation: evaluated: 12, effectively constant: 1