Skip to content

Commit 7c1fa84

Browse files
stereotype441commit-bot@chromium.org
authored andcommitted
Refactor the logic for inferring for-each loop variable types.
Currently we only use this logic when the for-each loop declares its own loop variable, and that loop variable doesn't have an explicit type. However, for NNBD, we'll need to use the same logic for when the for-each loop doesn't declare its own loop variable, so that flow analysis can see whether the implicit assignment to the loop variable should un-do type promotions or not. Since flow analysis integrates via the ResolverVisitor, we need the inferred type to be accessible to the ResolverVisitor. So we create a new method `StaticTypeAnalyzer.computeForEachElementType` to compute the type, and call it from `ResolverVisitor`. Change-Id: I544d72371a6c710297e467b9b37bd909490a7336 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/122880 Reviewed-by: Konstantin Shcheglov <[email protected]>
1 parent 31de45b commit 7c1fa84

File tree

2 files changed

+43
-52
lines changed

2 files changed

+43
-52
lines changed

pkg/analyzer/lib/src/generated/resolver.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3513,6 +3513,15 @@ class ResolverVisitor extends ScopedVisitor {
35133513
//
35143514
iterable?.accept(this);
35153515
loopVariable?.accept(this);
3516+
var elementType = typeAnalyzer.computeForEachElementType(
3517+
iterable, node.awaitKeyword != null);
3518+
if (loopVariable != null &&
3519+
elementType != null &&
3520+
loopVariable.type == null) {
3521+
var loopVariableElement =
3522+
loopVariable.declaredElement as LocalVariableElementImpl;
3523+
loopVariableElement.type = elementType;
3524+
}
35163525
_flowAnalysis?.flow?.forEach_bodyBegin(
35173526
node,
35183527
identifierElement is VariableElement
@@ -3592,6 +3601,15 @@ class ResolverVisitor extends ScopedVisitor {
35923601
//
35933602
iterable?.accept(this);
35943603
loopVariable?.accept(this);
3604+
var elementType = typeAnalyzer.computeForEachElementType(
3605+
iterable, node.awaitKeyword != null);
3606+
if (loopVariable != null &&
3607+
elementType != null &&
3608+
loopVariable.type == null) {
3609+
var loopVariableElement =
3610+
loopVariable.declaredElement as LocalVariableElementImpl;
3611+
loopVariableElement.type = elementType;
3612+
}
35953613

35963614
_flowAnalysis?.flow?.forEach_bodyBegin(
35973615
node,

pkg/analyzer/lib/src/generated/static_type_analyzer.dart

Lines changed: 25 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,31 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<void> {
132132
*/
133133
bool get _nonNullableEnabled => _featureSet.isEnabled(Feature.non_nullable);
134134

135+
/**
136+
* Given an iterable expression from a foreach loop, attempt to infer
137+
* a type for the elements being iterated over. Inference is based
138+
* on the type of the iterator or stream over which the foreach loop
139+
* is defined.
140+
*/
141+
DartType computeForEachElementType(Expression iterable, bool isAsync) {
142+
DartType iterableType = iterable.staticType;
143+
if (iterableType == null) return null;
144+
iterableType = iterableType.resolveToBound(_typeProvider.objectType);
145+
146+
ClassElement iteratedElement =
147+
isAsync ? _typeProvider.streamElement : _typeProvider.iterableElement;
148+
149+
InterfaceType iteratedType = iterableType is InterfaceTypeImpl
150+
? iterableType.asInstanceOf(iteratedElement)
151+
: null;
152+
153+
if (iteratedType != null) {
154+
return iteratedType.typeArguments.single;
155+
} else {
156+
return null;
157+
}
158+
}
159+
135160
/**
136161
* Given a constructor name [node] and a type [type], record an inferred type
137162
* for the constructor if in strong mode. This is used to fill in any
@@ -545,12 +570,6 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<void> {
545570
_analyzeLeastUpperBound(node, node.thenExpression, node.elseExpression);
546571
}
547572

548-
@override
549-
void visitDeclaredIdentifier(DeclaredIdentifier node) {
550-
super.visitDeclaredIdentifier(node);
551-
_inferForEachLoopVariableType(node);
552-
}
553-
554573
/**
555574
* The Dart Language Specification, 12.3: <blockquote>The static type of a literal double is
556575
* double.</blockquote>
@@ -1640,52 +1659,6 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<void> {
16401659
}
16411660
}
16421661

1643-
/**
1644-
* Given a declared identifier from a foreach loop, attempt to infer
1645-
* a type for it if one is not already present. Inference is based
1646-
* on the type of the iterator or stream over which the foreach loop
1647-
* is defined.
1648-
*/
1649-
void _inferForEachLoopVariableType(DeclaredIdentifier loopVariable) {
1650-
if (loopVariable != null && loopVariable.type == null) {
1651-
AstNode parent = loopVariable.parent;
1652-
Token awaitKeyword;
1653-
Expression iterable;
1654-
if (parent is ForEachPartsWithDeclaration) {
1655-
AstNode parentParent = parent.parent;
1656-
if (parentParent is ForStatementImpl) {
1657-
awaitKeyword = parentParent.awaitKeyword;
1658-
} else if (parentParent is ForElement) {
1659-
awaitKeyword = parentParent.awaitKeyword;
1660-
} else {
1661-
return;
1662-
}
1663-
iterable = parent.iterable;
1664-
} else {
1665-
return;
1666-
}
1667-
if (iterable != null) {
1668-
LocalVariableElementImpl element = loopVariable.declaredElement;
1669-
1670-
DartType iterableType = iterable.staticType;
1671-
iterableType = iterableType.resolveToBound(_typeProvider.objectType);
1672-
1673-
ClassElement iteratedElement = (awaitKeyword == null)
1674-
? _typeProvider.iterableElement
1675-
: _typeProvider.streamElement;
1676-
1677-
InterfaceType iteratedType = iterableType is InterfaceTypeImpl
1678-
? iterableType.asInstanceOf(iteratedElement)
1679-
: null;
1680-
1681-
if (element != null && iteratedType != null) {
1682-
DartType elementType = iteratedType.typeArguments.single;
1683-
element.type = elementType;
1684-
}
1685-
}
1686-
}
1687-
}
1688-
16891662
/**
16901663
* Given a possibly generic invocation like `o.m(args)` or `(f)(args)` try to
16911664
* infer the instantiated generic function type.

0 commit comments

Comments
 (0)