Index: packages/analyzer/lib/src/generated/resolver.dart |
diff --git a/analyzer/lib/src/generated/resolver.dart b/packages/analyzer/lib/src/generated/resolver.dart |
similarity index 92% |
rename from analyzer/lib/src/generated/resolver.dart |
rename to packages/analyzer/lib/src/generated/resolver.dart |
index 49fc6c797dbba3b06d1751515bcc705ed477f46f..a5b2e92abb20313d3747f572a60bcc6e17006206 100644 |
--- a/analyzer/lib/src/generated/resolver.dart |
+++ b/packages/analyzer/lib/src/generated/resolver.dart |
@@ -44,6 +44,10 @@ typedef TypeResolverVisitor TypeResolverVisitorFactory( |
typedef void VoidFunction(); |
+typedef bool _GuardedSubtypeChecker<T>(T t1, T t2, Set<Element> visited); |
+ |
+typedef bool _SubtypeChecker<T>(T t1, T t2); |
+ |
/** |
* Instances of the class `BestPracticesVerifier` traverse an AST structure looking for |
* violations of Dart best practices. |
@@ -73,12 +77,19 @@ class BestPracticesVerifier extends RecursiveAstVisitor<Object> { |
final InterfaceType _futureNullType; |
/** |
+ * The type system primitives |
+ */ |
+ TypeSystem _typeSystem; |
+ |
+ /** |
* Create a new instance of the [BestPracticesVerifier]. |
* |
* @param errorReporter the error reporter |
*/ |
- BestPracticesVerifier(this._errorReporter, TypeProvider typeProvider) |
- : _futureNullType = typeProvider.futureNullType; |
+ BestPracticesVerifier(this._errorReporter, TypeProvider typeProvider, |
+ {TypeSystem typeSystem}) |
+ : _futureNullType = typeProvider.futureNullType, |
+ _typeSystem = (typeSystem != null) ? typeSystem : new TypeSystemImpl(); |
@override |
Object visitArgumentList(ArgumentList node) { |
@@ -293,15 +304,18 @@ class BestPracticesVerifier extends RecursiveAstVisitor<Object> { |
* @return `true` if and only if an hint code is generated on the passed node |
* See [HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE]. |
*/ |
- bool _checkForArgumentTypeNotAssignable(Expression expression, |
- DartType expectedStaticType, DartType actualStaticType, |
- DartType expectedPropagatedType, DartType actualPropagatedType, |
+ bool _checkForArgumentTypeNotAssignable( |
+ Expression expression, |
+ DartType expectedStaticType, |
+ DartType actualStaticType, |
+ DartType expectedPropagatedType, |
+ DartType actualPropagatedType, |
ErrorCode hintCode) { |
// |
// Warning case: test static type information |
// |
if (actualStaticType != null && expectedStaticType != null) { |
- if (!actualStaticType.isAssignableTo(expectedStaticType)) { |
+ if (!_typeSystem.isAssignableTo(actualStaticType, expectedStaticType)) { |
// A warning was created in the ErrorVerifier, return false, don't |
// create a hint when a warning has already been created. |
return false; |
@@ -317,7 +331,7 @@ class BestPracticesVerifier extends RecursiveAstVisitor<Object> { |
DartType actualBestType = |
actualPropagatedType != null ? actualPropagatedType : actualStaticType; |
if (actualBestType != null && expectedBestType != null) { |
- if (!actualBestType.isAssignableTo(expectedBestType)) { |
+ if (!_typeSystem.isAssignableTo(actualBestType, expectedBestType)) { |
_errorReporter.reportTypeErrorForNode( |
hintCode, expression, [actualBestType, expectedBestType]); |
return true; |
@@ -347,8 +361,10 @@ class BestPracticesVerifier extends RecursiveAstVisitor<Object> { |
DartType propagatedParameterType = propagatedParameterElement == null |
? null |
: propagatedParameterElement.type; |
- return _checkForArgumentTypeNotAssignableWithExpectedTypes(argument, |
- staticParameterType, propagatedParameterType, |
+ return _checkForArgumentTypeNotAssignableWithExpectedTypes( |
+ argument, |
+ staticParameterType, |
+ propagatedParameterType, |
HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE); |
} |
@@ -364,11 +380,17 @@ class BestPracticesVerifier extends RecursiveAstVisitor<Object> { |
* See [HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE]. |
*/ |
bool _checkForArgumentTypeNotAssignableWithExpectedTypes( |
- Expression expression, DartType expectedStaticType, |
- DartType expectedPropagatedType, ErrorCode errorCode) => |
- _checkForArgumentTypeNotAssignable(expression, expectedStaticType, |
- expression.staticType, expectedPropagatedType, |
- expression.propagatedType, errorCode); |
+ Expression expression, |
+ DartType expectedStaticType, |
+ DartType expectedPropagatedType, |
+ ErrorCode errorCode) => |
+ _checkForArgumentTypeNotAssignable( |
+ expression, |
+ expectedStaticType, |
+ expression.staticType, |
+ expectedPropagatedType, |
+ expression.propagatedType, |
+ errorCode); |
/** |
* This verifies that the passed arguments can be assigned to their corresponding parameters. |
@@ -508,14 +530,14 @@ class BestPracticesVerifier extends RecursiveAstVisitor<Object> { |
? ErrorVerifier.getStaticType(lhs) |
: leftVariableElement.type; |
DartType staticRightType = ErrorVerifier.getStaticType(rhs); |
- if (!staticRightType.isAssignableTo(leftType)) { |
+ if (!_typeSystem.isAssignableTo(staticRightType, leftType)) { |
// The warning was generated on this rhs |
return false; |
} |
// Test for, and then generate the hint |
DartType bestRightType = rhs.bestType; |
if (leftType != null && bestRightType != null) { |
- if (!bestRightType.isAssignableTo(leftType)) { |
+ if (!_typeSystem.isAssignableTo(bestRightType, leftType)) { |
_errorReporter.reportTypeErrorForNode( |
HintCode.INVALID_ASSIGNMENT, rhs, [bestRightType, leftType]); |
return true; |
@@ -541,7 +563,8 @@ class BestPracticesVerifier extends RecursiveAstVisitor<Object> { |
} |
if (importedLibrary.hasLoadLibraryFunction) { |
_errorReporter.reportErrorForNode( |
- HintCode.IMPORT_DEFERRED_LIBRARY_WITH_LOAD_FUNCTION, node, |
+ HintCode.IMPORT_DEFERRED_LIBRARY_WITH_LOAD_FUNCTION, |
+ node, |
[importedLibrary.name]); |
return true; |
} |
@@ -581,7 +604,8 @@ class BestPracticesVerifier extends RecursiveAstVisitor<Object> { |
} |
// For async, give no hint if Future<Null> is assignable to the return |
// type. |
- if (body.isAsynchronous && _futureNullType.isAssignableTo(returnTypeType)) { |
+ if (body.isAsynchronous && |
+ _typeSystem.isAssignableTo(_futureNullType, returnTypeType)) { |
return false; |
} |
// Check the block for a return statement, if not, create the hint |
@@ -740,13 +764,17 @@ class ClassScope extends EnclosedScope { |
AnalysisError getErrorForDuplicate(Element existing, Element duplicate) { |
if (existing is PropertyAccessorElement && duplicate is MethodElement) { |
if (existing.nameOffset < duplicate.nameOffset) { |
- return new AnalysisError(duplicate.source, duplicate.nameOffset, |
- duplicate.displayName.length, |
+ return new AnalysisError( |
+ duplicate.source, |
+ duplicate.nameOffset, |
+ duplicate.nameLength, |
CompileTimeErrorCode.METHOD_AND_GETTER_WITH_SAME_NAME, |
[existing.displayName]); |
} else { |
- return new AnalysisError(existing.source, existing.nameOffset, |
- existing.displayName.length, |
+ return new AnalysisError( |
+ existing.source, |
+ existing.nameOffset, |
+ existing.nameLength, |
CompileTimeErrorCode.GETTER_AND_METHOD_WITH_SAME_NAME, |
[existing.displayName]); |
} |
@@ -823,6 +851,11 @@ class ConstantVerifier extends RecursiveAstVisitor<Object> { |
final TypeProvider _typeProvider; |
/** |
+ * The type system in use. |
+ */ |
+ final TypeSystem _typeSystem; |
+ |
+ /** |
* The set of variables declared using '-D' on the command line. |
*/ |
final DeclaredVariables declaredVariables; |
@@ -857,8 +890,10 @@ class ConstantVerifier extends RecursiveAstVisitor<Object> { |
* |
* @param errorReporter the error reporter by which errors will be reported |
*/ |
- ConstantVerifier(this._errorReporter, this._currentLibrary, |
- this._typeProvider, this.declaredVariables) { |
+ ConstantVerifier(this._errorReporter, LibraryElement currentLibrary, |
+ this._typeProvider, this.declaredVariables) |
+ : _currentLibrary = currentLibrary, |
+ _typeSystem = currentLibrary.context.typeSystem { |
this._boolType = _typeProvider.boolType; |
this._intType = _typeProvider.intType; |
this._numType = _typeProvider.numType; |
@@ -916,11 +951,15 @@ class ConstantVerifier extends RecursiveAstVisitor<Object> { |
ConstructorElement constructor = node.staticElement; |
if (constructor != null) { |
ConstantEvaluationEngine evaluationEngine = |
- new ConstantEvaluationEngine(_typeProvider, declaredVariables); |
+ new ConstantEvaluationEngine(_typeProvider, declaredVariables, |
+ typeSystem: _typeSystem); |
ConstantVisitor constantVisitor = |
new ConstantVisitor(evaluationEngine, _errorReporter); |
- evaluationEngine.evaluateConstructorCall(node, |
- node.argumentList.arguments, constructor, constantVisitor, |
+ evaluationEngine.evaluateConstructorCall( |
+ node, |
+ node.argumentList.arguments, |
+ constructor, |
+ constantVisitor, |
_errorReporter); |
} |
} |
@@ -976,7 +1015,8 @@ class ConstantVerifier extends RecursiveAstVisitor<Object> { |
if (_implementsEqualsWhenNotAllowed(type)) { |
_errorReporter.reportErrorForNode( |
CompileTimeErrorCode.CONST_MAP_KEY_EXPRESSION_TYPE_IMPLEMENTS_EQUALS, |
- key, [type.displayName]); |
+ key, |
+ [type.displayName]); |
} |
} |
} else { |
@@ -986,7 +1026,8 @@ class ConstantVerifier extends RecursiveAstVisitor<Object> { |
ErrorReporter subErrorReporter = |
new ErrorReporter(errorListener, _errorReporter.source); |
DartObjectImpl result = key.accept(new ConstantVisitor( |
- new ConstantEvaluationEngine(_typeProvider, declaredVariables), |
+ new ConstantEvaluationEngine(_typeProvider, declaredVariables, |
+ typeSystem: _typeSystem), |
subErrorReporter)); |
if (result != null) { |
if (keys.contains(result)) { |
@@ -1040,7 +1081,8 @@ class ConstantVerifier extends RecursiveAstVisitor<Object> { |
if (firstType != nType) { |
_errorReporter.reportErrorForNode( |
CompileTimeErrorCode.INCONSISTENT_CASE_EXPRESSION_TYPES, |
- expression, [expression.toSource(), firstType.displayName]); |
+ expression, |
+ [expression.toSource(), firstType.displayName]); |
foundError = true; |
} |
} |
@@ -1093,7 +1135,8 @@ class ConstantVerifier extends RecursiveAstVisitor<Object> { |
// report error |
_errorReporter.reportErrorForToken( |
CompileTimeErrorCode.CASE_EXPRESSION_TYPE_IMPLEMENTS_EQUALS, |
- node.switchKeyword, [type.displayName]); |
+ node.switchKeyword, |
+ [type.displayName]); |
return true; |
} |
@@ -1190,7 +1233,8 @@ class ConstantVerifier extends RecursiveAstVisitor<Object> { |
ErrorReporter subErrorReporter = |
new ErrorReporter(errorListener, _errorReporter.source); |
DartObjectImpl result = expression.accept(new ConstantVisitor( |
- new ConstantEvaluationEngine(_typeProvider, declaredVariables), |
+ new ConstantEvaluationEngine(_typeProvider, declaredVariables, |
+ typeSystem: _typeSystem), |
subErrorReporter)); |
_reportErrors(errorListener.errors, errorCode); |
return result; |
@@ -1298,12 +1342,14 @@ class ConstantVerifier extends RecursiveAstVisitor<Object> { |
ErrorReporter subErrorReporter = |
new ErrorReporter(errorListener, _errorReporter.source); |
DartObjectImpl result = initializer.accept(new ConstantVisitor( |
- new ConstantEvaluationEngine( |
- _typeProvider, declaredVariables), subErrorReporter)); |
+ new ConstantEvaluationEngine(_typeProvider, declaredVariables, |
+ typeSystem: _typeSystem), |
+ subErrorReporter)); |
if (result == null) { |
_errorReporter.reportErrorForNode( |
CompileTimeErrorCode.CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZED_BY_NON_CONST, |
- errorSite, [variableDeclaration.name.name]); |
+ errorSite, |
+ [variableDeclaration.name.name]); |
} |
} |
} |
@@ -1326,7 +1372,8 @@ class ConstantVerifier extends RecursiveAstVisitor<Object> { |
new ErrorReporter(errorListener, _errorReporter.source); |
DartObjectImpl result = expression.accept( |
new _ConstantVerifier_validateInitializerExpression(_typeProvider, |
- subErrorReporter, this, parameterElements, declaredVariables)); |
+ subErrorReporter, this, parameterElements, declaredVariables, |
+ typeSystem: _typeSystem)); |
_reportErrors(errorListener.errors, |
CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER); |
if (result != null) { |
@@ -1451,11 +1498,18 @@ class DeadCodeVerifier extends RecursiveAstVisitor<Object> { |
final ErrorReporter _errorReporter; |
/** |
+ * The type system for this visitor |
+ */ |
+ final TypeSystem _typeSystem; |
+ |
+ /** |
* Create a new instance of the [DeadCodeVerifier]. |
* |
* @param errorReporter the error reporter |
*/ |
- DeadCodeVerifier(this._errorReporter); |
+ DeadCodeVerifier(this._errorReporter, {TypeSystem typeSystem}) |
+ : this._typeSystem = |
+ (typeSystem != null) ? typeSystem : new TypeSystemImpl(); |
@override |
Object visitBinaryExpression(BinaryExpression node) { |
@@ -1620,15 +1674,15 @@ class DeadCodeVerifier extends RecursiveAstVisitor<Object> { |
} |
} |
for (DartType type in visitedTypes) { |
- if (currentType.isSubtypeOf(type)) { |
+ if (_typeSystem.isSubtypeOf(currentType, type)) { |
CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1]; |
int offset = catchClause.offset; |
int length = lastCatchClause.end - offset; |
_errorReporter.reportErrorForOffset( |
- HintCode.DEAD_CODE_ON_CATCH_SUBTYPE, offset, length, [ |
- currentType.displayName, |
- type.displayName |
- ]); |
+ HintCode.DEAD_CODE_ON_CATCH_SUBTYPE, |
+ offset, |
+ length, |
+ [currentType.displayName, type.displayName]); |
return null; |
} |
} |
@@ -1925,9 +1979,10 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> { |
String uri = _getStringValue(node.uri); |
if (uri != null) { |
LibraryElement library = _enclosingUnit.library; |
- ExportElement exportElement = _findExport(library.exports, |
- _enclosingUnit.context.sourceFactory.resolveUri( |
- _enclosingUnit.source, uri)); |
+ ExportElement exportElement = _findExport( |
+ library.exports, |
+ _enclosingUnit.context.sourceFactory |
+ .resolveUri(_enclosingUnit.source, uri)); |
node.element = exportElement; |
} |
return super.visitExportDirective(node); |
@@ -2031,9 +2086,11 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> { |
String uri = _getStringValue(node.uri); |
if (uri != null) { |
LibraryElement library = _enclosingUnit.library; |
- ImportElement importElement = _findImport(library.imports, |
- _enclosingUnit.context.sourceFactory.resolveUri( |
- _enclosingUnit.source, uri), node.prefix); |
+ ImportElement importElement = _findImport( |
+ library.imports, |
+ _enclosingUnit.context.sourceFactory |
+ .resolveUri(_enclosingUnit.source, uri), |
+ node.prefix); |
node.element = importElement; |
} |
return super.visitImportDirective(node); |
@@ -2084,8 +2141,8 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> { |
Object visitPartDirective(PartDirective node) { |
String uri = _getStringValue(node.uri); |
if (uri != null) { |
- Source partSource = _enclosingUnit.context.sourceFactory.resolveUri( |
- _enclosingUnit.source, uri); |
+ Source partSource = _enclosingUnit.context.sourceFactory |
+ .resolveUri(_enclosingUnit.source, uri); |
node.element = _findPart(_enclosingUnit.library.parts, partSource); |
} |
return super.visitPartDirective(node); |
@@ -2404,6 +2461,9 @@ class ElementBuilder extends RecursiveAstVisitor<Object> { |
// exception |
LocalVariableElementImpl exception = |
new LocalVariableElementImpl.forNode(exceptionParameter); |
+ if (node.exceptionType == null) { |
+ exception.hasImplicitType = true; |
+ } |
_currentHolder.addLocalVariable(exception); |
exceptionParameter.staticElement = exception; |
// stack trace |
@@ -2455,6 +2515,7 @@ class ElementBuilder extends RecursiveAstVisitor<Object> { |
// |
constructors = _createDefaultConstructors(interfaceType); |
} |
+ _setDocRange(element, node); |
element.abstract = node.isAbstract; |
element.accessors = holder.accessors; |
element.constructors = constructors; |
@@ -2528,6 +2589,7 @@ class ElementBuilder extends RecursiveAstVisitor<Object> { |
SimpleIdentifier constructorName = node.name; |
ConstructorElementImpl element = |
new ConstructorElementImpl.forNode(constructorName); |
+ _setDocRange(element, node); |
if (node.externalKeyword != null) { |
element.external = true; |
} |
@@ -2573,6 +2635,9 @@ class ElementBuilder extends RecursiveAstVisitor<Object> { |
element.setVisibleRange(declarationEnd, statementEnd - declarationEnd - 1); |
element.const3 = node.isConst; |
element.final2 = node.isFinal; |
+ if (node.type == null) { |
+ element.hasImplicitType = true; |
+ } |
_currentHolder.addLocalVariable(element); |
variableName.staticElement = element; |
return super.visitDeclaredIdentifier(node); |
@@ -2613,6 +2678,10 @@ class ElementBuilder extends RecursiveAstVisitor<Object> { |
} |
// visible range |
_setParameterVisibleRange(node, parameter); |
+ if (normalParameter is SimpleFormalParameter && |
+ normalParameter.type == null) { |
+ parameter.hasImplicitType = true; |
+ } |
_currentHolder.addParameter(parameter); |
parameterName.staticElement = parameter; |
normalParameter.accept(this); |
@@ -2625,6 +2694,7 @@ class ElementBuilder extends RecursiveAstVisitor<Object> { |
SimpleIdentifier enumName = node.name; |
ClassElementImpl enumElement = new ClassElementImpl.forNode(enumName); |
enumElement.enum2 = true; |
+ _setDocRange(enumElement, node); |
InterfaceTypeImpl enumType = new InterfaceTypeImpl(enumElement); |
enumElement.type = enumType; |
// The equivalent code for enums in the spec shows a single constructor, |
@@ -2697,6 +2767,7 @@ class ElementBuilder extends RecursiveAstVisitor<Object> { |
SimpleIdentifier functionName = node.name; |
FunctionElementImpl element = |
new FunctionElementImpl.forNode(functionName); |
+ _setDocRange(element, node); |
if (node.externalKeyword != null) { |
element.external = true; |
} |
@@ -2719,6 +2790,9 @@ class ElementBuilder extends RecursiveAstVisitor<Object> { |
element.setVisibleRange(functionEnd, blockEnd - functionEnd - 1); |
} |
} |
+ if (node.returnType == null) { |
+ element.hasImplicitReturnType = true; |
+ } |
_currentHolder.addFunction(element); |
expression.element = element; |
functionName.staticElement = element; |
@@ -2740,6 +2814,7 @@ class ElementBuilder extends RecursiveAstVisitor<Object> { |
if (node.isGetter) { |
PropertyAccessorElementImpl getter = |
new PropertyAccessorElementImpl.forNode(propertyNameNode); |
+ _setDocRange(getter, node); |
if (node.externalKeyword != null) { |
getter.external = true; |
} |
@@ -2756,12 +2831,16 @@ class ElementBuilder extends RecursiveAstVisitor<Object> { |
getter.getter = true; |
getter.static = true; |
variable.getter = getter; |
+ if (node.returnType == null) { |
+ getter.hasImplicitReturnType = true; |
+ } |
_currentHolder.addAccessor(getter); |
expression.element = getter; |
propertyNameNode.staticElement = getter; |
} else { |
PropertyAccessorElementImpl setter = |
new PropertyAccessorElementImpl.forNode(propertyNameNode); |
+ _setDocRange(setter, node); |
if (node.externalKeyword != null) { |
setter.external = true; |
} |
@@ -2832,6 +2911,7 @@ class ElementBuilder extends RecursiveAstVisitor<Object> { |
_functionTypesToFix.add(type); |
} |
element.type = type; |
+ element.hasImplicitReturnType = true; |
_currentHolder.addFunction(element); |
node.element = element; |
holder.validate(); |
@@ -2847,6 +2927,7 @@ class ElementBuilder extends RecursiveAstVisitor<Object> { |
List<TypeParameterElement> typeParameters = holder.typeParameters; |
FunctionTypeAliasElementImpl element = |
new FunctionTypeAliasElementImpl.forNode(aliasName); |
+ _setDocRange(element, node); |
element.parameters = parameters; |
element.typeParameters = typeParameters; |
FunctionTypeImpl type = new FunctionTypeImpl.forTypedef(element); |
@@ -2918,6 +2999,7 @@ class ElementBuilder extends RecursiveAstVisitor<Object> { |
} |
MethodElementImpl element = |
new MethodElementImpl(nameOfMethod, methodName.offset); |
+ _setDocRange(element, node); |
element.abstract = node.isAbstract; |
if (node.externalKeyword != null) { |
element.external = true; |
@@ -2934,6 +3016,9 @@ class ElementBuilder extends RecursiveAstVisitor<Object> { |
if (body.isGenerator) { |
element.generator = true; |
} |
+ if (node.returnType == null) { |
+ element.hasImplicitReturnType = true; |
+ } |
_currentHolder.addMethod(element); |
methodName.staticElement = element; |
} else { |
@@ -2951,6 +3036,7 @@ class ElementBuilder extends RecursiveAstVisitor<Object> { |
if (node.isGetter) { |
PropertyAccessorElementImpl getter = |
new PropertyAccessorElementImpl.forNode(propertyNameNode); |
+ _setDocRange(getter, node); |
if (node.externalKeyword != null) { |
getter.external = true; |
} |
@@ -2968,11 +3054,15 @@ class ElementBuilder extends RecursiveAstVisitor<Object> { |
getter.getter = true; |
getter.static = isStatic; |
field.getter = getter; |
+ if (node.returnType == null) { |
+ getter.hasImplicitReturnType = true; |
+ } |
_currentHolder.addAccessor(getter); |
propertyNameNode.staticElement = getter; |
} else { |
PropertyAccessorElementImpl setter = |
new PropertyAccessorElementImpl.forNode(propertyNameNode); |
+ _setDocRange(setter, node); |
if (node.externalKeyword != null) { |
setter.external = true; |
} |
@@ -3012,8 +3102,8 @@ class ElementBuilder extends RecursiveAstVisitor<Object> { |
} else { |
String message = |
"Exception caught in ElementBuilder.visitMethodDeclaration()"; |
- AnalysisEngine.instance.logger.logError( |
- message, new CaughtException(exception, stackTrace)); |
+ AnalysisEngine.instance.logger |
+ .logError(message, new CaughtException(exception, stackTrace)); |
} |
} finally { |
if (node.name.staticElement == null) { |
@@ -3025,7 +3115,8 @@ class ElementBuilder extends RecursiveAstVisitor<Object> { |
buffer.write(" in "); |
buffer.write(classNode.name); |
buffer.write(" was not set while trying to resolve types."); |
- AnalysisEngine.instance.logger.logError(buffer.toString(), |
+ AnalysisEngine.instance.logger.logError( |
+ buffer.toString(), |
new CaughtException( |
new AnalysisException(buffer.toString()), null)); |
} |
@@ -3043,6 +3134,9 @@ class ElementBuilder extends RecursiveAstVisitor<Object> { |
parameter.final2 = node.isFinal; |
parameter.parameterKind = node.kind; |
_setParameterVisibleRange(node, parameter); |
+ if (node.type == null) { |
+ parameter.hasImplicitType = true; |
+ } |
_currentHolder.addParameter(parameter); |
parameterName.staticElement = parameter; |
} |
@@ -3105,6 +3199,12 @@ class ElementBuilder extends RecursiveAstVisitor<Object> { |
field = new FieldElementImpl.forNode(fieldName); |
} |
element = field; |
+ if (node.parent.parent is FieldDeclaration) { |
+ _setDocRange(element, node.parent.parent); |
+ } |
+ if ((node.parent as VariableDeclarationList).type == null) { |
+ field.hasImplicitType = true; |
+ } |
_currentHolder.addField(field); |
fieldName.staticElement = field; |
} else if (_inFunction) { |
@@ -3120,6 +3220,9 @@ class ElementBuilder extends RecursiveAstVisitor<Object> { |
// TODO(brianwilkerson) This isn't right for variables declared in a for |
// loop. |
variable.setVisibleRange(enclosingBlock.offset, enclosingBlock.length); |
+ if ((node.parent as VariableDeclarationList).type == null) { |
+ variable.hasImplicitType = true; |
+ } |
_currentHolder.addLocalVariable(variable); |
variableName.staticElement = element; |
} else { |
@@ -3131,6 +3234,9 @@ class ElementBuilder extends RecursiveAstVisitor<Object> { |
variable = new TopLevelVariableElementImpl.forNode(variableName); |
} |
element = variable; |
+ if ((node.parent as VariableDeclarationList).type == null) { |
+ variable.hasImplicitType = true; |
+ } |
_currentHolder.addTopLevelVariable(variable); |
variableName.staticElement = element; |
} |
@@ -3162,6 +3268,9 @@ class ElementBuilder extends RecursiveAstVisitor<Object> { |
PropertyAccessorElementImpl getter = |
new PropertyAccessorElementImpl.forVariable(element); |
getter.getter = true; |
+ if (element.hasImplicitType) { |
+ getter.hasImplicitReturnType = true; |
+ } |
_currentHolder.addAccessor(getter); |
element.getter = getter; |
if (!isConst && !isFinal) { |
@@ -3258,6 +3367,17 @@ class ElementBuilder extends RecursiveAstVisitor<Object> { |
} |
/** |
+ * If the given [node] has a documentation comment, remember its range |
+ * into the given [element]. |
+ */ |
+ void _setDocRange(ElementImpl element, AnnotatedNode node) { |
+ Comment comment = node.documentationComment; |
+ if (comment != null && comment.isDocumentation) { |
+ element.setDocRange(comment.offset, comment.length); |
+ } |
+ } |
+ |
+ /** |
* Sets the visible source range for formal parameter. |
*/ |
void _setParameterVisibleRange( |
@@ -3726,8 +3846,10 @@ class EnclosedScope extends Scope { |
if (_hasHiddenName) { |
Element hiddenElement = _hiddenElements[name]; |
if (hiddenElement != null) { |
- errorListener.onError(new AnalysisError(getSource(identifier), |
- identifier.offset, identifier.length, |
+ errorListener.onError(new AnalysisError( |
+ getSource(identifier), |
+ identifier.offset, |
+ identifier.length, |
CompileTimeErrorCode.REFERENCED_BEFORE_DECLARATION, [])); |
return hiddenElement; |
} |
@@ -3862,11 +3984,23 @@ class ExitDetector extends GeneralizingAstVisitor<bool> { |
bool visitAsExpression(AsExpression node) => _nodeExits(node.expression); |
@override |
- bool visitAssertStatement(AssertStatement node) => _nodeExits(node.condition); |
+ bool visitAssertStatement(AssertStatement node) => false; |
@override |
- bool visitAssignmentExpression(AssignmentExpression node) => |
- _nodeExits(node.leftHandSide) || _nodeExits(node.rightHandSide); |
+ bool visitAssignmentExpression(AssignmentExpression node) { |
+ Expression leftHandSide = node.leftHandSide; |
+ if (_nodeExits(leftHandSide)) { |
+ return true; |
+ } |
+ if (node.operator.type == sc.TokenType.QUESTION_QUESTION_EQ) { |
+ return false; |
+ } |
+ if (leftHandSide is PropertyAccess && |
+ leftHandSide.operator.type == sc.TokenType.QUESTION_PERIOD) { |
+ return false; |
+ } |
+ return _nodeExits(node.rightHandSide); |
+ } |
@override |
bool visitAwaitExpression(AwaitExpression node) => |
@@ -3875,9 +4009,10 @@ class ExitDetector extends GeneralizingAstVisitor<bool> { |
@override |
bool visitBinaryExpression(BinaryExpression node) { |
Expression lhsExpression = node.leftOperand; |
+ Expression rhsExpression = node.rightOperand; |
sc.TokenType operatorType = node.operator.type; |
- // If the operator is || and the left hand side is false literal, don't |
- // consider the RHS of the binary expression. |
+ // If the operator is ||, then only consider the RHS of the binary |
+ // expression if the left hand side is the false literal. |
// TODO(jwren) Do we want to take constant expressions into account, |
// evaluate if(false) {} differently than if(<condition>), when <condition> |
// evaluates to a constant false value? |
@@ -3885,21 +4020,27 @@ class ExitDetector extends GeneralizingAstVisitor<bool> { |
if (lhsExpression is BooleanLiteral) { |
BooleanLiteral booleanLiteral = lhsExpression; |
if (!booleanLiteral.value) { |
- return false; |
+ return _nodeExits(rhsExpression); |
} |
} |
+ return _nodeExits(lhsExpression); |
} |
- // If the operator is && and the left hand side is true literal, don't |
- // consider the RHS of the binary expression. |
+ // If the operator is &&, then only consider the RHS of the binary |
+ // expression if the left hand side is the true literal. |
if (operatorType == sc.TokenType.AMPERSAND_AMPERSAND) { |
if (lhsExpression is BooleanLiteral) { |
BooleanLiteral booleanLiteral = lhsExpression; |
if (booleanLiteral.value) { |
- return false; |
+ return _nodeExits(rhsExpression); |
} |
} |
+ return _nodeExits(lhsExpression); |
+ } |
+ // If the operator is ??, then don't consider the RHS of the binary |
+ // expression. |
+ if (operatorType == sc.TokenType.QUESTION_QUESTION) { |
+ return _nodeExits(lhsExpression); |
} |
- Expression rhsExpression = node.rightOperand; |
return _nodeExits(lhsExpression) || _nodeExits(rhsExpression); |
} |
@@ -4094,8 +4235,13 @@ class ExitDetector extends GeneralizingAstVisitor<bool> { |
@override |
bool visitMethodInvocation(MethodInvocation node) { |
Expression target = node.realTarget; |
- if (target != null && target.accept(this)) { |
- return true; |
+ if (target != null) { |
+ if (target.accept(this)) { |
+ return true; |
+ } |
+ if (node.operator.type == sc.TokenType.QUESTION_PERIOD) { |
+ return false; |
+ } |
} |
return _nodeExits(node.argumentList); |
} |
@@ -4707,15 +4853,16 @@ class HintGenerator { |
ErrorReporter errorReporter = new ErrorReporter(_errorListener, source); |
unit.accept(_usedImportedElementsVisitor); |
// dead code analysis |
- unit.accept(new DeadCodeVerifier(errorReporter)); |
+ unit.accept( |
+ new DeadCodeVerifier(errorReporter, typeSystem: _context.typeSystem)); |
unit.accept(_usedLocalElementsVisitor); |
// dart2js analysis |
if (_enableDart2JSHints) { |
unit.accept(new Dart2JSVerifier(errorReporter)); |
} |
// Dart best practices |
- unit.accept( |
- new BestPracticesVerifier(errorReporter, _context.typeProvider)); |
+ unit.accept(new BestPracticesVerifier(errorReporter, _context.typeProvider, |
+ typeSystem: _context.typeSystem)); |
unit.accept(new OverrideVerifier(errorReporter, _manager)); |
// Find to-do comments |
new ToDoFinder(errorReporter).findIn(unit); |
@@ -4758,12 +4905,7 @@ class HtmlTagInfo { |
* @param classToTagsMap a table mapping the classes defined in the HTML file to an array |
* containing the names of tags with that class |
*/ |
- HtmlTagInfo(List<String> allTags, HashMap<String, String> idToTagMap, |
- HashMap<String, List<String>> classToTagsMap) { |
- this.allTags = allTags; |
- this.idToTagMap = idToTagMap; |
- this.classToTagsMap = classToTagsMap; |
- } |
+ HtmlTagInfo(this.allTags, this.idToTagMap, this.classToTagsMap); |
/** |
* Return an array containing the tags that have the given class, or {@code null} if there are no |
@@ -5678,7 +5820,8 @@ class InheritanceManager { |
* @return the passed function type with any parameterized types substituted |
*/ |
FunctionType substituteTypeArgumentsInMemberFromInheritance( |
- FunctionType baseFunctionType, String memberName, |
+ FunctionType baseFunctionType, |
+ String memberName, |
InterfaceType definingType) { |
// if the baseFunctionType is null, or does not have any parameters, |
// return it. |
@@ -6180,11 +6323,13 @@ class InheritanceManager { |
continue; |
} |
bool subtypeOfAllTypes = true; |
+ TypeSystem typeSystem = _library.context.typeSystem; |
for (int j = 0; |
j < numOfEltsWithMatchingNames && subtypeOfAllTypes; |
j++) { |
if (i != j) { |
- if (!subtype.isSubtypeOf(executableElementTypes[j])) { |
+ if (!typeSystem.isSubtypeOf( |
+ subtype, executableElementTypes[j])) { |
subtypeOfAllTypes = false; |
break; |
} |
@@ -6235,12 +6380,12 @@ class InheritanceManager { |
if (!classHasMember) { |
String firstTwoFuntionTypesStr = |
"${executableElementTypes[0]}, ${executableElementTypes[1]}"; |
- _reportError(classElt, classElt.nameOffset, |
- classElt.displayName.length, |
- StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE, [ |
- key, |
- firstTwoFuntionTypesStr |
- ]); |
+ _reportError( |
+ classElt, |
+ classElt.nameOffset, |
+ classElt.nameLength, |
+ StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE, |
+ [key, firstTwoFuntionTypesStr]); |
} |
} else { |
// |
@@ -6252,9 +6397,8 @@ class InheritanceManager { |
// Tests: test_getMapOfMembersInheritedFromInterfaces_ |
// union_multipleSubtypes_* |
// |
- List<ExecutableElement> elementArrayToMerge = |
- new List<ExecutableElement>( |
- subtypesOfAllOtherTypesIndexes.length); |
+ List<ExecutableElement> elementArrayToMerge = new List< |
+ ExecutableElement>(subtypesOfAllOtherTypesIndexes.length); |
for (int i = 0; i < elementArrayToMerge.length; i++) { |
elementArrayToMerge[i] = |
elements[subtypesOfAllOtherTypesIndexes[i]]; |
@@ -6265,8 +6409,10 @@ class InheritanceManager { |
} |
} |
} else { |
- _reportError(classElt, classElt.nameOffset, |
- classElt.displayName.length, |
+ _reportError( |
+ classElt, |
+ classElt.nameOffset, |
+ classElt.nameLength, |
StaticWarningCode.INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHOD, |
[key]); |
} |
@@ -6388,8 +6534,11 @@ class InheritanceManager { |
} |
namedParametersList.addAll(_getNamedParameterNames(element)); |
} |
- return _createSyntheticExecutableElement(elementArrayToMerge, |
- elementArrayToMerge[0].displayName, r, h - r, |
+ return _createSyntheticExecutableElement( |
+ elementArrayToMerge, |
+ elementArrayToMerge[0].displayName, |
+ r, |
+ h - r, |
new List.from(namedParametersList)); |
} |
@@ -6405,8 +6554,10 @@ class InheritanceManager { |
* @return the created synthetic element |
*/ |
static ExecutableElement _createSyntheticExecutableElement( |
- List<ExecutableElement> elementArrayToMerge, String name, |
- int numOfRequiredParameters, int numOfPositionalParameters, |
+ List<ExecutableElement> elementArrayToMerge, |
+ String name, |
+ int numOfRequiredParameters, |
+ int numOfPositionalParameters, |
List<String> namedParameters) { |
DynamicTypeImpl dynamicType = DynamicTypeImpl.instance; |
SimpleIdentifier nameIdentifier = new SimpleIdentifier( |
@@ -6788,8 +6939,8 @@ class Library { |
LibraryElementImpl get libraryElement { |
if (_libraryElement == null) { |
try { |
- _libraryElement = _analysisContext |
- .computeLibraryElement(librarySource) as LibraryElementImpl; |
+ _libraryElement = _analysisContext.computeLibraryElement(librarySource) |
+ as LibraryElementImpl; |
} on AnalysisException catch (exception, stackTrace) { |
AnalysisEngine.instance.logger.logError( |
"Could not compute library element for ${librarySource.fullName}", |
@@ -6866,9 +7017,12 @@ class Library { |
Source source = |
_analysisContext.sourceFactory.resolveUri(librarySource, uriContent); |
if (!_analysisContext.exists(source)) { |
- errorListener.onError(new AnalysisError(librarySource, |
- uriLiteral.offset, uriLiteral.length, |
- CompileTimeErrorCode.URI_DOES_NOT_EXIST, [uriContent])); |
+ errorListener.onError(new AnalysisError( |
+ librarySource, |
+ uriLiteral.offset, |
+ uriLiteral.length, |
+ CompileTimeErrorCode.URI_DOES_NOT_EXIST, |
+ [uriContent])); |
} |
return source; |
} on URISyntaxException { |
@@ -6934,6 +7088,7 @@ class LibraryElementBuilder { |
.buildCompilationUnit( |
librarySource, definingCompilationUnit, librarySource); |
NodeList<Directive> directives = definingCompilationUnit.directives; |
+ LibraryDirective libraryDirective = null; |
LibraryIdentifier libraryNameNode = null; |
bool hasPartDirective = false; |
FunctionElement entryPoint = |
@@ -6951,6 +7106,7 @@ class LibraryElementBuilder { |
// |
if (directive is LibraryDirective) { |
if (libraryNameNode == null) { |
+ libraryDirective = directive; |
libraryNameNode = directive.name; |
directivesToResolve.add(directive); |
} |
@@ -6973,21 +7129,24 @@ class LibraryElementBuilder { |
String partLibraryName = |
_getPartLibraryName(partSource, partUnit, directivesToResolve); |
if (partLibraryName == null) { |
- _errorListener.onError(new AnalysisError(librarySource, |
- partUri.offset, partUri.length, |
- CompileTimeErrorCode.PART_OF_NON_PART, [partUri.toSource()])); |
+ _errorListener.onError(new AnalysisError( |
+ librarySource, |
+ partUri.offset, |
+ partUri.length, |
+ CompileTimeErrorCode.PART_OF_NON_PART, |
+ [partUri.toSource()])); |
} else if (libraryNameNode == null) { |
// TODO(brianwilkerson) Collect the names declared by the part. |
// If they are all the same then we can use that name as the |
// inferred name of the library and present it in a quick-fix. |
// partLibraryNames.add(partLibraryName); |
} else if (libraryNameNode.name != partLibraryName) { |
- _errorListener.onError(new AnalysisError(librarySource, |
- partUri.offset, partUri.length, |
- StaticWarningCode.PART_OF_DIFFERENT_LIBRARY, [ |
- libraryNameNode.name, |
- partLibraryName |
- ])); |
+ _errorListener.onError(new AnalysisError( |
+ librarySource, |
+ partUri.offset, |
+ partUri.length, |
+ StaticWarningCode.PART_OF_DIFFERENT_LIBRARY, |
+ [libraryNameNode.name, partLibraryName])); |
} |
if (entryPoint == null) { |
entryPoint = _findEntryPoint(part); |
@@ -7006,6 +7165,7 @@ class LibraryElementBuilder { |
// |
LibraryElementImpl libraryElement = new LibraryElementImpl.forNode( |
_analysisContext.getContextFor(librarySource), libraryNameNode); |
+ _setDocRange(libraryElement, libraryDirective); |
libraryElement.definingCompilationUnit = definingCompilationUnitElement; |
if (entryPoint != null) { |
libraryElement.entryPoint = entryPoint; |
@@ -7037,6 +7197,7 @@ class LibraryElementBuilder { |
.buildCompilationUnit( |
librarySource, definingCompilationUnit, librarySource); |
NodeList<Directive> directives = definingCompilationUnit.directives; |
+ LibraryDirective libraryDirective = null; |
LibraryIdentifier libraryNameNode = null; |
bool hasPartDirective = false; |
FunctionElement entryPoint = |
@@ -7054,6 +7215,7 @@ class LibraryElementBuilder { |
// |
if (directive is LibraryDirective) { |
if (libraryNameNode == null) { |
+ libraryDirective = directive; |
libraryNameNode = directive.name; |
directivesToResolve.add(directive); |
} |
@@ -7077,21 +7239,24 @@ class LibraryElementBuilder { |
String partLibraryName = |
_getPartLibraryName(partSource, partUnit, directivesToResolve); |
if (partLibraryName == null) { |
- _errorListener.onError(new AnalysisError(librarySource, |
- partUri.offset, partUri.length, |
- CompileTimeErrorCode.PART_OF_NON_PART, [partUri.toSource()])); |
+ _errorListener.onError(new AnalysisError( |
+ librarySource, |
+ partUri.offset, |
+ partUri.length, |
+ CompileTimeErrorCode.PART_OF_NON_PART, |
+ [partUri.toSource()])); |
} else if (libraryNameNode == null) { |
// TODO(brianwilkerson) Collect the names declared by the part. |
// If they are all the same then we can use that name as the |
// inferred name of the library and present it in a quick-fix. |
// partLibraryNames.add(partLibraryName); |
} else if (libraryNameNode.name != partLibraryName) { |
- _errorListener.onError(new AnalysisError(librarySource, |
- partUri.offset, partUri.length, |
- StaticWarningCode.PART_OF_DIFFERENT_LIBRARY, [ |
- libraryNameNode.name, |
- partLibraryName |
- ])); |
+ _errorListener.onError(new AnalysisError( |
+ librarySource, |
+ partUri.offset, |
+ partUri.length, |
+ StaticWarningCode.PART_OF_DIFFERENT_LIBRARY, |
+ [libraryNameNode.name, partLibraryName])); |
} |
if (entryPoint == null) { |
entryPoint = _findEntryPoint(part); |
@@ -7111,6 +7276,7 @@ class LibraryElementBuilder { |
// |
LibraryElementImpl libraryElement = new LibraryElementImpl.forNode( |
_analysisContext.getContextFor(librarySource), libraryNameNode); |
+ _setDocRange(libraryElement, libraryDirective); |
libraryElement.definingCompilationUnit = definingCompilationUnitElement; |
if (entryPoint != null) { |
libraryElement.entryPoint = entryPoint; |
@@ -7214,6 +7380,19 @@ class LibraryElementBuilder { |
} |
} |
} |
+ |
+ /** |
+ * If the given [node] has a documentation comment, remember its range |
+ * into the given [element]. |
+ */ |
+ void _setDocRange(ElementImpl element, LibraryDirective node) { |
+ if (node != null) { |
+ Comment comment = node.documentationComment; |
+ if (comment != null && comment.isDocumentation) { |
+ element.setDocRange(comment.offset, comment.length); |
+ } |
+ } |
+ } |
} |
/** |
@@ -7296,8 +7475,10 @@ class LibraryImportScope extends Scope { |
libraryNames[i] = _getLibraryName(conflictingMembers[i]); |
} |
libraryNames.sort(); |
- errorListener.onError(new AnalysisError(getSource(identifier), |
- identifier.offset, identifier.length, |
+ errorListener.onError(new AnalysisError( |
+ getSource(identifier), |
+ identifier.offset, |
+ identifier.length, |
StaticWarningCode.AMBIGUOUS_IMPORT, [ |
foundEltName, |
StringUtilities.printListOfQuotedNames(libraryNames) |
@@ -7398,13 +7579,12 @@ class LibraryImportScope extends Scope { |
if (sdkElement != null && nonSdkElements.length > 0) { |
String sdkLibName = _getLibraryName(sdkElement); |
String otherLibName = _getLibraryName(nonSdkElements[0]); |
- errorListener.onError(new AnalysisError(getSource(identifier), |
- identifier.offset, identifier.length, |
- StaticWarningCode.CONFLICTING_DART_IMPORT, [ |
- name, |
- sdkLibName, |
- otherLibName |
- ])); |
+ errorListener.onError(new AnalysisError( |
+ getSource(identifier), |
+ identifier.offset, |
+ identifier.length, |
+ StaticWarningCode.CONFLICTING_DART_IMPORT, |
+ [name, sdkLibName, otherLibName])); |
} |
if (nonSdkElements.length == conflictingElements.length) { |
// None of the members were removed |
@@ -7466,6 +7646,11 @@ class LibraryResolver { |
TypeProvider _typeProvider; |
/** |
+ * The type system in use for the library |
+ */ |
+ TypeSystem _typeSystem; |
+ |
+ /** |
* A table mapping library sources to the information being maintained for those libraries. |
*/ |
HashMap<Source, Library> _libraryMap = new HashMap<Source, Library>(); |
@@ -7508,6 +7693,11 @@ class LibraryResolver { |
TypeProvider get typeProvider => _typeProvider; |
/** |
+ * The type system in use. |
+ */ |
+ TypeSystem get typeSystem => _typeSystem; |
+ |
+ /** |
* Create an object to represent the information about the library defined by the compilation unit |
* with the given source. |
* |
@@ -7592,6 +7782,7 @@ class LibraryResolver { |
} |
_buildDirectiveModels(); |
_typeProvider = new TypeProviderImpl(coreElement, asyncElement); |
+ _typeSystem = TypeSystem.create(analysisContext); |
_buildTypeHierarchies(); |
// |
// Perform resolution and type analysis. |
@@ -7670,6 +7861,7 @@ class LibraryResolver { |
} |
_buildDirectiveModels(); |
_typeProvider = new TypeProviderImpl(coreElement, asyncElement); |
+ _typeSystem = TypeSystem.create(analysisContext); |
_buildEnumMembers(); |
_buildTypeHierarchies(); |
// |
@@ -7753,7 +7945,8 @@ class LibraryResolver { |
* @param visitedLibraries the libraries that have already been visited, used to prevent infinite |
* recursion |
*/ |
- void _addToDependencyMap(Library library, |
+ void _addToDependencyMap( |
+ Library library, |
HashMap<Library, List<Library>> dependencyMap, |
Set<Library> visitedLibraries) { |
if (visitedLibraries.add(library)) { |
@@ -7858,8 +8051,11 @@ class LibraryResolver { |
ErrorCode errorCode = (importElement.isDeferred |
? StaticWarningCode.IMPORT_OF_NON_LIBRARY |
: CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY); |
- _errorListener.onError(new AnalysisError(library.librarySource, |
- uriLiteral.offset, uriLiteral.length, errorCode, |
+ _errorListener.onError(new AnalysisError( |
+ library.librarySource, |
+ uriLiteral.offset, |
+ uriLiteral.length, |
+ errorCode, |
[uriLiteral.toSource()])); |
} |
} |
@@ -7888,8 +8084,10 @@ class LibraryResolver { |
exports.add(exportElement); |
if (analysisContext.computeKindOf(exportedSource) != |
SourceKind.LIBRARY) { |
- _errorListener.onError(new AnalysisError(library.librarySource, |
- uriLiteral.offset, uriLiteral.length, |
+ _errorListener.onError(new AnalysisError( |
+ library.librarySource, |
+ uriLiteral.offset, |
+ uriLiteral.length, |
CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY, |
[uriLiteral.toSource()])); |
} |
@@ -8046,7 +8244,8 @@ class LibraryResolver { |
*/ |
void _computeLibraryDependencies(Library library) { |
Source librarySource = library.librarySource; |
- _computeLibraryDependenciesFromDirectives(library, |
+ _computeLibraryDependenciesFromDirectives( |
+ library, |
analysisContext.computeImportedLibraries(librarySource), |
analysisContext.computeExportedLibraries(librarySource)); |
} |
@@ -8175,7 +8374,11 @@ class LibraryResolver { |
void _performConstantEvaluation() { |
PerformanceStatistics.resolve.makeCurrentWhile(() { |
ConstantValueComputer computer = new ConstantValueComputer( |
- analysisContext, _typeProvider, analysisContext.declaredVariables); |
+ analysisContext, |
+ _typeProvider, |
+ analysisContext.declaredVariables, |
+ null, |
+ _typeSystem); |
for (Library library in _librariesInCycles) { |
for (Source source in library.compilationUnitSources) { |
try { |
@@ -8200,7 +8403,9 @@ class LibraryResolver { |
ErrorReporter errorReporter = |
new ErrorReporter(_errorListener, source); |
ConstantVerifier constantVerifier = new ConstantVerifier( |
- errorReporter, library.libraryElement, _typeProvider, |
+ errorReporter, |
+ library.libraryElement, |
+ _typeProvider, |
analysisContext.declaredVariables); |
unit.accept(constantVerifier); |
} on AnalysisException catch (exception, stackTrace) { |
@@ -8306,6 +8511,11 @@ class LibraryResolver2 { |
TypeProvider _typeProvider; |
/** |
+ * The type system in use for the library |
+ */ |
+ TypeSystem _typeSystem; |
+ |
+ /** |
* A table mapping library sources to the information being maintained for those libraries. |
*/ |
HashMap<Source, ResolvableLibrary> _libraryMap = |
@@ -8395,6 +8605,7 @@ class LibraryResolver2 { |
} |
_buildDirectiveModels(); |
_typeProvider = new TypeProviderImpl(coreElement, asyncElement); |
+ _typeSystem = TypeSystem.create(analysisContext); |
_buildEnumMembers(); |
_buildTypeHierarchies(); |
// |
@@ -8503,8 +8714,11 @@ class LibraryResolver2 { |
ErrorCode errorCode = (importElement.isDeferred |
? StaticWarningCode.IMPORT_OF_NON_LIBRARY |
: CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY); |
- _errorListener.onError(new AnalysisError(library.librarySource, |
- uriLiteral.offset, uriLiteral.length, errorCode, |
+ _errorListener.onError(new AnalysisError( |
+ library.librarySource, |
+ uriLiteral.offset, |
+ uriLiteral.length, |
+ errorCode, |
[uriLiteral.toSource()])); |
} |
} |
@@ -8536,8 +8750,10 @@ class LibraryResolver2 { |
exports.add(exportElement); |
if (analysisContext.computeKindOf(exportedSource) != |
SourceKind.LIBRARY) { |
- _errorListener.onError(new AnalysisError(library.librarySource, |
- uriLiteral.offset, uriLiteral.length, |
+ _errorListener.onError(new AnalysisError( |
+ library.librarySource, |
+ uriLiteral.offset, |
+ uriLiteral.length, |
CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY, |
[uriLiteral.toSource()])); |
} |
@@ -8631,7 +8847,9 @@ class LibraryResolver2 { |
Source source = unit.source; |
CompilationUnit ast = unit.compilationUnit; |
TypeResolverVisitor visitor = new TypeResolverVisitor( |
- library.libraryElement, source, _typeProvider, |
+ library.libraryElement, |
+ source, |
+ _typeProvider, |
library.libraryScope.errorListener, |
nameScope: library.libraryScope); |
ast.accept(visitor); |
@@ -8661,7 +8879,11 @@ class LibraryResolver2 { |
void _performConstantEvaluation() { |
PerformanceStatistics.resolve.makeCurrentWhile(() { |
ConstantValueComputer computer = new ConstantValueComputer( |
- analysisContext, _typeProvider, analysisContext.declaredVariables); |
+ analysisContext, |
+ _typeProvider, |
+ analysisContext.declaredVariables, |
+ null, |
+ _typeSystem); |
for (ResolvableLibrary library in _librariesInCycle) { |
for (ResolvableCompilationUnit unit |
in library.resolvableCompilationUnits) { |
@@ -8681,7 +8903,9 @@ class LibraryResolver2 { |
ErrorReporter errorReporter = |
new ErrorReporter(_errorListener, unit.source); |
ConstantVerifier constantVerifier = new ConstantVerifier( |
- errorReporter, library.libraryElement, _typeProvider, |
+ errorReporter, |
+ library.libraryElement, |
+ _typeProvider, |
analysisContext.declaredVariables); |
ast.accept(constantVerifier); |
} |
@@ -8751,46 +8975,6 @@ class LibraryResolver2 { |
} |
/** |
- * Instances of the class `TypeAliasInfo` hold information about a [TypeAlias]. |
- */ |
-class LibraryResolver2_TypeAliasInfo { |
- final ResolvableLibrary _library; |
- |
- final Source _source; |
- |
- final FunctionTypeAlias _typeAlias; |
- |
- /** |
- * Initialize a newly created information holder with the given information. |
- * |
- * @param library the library containing the type alias |
- * @param source the source of the file containing the type alias |
- * @param typeAlias the type alias being remembered |
- */ |
- LibraryResolver2_TypeAliasInfo(this._library, this._source, this._typeAlias); |
-} |
- |
-/** |
- * Instances of the class `TypeAliasInfo` hold information about a [TypeAlias]. |
- */ |
-class LibraryResolver_TypeAliasInfo { |
- final Library _library; |
- |
- final Source _source; |
- |
- final FunctionTypeAlias _typeAlias; |
- |
- /** |
- * Initialize a newly created information holder with the given information. |
- * |
- * @param library the library containing the type alias |
- * @param source the source of the file containing the type alias |
- * @param typeAlias the type alias being remembered |
- */ |
- LibraryResolver_TypeAliasInfo(this._library, this._source, this._typeAlias); |
-} |
- |
-/** |
* Instances of the class `LibraryScope` implement a scope containing all of the names defined |
* in a given library. |
*/ |
@@ -8819,8 +9003,10 @@ class LibraryScope extends EnclosedScope { |
offset = accessor.variable.nameOffset; |
} |
} |
- return new AnalysisError(duplicate.source, offset, |
- duplicate.displayName.length, |
+ return new AnalysisError( |
+ duplicate.source, |
+ offset, |
+ duplicate.nameLength, |
CompileTimeErrorCode.PREFIX_COLLIDES_WITH_TOP_LEVEL_MEMBER, |
[existing.displayName]); |
} |
@@ -9082,8 +9268,7 @@ class Namespace { |
* |
* @return a table containing the same mappings as those defined by this namespace |
*/ |
- Map<String, Element> get definedNames => |
- new HashMap<String, Element>.from(_definedNames); |
+ Map<String, Element> get definedNames => _definedNames; |
/** |
* Return the element in this namespace that is available to the containing scope using the given |
@@ -9233,7 +9418,7 @@ class NamespaceBuilder { |
List<NamespaceCombinator> combinators) { |
for (NamespaceCombinator combinator in combinators) { |
if (combinator is HideElementCombinator) { |
- _hide(definedNames, combinator.hiddenNames); |
+ definedNames = _hide(definedNames, combinator.hiddenNames); |
} else if (combinator is ShowElementCombinator) { |
definedNames = _show(definedNames, combinator.shownNames); |
} else { |
@@ -9301,7 +9486,8 @@ class NamespaceBuilder { |
definedNames.addAll(exportedNames); |
} |
} |
- _addAllFromNamespace(definedNames, |
+ _addAllFromNamespace( |
+ definedNames, |
(library.context as InternalAnalysisContext) |
.getPublicNamespace(library)); |
return definedNames; |
@@ -9311,24 +9497,22 @@ class NamespaceBuilder { |
} |
/** |
- * Hide all of the given names by removing them from the given collection of defined names. |
- * |
- * @param definedNames the names that were defined before this operation |
- * @param hiddenNames the names to be hidden |
+ * Return a new map of names which has all the names from [definedNames] |
+ * with exception of [hiddenNames]. |
*/ |
- void _hide(HashMap<String, Element> definedNames, List<String> hiddenNames) { |
+ Map<String, Element> _hide( |
+ HashMap<String, Element> definedNames, List<String> hiddenNames) { |
+ HashMap<String, Element> newNames = |
+ new HashMap<String, Element>.from(definedNames); |
for (String name in hiddenNames) { |
- definedNames.remove(name); |
- definedNames.remove("$name="); |
+ newNames.remove(name); |
+ newNames.remove("$name="); |
} |
+ return newNames; |
} |
/** |
- * Show only the given names by removing all other names from the given collection of defined |
- * names. |
- * |
- * @param definedNames the names that were defined before this operation |
- * @param shownNames the names to be shown |
+ * Return a new map of names which has only [shownNames] from [definedNames]. |
*/ |
HashMap<String, Element> _show( |
HashMap<String, Element> definedNames, List<String> shownNames) { |
@@ -9422,6 +9606,155 @@ class OverrideVerifier extends RecursiveAstVisitor<Object> { |
} |
/** |
+ * An AST visitor that is used to resolve the some of the nodes within a single |
+ * compilation unit. The nodes that are skipped are those that are within |
+ * function bodies. |
+ */ |
+class PartialResolverVisitor extends ResolverVisitor { |
+ /** |
+ * A flag indicating whether the resolver is being run in strong mode. |
+ */ |
+ final bool strongMode; |
+ |
+ /** |
+ * The static variables and fields that have an initializer. These are the |
+ * variables that need to be re-resolved after static variables have their |
+ * types inferred. A subset of these variables are those whose types should |
+ * be inferred. The list will be empty unless the resolver is being run in |
+ * strong mode. |
+ */ |
+ final List<VariableElement> variablesAndFields = <VariableElement>[]; |
+ |
+ /** |
+ * A flag indicating whether we should discard errors while resolving the |
+ * initializer for variable declarations. We do this for top-level variables |
+ * and fields because their initializer will be re-resolved at a later time. |
+ */ |
+ bool discardErrorsInInitializer = false; |
+ |
+ /** |
+ * Initialize a newly created visitor to resolve the nodes in an AST node. |
+ * |
+ * The [definingLibrary] is the element for the library containing the node |
+ * being visited. The [source] is the source representing the compilation unit |
+ * containing the node being visited. The [typeProvider] is the object used to |
+ * access the types from the core library. The [errorListener] is the error |
+ * listener that will be informed of any errors that are found during |
+ * resolution. The [nameScope] is the scope used to resolve identifiers in the |
+ * node that will first be visited. If `null` or unspecified, a new |
+ * [LibraryScope] will be created based on [definingLibrary] and |
+ * [typeProvider]. The [inheritanceManager] is used to perform inheritance |
+ * lookups. If `null` or unspecified, a new [InheritanceManager] will be |
+ * created based on [definingLibrary]. The [typeAnalyzerFactory] is used to |
+ * create the type analyzer. If `null` or unspecified, a type analyzer of |
+ * type [StaticTypeAnalyzer] will be created. |
+ */ |
+ PartialResolverVisitor(LibraryElement definingLibrary, Source source, |
+ TypeProvider typeProvider, AnalysisErrorListener errorListener, |
+ {Scope nameScope, |
+ InheritanceManager inheritanceManager, |
+ StaticTypeAnalyzerFactory typeAnalyzerFactory}) |
+ : strongMode = definingLibrary.context.analysisOptions.strongMode, |
+ super(definingLibrary, source, typeProvider, |
+ new DisablableErrorListener(errorListener)); |
+ |
+ @override |
+ Object visitBlockFunctionBody(BlockFunctionBody node) { |
+ if (_shouldBeSkipped(node)) { |
+ return null; |
+ } |
+ return super.visitBlockFunctionBody(node); |
+ } |
+ |
+ @override |
+ Object visitExpressionFunctionBody(ExpressionFunctionBody node) { |
+ if (_shouldBeSkipped(node)) { |
+ return null; |
+ } |
+ return super.visitExpressionFunctionBody(node); |
+ } |
+ |
+ @override |
+ Object visitFieldDeclaration(FieldDeclaration node) { |
+ if (strongMode && node.isStatic) { |
+ _addVariables(node.fields.variables); |
+ bool wasDiscarding = discardErrorsInInitializer; |
+ discardErrorsInInitializer = true; |
+ try { |
+ return super.visitFieldDeclaration(node); |
+ } finally { |
+ discardErrorsInInitializer = wasDiscarding; |
+ } |
+ } |
+ return super.visitFieldDeclaration(node); |
+ } |
+ |
+ @override |
+ Object visitNode(AstNode node) { |
+ if (discardErrorsInInitializer) { |
+ AstNode parent = node.parent; |
+ if (parent is VariableDeclaration && parent.initializer == node) { |
+ DisablableErrorListener listener = errorListener; |
+ return listener.disableWhile(() => super.visitNode(node)); |
+ } |
+ } |
+ return super.visitNode(node); |
+ } |
+ |
+ @override |
+ Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { |
+ if (strongMode) { |
+ _addVariables(node.variables.variables); |
+ bool wasDiscarding = discardErrorsInInitializer; |
+ discardErrorsInInitializer = true; |
+ try { |
+ return super.visitTopLevelVariableDeclaration(node); |
+ } finally { |
+ discardErrorsInInitializer = wasDiscarding; |
+ } |
+ } |
+ return super.visitTopLevelVariableDeclaration(node); |
+ } |
+ |
+ /** |
+ * Add all of the [variables] with initializers to the list of variables whose |
+ * type can be inferred. Technically, we only infer the types of variables |
+ * that do not have a static type, but all variables with initializers |
+ * potentially need to be re-resolved after inference because they might |
+ * refer to a field whose type was inferred. |
+ */ |
+ void _addVariables(NodeList<VariableDeclaration> variables) { |
+ for (VariableDeclaration variable in variables) { |
+ if (variable.initializer != null) { |
+ variablesAndFields.add(variable.element); |
+ } |
+ } |
+ } |
+ |
+ /** |
+ * Return `true` if the given function body should be skipped because it is |
+ * the body of a top-level function, method or constructor. |
+ */ |
+ bool _shouldBeSkipped(FunctionBody body) { |
+ AstNode parent = body.parent; |
+ if (parent is MethodDeclaration) { |
+ return parent.body == body; |
+ } |
+ if (parent is ConstructorDeclaration) { |
+ return parent.body == body; |
+ } |
+ if (parent is FunctionExpression) { |
+ AstNode parent2 = parent.parent; |
+ if (parent2 is FunctionDeclaration && |
+ parent2.parent is! FunctionDeclarationStatement) { |
+ return parent.body == body; |
+ } |
+ } |
+ return false; |
+ } |
+} |
+ |
+/** |
* Instances of the class `PubVerifier` traverse an AST structure looking for deviations from |
* pub best practices. |
*/ |
@@ -9954,6 +10287,11 @@ class ResolverVisitor extends ScopedVisitor { |
*/ |
StaticTypeAnalyzer typeAnalyzer; |
+ /* |
+ * The type system in use during resolution. |
+ */ |
+ TypeSystem typeSystem; |
+ |
/** |
* The class element representing the class containing the current node, |
* or `null` if the current node is not contained in a class. |
@@ -10007,34 +10345,34 @@ class ResolverVisitor extends ScopedVisitor { |
/** |
* Initialize a newly created visitor to resolve the nodes in an AST node. |
* |
- * [definingLibrary] is the element for the library containing the node being |
- * visited. |
- * [source] is the source representing the compilation unit containing the |
- * node being visited. |
- * [typeProvider] the object used to access the types from the core library. |
- * [errorListener] the error listener that will be informed of any errors |
- * that are found during resolution. |
- * [nameScope] is the scope used to resolve identifiers in the node that will |
- * first be visited. If `null` or unspecified, a new [LibraryScope] will be |
- * created based on [definingLibrary] and [typeProvider]. |
- * [inheritanceManager] is used to perform inheritance lookups. If `null` or |
- * unspecified, a new [InheritanceManager] will be created based on |
- * [definingLibrary]. |
- * [typeAnalyzerFactory] is used to create the type analyzer. If `null` or |
- * unspecified, a type analyzer of type [StaticTypeAnalyzer] will be created. |
+ * The [definingLibrary] is the element for the library containing the node |
+ * being visited. The [source] is the source representing the compilation unit |
+ * containing the node being visited. The [typeProvider] is the object used to |
+ * access the types from the core library. The [errorListener] is the error |
+ * listener that will be informed of any errors that are found during |
+ * resolution. The [nameScope] is the scope used to resolve identifiers in the |
+ * node that will first be visited. If `null` or unspecified, a new |
+ * [LibraryScope] will be created based on [definingLibrary] and |
+ * [typeProvider]. The [inheritanceManager] is used to perform inheritance |
+ * lookups. If `null` or unspecified, a new [InheritanceManager] will be |
+ * created based on [definingLibrary]. The [typeAnalyzerFactory] is used to |
+ * create the type analyzer. If `null` or unspecified, a type analyzer of |
+ * type [StaticTypeAnalyzer] will be created. |
*/ |
ResolverVisitor(LibraryElement definingLibrary, Source source, |
TypeProvider typeProvider, AnalysisErrorListener errorListener, |
- {Scope nameScope, InheritanceManager inheritanceManager, |
+ {Scope nameScope, |
+ InheritanceManager inheritanceManager, |
StaticTypeAnalyzerFactory typeAnalyzerFactory}) |
: super(definingLibrary, source, typeProvider, errorListener, |
- nameScope: nameScope) { |
+ nameScope: nameScope) { |
if (inheritanceManager == null) { |
this._inheritanceManager = new InheritanceManager(definingLibrary); |
} else { |
this._inheritanceManager = inheritanceManager; |
} |
this.elementResolver = new ElementResolver(this); |
+ this.typeSystem = definingLibrary.context.typeSystem; |
if (typeAnalyzerFactory == null) { |
this.typeAnalyzer = new StaticTypeAnalyzer(this); |
} else { |
@@ -10056,10 +10394,10 @@ class ResolverVisitor extends ScopedVisitor { |
Library library, Source source, TypeProvider typeProvider, |
{StaticTypeAnalyzerFactory typeAnalyzerFactory}) |
: this( |
- library.libraryElement, source, typeProvider, library.errorListener, |
- nameScope: library.libraryScope, |
- inheritanceManager: library.inheritanceManager, |
- typeAnalyzerFactory: typeAnalyzerFactory); |
+ library.libraryElement, source, typeProvider, library.errorListener, |
+ nameScope: library.libraryScope, |
+ inheritanceManager: library.inheritanceManager, |
+ typeAnalyzerFactory: typeAnalyzerFactory); |
/** |
* Return the element representing the function containing the current node, or `null` if |
@@ -10159,7 +10497,14 @@ class ResolverVisitor extends ScopedVisitor { |
/** |
* Prepares this [ResolverVisitor] to using it for incremental resolution. |
*/ |
- void initForIncrementalResolution() { |
+ void initForIncrementalResolution([Declaration declaration = null]) { |
+ if (declaration != null) { |
+ Element element = declaration.element; |
+ if (element is ExecutableElement) { |
+ _enclosingFunction = element; |
+ } |
+ _commentBeforeFunction = declaration.documentationComment; |
+ } |
_overrideManager.enterScope(); |
} |
@@ -10203,6 +10548,14 @@ class ResolverVisitor extends ScopedVisitor { |
*/ |
DartType overrideVariable(VariableElement element, DartType potentialType, |
bool allowPrecisionLoss) { |
+ // TODO(scheglov) type propagation for instance/top-level fields |
+ // was disabled because it depends on the order or visiting. |
+ // If both field and its client are in the same unit, and we visit |
+ // the client before the field, then propagated type is not set yet. |
+ if (element is PropertyInducingElement) { |
+ return null; |
+ } |
+ |
if (potentialType == null || potentialType.isBottom) { |
return null; |
} |
@@ -10235,18 +10588,6 @@ class ResolverVisitor extends ScopedVisitor { |
allowPrecisionLoss || |
!currentType.isMoreSpecificThan(potentialType) || |
potentialType.isMoreSpecificThan(currentType)) { |
- // TODO(scheglov) type propagation for instance/top-level fields |
- // was disabled because it depends on the order or visiting. |
- // If both field and its client are in the same unit, and we visit |
- // the client before the field, then propagated type is not set yet. |
-// if (element is PropertyInducingElement) { |
-// PropertyInducingElement variable = element; |
-// if (!variable.isConst && !variable.isFinal) { |
-// return; |
-// } |
-// (variable as PropertyInducingElementImpl).propagatedType = |
-// potentialType; |
-// } |
_overrideManager.setType(element, potentialType); |
return potentialType; |
} |
@@ -10254,6 +10595,15 @@ class ResolverVisitor extends ScopedVisitor { |
} |
/** |
+ * A client is about to resolve a member in the given class declaration. |
+ */ |
+ void prepareToResolveMembersInClass(ClassDeclaration node) { |
+ _enclosingClassDeclaration = node; |
+ enclosingClass = node.element; |
+ typeAnalyzer.thisType = enclosingClass == null ? null : enclosingClass.type; |
+ } |
+ |
+ /** |
* If the given [type] is valid, strongly more specific than the |
* existing static type of the given [expression], record it as a propagated |
* type of the given [expression]. Otherwise, reset it to `null`. |
@@ -10604,6 +10954,11 @@ class ResolverVisitor extends ScopedVisitor { |
@override |
Object visitDefaultFormalParameter(DefaultFormalParameter node) { |
super.visitDefaultFormalParameter(node); |
+ ParameterElement element = node.element; |
+ if (element.initializer != null && node.defaultValue != null) { |
+ (element.initializer as FunctionElementImpl).returnType = |
+ node.defaultValue.staticType; |
+ } |
FormalParameterList parent = node.parent; |
AstNode grandparent = parent.parent; |
if (grandparent is ConstructorDeclaration && |
@@ -10650,9 +11005,21 @@ class ResolverVisitor extends ScopedVisitor { |
ElementResolver.setMetadata(node.element, node); |
} |
// |
- // There is nothing else to do because everything else was resolved by the |
- // element builder. |
+ // Continue the enum resolution. |
// |
+ ClassElement outerType = enclosingClass; |
+ try { |
+ enclosingClass = node.element; |
+ typeAnalyzer.thisType = |
+ enclosingClass == null ? null : enclosingClass.type; |
+ super.visitEnumDeclaration(node); |
+ node.accept(elementResolver); |
+ node.accept(typeAnalyzer); |
+ } finally { |
+ typeAnalyzer.thisType = outerType == null ? null : outerType.type; |
+ enclosingClass = outerType; |
+ _enclosingClassDeclaration = null; |
+ } |
return null; |
} |
@@ -10715,16 +11082,24 @@ class ResolverVisitor extends ScopedVisitor { |
if (loopVariable != null && iterable != null) { |
LocalVariableElement loopElement = loopVariable.element; |
if (loopElement != null) { |
- DartType iteratorElementType = _getIteratorElementType(iterable); |
- overrideVariable(loopElement, iteratorElementType, true); |
- _recordPropagatedType(loopVariable.identifier, iteratorElementType); |
+ DartType propagatedType = null; |
+ if (node.awaitKeyword == null) { |
+ propagatedType = _getIteratorElementType(iterable); |
+ } else { |
+ propagatedType = _getStreamElementType(iterable); |
+ } |
+ if (propagatedType != null) { |
+ overrideVariable(loopElement, propagatedType, true); |
+ recordPropagatedTypeIfBetter( |
+ loopVariable.identifier, propagatedType); |
+ } |
} |
} else if (identifier != null && iterable != null) { |
Element identifierElement = identifier.staticElement; |
if (identifierElement is VariableElement) { |
DartType iteratorElementType = _getIteratorElementType(iterable); |
overrideVariable(identifierElement, iteratorElementType, true); |
- _recordPropagatedType(identifier, iteratorElementType); |
+ recordPropagatedTypeIfBetter(identifier, iteratorElementType); |
} |
} |
visitStatementInScope(body); |
@@ -11022,6 +11397,10 @@ class ResolverVisitor extends ScopedVisitor { |
Object visitVariableDeclaration(VariableDeclaration node) { |
super.visitVariableDeclaration(node); |
VariableElement element = node.element; |
+ if (element.initializer != null && node.initializer != null) { |
+ (element.initializer as FunctionElementImpl).returnType = |
+ node.initializer.staticType; |
+ } |
// Note: in addition to cloning the initializers for const variables, we |
// have to clone the initializers for non-static final fields (because if |
// they occur in a class with a const constructor, they will be needed to |
@@ -11099,12 +11478,11 @@ class ResolverVisitor extends ScopedVisitor { |
} |
/** |
- * The given expression is the expression used to compute the iterator for a for-each statement. |
- * Attempt to compute the type of objects that will be assigned to the loop variable and return |
- * that type. Return `null` if the type could not be determined. |
- * |
- * @param iterator the iterator for a for-each statement |
- * @return the type of objects that will be assigned to the loop variable |
+ * The given expression is the expression used to compute the iterator for a |
+ * for-each statement. Attempt to compute the type of objects that will be |
+ * assigned to the loop variable and return that type. Return `null` if the |
+ * type could not be determined. The [iteratorExpression] is the expression |
+ * that will return the Iterable being iterated over. |
*/ |
DartType _getIteratorElementType(Expression iteratorExpression) { |
DartType expressionType = iteratorExpression.bestType; |
@@ -11132,6 +11510,44 @@ class ResolverVisitor extends ScopedVisitor { |
} |
/** |
+ * The given expression is the expression used to compute the stream for an |
+ * asyncronous for-each statement. Attempt to compute the type of objects that |
+ * will be assigned to the loop variable and return that type. Return `null` |
+ * if the type could not be determined. The [streamExpression] is the |
+ * expression that will return the stream being iterated over. |
+ */ |
+ DartType _getStreamElementType(Expression streamExpression) { |
+ DartType streamType = streamExpression.bestType; |
+ if (streamType is InterfaceType) { |
+ FunctionType listenFunction = |
+ _inheritanceManager.lookupMemberType(streamType, "listen"); |
+ if (listenFunction == null) { |
+ return null; |
+ } |
+ List<ParameterElement> listenParameters = listenFunction.parameters; |
+ if (listenParameters == null || listenParameters.length < 1) { |
+ return null; |
+ } |
+ DartType onDataType = listenParameters[0].type; |
+ if (onDataType is FunctionType) { |
+ List<ParameterElement> onDataParameters = onDataType.parameters; |
+ if (onDataParameters == null || onDataParameters.length < 1) { |
+ return null; |
+ } |
+ DartType eventType = onDataParameters[0].type; |
+ // TODO(paulberry): checking that typeParameters.isNotEmpty is a |
+ // band-aid fix for dartbug.com/24191. Figure out what the correct |
+ // logic should be. |
+ if (streamType.typeParameters.isNotEmpty && |
+ eventType.element == streamType.typeParameters[0]) { |
+ return streamType.typeArguments[0]; |
+ } |
+ } |
+ } |
+ return null; |
+ } |
+ |
+ /** |
* If given "mayBeClosure" is [FunctionExpression] without explicit parameters types and its |
* required type is [FunctionType], then infer parameters types from [FunctionType]. |
*/ |
@@ -11150,7 +11566,7 @@ class ResolverVisitor extends ScopedVisitor { |
// If the expectedClosureType is not more specific than the static type, |
// return. |
DartType staticClosureType = |
- (closure.element != null ? closure.element.type : null) as DartType; |
+ closure.element != null ? closure.element.type : null; |
if (staticClosureType != null && |
!expectedClosureType.isMoreSpecificThan(staticClosureType)) { |
return; |
@@ -11423,18 +11839,6 @@ class ResolverVisitor extends ScopedVisitor { |
_propagateTrueState(condition.expression); |
} |
} |
- |
- /** |
- * Record that the propagated type of the given node is the given type. |
- * |
- * @param expression the node whose type is to be recorded |
- * @param type the propagated type of the node |
- */ |
- void _recordPropagatedType(Expression expression, DartType type) { |
- if (type != null && !type.isDynamic) { |
- expression.propagatedType = type; |
- } |
- } |
} |
/** |
@@ -11540,9 +11944,8 @@ abstract class Scope { |
// TODO(jwren) There are 4 error codes for duplicate, but only 1 is being |
// generated. |
Source source = duplicate.source; |
- return new AnalysisError(source, duplicate.nameOffset, |
- duplicate.displayName.length, CompileTimeErrorCode.DUPLICATE_DEFINITION, |
- [existing.displayName]); |
+ return new AnalysisError(source, duplicate.nameOffset, duplicate.nameLength, |
+ CompileTimeErrorCode.DUPLICATE_DEFINITION, [existing.displayName]); |
} |
/** |
@@ -11640,7 +12043,7 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<Object> { |
/** |
* The element for the library containing the compilation unit being visited. |
*/ |
- LibraryElement _definingLibrary; |
+ final LibraryElement definingLibrary; |
/** |
* The source representing the compilation unit being visited. |
@@ -11650,7 +12053,7 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<Object> { |
/** |
* The error listener that will be informed of any errors that are found during resolution. |
*/ |
- AnalysisErrorListener _errorListener; |
+ final AnalysisErrorListener errorListener; |
/** |
* The scope used to resolve identifiers. |
@@ -11694,10 +12097,9 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<Object> { |
* first be visited. If `null` or unspecified, a new [LibraryScope] will be |
* created based on [definingLibrary] and [typeProvider]. |
*/ |
- ScopedVisitor(LibraryElement definingLibrary, this.source, this.typeProvider, |
- AnalysisErrorListener errorListener, {Scope nameScope}) { |
- this._definingLibrary = definingLibrary; |
- this._errorListener = errorListener; |
+ ScopedVisitor( |
+ this.definingLibrary, this.source, this.typeProvider, this.errorListener, |
+ {Scope nameScope}) { |
if (nameScope == null) { |
this.nameScope = new LibraryScope(definingLibrary, errorListener); |
} else { |
@@ -11706,13 +12108,6 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<Object> { |
} |
/** |
- * Return the library element for the library containing the compilation unit being resolved. |
- * |
- * @return the library element for the library containing the compilation unit being resolved |
- */ |
- LibraryElement get definingLibrary => _definingLibrary; |
- |
- /** |
* Return the implicit label scope in which the current node is being |
* resolved. |
*/ |
@@ -11748,7 +12143,7 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<Object> { |
*/ |
void reportErrorForNode(ErrorCode errorCode, AstNode node, |
[List<Object> arguments]) { |
- _errorListener.onError(new AnalysisError( |
+ errorListener.onError(new AnalysisError( |
source, node.offset, node.length, errorCode, arguments)); |
} |
@@ -11762,7 +12157,7 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<Object> { |
*/ |
void reportErrorForOffset(ErrorCode errorCode, int offset, int length, |
[List<Object> arguments]) { |
- _errorListener.onError( |
+ errorListener.onError( |
new AnalysisError(source, offset, length, errorCode, arguments)); |
} |
@@ -11775,7 +12170,7 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<Object> { |
*/ |
void reportErrorForToken(ErrorCode errorCode, sc.Token token, |
[List<Object> arguments]) { |
- _errorListener.onError(new AnalysisError( |
+ errorListener.onError(new AnalysisError( |
source, token.offset, token.length, errorCode, arguments)); |
} |
@@ -11946,6 +12341,38 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<Object> { |
} |
@override |
+ Object visitEnumDeclaration(EnumDeclaration node) { |
+ ClassElement classElement = node.element; |
+ Scope outerScope = nameScope; |
+ try { |
+ if (classElement == null) { |
+ AnalysisEngine.instance.logger.logInformation( |
+ "Missing element for enum declaration ${node.name.name} in ${definingLibrary.source.fullName}", |
+ new CaughtException(new AnalysisException(), null)); |
+ super.visitEnumDeclaration(node); |
+ } else { |
+ ClassElement outerClass = enclosingClass; |
+ try { |
+ enclosingClass = node.element; |
+ nameScope = new ClassScope(nameScope, classElement); |
+ visitEnumMembersInScope(node); |
+ } finally { |
+ enclosingClass = outerClass; |
+ } |
+ } |
+ } finally { |
+ nameScope = outerScope; |
+ } |
+ return null; |
+ } |
+ |
+ void visitEnumMembersInScope(EnumDeclaration node) { |
+ safelyVisit(node.documentationComment); |
+ node.metadata.accept(this); |
+ node.constants.accept(this); |
+ } |
+ |
+ @override |
Object visitForEachStatement(ForEachStatement node) { |
Scope outerNameScope = nameScope; |
ImplicitLabelScope outerImplicitScope = _implicitLabelScope; |
@@ -12296,6 +12723,310 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<Object> { |
} |
/** |
+ * Implementation of [TypeSystem] using the strong mode rules. |
+ * https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md |
+ */ |
+class StrongTypeSystemImpl implements TypeSystem { |
+ final _specTypeSystem = new TypeSystemImpl(); |
+ |
+ StrongTypeSystemImpl(); |
+ |
+ @override |
+ DartType getLeastUpperBound( |
+ TypeProvider typeProvider, DartType type1, DartType type2) { |
+ // TODO(leafp): Implement a strong mode version of this. |
+ return _specTypeSystem.getLeastUpperBound(typeProvider, type1, type2); |
+ } |
+ |
+ // TODO(leafp): Document the rules in play here |
+ @override |
+ bool isAssignableTo(DartType fromType, DartType toType) { |
+ // An actual subtype |
+ if (isSubtypeOf(fromType, toType)) { |
+ return true; |
+ } |
+ |
+ // Don't allow implicit downcasts between function types |
+ // and call method objects, as these will almost always fail. |
+ if ((fromType is FunctionType && _getCallMethodType(toType) != null) || |
+ (toType is FunctionType && _getCallMethodType(fromType) != null)) { |
+ return false; |
+ } |
+ |
+ // If the subtype relation goes the other way, allow the implicit downcast. |
+ // TODO(leafp): Emit warnings and hints for these in some way. |
+ // TODO(leafp): Consider adding a flag to disable these? Or just rely on |
+ // --warnings-as-errors? |
+ if (isSubtypeOf(toType, fromType) || |
+ _specTypeSystem.isAssignableTo(toType, fromType)) { |
+ // TODO(leafp): error if type is known to be exact (literal, |
+ // instance creation). |
+ // TODO(leafp): Warn on composite downcast. |
+ // TODO(leafp): hint on object/dynamic downcast. |
+ // TODO(leafp): Consider allowing assignment casts. |
+ return true; |
+ } |
+ |
+ return false; |
+ } |
+ |
+ @override |
+ bool isSubtypeOf(DartType leftType, DartType rightType) { |
+ return _isSubtypeOf(leftType, rightType, null); |
+ } |
+ |
+ FunctionType _getCallMethodType(DartType t) { |
+ if (t is InterfaceType) { |
+ ClassElement element = t.element; |
+ InheritanceManager manager = new InheritanceManager(element.library); |
+ FunctionType callType = manager.lookupMemberType(t, "call"); |
+ return callType; |
+ } |
+ return null; |
+ } |
+ |
+ // Given a type t, if t is an interface type with a call method |
+ // defined, return the function type for the call method, otherwise |
+ // return null. |
+ _GuardedSubtypeChecker<DartType> _guard( |
+ _GuardedSubtypeChecker<DartType> check) { |
+ return (DartType t1, DartType t2, Set<Element> visited) { |
+ Element element = t1.element; |
+ if (visited == null) { |
+ visited = new HashSet<Element>(); |
+ } |
+ if (element == null || !visited.add(element)) { |
+ return false; |
+ } |
+ try { |
+ return check(t1, t2, visited); |
+ } finally { |
+ visited.remove(element); |
+ } |
+ }; |
+ } |
+ |
+ bool _isBottom(DartType t, {bool dynamicIsBottom: false}) { |
+ return (t.isDynamic && dynamicIsBottom) || t.isBottom; |
+ } |
+ |
+ // Guard against loops in the class hierarchy |
+ /** |
+ * Check that [f1] is a subtype of [f2]. |
+ * [fuzzyArrows] indicates whether or not the f1 and f2 should be |
+ * treated as fuzzy arrow types (and hence dynamic parameters to f2 treated |
+ * as bottom). |
+ */ |
+ bool _isFunctionSubtypeOf(FunctionType f1, FunctionType f2, |
+ {bool fuzzyArrows: true}) { |
+ final r1s = f1.normalParameterTypes; |
+ final o1s = f1.optionalParameterTypes; |
+ final n1s = f1.namedParameterTypes; |
+ final r2s = f2.normalParameterTypes; |
+ final o2s = f2.optionalParameterTypes; |
+ final n2s = f2.namedParameterTypes; |
+ final ret1 = f1.returnType; |
+ final ret2 = f2.returnType; |
+ |
+ // A -> B <: C -> D if C <: A and |
+ // either D is void or B <: D |
+ if (!ret2.isVoid && !isSubtypeOf(ret1, ret2)) { |
+ return false; |
+ } |
+ |
+ // Reject if one has named and the other has optional |
+ if (n1s.length > 0 && o2s.length > 0) { |
+ return false; |
+ } |
+ if (n2s.length > 0 && o1s.length > 0) { |
+ return false; |
+ } |
+ |
+ // Rebind _isSubtypeOf for convenience |
+ _SubtypeChecker<DartType> parameterSubtype = (DartType t1, DartType t2) => |
+ _isSubtypeOf(t1, t2, null, dynamicIsBottom: fuzzyArrows); |
+ |
+ // f2 has named parameters |
+ if (n2s.length > 0) { |
+ // Check that every named parameter in f2 has a match in f1 |
+ for (String k2 in n2s.keys) { |
+ if (!n1s.containsKey(k2)) { |
+ return false; |
+ } |
+ if (!parameterSubtype(n2s[k2], n1s[k2])) { |
+ return false; |
+ } |
+ } |
+ } |
+ // If we get here, we either have no named parameters, |
+ // or else the named parameters match and we have no optional |
+ // parameters |
+ |
+ // If f1 has more required parameters, reject |
+ if (r1s.length > r2s.length) { |
+ return false; |
+ } |
+ |
+ // If f2 has more required + optional parameters, reject |
+ if (r2s.length + o2s.length > r1s.length + o1s.length) { |
+ return false; |
+ } |
+ |
+ // The parameter lists must look like the following at this point |
+ // where rrr is a region of required, and ooo is a region of optionals. |
+ // f1: rrr ooo ooo ooo |
+ // f2: rrr rrr ooo |
+ int rr = r1s.length; // required in both |
+ int or = r2s.length - r1s.length; // optional in f1, required in f2 |
+ int oo = o2s.length; // optional in both |
+ |
+ for (int i = 0; i < rr; ++i) { |
+ if (!parameterSubtype(r2s[i], r1s[i])) { |
+ return false; |
+ } |
+ } |
+ for (int i = 0, j = rr; i < or; ++i, ++j) { |
+ if (!parameterSubtype(r2s[j], o1s[i])) { |
+ return false; |
+ } |
+ } |
+ for (int i = or, j = 0; i < oo; ++i, ++j) { |
+ if (!parameterSubtype(o2s[j], o1s[i])) { |
+ return false; |
+ } |
+ } |
+ return true; |
+ } |
+ |
+ bool _isInterfaceSubtypeOf( |
+ InterfaceType i1, InterfaceType i2, Set<Element> visited) { |
+ // Guard recursive calls |
+ _GuardedSubtypeChecker<InterfaceType> guardedInterfaceSubtype = |
+ _guard(_isInterfaceSubtypeOf); |
+ |
+ if (i1 == i2) { |
+ return true; |
+ } |
+ |
+ if (i1.element == i2.element) { |
+ List<DartType> tArgs1 = i1.typeArguments; |
+ List<DartType> tArgs2 = i2.typeArguments; |
+ |
+ assert(tArgs1.length == tArgs2.length); |
+ |
+ for (int i = 0; i < tArgs1.length; i++) { |
+ DartType t1 = tArgs1[i]; |
+ DartType t2 = tArgs2[i]; |
+ if (!isSubtypeOf(t1, t2)) { |
+ return false; |
+ } |
+ } |
+ return true; |
+ } |
+ |
+ if (i2.isDartCoreFunction && i1.element.getMethod("call") != null) { |
+ return true; |
+ } |
+ |
+ if (i1.isObject) { |
+ return false; |
+ } |
+ |
+ if (guardedInterfaceSubtype(i1.superclass, i2, visited)) { |
+ return true; |
+ } |
+ |
+ for (final parent in i1.interfaces) { |
+ if (guardedInterfaceSubtype(parent, i2, visited)) { |
+ return true; |
+ } |
+ } |
+ |
+ for (final parent in i1.mixins) { |
+ if (guardedInterfaceSubtype(parent, i2, visited)) { |
+ return true; |
+ } |
+ } |
+ |
+ return false; |
+ } |
+ |
+ bool _isSubtypeOf(DartType t1, DartType t2, Set<Element> visited, |
+ {bool dynamicIsBottom: false}) { |
+ // Guard recursive calls |
+ _GuardedSubtypeChecker<DartType> guardedSubtype = _guard(_isSubtypeOf); |
+ |
+ if (t1 == t2) { |
+ return true; |
+ } |
+ |
+ // The types are void, dynamic, bottom, interface types, function types |
+ // and type parameters. We proceed by eliminating these different classes |
+ // from consideration. |
+ |
+ // Trivially true. |
+ if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) || |
+ _isBottom(t1, dynamicIsBottom: dynamicIsBottom)) { |
+ return true; |
+ } |
+ |
+ // Trivially false. |
+ if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) || |
+ _isBottom(t2, dynamicIsBottom: dynamicIsBottom)) { |
+ return false; |
+ } |
+ |
+ // S <: T where S is a type variable |
+ // T is not dynamic or object (handled above) |
+ // S != T (handled above) |
+ // So only true if bound of S is S' and |
+ // S' <: T |
+ if (t1 is TypeParameterType) { |
+ DartType bound = t1.element.bound; |
+ if (bound == null) return false; |
+ return guardedSubtype(bound, t2, visited); |
+ } |
+ |
+ if (t2 is TypeParameterType) { |
+ return false; |
+ } |
+ |
+ if (t1.isVoid || t2.isVoid) { |
+ return false; |
+ } |
+ |
+ // We've eliminated void, dynamic, bottom, and type parameters. The only |
+ // cases are the combinations of interface type and function type. |
+ |
+ // A function type can only subtype an interface type if |
+ // the interface type is Function |
+ if (t1 is FunctionType && t2 is InterfaceType) { |
+ return t2.isDartCoreFunction; |
+ } |
+ |
+ // An interface type can only subtype a function type if |
+ // the interface type declares a call method with a type |
+ // which is a super type of the function type. |
+ if (t1 is InterfaceType && t2 is FunctionType) { |
+ var callType = _getCallMethodType(t1); |
+ return (callType != null) && _isFunctionSubtypeOf(callType, t2); |
+ } |
+ |
+ // Two interface types |
+ if (t1 is InterfaceType && t2 is InterfaceType) { |
+ return _isInterfaceSubtypeOf(t1, t2, visited); |
+ } |
+ |
+ return _isFunctionSubtypeOf(t1 as FunctionType, t2 as FunctionType); |
+ } |
+ |
+ // TODO(leafp): Document the rules in play here |
+ bool _isTop(DartType t, {bool dynamicIsBottom: false}) { |
+ return (t.isDynamic && !dynamicIsBottom) || t.isObject; |
+ } |
+} |
+ |
+/** |
* Instances of this class manage the knowledge of what the set of subtypes are for a given type. |
*/ |
class SubtypeManager { |
@@ -13243,13 +13974,13 @@ class TypeProviderImpl implements TypeProvider { |
@override |
List<InterfaceType> get nonSubtypableTypes => <InterfaceType>[ |
- nullType, |
- numType, |
- intType, |
- doubleType, |
- boolType, |
- stringType |
- ]; |
+ nullType, |
+ numType, |
+ intType, |
+ doubleType, |
+ boolType, |
+ stringType |
+ ]; |
@override |
DartObjectImpl get nullObject { |
@@ -13380,7 +14111,7 @@ class TypeResolverVisitor extends ScopedVisitor { |
TypeProvider typeProvider, AnalysisErrorListener errorListener, |
{Scope nameScope}) |
: super(definingLibrary, source, typeProvider, errorListener, |
- nameScope: nameScope) { |
+ nameScope: nameScope) { |
_dynamicType = typeProvider.dynamicType; |
_undefinedType = typeProvider.undefinedType; |
} |
@@ -13585,6 +14316,7 @@ class TypeResolverVisitor extends ScopedVisitor { |
DartType type; |
TypeName typeName = node.type; |
if (typeName == null) { |
+ element.hasImplicitType = true; |
type = _dynamicType; |
if (parameter is FieldFormalParameterElement) { |
FieldElement fieldElement = |
@@ -13776,13 +14508,15 @@ class TypeResolverVisitor extends ScopedVisitor { |
(parent.parent as InstanceCreationExpression).isConst) { |
// If, if this is a const expression, then generate a |
// CompileTimeErrorCode.CONST_WITH_NON_TYPE error. |
- reportErrorForNode(CompileTimeErrorCode.CONST_WITH_NON_TYPE, |
+ reportErrorForNode( |
+ CompileTimeErrorCode.CONST_WITH_NON_TYPE, |
prefixedIdentifier.identifier, |
[prefixedIdentifier.identifier.name]); |
} else { |
// Else, if this expression is a new expression, report a |
// NEW_WITH_NON_TYPE warning. |
- reportErrorForNode(StaticWarningCode.NEW_WITH_NON_TYPE, |
+ reportErrorForNode( |
+ StaticWarningCode.NEW_WITH_NON_TYPE, |
prefixedIdentifier.identifier, |
[prefixedIdentifier.identifier.name]); |
} |
@@ -13960,11 +14694,8 @@ class TypeResolverVisitor extends ScopedVisitor { |
typeArguments[i] = argumentType; |
} |
} else { |
- reportErrorForNode(_getInvalidTypeParametersErrorCode(node), node, [ |
- typeName.name, |
- parameterCount, |
- argumentCount |
- ]); |
+ reportErrorForNode(_getInvalidTypeParametersErrorCode(node), node, |
+ [typeName.name, parameterCount, argumentCount]); |
for (int i = 0; i < parameterCount; i++) { |
typeArguments[i] = _dynamicType; |
} |
@@ -14328,7 +15059,8 @@ class TypeResolverVisitor extends ScopedVisitor { |
void _resolve(ClassElementImpl classElement, WithClause withClause, |
ImplementsClause implementsClause) { |
if (withClause != null) { |
- List<InterfaceType> mixinTypes = _resolveTypes(withClause.mixinTypes, |
+ List<InterfaceType> mixinTypes = _resolveTypes( |
+ withClause.mixinTypes, |
CompileTimeErrorCode.MIXIN_OF_NON_CLASS, |
CompileTimeErrorCode.MIXIN_OF_ENUM, |
CompileTimeErrorCode.MIXIN_OF_NON_CLASS); |
@@ -14340,7 +15072,8 @@ class TypeResolverVisitor extends ScopedVisitor { |
} |
if (implementsClause != null) { |
NodeList<TypeName> interfaces = implementsClause.interfaces; |
- List<InterfaceType> interfaceTypes = _resolveTypes(interfaces, |
+ List<InterfaceType> interfaceTypes = _resolveTypes( |
+ interfaces, |
CompileTimeErrorCode.IMPLEMENTS_NON_CLASS, |
CompileTimeErrorCode.IMPLEMENTS_ENUM, |
CompileTimeErrorCode.IMPLEMENTS_DYNAMIC); |
@@ -14415,8 +15148,10 @@ class TypeResolverVisitor extends ScopedVisitor { |
* @param dynamicTypeError the error to produce if the type name is "dynamic" |
* @return an array containing all of the types that were resolved. |
*/ |
- List<InterfaceType> _resolveTypes(NodeList<TypeName> typeNames, |
- ErrorCode nonTypeError, ErrorCode enumTypeError, |
+ List<InterfaceType> _resolveTypes( |
+ NodeList<TypeName> typeNames, |
+ ErrorCode nonTypeError, |
+ ErrorCode enumTypeError, |
ErrorCode dynamicTypeError) { |
List<InterfaceType> types = new List<InterfaceType>(); |
for (TypeName typeName in typeNames) { |
@@ -14525,27 +15260,42 @@ class TypeResolverVisitor extends ScopedVisitor { |
*/ |
abstract class TypeSystem { |
/** |
- * Return the [TypeProvider] associated with this [TypeSystem]. |
+ * Compute the least upper bound of two types. |
*/ |
- TypeProvider get typeProvider; |
+ DartType getLeastUpperBound( |
+ TypeProvider typeProvider, DartType type1, DartType type2); |
/** |
- * Compute the least upper bound of two types. |
+ * Return `true` if the [leftType] is assignable to the [rightType] (that is, |
+ * if leftType <==> rightType). |
+ */ |
+ bool isAssignableTo(DartType leftType, DartType rightType); |
+ |
+ /** |
+ * Return `true` if the [leftType] is a subtype of the [rightType] (that is, |
+ * if leftType <: rightType). |
+ */ |
+ bool isSubtypeOf(DartType leftType, DartType rightType); |
+ |
+ /** |
+ * Create either a strong mode or regular type system based on context. |
*/ |
- DartType getLeastUpperBound(DartType type1, DartType type2); |
+ static TypeSystem create(AnalysisContext context) { |
+ return (context.analysisOptions.strongMode) |
+ ? new StrongTypeSystemImpl() |
+ : new TypeSystemImpl(); |
+ } |
} |
/** |
* Implementation of [TypeSystem] using the rules in the Dart specification. |
*/ |
class TypeSystemImpl implements TypeSystem { |
- @override |
- final TypeProvider typeProvider; |
- |
- TypeSystemImpl(this.typeProvider); |
+ TypeSystemImpl(); |
@override |
- DartType getLeastUpperBound(DartType type1, DartType type2) { |
+ DartType getLeastUpperBound( |
+ TypeProvider typeProvider, DartType type1, DartType type2) { |
// The least upper bound relation is reflexive. |
if (identical(type1, type2)) { |
return type1; |
@@ -14622,6 +15372,16 @@ class TypeSystemImpl implements TypeSystem { |
return typeProvider.dynamicType; |
} |
} |
+ |
+ @override |
+ bool isAssignableTo(DartType leftType, DartType rightType) { |
+ return leftType.isAssignableTo(rightType); |
+ } |
+ |
+ @override |
+ bool isSubtypeOf(DartType leftType, DartType rightType) { |
+ return leftType.isSubtypeOf(rightType); |
+ } |
} |
/** |
@@ -14648,10 +15408,8 @@ class UnusedLocalElementsVerifier extends RecursiveElementVisitor { |
@override |
visitClassElement(ClassElement element) { |
if (!_isUsedElement(element)) { |
- _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [ |
- element.kind.displayName, |
- element.displayName |
- ]); |
+ _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, |
+ [element.kind.displayName, element.displayName]); |
} |
super.visitClassElement(element); |
} |
@@ -14668,10 +15426,8 @@ class UnusedLocalElementsVerifier extends RecursiveElementVisitor { |
@override |
visitFunctionElement(FunctionElement element) { |
if (!_isUsedElement(element)) { |
- _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [ |
- element.kind.displayName, |
- element.displayName |
- ]); |
+ _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, |
+ [element.kind.displayName, element.displayName]); |
} |
super.visitFunctionElement(element); |
} |
@@ -14679,10 +15435,8 @@ class UnusedLocalElementsVerifier extends RecursiveElementVisitor { |
@override |
visitFunctionTypeAliasElement(FunctionTypeAliasElement element) { |
if (!_isUsedElement(element)) { |
- _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [ |
- element.kind.displayName, |
- element.displayName |
- ]); |
+ _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, |
+ [element.kind.displayName, element.displayName]); |
} |
super.visitFunctionTypeAliasElement(element); |
} |
@@ -14705,10 +15459,8 @@ class UnusedLocalElementsVerifier extends RecursiveElementVisitor { |
@override |
visitMethodElement(MethodElement element) { |
if (!_isUsedMember(element)) { |
- _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [ |
- element.kind.displayName, |
- element.displayName |
- ]); |
+ _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, |
+ [element.kind.displayName, element.displayName]); |
} |
super.visitMethodElement(element); |
} |
@@ -14716,10 +15468,8 @@ class UnusedLocalElementsVerifier extends RecursiveElementVisitor { |
@override |
visitPropertyAccessorElement(PropertyAccessorElement element) { |
if (!_isUsedMember(element)) { |
- _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [ |
- element.kind.displayName, |
- element.displayName |
- ]); |
+ _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, |
+ [element.kind.displayName, element.displayName]); |
} |
super.visitPropertyAccessorElement(element); |
} |
@@ -14780,8 +15530,7 @@ class UnusedLocalElementsVerifier extends RecursiveElementVisitor { |
ErrorCode errorCode, Element element, List<Object> arguments) { |
if (element != null) { |
_errorListener.onError(new AnalysisError(element.source, |
- element.nameOffset, element.displayName.length, errorCode, |
- arguments)); |
+ element.nameOffset, element.nameLength, errorCode, arguments)); |
} |
} |
} |
@@ -14908,7 +15657,7 @@ class VariableResolverVisitor extends ScopedVisitor { |
TypeProvider typeProvider, AnalysisErrorListener errorListener, |
{Scope nameScope}) |
: super(definingLibrary, source, typeProvider, errorListener, |
- nameScope: nameScope); |
+ nameScope: nameScope); |
/** |
* Initialize a newly created visitor to resolve the nodes in a compilation unit. |
@@ -14923,8 +15672,8 @@ class VariableResolverVisitor extends ScopedVisitor { |
VariableResolverVisitor.con1( |
Library library, Source source, TypeProvider typeProvider) |
: this( |
- library.libraryElement, source, typeProvider, library.errorListener, |
- nameScope: library.libraryScope); |
+ library.libraryElement, source, typeProvider, library.errorListener, |
+ nameScope: library.libraryScope); |
@override |
Object visitExportDirective(ExportDirective node) => null; |
@@ -15033,11 +15782,20 @@ class _ConstantVerifier_validateInitializerExpression extends ConstantVisitor { |
List<ParameterElement> parameterElements; |
- _ConstantVerifier_validateInitializerExpression(TypeProvider typeProvider, |
- ErrorReporter errorReporter, this.verifier, this.parameterElements, |
- DeclaredVariables declaredVariables) |
- : super(new ConstantEvaluationEngine(typeProvider, declaredVariables), |
- errorReporter); |
+ TypeSystem _typeSystem; |
+ |
+ _ConstantVerifier_validateInitializerExpression( |
+ TypeProvider typeProvider, |
+ ErrorReporter errorReporter, |
+ this.verifier, |
+ this.parameterElements, |
+ DeclaredVariables declaredVariables, |
+ {TypeSystem typeSystem}) |
+ : _typeSystem = (typeSystem != null) ? typeSystem : new TypeSystemImpl(), |
+ super( |
+ new ConstantEvaluationEngine(typeProvider, declaredVariables, |
+ typeSystem: typeSystem), |
+ errorReporter); |
@override |
DartObjectImpl visitSimpleIdentifier(SimpleIdentifier node) { |
@@ -15049,19 +15807,20 @@ class _ConstantVerifier_validateInitializerExpression extends ConstantVisitor { |
if (type.isDynamic) { |
return new DartObjectImpl( |
verifier._typeProvider.objectType, DynamicState.DYNAMIC_STATE); |
- } else if (type.isSubtypeOf(verifier._boolType)) { |
+ } else if (_typeSystem.isSubtypeOf(type, verifier._boolType)) { |
return new DartObjectImpl( |
verifier._typeProvider.boolType, BoolState.UNKNOWN_VALUE); |
- } else if (type.isSubtypeOf(verifier._typeProvider.doubleType)) { |
+ } else if (_typeSystem.isSubtypeOf( |
+ type, verifier._typeProvider.doubleType)) { |
return new DartObjectImpl( |
verifier._typeProvider.doubleType, DoubleState.UNKNOWN_VALUE); |
- } else if (type.isSubtypeOf(verifier._intType)) { |
+ } else if (_typeSystem.isSubtypeOf(type, verifier._intType)) { |
return new DartObjectImpl( |
verifier._typeProvider.intType, IntState.UNKNOWN_VALUE); |
- } else if (type.isSubtypeOf(verifier._numType)) { |
+ } else if (_typeSystem.isSubtypeOf(type, verifier._numType)) { |
return new DartObjectImpl( |
verifier._typeProvider.numType, NumState.UNKNOWN_VALUE); |
- } else if (type.isSubtypeOf(verifier._stringType)) { |
+ } else if (_typeSystem.isSubtypeOf(type, verifier._stringType)) { |
return new DartObjectImpl( |
verifier._typeProvider.stringType, StringState.UNKNOWN_VALUE); |
} |