| 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);
|
| }
|
|
|