@@ -829,101 +829,40 @@ class InferenceVisitor
829829 return new ExpressionInferenceResult (inferredType, iterable);
830830 }
831831
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) {
853834 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);
860836 } 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);
898838 } 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);
913840 } else if (syntheticAssignment is StaticSet ) {
914- syntheticStaticSet = syntheticAssignment;
915- syntheticWriteType = elementType = syntheticStaticSet.target.setterType;
916- rhs = syntheticStaticSet.value;
841+ return new StaticForInVariable (syntheticAssignment);
917842 } else if (syntheticAssignment is InvalidExpression || hasProblem) {
918- elementType = const UnknownType ( );
843+ return new InvalidForInVariable (syntheticAssignment );
919844 } else {
920- unhandled (
845+ return unhandled (
921846 "${syntheticAssignment .runtimeType }" ,
922847 "handleForInStatementWithoutVariable" ,
923848 syntheticAssignment.fileOffset,
924849 inferrer.helper.uri);
925850 }
851+ }
926852
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);
927866 ExpressionInferenceResult iterableResult = inferForInIterable (
928867 iterable, elementType, typeChecksNeeded,
929868 isAsync: isAsync);
@@ -933,41 +872,14 @@ class InferenceVisitor
933872 }
934873 // This is matched by the call to [forEach_end] in
935874 // [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);
946877 if (expressionEffects != null ) {
947878 StatementInferenceResult result =
948879 inferrer.inferStatement (expressionEffects);
949880 expressionEffects =
950881 result.hasChanged ? result.statement : expressionEffects;
951882 }
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- }
971883 return new ForInResult (variable, iterableResult.expression,
972884 syntheticAssignment, expressionEffects);
973885 }
@@ -5418,3 +5330,168 @@ class ForInResult {
54185330 String toString () => 'ForInResult($variable ,$iterable ,'
54195331 '$syntheticAssignment ,$expressionSideEffects )' ;
54205332}
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