@@ -829,101 +829,40 @@ class InferenceVisitor
829
829
return new ExpressionInferenceResult (inferredType, iterable);
830
830
}
831
831
832
- ForInResult handleForInWithoutVariable (
833
- TreeNode node,
834
- VariableDeclaration variable,
835
- Expression iterable,
836
- Expression syntheticAssignment,
837
- Statement expressionEffects,
838
- {bool isAsync: false ,
839
- bool hasProblem}) {
840
- assert (hasProblem != null );
841
- DartType elementType;
842
- bool typeChecksNeeded = ! inferrer.isTopLevel;
843
- DartType syntheticWriteType;
844
- Expression rhs;
845
- // If `true`, the synthetic statement should not be visited.
846
- bool skipStatement = false ;
847
- // TODO(johnniwinther): Refactor handling of synthetic assignment to avoid
848
- // case handling here.
849
- VariableSet syntheticVariableSet;
850
- PropertySet syntheticPropertySet;
851
- SuperPropertySet syntheticSuperPropertySet;
852
- StaticSet syntheticStaticSet;
832
+ ForInVariable computeForInVariable (
833
+ Expression syntheticAssignment, bool hasProblem) {
853
834
if (syntheticAssignment is VariableSet ) {
854
- syntheticVariableSet = syntheticAssignment;
855
- syntheticWriteType = elementType = syntheticVariableSet.variable.type;
856
- rhs = syntheticVariableSet.value;
857
- // This expression is fully handled in this method so we should not
858
- // visit the synthetic statement.
859
- skipStatement = true ;
835
+ return new LocalForInVariable (syntheticAssignment);
860
836
} else if (syntheticAssignment is PropertySet ) {
861
- syntheticPropertySet = syntheticAssignment;
862
- ExpressionInferenceResult receiverResult = inferrer.inferExpression (
863
- syntheticPropertySet.receiver, const UnknownType (), true );
864
- syntheticPropertySet.receiver = receiverResult.expression
865
- ..parent = syntheticPropertySet;
866
- DartType receiverType = receiverResult.inferredType;
867
- ObjectAccessTarget writeTarget = inferrer.findInterfaceMember (
868
- receiverType,
869
- syntheticPropertySet.name,
870
- syntheticPropertySet.fileOffset,
871
- setter: true ,
872
- instrumented: true ,
873
- includeExtensionMethods: true );
874
- syntheticWriteType =
875
- elementType = inferrer.getSetterType (writeTarget, receiverType);
876
- Expression error = inferrer.reportMissingInterfaceMember (
877
- writeTarget,
878
- receiverType,
879
- syntheticPropertySet.name,
880
- syntheticPropertySet.fileOffset,
881
- templateUndefinedSetter);
882
- if (error != null ) {
883
- rhs = error;
884
- } else {
885
- if (writeTarget.isInstanceMember) {
886
- if (inferrer.instrumentation != null &&
887
- receiverType == const DynamicType ()) {
888
- inferrer.instrumentation.record (
889
- inferrer.uriForInstrumentation,
890
- syntheticPropertySet.fileOffset,
891
- 'target' ,
892
- new InstrumentationValueForMember (writeTarget.member));
893
- }
894
- syntheticPropertySet.interfaceTarget = writeTarget.member;
895
- }
896
- rhs = syntheticPropertySet.value;
897
- }
837
+ return new PropertyForInVariable (syntheticAssignment);
898
838
} else if (syntheticAssignment is SuperPropertySet ) {
899
- syntheticSuperPropertySet = syntheticAssignment;
900
- DartType receiverType = inferrer.thisType;
901
- ObjectAccessTarget writeTarget = inferrer.findInterfaceMember (
902
- receiverType,
903
- syntheticSuperPropertySet.name,
904
- syntheticSuperPropertySet.fileOffset,
905
- setter: true ,
906
- instrumented: true );
907
- if (writeTarget.isInstanceMember) {
908
- syntheticSuperPropertySet.interfaceTarget = writeTarget.member;
909
- }
910
- syntheticWriteType =
911
- elementType = inferrer.getSetterType (writeTarget, receiverType);
912
- rhs = syntheticSuperPropertySet.value;
839
+ return new SuperPropertyForInVariable (syntheticAssignment);
913
840
} else if (syntheticAssignment is StaticSet ) {
914
- syntheticStaticSet = syntheticAssignment;
915
- syntheticWriteType = elementType = syntheticStaticSet.target.setterType;
916
- rhs = syntheticStaticSet.value;
841
+ return new StaticForInVariable (syntheticAssignment);
917
842
} else if (syntheticAssignment is InvalidExpression || hasProblem) {
918
- elementType = const UnknownType ( );
843
+ return new InvalidForInVariable (syntheticAssignment );
919
844
} else {
920
- unhandled (
845
+ return unhandled (
921
846
"${syntheticAssignment .runtimeType }" ,
922
847
"handleForInStatementWithoutVariable" ,
923
848
syntheticAssignment.fileOffset,
924
849
inferrer.helper.uri);
925
850
}
851
+ }
926
852
853
+ ForInResult handleForInWithoutVariable (
854
+ TreeNode node,
855
+ VariableDeclaration variable,
856
+ Expression iterable,
857
+ Expression syntheticAssignment,
858
+ Statement expressionEffects,
859
+ {bool isAsync: false ,
860
+ bool hasProblem}) {
861
+ assert (hasProblem != null );
862
+ bool typeChecksNeeded = ! inferrer.isTopLevel;
863
+ ForInVariable forInVariable =
864
+ computeForInVariable (syntheticAssignment, hasProblem);
865
+ DartType elementType = forInVariable.computeElementType (inferrer);
927
866
ExpressionInferenceResult iterableResult = inferForInIterable (
928
867
iterable, elementType, typeChecksNeeded,
929
868
isAsync: isAsync);
@@ -933,41 +872,14 @@ class InferenceVisitor
933
872
}
934
873
// This is matched by the call to [forEach_end] in
935
874
// [inferElement], [inferMapEntry] or [inferForInStatement].
936
- inferrer.flowAnalysis.forEach_bodyBegin (node, variable, variable.type);
937
- if (syntheticVariableSet != null ) {
938
- inferrer.flowAnalysis.write (syntheticVariableSet.variable, variable.type);
939
- }
940
- if (syntheticAssignment != null && ! skipStatement) {
941
- ExpressionInferenceResult result = inferrer.inferExpression (
942
- syntheticAssignment, const UnknownType (), ! inferrer.isTopLevel,
943
- isVoidAllowed: true );
944
- syntheticAssignment = result.expression;
945
- }
875
+ inferrer.flowAnalysis.forEach_bodyBegin (node, variable, inferredType);
876
+ syntheticAssignment = forInVariable.inferAssignment (inferrer, inferredType);
946
877
if (expressionEffects != null ) {
947
878
StatementInferenceResult result =
948
879
inferrer.inferStatement (expressionEffects);
949
880
expressionEffects =
950
881
result.hasChanged ? result.statement : expressionEffects;
951
882
}
952
-
953
- if (syntheticWriteType != null ) {
954
- rhs = inferrer.ensureAssignable (
955
- greatestClosure (inferrer.coreTypes, syntheticWriteType),
956
- variable.type,
957
- rhs,
958
- errorTemplate: templateForInLoopElementTypeNotAssignable,
959
- isVoidAllowed: true );
960
- if (syntheticVariableSet != null ) {
961
- syntheticVariableSet.value = rhs..parent = syntheticVariableSet;
962
- } else if (syntheticPropertySet != null ) {
963
- syntheticPropertySet.value = rhs..parent = syntheticPropertySet;
964
- } else if (syntheticSuperPropertySet != null ) {
965
- syntheticSuperPropertySet.value = rhs
966
- ..parent = syntheticSuperPropertySet;
967
- } else if (syntheticStaticSet != null ) {
968
- syntheticStaticSet.value = rhs..parent = syntheticStaticSet;
969
- }
970
- }
971
883
return new ForInResult (variable, iterableResult.expression,
972
884
syntheticAssignment, expressionEffects);
973
885
}
@@ -5418,3 +5330,168 @@ class ForInResult {
5418
5330
String toString () => 'ForInResult($variable ,$iterable ,'
5419
5331
'$syntheticAssignment ,$expressionSideEffects )' ;
5420
5332
}
5333
+
5334
+ abstract class ForInVariable {
5335
+ /// Computes the type of the elements expected for this for-in variable.
5336
+ DartType computeElementType (TypeInferrerImpl inferrer);
5337
+
5338
+ /// Infers the assignment to this for-in variable with a value of type
5339
+ /// [rhsType] . The resulting expression is returned.
5340
+ Expression inferAssignment (TypeInferrerImpl inferrer, DartType rhsType);
5341
+ }
5342
+
5343
+ class LocalForInVariable implements ForInVariable {
5344
+ VariableSet variableSet;
5345
+
5346
+ LocalForInVariable (this .variableSet);
5347
+
5348
+ DartType computeElementType (TypeInferrerImpl inferrer) =>
5349
+ variableSet.variable.type;
5350
+
5351
+ Expression inferAssignment (TypeInferrerImpl inferrer, DartType rhsType) {
5352
+ Expression rhs = inferrer.ensureAssignable (
5353
+ greatestClosure (inferrer.coreTypes, variableSet.variable.type),
5354
+ rhsType,
5355
+ variableSet.value,
5356
+ errorTemplate: templateForInLoopElementTypeNotAssignable,
5357
+ isVoidAllowed: true );
5358
+
5359
+ variableSet.value = rhs..parent = variableSet;
5360
+ inferrer.flowAnalysis.write (variableSet.variable, rhsType);
5361
+ return variableSet;
5362
+ }
5363
+ }
5364
+
5365
+ class PropertyForInVariable implements ForInVariable {
5366
+ final PropertySet propertySet;
5367
+
5368
+ DartType _writeType;
5369
+
5370
+ Expression _rhs;
5371
+
5372
+ PropertyForInVariable (this .propertySet);
5373
+
5374
+ @override
5375
+ DartType computeElementType (TypeInferrerImpl inferrer) {
5376
+ ExpressionInferenceResult receiverResult = inferrer.inferExpression (
5377
+ propertySet.receiver, const UnknownType (), true );
5378
+ propertySet.receiver = receiverResult.expression..parent = propertySet;
5379
+ DartType receiverType = receiverResult.inferredType;
5380
+ ObjectAccessTarget writeTarget = inferrer.findInterfaceMember (
5381
+ receiverType, propertySet.name, propertySet.fileOffset,
5382
+ setter: true , instrumented: true , includeExtensionMethods: true );
5383
+ DartType elementType =
5384
+ _writeType = inferrer.getSetterType (writeTarget, receiverType);
5385
+ Expression error = inferrer.reportMissingInterfaceMember (
5386
+ writeTarget,
5387
+ receiverType,
5388
+ propertySet.name,
5389
+ propertySet.fileOffset,
5390
+ templateUndefinedSetter);
5391
+ if (error != null ) {
5392
+ _rhs = error;
5393
+ } else {
5394
+ if (writeTarget.isInstanceMember) {
5395
+ if (inferrer.instrumentation != null &&
5396
+ receiverType == const DynamicType ()) {
5397
+ inferrer.instrumentation.record (
5398
+ inferrer.uriForInstrumentation,
5399
+ propertySet.fileOffset,
5400
+ 'target' ,
5401
+ new InstrumentationValueForMember (writeTarget.member));
5402
+ }
5403
+ propertySet.interfaceTarget = writeTarget.member;
5404
+ }
5405
+ _rhs = propertySet.value;
5406
+ }
5407
+ return elementType;
5408
+ }
5409
+
5410
+ @override
5411
+ Expression inferAssignment (TypeInferrerImpl inferrer, DartType rhsType) {
5412
+ Expression rhs = inferrer.ensureAssignable (
5413
+ greatestClosure (inferrer.coreTypes, _writeType), rhsType, _rhs,
5414
+ errorTemplate: templateForInLoopElementTypeNotAssignable,
5415
+ isVoidAllowed: true );
5416
+
5417
+ propertySet.value = rhs..parent = propertySet;
5418
+ ExpressionInferenceResult result = inferrer.inferExpression (
5419
+ propertySet, const UnknownType (), ! inferrer.isTopLevel,
5420
+ isVoidAllowed: true );
5421
+ return result.expression;
5422
+ }
5423
+ }
5424
+
5425
+ class SuperPropertyForInVariable implements ForInVariable {
5426
+ final SuperPropertySet superPropertySet;
5427
+
5428
+ DartType _writeType;
5429
+
5430
+ SuperPropertyForInVariable (this .superPropertySet);
5431
+
5432
+ @override
5433
+ DartType computeElementType (TypeInferrerImpl inferrer) {
5434
+ DartType receiverType = inferrer.thisType;
5435
+ ObjectAccessTarget writeTarget = inferrer.findInterfaceMember (
5436
+ receiverType, superPropertySet.name, superPropertySet.fileOffset,
5437
+ setter: true , instrumented: true );
5438
+ if (writeTarget.isInstanceMember) {
5439
+ superPropertySet.interfaceTarget = writeTarget.member;
5440
+ }
5441
+ return _writeType = inferrer.getSetterType (writeTarget, receiverType);
5442
+ }
5443
+
5444
+ @override
5445
+ Expression inferAssignment (TypeInferrerImpl inferrer, DartType rhsType) {
5446
+ Expression rhs = inferrer.ensureAssignable (
5447
+ greatestClosure (inferrer.coreTypes, _writeType),
5448
+ rhsType,
5449
+ superPropertySet.value,
5450
+ errorTemplate: templateForInLoopElementTypeNotAssignable,
5451
+ isVoidAllowed: true );
5452
+ superPropertySet.value = rhs..parent = superPropertySet;
5453
+ ExpressionInferenceResult result = inferrer.inferExpression (
5454
+ superPropertySet, const UnknownType (), ! inferrer.isTopLevel,
5455
+ isVoidAllowed: true );
5456
+ return result.expression;
5457
+ }
5458
+ }
5459
+
5460
+ class StaticForInVariable implements ForInVariable {
5461
+ final StaticSet staticSet;
5462
+
5463
+ StaticForInVariable (this .staticSet);
5464
+
5465
+ @override
5466
+ DartType computeElementType (TypeInferrerImpl inferrer) =>
5467
+ staticSet.target.setterType;
5468
+
5469
+ @override
5470
+ Expression inferAssignment (TypeInferrerImpl inferrer, DartType rhsType) {
5471
+ Expression rhs = inferrer.ensureAssignable (
5472
+ greatestClosure (inferrer.coreTypes, staticSet.target.setterType),
5473
+ rhsType,
5474
+ staticSet.value,
5475
+ errorTemplate: templateForInLoopElementTypeNotAssignable,
5476
+ isVoidAllowed: true );
5477
+
5478
+ staticSet.value = rhs..parent = staticSet;
5479
+ ExpressionInferenceResult result = inferrer.inferExpression (
5480
+ staticSet, const UnknownType (), ! inferrer.isTopLevel,
5481
+ isVoidAllowed: true );
5482
+ return result.expression;
5483
+ }
5484
+ }
5485
+
5486
+ class InvalidForInVariable implements ForInVariable {
5487
+ final Expression expression;
5488
+
5489
+ InvalidForInVariable (this .expression);
5490
+
5491
+ @override
5492
+ DartType computeElementType (TypeInferrerImpl inferrer) => const UnknownType ();
5493
+
5494
+ @override
5495
+ Expression inferAssignment (TypeInferrerImpl inferrer, DartType rhsType) =>
5496
+ expression;
5497
+ }
0 commit comments