Skip to content

Commit f1ce203

Browse files
chloestefantsovaCommit Queue
authored and
Commit Queue
committed
[cfe] Add desugaring of simple cases of pattern variable declaration
The late variables aren't supported in this CL. Part of #49749 Change-Id: Iebc50f716e3575c6dd7bce915e5e294d4c8c8363 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/276525 Commit-Queue: Chloe Stefantsova <[email protected]> Reviewed-by: Johnni Winther <[email protected]>
1 parent cb478b2 commit f1ce203

File tree

103 files changed

+1473
-138
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

103 files changed

+1473
-138
lines changed

pkg/front_end/lib/src/fasta/kernel/body_builder.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8552,10 +8552,16 @@ class BodyBuilder extends StackListenerImpl
85528552
]));
85538553
Expression initializer = popForValue();
85548554
Pattern pattern = toPattern(pop());
8555+
bool isFinal = keyword.lexeme == 'final';
8556+
for (VariableDeclaration variable in pattern.declaredVariables) {
8557+
variable.isFinal = isFinal;
8558+
declareVariable(variable, scope);
8559+
typeInferrer.assignedVariables.declare(variable);
8560+
}
85558561
// TODO(johnniwinther,cstefantsova): Handle metadata.
85568562
pop(NullValue.Metadata) as List<Expression>?;
85578563
push(new PatternVariableDeclaration(pattern, initializer,
8558-
offset: keyword.charOffset, isFinal: keyword.lexeme == 'final'));
8564+
offset: keyword.charOffset, isFinal: isFinal));
85598565
}
85608566
}
85618567

pkg/front_end/lib/src/fasta/kernel/internal_ast.dart

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5126,10 +5126,9 @@ class MapPatternEntry extends TreeNode with InternalTreeNode {
51265126
}
51275127

51285128
class MapPattern extends Pattern {
5129-
final DartType? keyType;
5130-
final DartType? valueType;
5129+
DartType? keyType;
5130+
DartType? valueType;
51315131
final List<MapPatternEntry> entries;
5132-
late final InterfaceType type;
51335132

51345133
@override
51355134
List<VariableDeclaration> get declaredVariables =>
@@ -5173,13 +5172,18 @@ class MapPattern extends Pattern {
51735172
DartType matchedType,
51745173
Expression variableInitializingContext,
51755174
InferenceVisitorBase inferenceVisitor) {
5176-
DartType valueType = type.typeArguments[1];
5175+
DartType keyType = this.keyType ?? const DynamicType();
5176+
DartType valueType = this.valueType ?? const DynamicType();
5177+
DartType targetMapType = new InterfaceType(
5178+
inferenceVisitor.coreTypes.mapClass,
5179+
Nullability.nonNullable,
5180+
[keyType, valueType]);
51775181

51785182
ObjectAccessTarget containsKeyTarget = inferenceVisitor.findInterfaceMember(
5179-
type, containsKeyName, fileOffset,
5183+
targetMapType, containsKeyName, fileOffset,
51805184
callSiteAccessKind: CallSiteAccessKind.methodInvocation);
51815185
bool typeCheckForTargetMapNeeded =
5182-
!inferenceVisitor.isAssignable(type, matchedType) ||
5186+
!inferenceVisitor.isAssignable(targetMapType, matchedType) ||
51835187
matchedType is DynamicType;
51845188

51855189
// mapVariable: `matchedType` MVAR = `matchedExpression`
@@ -5198,7 +5202,7 @@ class MapPattern extends Pattern {
51985202
InstanceAccessKind.Instance,
51995203
inferenceVisitor.engine.forest
52005204
.createVariableGet(fileOffset, mapVariable)
5201-
..promotedType = typeCheckForTargetMapNeeded ? type : null,
5205+
..promotedType = typeCheckForTargetMapNeeded ? targetMapType : null,
52025206
containsKeyName,
52035207
inferenceVisitor.engine.forest
52045208
.createArguments(fileOffset, [keyPattern.expression]),
@@ -5224,7 +5228,7 @@ class MapPattern extends Pattern {
52245228
fileOffset,
52255229
inferenceVisitor.engine.forest
52265230
.createVariableGet(fileOffset, mapVariable),
5227-
type,
5231+
targetMapType,
52285232
forNonNullableByDefault: inferenceVisitor.isNonNullableByDefault);
52295233
}
52305234

@@ -5242,7 +5246,7 @@ class MapPattern extends Pattern {
52425246
}
52435247

52445248
ObjectAccessTarget valueAccess = inferenceVisitor.findInterfaceMember(
5245-
type, indexGetName, fileOffset,
5249+
targetMapType, indexGetName, fileOffset,
52465250
callSiteAccessKind: CallSiteAccessKind.operatorInvocation);
52475251
FunctionType valueAccessFunctionType =
52485252
valueAccess.getFunctionType(inferenceVisitor);
@@ -5263,7 +5267,7 @@ class MapPattern extends Pattern {
52635267
InstanceAccessKind.Instance,
52645268
inferenceVisitor.engine.forest
52655269
.createVariableGet(fileOffset, mapVariable)
5266-
..promotedType = typeCheckForTargetMapNeeded ? type : null,
5270+
..promotedType = typeCheckForTargetMapNeeded ? targetMapType : null,
52675271
indexGetName,
52685272
inferenceVisitor.engine.forest.createArguments(
52695273
fileOffset, [cloner.clone(keyPattern.expression)]),

pkg/front_end/lib/src/fasta/type_inference/inference_visitor.dart

Lines changed: 123 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
66
import 'package:_fe_analyzer_shared/src/type_inference/type_analysis_result.dart';
77
import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer.dart'
8-
hide NamedType, RecordType;
8+
hide NamedType, RecordType, MapPatternEntry;
99
import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer.dart'
1010
as shared;
11+
import 'package:_fe_analyzer_shared/src/type_inference/type_operations.dart';
1112
import 'package:_fe_analyzer_shared/src/util/link.dart';
1213
import 'package:front_end/src/api_prototype/lowering_predicates.dart';
1314
import 'package:kernel/ast.dart';
@@ -8263,8 +8264,91 @@ class InferenceVisitorImpl extends InferenceVisitorBase
82638264

82648265
StatementInferenceResult visitPatternVariableDeclaration(
82658266
PatternVariableDeclaration node) {
8266-
return new StatementInferenceResult.single(
8267-
new ExpressionStatement(new InvalidExpression('$node')));
8267+
// TODO(cstefantsova): Support late variables.
8268+
analyzePatternVariableDeclarationStatement(
8269+
node, node.pattern, node.initializer,
8270+
isFinal: node.isFinal, isLate: false);
8271+
Expression initializer = node.initializer;
8272+
// Stack: (Expression initializer)
8273+
Node? rewrite = popRewrite();
8274+
if (!identical(initializer, rewrite)) {
8275+
initializer = rewrite as Expression;
8276+
}
8277+
8278+
// TODO(cstefantsova): Do we need a more precise type for the variable?
8279+
VariableDeclaration matchedExpressionVariable = engine.forest
8280+
.createVariableDeclarationForValue(initializer,
8281+
type: const DynamicType());
8282+
8283+
// isPatternMatchingFailed: bool VAR = true;
8284+
VariableDeclaration isPatternMatchingFailed = engine.forest
8285+
.createVariableDeclarationForValue(
8286+
engine.forest.createBoolLiteral(node.fileOffset, true),
8287+
type: coreTypes.boolNonNullableRawType);
8288+
8289+
// patternMatchedSet: `isPatternMatchingFailed` = false;
8290+
// ==> VAR = true;
8291+
Statement patternMatchedSet = engine.forest.createExpressionStatement(
8292+
node.fileOffset,
8293+
engine.forest.createVariableSet(
8294+
node.fileOffset,
8295+
isPatternMatchingFailed,
8296+
engine.forest.createBoolLiteral(node.fileOffset, false)));
8297+
8298+
PatternTransformationResult transformationResult = node.pattern.transform(
8299+
engine.forest
8300+
.createVariableGet(node.fileOffset, matchedExpressionVariable),
8301+
const DynamicType(),
8302+
engine.forest
8303+
.createVariableGet(node.fileOffset, matchedExpressionVariable),
8304+
this);
8305+
8306+
List<VariableDeclaration> declaredVariableHelpers = [];
8307+
List<Statement> replacementStatements = [];
8308+
for (VariableDeclaration declaredVariable
8309+
in node.pattern.declaredVariables) {
8310+
VariableDeclaration declaredVariableHelper = engine.forest
8311+
.createVariableDeclaration(node.fileOffset, null,
8312+
type: const DynamicType());
8313+
replacementStatements.add(engine.forest.createExpressionStatement(
8314+
node.fileOffset,
8315+
engine.forest.createVariableSet(node.fileOffset,
8316+
declaredVariableHelper, declaredVariable.initializer!)));
8317+
declaredVariable.initializer = engine.forest
8318+
.createVariableGet(node.fileOffset, declaredVariableHelper)
8319+
..promotedType = declaredVariable.type
8320+
..parent = declaredVariable;
8321+
declaredVariableHelpers.add(declaredVariableHelper);
8322+
}
8323+
replacementStatements.add(patternMatchedSet);
8324+
8325+
replacementStatements = _transformationResultToStatements(
8326+
node.fileOffset, transformationResult, replacementStatements);
8327+
8328+
replacementStatements = [
8329+
matchedExpressionVariable,
8330+
isPatternMatchingFailed,
8331+
...declaredVariableHelpers,
8332+
...replacementStatements,
8333+
// TODO(cstefantsova): Figure out the right exception to throw.
8334+
engine.forest.createIfStatement(
8335+
node.fileOffset,
8336+
engine.forest
8337+
.createVariableGet(node.fileOffset, isPatternMatchingFailed),
8338+
engine.forest.createExpressionStatement(
8339+
node.fileOffset,
8340+
new Throw(
8341+
new ConstructorInvocation(
8342+
coreTypes.reachabilityErrorConstructor,
8343+
engine.forest.createArguments(node.fileOffset, []))
8344+
..fileOffset = node.fileOffset)
8345+
..fileOffset = node.fileOffset),
8346+
null),
8347+
...node.pattern.declaredVariables
8348+
];
8349+
8350+
return new StatementInferenceResult.multiple(
8351+
node.fileOffset, replacementStatements);
82688352
}
82698353

82708354
@override
@@ -9151,21 +9235,26 @@ class InferenceVisitorImpl extends InferenceVisitorBase
91519235
MapPattern pattern, {
91529236
required SharedMatchContext context,
91539237
}) {
9154-
// TODO(cstefantsova): Use [analyzeMapPattern] when it's available.
9155-
// Until then, an ad-hoc inference is used.
9156-
DartType keyType = const DynamicType();
9157-
DartType valueType = const DynamicType();
9238+
analyzeMapPattern(context, pattern,
9239+
typeArguments: new MapPatternTypeArguments<DartType>(
9240+
keyType: pattern.keyType ?? const DynamicType(),
9241+
valueType: pattern.valueType ?? const DynamicType()),
9242+
elements: pattern.entries);
91589243
DartType matchedType = flow.getMatchedValueType();
9244+
for (int i = pattern.entries.length - 1; i >= 0; i--) {
9245+
Node? rewrite = popRewrite();
9246+
if (!identical(pattern.entries[i], rewrite)) {
9247+
pattern.entries[i] = (rewrite as MapPatternEntry)..parent = pattern;
9248+
}
9249+
}
91599250
if (matchedType is InterfaceType) {
9160-
List<DartType>? typeArguments = hierarchyBuilder
9251+
List<DartType>? mapTypeArguments = hierarchyBuilder
91619252
.getTypeArgumentsAsInstanceOf(matchedType, coreTypes.mapClass);
9162-
if (typeArguments != null) {
9163-
keyType = typeArguments[0];
9164-
valueType = typeArguments[1];
9253+
if (mapTypeArguments != null && mapTypeArguments.length == 2) {
9254+
pattern.keyType = mapTypeArguments[0];
9255+
pattern.valueType = mapTypeArguments[1];
91659256
}
91669257
}
9167-
pattern.type = new InterfaceType(coreTypes.mapClass,
9168-
Nullability.nonNullable, <DartType>[keyType, valueType]);
91699258
return const PatternInferenceResult();
91709259
}
91719260

@@ -9185,12 +9274,14 @@ class InferenceVisitorImpl extends InferenceVisitorBase
91859274
for (Pattern fieldPattern in pattern.patterns)
91869275
new RecordPatternField(
91879276
node: fieldPattern,
9188-
pattern: fieldPattern,
9277+
pattern: fieldPattern is NamedPattern
9278+
? fieldPattern.pattern
9279+
: fieldPattern,
91899280
name: fieldPattern is NamedPattern ? fieldPattern.name : null)
91909281
];
9191-
DartType patternType =
9282+
DartType recordType =
91929283
analyzeRecordPattern(context, pattern, fields: fields);
9193-
pattern.type = patternType as RecordType;
9284+
pattern.type = recordType as RecordType;
91949285
return const PatternInferenceResult();
91959286
}
91969287

@@ -9328,20 +9419,30 @@ class InferenceVisitorImpl extends InferenceVisitorBase
93289419
@override
93299420
shared.MapPatternEntry<Expression, Pattern>? getMapPatternEntry(
93309421
Node element) {
9331-
// TODO(scheglov): implement getMapPatternEntry
9332-
throw new UnimplementedError('TODO(scheglov)');
9422+
element as MapPatternEntry;
9423+
return new shared.MapPatternEntry<Expression, Pattern>(
9424+
key: (element.key as ExpressionPattern).expression,
9425+
value: element.value);
93339426
}
93349427

93359428
@override
93369429
void handleMapPatternEntry(Pattern container, Node entryElement) {
9337-
// TODO(scheglov): implement handleMapPatternEntry
9338-
throw new UnimplementedError('TODO(scheglov)');
9430+
entryElement as MapPatternEntry;
9431+
ExpressionPattern pattern = entryElement.key as ExpressionPattern;
9432+
Node? key = popRewrite();
9433+
if (!identical(pattern.expression, key)) {
9434+
entryElement = new MapPatternEntry(
9435+
new ExpressionPattern(key as Expression),
9436+
entryElement.value,
9437+
entryElement.fileOffset);
9438+
}
9439+
pushRewrite(entryElement);
93399440
}
93409441

93419442
@override
93429443
DartType mapType({required DartType keyType, required DartType valueType}) {
9343-
// TODO(scheglov): implement mapType
9344-
throw new UnimplementedError('TODO(scheglov)');
9444+
return new InterfaceType(coreTypes.mapClass, Nullability.nonNullable,
9445+
<DartType>[keyType, valueType]);
93459446
}
93469447

93479448
@override

pkg/front_end/test/spell_checking_list_tests.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,7 @@ offers
467467
oh
468468
okay
469469
ol
470+
onefour
470471
onull
471472
oo
472473
oobar

pkg/front_end/testcases/patterns/cast_inside_record_pattern_implicitly_named.dart.strong.expect

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ static method test(dynamic x) → dynamic {
2626
#L2:
2727
case #C1:
2828
{
29-
dynamic n = #t1{dynamic};
29+
core::int n = #t1{core::int};
3030
{
3131
break #L1;
3232
}

pkg/front_end/testcases/patterns/cast_inside_record_pattern_implicitly_named.dart.strong.transformed.expect

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ static method test(dynamic x) → dynamic {
2626
#L2:
2727
case #C1:
2828
{
29-
dynamic n = #t1{dynamic};
29+
core::int n = #t1{core::int};
3030
{
3131
break #L1;
3232
}

pkg/front_end/testcases/patterns/cast_inside_record_pattern_implicitly_named.dart.weak.expect

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ static method test(dynamic x) → dynamic {
2626
#L2:
2727
case #C1:
2828
{
29-
dynamic n = #t1{dynamic};
29+
core::int n = #t1{core::int};
3030
{
3131
break #L1;
3232
}

pkg/front_end/testcases/patterns/cast_inside_record_pattern_implicitly_named.dart.weak.modular.expect

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ static method test(dynamic x) → dynamic {
2626
#L2:
2727
case #C1:
2828
{
29-
dynamic n = #t1{dynamic};
29+
core::int n = #t1{core::int};
3030
{
3131
break #L1;
3232
}

pkg/front_end/testcases/patterns/cast_inside_record_pattern_implicitly_named.dart.weak.transformed.expect

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ static method test(dynamic x) → dynamic {
2626
#L2:
2727
case #C1:
2828
{
29-
dynamic n = #t1{dynamic};
29+
core::int n = #t1{core::int};
3030
{
3131
break #L1;
3232
}

pkg/front_end/testcases/patterns/map_pattern_inside_case_with_type_arguments.dart.strong.expect

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ static method test(dynamic x) → dynamic {
1010
final core::bool #t3 = false;
1111
if(!#t3) {
1212
final dynamic #t4 = #t1;
13-
if(#t4 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && (#t4{core::Map<dynamic, dynamic>}.{core::Map::containsKey}("a"){(core::Object?) → core::bool} && #t4{core::Map<dynamic, dynamic>}.{core::Map::containsKey}("b"){(core::Object?) → core::bool})) {
14-
final dynamic #t5 = #t4{core::Map<dynamic, dynamic>}.{core::Map::[]}("a"){(core::Object?) → dynamic};
15-
final dynamic #t6 = #t4{core::Map<dynamic, dynamic>}.{core::Map::[]}("b"){(core::Object?) → dynamic};
16-
if(#t5 =={core::Object::==}{(core::Object) → core::bool} 1 && #t6 =={core::Object::==}{(core::Object) → core::bool} 2) {
13+
if(#t4 is{ForNonNullableByDefault} core::Map<core::String, core::int> && (#t4{core::Map<core::String, core::int>}.{core::Map::containsKey}("a"){(core::Object?) → core::bool} && #t4{core::Map<core::String, core::int>}.{core::Map::containsKey}("b"){(core::Object?) → core::bool})) {
14+
final core::int #t5 = #t4{core::Map<core::String, core::int>}.{core::Map::[]}("a"){(core::Object?) → core::int?};
15+
final core::int #t6 = #t4{core::Map<core::String, core::int>}.{core::Map::[]}("b"){(core::Object?) → core::int?};
16+
if(#t5 =={core::num::==}{(core::Object) → core::bool} 1 && #t6 =={core::num::==}{(core::Object) → core::bool} 2) {
1717
#t2 = 0;
1818
#t3 = true;
1919
}

pkg/front_end/testcases/patterns/map_pattern_inside_case_with_type_arguments.dart.strong.transformed.expect

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ static method test(dynamic x) → dynamic {
1010
final core::bool #t3 = false;
1111
if(!#t3) {
1212
final dynamic #t4 = #t1;
13-
if(#t4 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && (#t4{core::Map<dynamic, dynamic>}.{core::Map::containsKey}("a"){(core::Object?) → core::bool} && #t4{core::Map<dynamic, dynamic>}.{core::Map::containsKey}("b"){(core::Object?) → core::bool})) {
14-
final dynamic #t5 = #t4{core::Map<dynamic, dynamic>}.{core::Map::[]}("a"){(core::Object?) → dynamic};
15-
final dynamic #t6 = #t4{core::Map<dynamic, dynamic>}.{core::Map::[]}("b"){(core::Object?) → dynamic};
16-
if(#t5 =={core::Object::==}{(core::Object) → core::bool} 1 && #t6 =={core::Object::==}{(core::Object) → core::bool} 2) {
13+
if(#t4 is{ForNonNullableByDefault} core::Map<core::String, core::int> && (#t4{core::Map<core::String, core::int>}.{core::Map::containsKey}("a"){(core::Object?) → core::bool} && #t4{core::Map<core::String, core::int>}.{core::Map::containsKey}("b"){(core::Object?) → core::bool})) {
14+
final core::int #t5 = #t4{core::Map<core::String, core::int>}.{core::Map::[]}("a"){(core::Object?) → core::int?};
15+
final core::int #t6 = #t4{core::Map<core::String, core::int>}.{core::Map::[]}("b"){(core::Object?) → core::int?};
16+
if(#t5 =={core::num::==}{(core::Object) → core::bool} 1 && #t6 =={core::num::==}{(core::Object) → core::bool} 2) {
1717
#t2 = 0;
1818
#t3 = true;
1919
}

pkg/front_end/testcases/patterns/map_pattern_inside_case_with_type_arguments.dart.weak.expect

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ static method test(dynamic x) → dynamic {
1010
final core::bool #t3 = false;
1111
if(!#t3) {
1212
final dynamic #t4 = #t1;
13-
if(#t4 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && (#t4{core::Map<dynamic, dynamic>}.{core::Map::containsKey}("a"){(core::Object?) → core::bool} && #t4{core::Map<dynamic, dynamic>}.{core::Map::containsKey}("b"){(core::Object?) → core::bool})) {
14-
final dynamic #t5 = #t4{core::Map<dynamic, dynamic>}.{core::Map::[]}("a"){(core::Object?) → dynamic};
15-
final dynamic #t6 = #t4{core::Map<dynamic, dynamic>}.{core::Map::[]}("b"){(core::Object?) → dynamic};
16-
if(#t5 =={core::Object::==}{(core::Object) → core::bool} 1 && #t6 =={core::Object::==}{(core::Object) → core::bool} 2) {
13+
if(#t4 is{ForNonNullableByDefault} core::Map<core::String, core::int> && (#t4{core::Map<core::String, core::int>}.{core::Map::containsKey}("a"){(core::Object?) → core::bool} && #t4{core::Map<core::String, core::int>}.{core::Map::containsKey}("b"){(core::Object?) → core::bool})) {
14+
final core::int #t5 = #t4{core::Map<core::String, core::int>}.{core::Map::[]}("a"){(core::Object?) → core::int?};
15+
final core::int #t6 = #t4{core::Map<core::String, core::int>}.{core::Map::[]}("b"){(core::Object?) → core::int?};
16+
if(#t5 =={core::num::==}{(core::Object) → core::bool} 1 && #t6 =={core::num::==}{(core::Object) → core::bool} 2) {
1717
#t2 = 0;
1818
#t3 = true;
1919
}

pkg/front_end/testcases/patterns/map_pattern_inside_case_with_type_arguments.dart.weak.modular.expect

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ static method test(dynamic x) → dynamic {
1010
final core::bool #t3 = false;
1111
if(!#t3) {
1212
final dynamic #t4 = #t1;
13-
if(#t4 is{ForNonNullableByDefault} core::Map<dynamic, dynamic> && (#t4{core::Map<dynamic, dynamic>}.{core::Map::containsKey}("a"){(core::Object?) → core::bool} && #t4{core::Map<dynamic, dynamic>}.{core::Map::containsKey}("b"){(core::Object?) → core::bool})) {
14-
final dynamic #t5 = #t4{core::Map<dynamic, dynamic>}.{core::Map::[]}("a"){(core::Object?) → dynamic};
15-
final dynamic #t6 = #t4{core::Map<dynamic, dynamic>}.{core::Map::[]}("b"){(core::Object?) → dynamic};
16-
if(#t5 =={core::Object::==}{(core::Object) → core::bool} 1 && #t6 =={core::Object::==}{(core::Object) → core::bool} 2) {
13+
if(#t4 is{ForNonNullableByDefault} core::Map<core::String, core::int> && (#t4{core::Map<core::String, core::int>}.{core::Map::containsKey}("a"){(core::Object?) → core::bool} && #t4{core::Map<core::String, core::int>}.{core::Map::containsKey}("b"){(core::Object?) → core::bool})) {
14+
final core::int #t5 = #t4{core::Map<core::String, core::int>}.{core::Map::[]}("a"){(core::Object?) → core::int?};
15+
final core::int #t6 = #t4{core::Map<core::String, core::int>}.{core::Map::[]}("b"){(core::Object?) → core::int?};
16+
if(#t5 =={core::num::==}{(core::Object) → core::bool} 1 && #t6 =={core::num::==}{(core::Object) → core::bool} 2) {
1717
#t2 = 0;
1818
#t3 = true;
1919
}

0 commit comments

Comments
 (0)