Skip to content

Commit a5f028e

Browse files
johnniwinthercommit-bot@chromium.org
authored andcommitted
[cfe] Add ForInVariable to encapsulate handling of for-in without variable declaration
Change-Id: I5e6ce4bfca26e8afd7fbf4dd60a3ffc3afafdf26 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/128586 Reviewed-by: Dmitry Stefantsov <[email protected]> Commit-Queue: Johnni Winther <[email protected]>
1 parent 1e9ee57 commit a5f028e

File tree

1 file changed

+189
-112
lines changed

1 file changed

+189
-112
lines changed

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

Lines changed: 189 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)