Index: pkg/compiler/lib/src/typechecker.dart |
diff --git a/pkg/compiler/lib/src/typechecker.dart b/pkg/compiler/lib/src/typechecker.dart |
index 74b9659d39e1bf3c60dc4a426305e3ca51a394d2..60b944e23d0f76e83df9d373a96adeb46894ac11 100644 |
--- a/pkg/compiler/lib/src/typechecker.dart |
+++ b/pkg/compiler/lib/src/typechecker.dart |
@@ -4,6 +4,8 @@ |
library dart2js.typechecker; |
+import 'common/names.dart' show |
+ Identifiers; |
import 'common/tasks.dart' show |
CompilerTask; |
import 'compiler.dart' show |
@@ -62,7 +64,7 @@ class TypeCheckerTask extends CompilerTask { |
if (element.isClass) return; |
if (element.isTypedef) return; |
ResolvedAst resolvedAst = element.resolvedAst; |
- compiler.withCurrentElement(element, () { |
+ compiler.withCurrentElement(element.implementation, () { |
measure(() { |
TypeCheckerVisitor visitor = new TypeCheckerVisitor( |
compiler, resolvedAst.elements, compiler.types); |
@@ -420,6 +422,16 @@ class TypeCheckerVisitor extends Visitor<DartType> { |
compiler.reportWarning(spannable, kind, arguments); |
} |
+ reportMessage(Spannable spannable, MessageKind kind, |
+ Map arguments, |
+ {bool isHint: false}) { |
+ if (isHint) { |
+ compiler.reportHint(spannable, kind, arguments); |
+ } else { |
+ compiler.reportWarning(spannable, kind, arguments); |
+ } |
+ } |
+ |
reportTypeInfo(Spannable spannable, MessageKind kind, |
[Map arguments = const {}]) { |
compiler.reportInfo(spannable, kind, arguments); |
@@ -733,7 +745,8 @@ class TypeCheckerVisitor extends Visitor<DartType> { |
ElementAccess lookupMember(Node node, DartType receiverType, String name, |
MemberKind memberKind, Element receiverElement, |
- {bool lookupClassMember: false}) { |
+ {bool lookupClassMember: false, |
+ bool isHint: false}) { |
if (receiverType.treatAsDynamic) { |
return const DynamicAccess(); |
} |
@@ -840,11 +853,12 @@ class TypeCheckerVisitor extends Visitor<DartType> { |
void findPrivateMember(MemberSignature member) { |
if (memberName.isSimilarTo(member.name)) { |
PrivateName privateName = member.name; |
- reportTypeWarning( |
+ reportMessage( |
node, |
MessageKind.PRIVATE_ACCESS, |
{'name': name, |
- 'libraryName': privateName.library.getLibraryOrScriptName()}); |
+ 'libraryName': privateName.library.getLibraryOrScriptName()}, |
+ isHint: isHint); |
foundPrivateMember = true; |
} |
} |
@@ -860,19 +874,22 @@ class TypeCheckerVisitor extends Visitor<DartType> { |
if (!foundPrivateMember) { |
switch (memberKind) { |
case MemberKind.METHOD: |
- reportTypeWarning(node, MessageKind.METHOD_NOT_FOUND, |
- {'className': receiverType.name, 'memberName': name}); |
+ reportMessage(node, MessageKind.METHOD_NOT_FOUND, |
+ {'className': receiverType.name, 'memberName': name}, |
+ isHint: isHint); |
break; |
case MemberKind.OPERATOR: |
- reportTypeWarning(node, MessageKind.OPERATOR_NOT_FOUND, |
- {'className': receiverType.name, 'memberName': name}); |
+ reportMessage(node, MessageKind.OPERATOR_NOT_FOUND, |
+ {'className': receiverType.name, 'memberName': name}, |
+ isHint: isHint); |
break; |
case MemberKind.GETTER: |
if (lookupMemberSignature(memberName.setter, interface) != null) { |
// A setter is present so warn explicitly about the missing |
// getter. |
- reportTypeWarning(node, MessageKind.GETTER_NOT_FOUND, |
- {'className': receiverType.name, 'memberName': name}); |
+ reportMessage(node, MessageKind.GETTER_NOT_FOUND, |
+ {'className': receiverType.name, 'memberName': name}, |
+ isHint: isHint); |
} else if (name == 'await') { |
Map arguments = {'className': receiverType.name}; |
String functionName = executableContext.name; |
@@ -883,15 +900,17 @@ class TypeCheckerVisitor extends Visitor<DartType> { |
kind = MessageKind.AWAIT_MEMBER_NOT_FOUND; |
arguments['functionName'] = functionName; |
} |
- reportTypeWarning(node, kind, arguments); |
+ reportMessage(node, kind, arguments, isHint: isHint); |
} else { |
- reportTypeWarning(node, MessageKind.MEMBER_NOT_FOUND, |
- {'className': receiverType.name, 'memberName': name}); |
+ reportMessage(node, MessageKind.MEMBER_NOT_FOUND, |
+ {'className': receiverType.name, 'memberName': name}, |
+ isHint: isHint); |
} |
break; |
case MemberKind.SETTER: |
- reportTypeWarning(node, MessageKind.SETTER_NOT_FOUND, |
- {'className': receiverType.name, 'memberName': name}); |
+ reportMessage(node, MessageKind.SETTER_NOT_FOUND, |
+ {'className': receiverType.name, 'memberName': name}, |
+ isHint: isHint); |
break; |
} |
} |
@@ -900,8 +919,9 @@ class TypeCheckerVisitor extends Visitor<DartType> { |
} |
DartType lookupMemberType(Node node, DartType type, String name, |
- MemberKind memberKind) { |
- return lookupMember(node, type, name, memberKind, null) |
+ MemberKind memberKind, |
+ {bool isHint: false}) { |
+ return lookupMember(node, type, name, memberKind, null, isHint: isHint) |
.computeType(compiler); |
} |
@@ -1804,7 +1824,29 @@ class TypeCheckerVisitor extends Visitor<DartType> { |
} |
visitSyncForIn(SyncForIn node) { |
- analyze(node.expression); |
+ DartType elementType; |
+ VariableDefinitions declaredIdentifier = |
+ node.declaredIdentifier.asVariableDefinitions(); |
+ if (declaredIdentifier != null) { |
+ elementType = |
+ analyzeWithDefault(declaredIdentifier.type, const DynamicType()); |
+ } else { |
+ elementType = analyze(node.declaredIdentifier); |
+ } |
+ DartType expressionType = analyze(node.expression); |
+ DartType iteratorType = lookupMemberType(node.expression, |
+ expressionType, Identifiers.iterator, MemberKind.GETTER); |
+ DartType currentType = lookupMemberType(node.expression, |
+ iteratorType, Identifiers.current, MemberKind.GETTER, |
+ isHint: true); |
+ if (!types.isAssignable(currentType, elementType)) { |
+ reportMessage(node.expression, |
+ MessageKind.FORIN_NOT_ASSIGNABLE, |
+ {'currentType': currentType, |
+ 'expressionType': expressionType, |
+ 'elementType': elementType}, |
+ isHint: true); |
+ } |
analyze(node.body); |
return const StatementType(); |
} |