Index: pkg/compiler/lib/src/typechecker.dart |
diff --git a/pkg/compiler/lib/src/typechecker.dart b/pkg/compiler/lib/src/typechecker.dart |
index 6ca167a27f0193c6d9c913a2896aa6a2e424a1d3..ec44ea0f7e2eae6fd9ea4a07e4ffaf22de28c540 100644 |
--- a/pkg/compiler/lib/src/typechecker.dart |
+++ b/pkg/compiler/lib/src/typechecker.dart |
@@ -14,6 +14,8 @@ import 'constants/expressions.dart'; |
import 'constants/values.dart'; |
import 'core_types.dart'; |
import 'dart_types.dart'; |
+import 'diagnostics/diagnostic_listener.dart' show |
+ DiagnosticMessage; |
import 'diagnostics/invariant.dart' show |
invariant; |
import 'diagnostics/messages.dart'; |
@@ -269,14 +271,9 @@ class TypePromotion { |
return new TypePromotion(node, variable, type)..messages.addAll(messages); |
} |
- void addHint(Spannable spannable, MessageKind kind, [Map arguments]) { |
- messages.add(new TypePromotionMessage(api.Diagnostic.HINT, |
- spannable, kind, arguments)); |
- } |
- |
- void addInfo(Spannable spannable, MessageKind kind, [Map arguments]) { |
- messages.add(new TypePromotionMessage(api.Diagnostic.INFO, |
- spannable, kind, arguments)); |
+ void addHint(DiagnosticMessage hint, |
+ [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) { |
+ messages.add(new TypePromotionMessage(hint, infos)); |
} |
String toString() { |
@@ -286,13 +283,10 @@ class TypePromotion { |
/// A hint or info message attached to a type promotion. |
class TypePromotionMessage { |
- api.Diagnostic diagnostic; |
- Spannable spannable; |
- MessageKind messageKind; |
- Map messageArguments; |
+ DiagnosticMessage hint; |
+ List<DiagnosticMessage> infos; |
- TypePromotionMessage(this.diagnostic, this.spannable, this.messageKind, |
- [this.messageArguments]); |
+ TypePromotionMessage(this.hint, this.infos); |
} |
class TypeCheckerVisitor extends Visitor<DartType> { |
@@ -400,40 +394,24 @@ class TypeCheckerVisitor extends Visitor<DartType> { |
reportTypeWarning(Spannable spannable, MessageKind kind, |
[Map arguments = const {}]) { |
- compiler.reportWarning(spannable, kind, arguments); |
+ compiler.reportWarningMessage(spannable, kind, arguments); |
} |
reportMessage(Spannable spannable, MessageKind kind, |
Map arguments, |
{bool isHint: false}) { |
if (isHint) { |
- compiler.reportHint(spannable, kind, arguments); |
+ compiler.reportHintMessage(spannable, kind, arguments); |
} else { |
- compiler.reportWarning(spannable, kind, arguments); |
+ compiler.reportWarningMessage(spannable, kind, arguments); |
} |
} |
- reportTypeInfo(Spannable spannable, MessageKind kind, |
- [Map arguments = const {}]) { |
- compiler.reportInfo(spannable, kind, arguments); |
- } |
- |
reportTypePromotionHint(TypePromotion typePromotion) { |
if (!reportedTypePromotions.contains(typePromotion)) { |
reportedTypePromotions.add(typePromotion); |
for (TypePromotionMessage message in typePromotion.messages) { |
- switch (message.diagnostic) { |
- case api.Diagnostic.HINT: |
- compiler.reportHint(message.spannable, |
- message.messageKind, |
- message.messageArguments); |
- break; |
- case api.Diagnostic.INFO: |
- compiler.reportInfo(message.spannable, |
- message.messageKind, |
- message.messageArguments); |
- break; |
- } |
+ compiler.reportHint(message.hint, message.infos); |
} |
} |
} |
@@ -483,44 +461,56 @@ class TypeCheckerVisitor extends Visitor<DartType> { |
List<Node> potentialMutationsIn = |
elements.getPotentialMutationsIn(node, variable); |
if (!potentialMutationsIn.isEmpty) { |
- typePromotion.addHint(typePromotion.node, |
+ DiagnosticMessage hint = compiler.createMessage( |
+ typePromotion.node, |
MessageKind.POTENTIAL_MUTATION, |
{'variableName': variableName, 'shownType': typePromotion.type}); |
+ List<DiagnosticMessage> infos = <DiagnosticMessage>[]; |
for (Node mutation in potentialMutationsIn) { |
- typePromotion.addInfo(mutation, |
+ infos.add(compiler.createMessage(mutation, |
MessageKind.POTENTIAL_MUTATION_HERE, |
- {'variableName': variableName}); |
+ {'variableName': variableName})); |
} |
+ typePromotion.addHint(hint, infos); |
} |
List<Node> potentialMutationsInClosures = |
elements.getPotentialMutationsInClosure(variable); |
if (!potentialMutationsInClosures.isEmpty) { |
- typePromotion.addHint(typePromotion.node, |
+ DiagnosticMessage hint = compiler.createMessage( |
+ typePromotion.node, |
MessageKind.POTENTIAL_MUTATION_IN_CLOSURE, |
{'variableName': variableName, 'shownType': typePromotion.type}); |
+ List<DiagnosticMessage> infos = <DiagnosticMessage>[]; |
for (Node mutation in potentialMutationsInClosures) { |
- typePromotion.addInfo(mutation, |
+ infos.add(compiler.createMessage( |
+ mutation, |
MessageKind.POTENTIAL_MUTATION_IN_CLOSURE_HERE, |
- {'variableName': variableName}); |
+ {'variableName': variableName})); |
} |
+ typePromotion.addHint(hint, infos); |
} |
if (checkAccesses) { |
List<Node> accesses = elements.getAccessesByClosureIn(node, variable); |
List<Node> mutations = elements.getPotentialMutations(variable); |
if (!accesses.isEmpty && !mutations.isEmpty) { |
- typePromotion.addHint(typePromotion.node, |
+ DiagnosticMessage hint = compiler.createMessage( |
+ typePromotion.node, |
MessageKind.ACCESSED_IN_CLOSURE, |
{'variableName': variableName, 'shownType': typePromotion.type}); |
+ List<DiagnosticMessage> infos = <DiagnosticMessage>[]; |
for (Node access in accesses) { |
- typePromotion.addInfo(access, |
+ infos.add(compiler.createMessage( |
+ access, |
MessageKind.ACCESSED_IN_CLOSURE_HERE, |
- {'variableName': variableName}); |
+ {'variableName': variableName})); |
} |
for (Node mutation in mutations) { |
- typePromotion.addInfo(mutation, |
+ infos.add(compiler.createMessage( |
+ mutation, |
MessageKind.POTENTIAL_MUTATION_HERE, |
- {'variableName': variableName}); |
+ {'variableName': variableName})); |
} |
+ typePromotion.addHint(hint, infos); |
} |
} |
} |
@@ -570,11 +560,15 @@ class TypeCheckerVisitor extends Visitor<DartType> { |
{bool isConst: false}) { |
if (!types.isAssignable(from, to)) { |
if (compiler.enableTypeAssertions && isConst) { |
- compiler.reportError(spannable, MessageKind.NOT_ASSIGNABLE, |
- {'fromType': from, 'toType': to}); |
+ compiler.reportErrorMessage( |
+ spannable, |
+ MessageKind.NOT_ASSIGNABLE, |
+ {'fromType': from, 'toType': to}); |
} else { |
- reportTypeWarning(spannable, MessageKind.NOT_ASSIGNABLE, |
- {'fromType': from, 'toType': to}); |
+ compiler.reportWarningMessage( |
+ spannable, |
+ MessageKind.NOT_ASSIGNABLE, |
+ {'fromType': from, 'toType': to}); |
} |
return false; |
} |
@@ -892,7 +886,43 @@ class TypeCheckerVisitor extends Visitor<DartType> { |
Link<Node> arguments = send.arguments; |
DartType unaliasedType = type.unalias(compiler); |
if (identical(unaliasedType.kind, TypeKind.FUNCTION)) { |
- bool error = false; |
+ |
+ /// Report [warning] including info(s) about the declaration of [element] |
+ /// or [type]. |
+ void reportWarning(DiagnosticMessage warning) { |
+ // TODO(johnniwinther): Support pointing to individual parameters on |
+ // assignability warnings. |
+ List<DiagnosticMessage> infos = <DiagnosticMessage>[]; |
+ Element declaration = element; |
+ if (declaration == null) { |
+ declaration = type.element; |
+ } else if (type.isTypedef) { |
+ infos.add(compiler.createMessage( |
+ declaration, |
+ MessageKind.THIS_IS_THE_DECLARATION, |
+ {'name': element.name})); |
+ declaration = type.element; |
+ } |
+ if (declaration != null) { |
+ infos.add(compiler.createMessage( |
+ declaration, MessageKind.THIS_IS_THE_METHOD)); |
+ } |
+ compiler.reportWarning(warning, infos); |
+ } |
+ |
+ /// Report a warning on [node] if [argumentType] is not assignable to |
+ /// [parameterType]. |
+ void checkAssignable(Spannable node, |
+ DartType argumentType, |
+ DartType parameterType) { |
+ if (!types.isAssignable(argumentType, parameterType)) { |
+ reportWarning(compiler.createMessage( |
+ node, |
+ MessageKind.NOT_ASSIGNABLE, |
+ {'fromType': argumentType, 'toType': parameterType})); |
+ } |
+ } |
+ |
FunctionType funType = unaliasedType; |
Iterator<DartType> parameterTypes = funType.parameterTypes.iterator; |
Iterator<DartType> optionalParameterTypes = |
@@ -906,73 +936,51 @@ class TypeCheckerVisitor extends Visitor<DartType> { |
DartType namedParameterType = |
funType.getNamedParameterType(argumentName); |
if (namedParameterType == null) { |
- error = true; |
// TODO(johnniwinther): Provide better information on the called |
// function. |
- reportTypeWarning(argument, MessageKind.NAMED_ARGUMENT_NOT_FOUND, |
- {'argumentName': argumentName}); |
+ reportWarning(compiler.createMessage( |
+ argument, |
+ MessageKind.NAMED_ARGUMENT_NOT_FOUND, |
+ {'argumentName': argumentName})); |
DartType argumentType = analyze(argument); |
if (argumentTypes != null) argumentTypes.addLast(argumentType); |
} else { |
DartType argumentType = analyze(argument); |
if (argumentTypes != null) argumentTypes.addLast(argumentType); |
- if (!checkAssignable(argument, argumentType, namedParameterType)) { |
- error = true; |
- } |
+ checkAssignable(argument, argumentType, namedParameterType); |
} |
} else { |
if (!parameterTypes.moveNext()) { |
if (!optionalParameterTypes.moveNext()) { |
- error = true; |
+ |
// TODO(johnniwinther): Provide better information on the |
// called function. |
- reportTypeWarning(argument, MessageKind.ADDITIONAL_ARGUMENT); |
+ reportWarning(compiler.createMessage( |
+ argument, MessageKind.ADDITIONAL_ARGUMENT)); |
DartType argumentType = analyze(argument); |
if (argumentTypes != null) argumentTypes.addLast(argumentType); |
} else { |
DartType argumentType = analyze(argument); |
if (argumentTypes != null) argumentTypes.addLast(argumentType); |
- if (!checkAssignable(argument, |
- argumentType, |
- optionalParameterTypes.current)) { |
- error = true; |
- } |
+ checkAssignable( |
+ argument, argumentType, optionalParameterTypes.current); |
} |
} else { |
DartType argumentType = analyze(argument); |
if (argumentTypes != null) argumentTypes.addLast(argumentType); |
- if (!checkAssignable(argument, argumentType, |
- parameterTypes.current)) { |
- error = true; |
- } |
+ checkAssignable(argument, argumentType, parameterTypes.current); |
} |
} |
arguments = arguments.tail; |
} |
if (parameterTypes.moveNext()) { |
- error = true; |
// TODO(johnniwinther): Provide better information on the called |
// function. |
- reportTypeWarning(send, MessageKind.MISSING_ARGUMENT, |
- {'argumentType': parameterTypes.current}); |
- } |
- if (error) { |
- // TODO(johnniwinther): Improve access to declaring element and handle |
- // synthesized member signatures. Currently function typed instance |
- // members provide no access to their own name. |
- if (element == null) { |
- element = type.element; |
- } else if (type.isTypedef) { |
- reportTypeInfo(element, |
- MessageKind.THIS_IS_THE_DECLARATION, |
- {'name': element.name}); |
- element = type.element; |
- } |
- if (element != null) { |
- reportTypeInfo(element, MessageKind.THIS_IS_THE_METHOD); |
- } |
+ reportWarning(compiler.createMessage( |
+ send, MessageKind.MISSING_ARGUMENT, |
+ {'argumentType': parameterTypes.current})); |
} |
} else { |
while(!arguments.isEmpty) { |
@@ -1213,27 +1221,30 @@ class TypeCheckerVisitor extends Visitor<DartType> { |
if (!types.isMoreSpecific(shownType, knownType)) { |
String variableName = variable.name; |
if (!types.isSubtype(shownType, knownType)) { |
- typePromotion.addHint(node, |
+ typePromotion.addHint(compiler.createMessage( |
+ node, |
MessageKind.NOT_MORE_SPECIFIC_SUBTYPE, |
{'variableName': variableName, |
'shownType': shownType, |
- 'knownType': knownType}); |
+ 'knownType': knownType})); |
} else { |
DartType shownTypeSuggestion = |
computeMoreSpecificType(shownType, knownType); |
if (shownTypeSuggestion != null) { |
- typePromotion.addHint(node, |
+ typePromotion.addHint(compiler.createMessage( |
+ node, |
MessageKind.NOT_MORE_SPECIFIC_SUGGESTION, |
{'variableName': variableName, |
'shownType': shownType, |
'shownTypeSuggestion': shownTypeSuggestion, |
- 'knownType': knownType}); |
+ 'knownType': knownType})); |
} else { |
- typePromotion.addHint(node, |
+ typePromotion.addHint(compiler.createMessage( |
+ node, |
MessageKind.NOT_MORE_SPECIFIC, |
{'variableName': variableName, |
'shownType': shownType, |
- 'knownType': knownType}); |
+ 'knownType': knownType})); |
} |
} |
} |
@@ -1925,9 +1936,11 @@ class TypeCheckerVisitor extends Visitor<DartType> { |
} |
unreferencedFields.addAll(enumValues.values); |
if (!unreferencedFields.isEmpty) { |
- compiler.reportWarning(node, MessageKind.MISSING_ENUM_CASES, |
+ compiler.reportWarningMessage( |
+ node, MessageKind.MISSING_ENUM_CASES, |
{'enumType': expressionType, |
- 'enumValues': unreferencedFields.map((e) => e.name).join(', ')}); |
+ 'enumValues': unreferencedFields.map( |
+ (e) => e.name).join(', ')}); |
} |
}); |
} |