Compute mixin application constructors in the ClassElement.constructors getter.

Previously we computed them during resolution, but this created a
problem: since the set of constructors for a mixin application depends
on the constructors in the superclass, and the superclass might itself
be a mixin application, it might theoretically be necessary to analyze
all files in the transitive import/export closure before it is
possible to compute the set of constructors for a class.  As a result,
in order to produce completion results after a non-incremental change
to file X, we have to re-analyze the entire transitive closure of
files importing or exporting X.  This takes prohibitively long.

This change moves the computation into the ClassElement.constructors
getter.  The computation is not cached, so now a change to file X only
requires rebuilding the element models for files directly importing X
(or directly importing files that contain X in their transitive export
closure).

Since the result of the computation is not cached, this will produce
an increase in analysis time, however since mixin applications are
used so rarely, the performance impact should be negligible.

Fixes #23732.

R=scheglov@google.com

Review URL: https://codereview.chromium.org//1215053003.
This commit is contained in:
Paul Berry
2015-06-30 07:35:26 -07:00
parent ede6cb71a5
commit 7671bce82a
14 changed files with 227 additions and 883 deletions
@@ -1094,7 +1094,6 @@ class AnalysisContextImpl implements InternalAnalysisContext {
setValue(LIBRARY_ELEMENT3, library);
setValue(LIBRARY_ELEMENT4, library);
setValue(LIBRARY_ELEMENT5, library);
setValue(LIBRARY_ELEMENT6, library);
setValue(LINE_INFO, new LineInfo(<int>[0]));
setValue(PARSE_ERRORS, AnalysisError.NO_ERRORS);
entry.setState(PARSED_UNIT, CacheState.FLUSHED);
+168 -27
View File
@@ -501,9 +501,15 @@ class ClassElementImpl extends ElementImpl implements ClassElement {
List<PropertyAccessorElement> _accessors = PropertyAccessorElement.EMPTY_LIST;
/**
* A list containing all of the constructors contained in this class.
* For classes which are not mixin applications, a list containing all of the
* constructors contained in this class, or `null` if the list of
* constructors has not yet been built.
*
* For classes which are mixin applications, the list of constructors is
* computed on the fly by the [constructors] getter, and this field is
* `null`.
*/
List<ConstructorElement> _constructors = ConstructorElement.EMPTY_LIST;
List<ConstructorElement> _constructors;
/**
* A list containing all of the fields contained in this class.
@@ -586,18 +592,74 @@ class ClassElementImpl extends ElementImpl implements ClassElement {
}
@override
List<ConstructorElement> get constructors => _constructors;
List<ConstructorElement> get constructors {
if (!isMixinApplication) {
assert(_constructors != null);
return _constructors == null
? ConstructorElement.EMPTY_LIST
: _constructors;
}
return _computeMixinAppConstructors();
}
/**
* Set the constructors contained in this class to the given [constructors].
*
* Should only be used for class elements that are not mixin applications.
*/
void set constructors(List<ConstructorElement> constructors) {
assert(!isMixinApplication);
for (ConstructorElement constructor in constructors) {
(constructor as ConstructorElementImpl).enclosingElement = this;
}
this._constructors = constructors;
}
/**
* Return `true` if [CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS] should
* be reported for this class.
*/
bool get doesMixinLackConstructors {
if (!isMixinApplication && mixins.isEmpty) {
// This class is not a mixin application and it doesn't have a "with"
// clause, so CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS is
// inapplicable.
return false;
}
if (supertype == null) {
// Should never happen, since Object is the only class that has no
// supertype, and it should have been caught by the test above.
assert(false);
return false;
}
// Find the nearest class in the supertype chain that is not a mixin
// application.
ClassElement nearestNonMixinClass = supertype.element;
if (nearestNonMixinClass.isMixinApplication) {
// Use a list to keep track of the classes we've seen, so that we won't
// go into an infinite loop in the event of a non-trivial loop in the
// class hierarchy.
List<ClassElementImpl> classesSeen = <ClassElementImpl>[this];
while (nearestNonMixinClass.isMixinApplication) {
if (classesSeen.contains(nearestNonMixinClass)) {
// Loop in the class hierarchy (which is reported elsewhere). Don't
// confuse the user with further errors.
return false;
}
classesSeen.add(nearestNonMixinClass);
if (nearestNonMixinClass.supertype == null) {
// Should never happen, since Object is the only class that has no
// supertype, and it is not a mixin application.
assert(false);
return false;
}
nearestNonMixinClass = nearestNonMixinClass.supertype.element;
}
}
return !nearestNonMixinClass.constructors.any(isSuperConstructorAccessible);
}
/**
* Set whether this class is defined by an enum declaration.
*/
@@ -732,16 +794,6 @@ class ClassElementImpl extends ElementImpl implements ClassElement {
setModifier(Modifier.MIXIN_APPLICATION, isMixinApplication);
}
bool get mixinErrorsReported => hasModifier(Modifier.MIXIN_ERRORS_REPORTED);
/**
* Set whether an error has reported explaining why this class is an
* invalid mixin application.
*/
void set mixinErrorsReported(bool value) {
setModifier(Modifier.MIXIN_ERRORS_REPORTED, value);
}
@override
List<TypeParameterElement> get typeParameters => _typeParameters;
@@ -996,6 +1048,103 @@ class ClassElementImpl extends ElementImpl implements ClassElement {
}
}
/**
* Compute a list of constructors for this class, which is a mixin
* application. If specified, [visitedClasses] is a list of the other mixin
* application classes which have been visited on the way to reaching this
* one (this is used to detect circularities).
*/
List<ConstructorElement> _computeMixinAppConstructors(
[List<ClassElementImpl> visitedClasses = null]) {
// First get the list of constructors of the superclass which need to be
// forwarded to this class.
Iterable<ConstructorElement> constructorsToForward;
if (supertype == null) {
// Shouldn't ever happen, since the only class with no supertype is
// Object, and it isn't a mixin application. But for safety's sake just
// assume an empty list.
assert(false);
constructorsToForward = <ConstructorElement>[];
} else if (!supertype.element.isMixinApplication) {
List<ConstructorElement> superclassConstructors =
supertype.element.constructors;
// Filter out any constructors with optional parameters (see
// dartbug.com/15101).
constructorsToForward =
superclassConstructors.where(isSuperConstructorAccessible);
} else {
if (visitedClasses == null) {
visitedClasses = <ClassElementImpl>[this];
} else {
if (visitedClasses.contains(this)) {
// Loop in the class hierarchy. Don't try to forward any
// constructors.
return <ConstructorElement>[];
}
visitedClasses.add(this);
}
try {
ClassElementImpl superclass = supertype.element;
constructorsToForward =
superclass._computeMixinAppConstructors(visitedClasses);
} finally {
visitedClasses.removeLast();
}
}
// Figure out the type parameter substitution we need to perform in order
// to produce constructors for this class. We want to be robust in the
// face of errors, so drop any extra type arguments and fill in any missing
// ones with `dynamic`.
List<DartType> parameterTypes =
TypeParameterTypeImpl.getTypes(supertype.typeParameters);
List<DartType> argumentTypes = new List<DartType>.filled(
parameterTypes.length, DynamicTypeImpl.instance);
for (int i = 0; i < supertype.typeArguments.length; i++) {
if (i >= argumentTypes.length) {
break;
}
argumentTypes[i] = supertype.typeArguments[i];
}
// Now create an implicit constructor for every constructor found above,
// substituting type parameters as appropriate.
return constructorsToForward
.map((ConstructorElement superclassConstructor) {
ConstructorElementImpl implicitConstructor =
new ConstructorElementImpl(superclassConstructor.name, -1);
implicitConstructor.synthetic = true;
implicitConstructor.redirectedConstructor = superclassConstructor;
implicitConstructor.const2 = superclassConstructor.isConst;
implicitConstructor.returnType = type;
List<ParameterElement> superParameters = superclassConstructor.parameters;
int count = superParameters.length;
if (count > 0) {
List<ParameterElement> implicitParameters =
new List<ParameterElement>(count);
for (int i = 0; i < count; i++) {
ParameterElement superParameter = superParameters[i];
ParameterElementImpl implicitParameter =
new ParameterElementImpl(superParameter.name, -1);
implicitParameter.const3 = superParameter.isConst;
implicitParameter.final2 = superParameter.isFinal;
implicitParameter.parameterKind = superParameter.parameterKind;
implicitParameter.synthetic = true;
implicitParameter.type =
superParameter.type.substitute2(argumentTypes, parameterTypes);
implicitParameters[i] = implicitParameter;
}
implicitConstructor.parameters = implicitParameters;
}
FunctionTypeImpl constructorType =
new FunctionTypeImpl(implicitConstructor);
constructorType.typeArguments = type.typeArguments;
implicitConstructor.type = constructorType;
implicitConstructor.enclosingElement = this;
return implicitConstructor;
}).toList();
}
PropertyAccessorElement _internalLookUpConcreteGetter(
String getterName, LibraryElement library, bool includeThisClass) {
PropertyAccessorElement getter =
@@ -8072,42 +8221,35 @@ class Modifier extends Enum<Modifier> {
static const Modifier MIXIN_APPLICATION =
const Modifier('MIXIN_APPLICATION', 12);
/**
* Indicates that an error has reported explaining why this class is an
* invalid mixin application.
*/
static const Modifier MIXIN_ERRORS_REPORTED =
const Modifier('MIXIN_ERRORS_REPORTED', 13);
/**
* Indicates that the value of a parameter or local variable might be mutated
* within the context.
*/
static const Modifier POTENTIALLY_MUTATED_IN_CONTEXT =
const Modifier('POTENTIALLY_MUTATED_IN_CONTEXT', 14);
const Modifier('POTENTIALLY_MUTATED_IN_CONTEXT', 13);
/**
* Indicates that the value of a parameter or local variable might be mutated
* within the scope.
*/
static const Modifier POTENTIALLY_MUTATED_IN_SCOPE =
const Modifier('POTENTIALLY_MUTATED_IN_SCOPE', 15);
const Modifier('POTENTIALLY_MUTATED_IN_SCOPE', 14);
/**
* Indicates that a class contains an explicit reference to 'super'.
*/
static const Modifier REFERENCES_SUPER =
const Modifier('REFERENCES_SUPER', 16);
const Modifier('REFERENCES_SUPER', 15);
/**
* Indicates that the pseudo-modifier 'set' was applied to the element.
*/
static const Modifier SETTER = const Modifier('SETTER', 17);
static const Modifier SETTER = const Modifier('SETTER', 16);
/**
* Indicates that the modifier 'static' was applied to the element.
*/
static const Modifier STATIC = const Modifier('STATIC', 18);
static const Modifier STATIC = const Modifier('STATIC', 17);
/**
* Indicates that the element does not appear in the source code but was
@@ -8115,7 +8257,7 @@ class Modifier extends Enum<Modifier> {
* constructors, an implicit zero-argument constructor will be created and it
* will be marked as being synthetic.
*/
static const Modifier SYNTHETIC = const Modifier('SYNTHETIC', 19);
static const Modifier SYNTHETIC = const Modifier('SYNTHETIC', 18);
static const List<Modifier> values = const [
ABSTRACT,
@@ -8131,7 +8273,6 @@ class Modifier extends Enum<Modifier> {
HAS_EXT_URI,
MIXIN,
MIXIN_APPLICATION,
MIXIN_ERRORS_REPORTED,
POTENTIALLY_MUTATED_IN_CONTEXT,
POTENTIALLY_MUTATED_IN_SCOPE,
REFERENCES_SUPER,
@@ -1049,7 +1049,7 @@ class ElementResolver extends SimpleAstVisitor<Object> {
ConstructorElement element =
superType.lookUpConstructor(superName, _definingLibrary);
if (element == null ||
(!enclosingClass.mixinErrorsReported &&
(!enclosingClass.doesMixinLackConstructors &&
!enclosingClass.isSuperConstructorAccessible(element))) {
if (name != null) {
_resolver.reportErrorForNode(
@@ -422,6 +422,7 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
_checkForConflictingInstanceGetterAndSuperclassMember();
_checkImplementsSuperClass(node);
_checkImplementsFunctionWithoutCall(node);
_checkForMixinHasNoConstructors(node);
}
}
visitClassDeclarationIncrementally(node);
@@ -474,6 +475,7 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
_checkForImplementsDeferredClass(implementsClause);
_checkForRecursiveInterfaceInheritance(_enclosingClass);
_checkForNonAbstractClassInheritsAbstractMember(node.name);
_checkForMixinHasNoConstructors(node);
}
} finally {
_enclosingClass = outerClassElement;
@@ -4164,6 +4166,18 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
return false;
}
/**
* Report the error [CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS] if
* appropriate.
*/
void _checkForMixinHasNoConstructors(AstNode node) {
if ((_enclosingClass as ClassElementImpl).doesMixinLackConstructors) {
ErrorCode errorCode = CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS;
_errorReporter.reportErrorForNode(
errorCode, node, [_enclosingClass.supertype]);
}
}
/**
* Verify that the given mixin has the 'Object' superclass. The [mixinName] is
* the node to report problem on. The [mixinElement] is the mixing to
@@ -4290,7 +4304,7 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
ClassDeclaration declaration) {
// do nothing if mixin errors have already been reported for this class.
ClassElementImpl enclosingClass = _enclosingClass;
if (enclosingClass.mixinErrorsReported) {
if (enclosingClass.doesMixinLackConstructors) {
return false;
}
// do nothing if there is explicit constructor
@@ -5183,7 +5197,7 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
}
// do nothing if mixin errors have already been reported for this class.
ClassElementImpl enclosingClass = _enclosingClass;
if (enclosingClass.mixinErrorsReported) {
if (enclosingClass.doesMixinLackConstructors) {
return false;
}
//
@@ -184,7 +184,6 @@ class DeclarationMatcher extends RecursiveAstVisitor {
_enclosingClass = element;
_processElement(element);
_assertSameTypeParameters(node.typeParameters, element.typeParameters);
_processElement(element.unnamedConstructor);
super.visitClassTypeAlias(node);
}
+5 -307
View File
@@ -5,9 +5,6 @@
library engine.resolver;
import 'dart:collection';
import "dart:math" as math;
import 'package:analyzer/src/generated/utilities_collection.dart';
import 'ast.dart';
import 'constant.dart';
@@ -2506,7 +2503,6 @@ class ElementBuilder extends RecursiveAstVisitor<Object> {
interfaceType.typeArguments = typeArguments;
element.type = interfaceType;
// set default constructor
element.constructors = _createDefaultConstructors(interfaceType);
for (FunctionTypeImpl functionType in _functionTypesToFix) {
functionType.typeArguments = typeArguments;
}
@@ -2631,6 +2627,11 @@ class ElementBuilder extends RecursiveAstVisitor<Object> {
enumElement.enum2 = true;
InterfaceTypeImpl enumType = new InterfaceTypeImpl(enumElement);
enumElement.type = enumType;
// The equivalent code for enums in the spec shows a single constructor,
// but that constructor is not callable (since it is a compile-time error
// to subclass, mix-in, implement, or explicitly instantiate an enum). So
// we represent this as having no constructors.
enumElement.constructors = ConstructorElement.EMPTY_LIST;
_currentHolder.addEnum(enumElement);
enumName.staticElement = enumElement;
return super.visitEnumDeclaration(node);
@@ -5144,275 +5145,6 @@ class HtmlUnitBuilder implements ht.XmlVisitor<Object> {
}
}
/**
* Instances of the class `ImplicitConstructorBuilder` are used to build
* implicit constructors for mixin applications, and to check for errors
* related to super constructor calls in class declarations with mixins.
*
* The visitor methods don't directly build the implicit constructors or check
* for errors, since they don't in general visit the classes in the proper
* order to do so correctly. Instead, they pass closures to
* ImplicitConstructorBuilderCallback to inform it of the computations to be
* done and their ordering dependencies.
*/
class ImplicitConstructorBuilder extends SimpleElementVisitor {
final AnalysisErrorListener errorListener;
/**
* Callback to receive the computations to be performed.
*/
final ImplicitConstructorBuilderCallback _callback;
/**
* Initialize a newly created visitor to build implicit constructors.
*
* The visit methods will pass closures to [_callback] to indicate what
* computation needs to be performed, and its dependency order.
*/
ImplicitConstructorBuilder(this.errorListener, this._callback);
@override
void visitClassElement(ClassElement classElement) {
(classElement as ClassElementImpl).mixinErrorsReported = false;
if (classElement.isMixinApplication) {
_visitClassTypeAlias(classElement);
} else {
_visitClassDeclaration(classElement);
}
}
@override
void visitCompilationUnitElement(CompilationUnitElement element) {
element.types.forEach(visitClassElement);
}
@override
void visitLibraryElement(LibraryElement element) {
element.units.forEach(visitCompilationUnitElement);
}
/**
* Create an implicit constructor that is copied from the given constructor, but that is in the
* given class.
*
* @param classType the class in which the implicit constructor is defined
* @param explicitConstructor the constructor on which the implicit constructor is modeled
* @param parameterTypes the types to be replaced when creating parameters
* @param argumentTypes the types with which the parameters are to be replaced
* @return the implicit constructor that was created
*/
ConstructorElement _createImplicitContructor(InterfaceType classType,
ConstructorElement explicitConstructor, List<DartType> parameterTypes,
List<DartType> argumentTypes) {
ConstructorElementImpl implicitConstructor =
new ConstructorElementImpl(explicitConstructor.name, -1);
implicitConstructor.synthetic = true;
implicitConstructor.redirectedConstructor = explicitConstructor;
implicitConstructor.const2 = explicitConstructor.isConst;
implicitConstructor.returnType = classType;
List<ParameterElement> explicitParameters = explicitConstructor.parameters;
int count = explicitParameters.length;
if (count > 0) {
List<ParameterElement> implicitParameters =
new List<ParameterElement>(count);
for (int i = 0; i < count; i++) {
ParameterElement explicitParameter = explicitParameters[i];
ParameterElementImpl implicitParameter =
new ParameterElementImpl(explicitParameter.name, -1);
implicitParameter.const3 = explicitParameter.isConst;
implicitParameter.final2 = explicitParameter.isFinal;
implicitParameter.parameterKind = explicitParameter.parameterKind;
implicitParameter.synthetic = true;
implicitParameter.type =
explicitParameter.type.substitute2(argumentTypes, parameterTypes);
implicitParameters[i] = implicitParameter;
}
implicitConstructor.parameters = implicitParameters;
}
FunctionTypeImpl type = new FunctionTypeImpl(implicitConstructor);
type.typeArguments = classType.typeArguments;
implicitConstructor.type = type;
return implicitConstructor;
}
/**
* Find all the constructors that should be forwarded from the given
* [superType], to the class or mixin application [classElement],
* and pass information about them to [callback].
*
* Return true if some constructors were considered. (A false return value
* can only happen if the supeclass is a built-in type, in which case it
* can't be used as a mixin anyway).
*/
bool _findForwardedConstructors(ClassElementImpl classElement,
InterfaceType superType, void callback(
ConstructorElement explicitConstructor, List<DartType> parameterTypes,
List<DartType> argumentTypes)) {
ClassElement superclassElement = superType.element;
List<ConstructorElement> constructors = superclassElement.constructors;
int count = constructors.length;
if (count == 0) {
return false;
}
List<DartType> parameterTypes =
TypeParameterTypeImpl.getTypes(superType.typeParameters);
List<DartType> argumentTypes = _getArgumentTypes(superType, parameterTypes);
for (int i = 0; i < count; i++) {
ConstructorElement explicitConstructor = constructors[i];
if (!explicitConstructor.isFactory &&
classElement.isSuperConstructorAccessible(explicitConstructor)) {
callback(explicitConstructor, parameterTypes, argumentTypes);
}
}
return true;
}
/**
* Return a list of argument types that corresponds to the [parameterTypes]
* and that are derived from the type arguments of the given [superType].
*/
List<DartType> _getArgumentTypes(
InterfaceType superType, List<DartType> parameterTypes) {
DynamicTypeImpl dynamic = DynamicTypeImpl.instance;
int parameterCount = parameterTypes.length;
List<DartType> types = new List<DartType>(parameterCount);
if (superType == null) {
types = new List<DartType>.filled(parameterCount, dynamic);
} else {
List<DartType> typeArguments = superType.typeArguments;
int argumentCount = math.min(typeArguments.length, parameterCount);
for (int i = 0; i < argumentCount; i++) {
types[i] = typeArguments[i];
}
for (int i = argumentCount; i < parameterCount; i++) {
types[i] = dynamic;
}
}
return types;
}
void _visitClassDeclaration(ClassElementImpl classElement) {
DartType superType = classElement.supertype;
if (superType != null && classElement.mixins.isNotEmpty) {
// We don't need to build any implicitly constructors for the mixin
// application (since there isn't an explicit element for it), but we
// need to verify that they _could_ be built.
if (superType is! InterfaceType) {
TypeProvider typeProvider = classElement.context.typeProvider;
superType = typeProvider.objectType;
}
ClassElement superElement = superType.element;
if (superElement != null) {
_callback(classElement, superElement, () {
bool constructorFound = false;
void callback(ConstructorElement explicitConstructor,
List<DartType> parameterTypes, List<DartType> argumentTypes) {
constructorFound = true;
}
if (_findForwardedConstructors(classElement, superType, callback) &&
!constructorFound) {
SourceRange withRange = classElement.withClauseRange;
errorListener.onError(new AnalysisError(classElement.source,
withRange.offset, withRange.length,
CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS,
[superElement.name]));
classElement.mixinErrorsReported = true;
}
});
}
}
}
void _visitClassTypeAlias(ClassElementImpl classElement) {
InterfaceType superType = classElement.supertype;
if (superType is InterfaceType) {
ClassElement superElement = superType.element;
_callback(classElement, superElement, () {
List<ConstructorElement> implicitConstructors =
new List<ConstructorElement>();
void callback(ConstructorElement explicitConstructor,
List<DartType> parameterTypes, List<DartType> argumentTypes) {
implicitConstructors.add(_createImplicitContructor(classElement.type,
explicitConstructor, parameterTypes, argumentTypes));
}
if (_findForwardedConstructors(classElement, superType, callback)) {
if (implicitConstructors.isEmpty) {
errorListener.onError(new AnalysisError(classElement.source,
classElement.nameOffset, classElement.name.length,
CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS,
[superElement.name]));
} else {
classElement.constructors = implicitConstructors;
}
}
});
}
}
}
/**
* An instance of this class is capable of running ImplicitConstructorBuilder
* over all classes in a library cycle.
*/
class ImplicitConstructorComputer {
/**
* Directed graph of dependencies between classes that need to have their
* implicit constructors computed. Each edge in the graph points from a
* derived class to its superclass. Implicit constructors will be computed
* for the superclass before they are compute for the derived class.
*/
DirectedGraph<ClassElement> _dependencies = new DirectedGraph<ClassElement>();
/**
* Map from ClassElement to the function which will compute the class's
* implicit constructors.
*/
Map<ClassElement, VoidFunction> _computations =
new HashMap<ClassElement, VoidFunction>();
/**
* Add the given [libraryElement] to the list of libraries which need to have
* implicit constructors built for them.
*/
void add(AnalysisErrorListener errorListener, LibraryElement libraryElement) {
libraryElement
.accept(new ImplicitConstructorBuilder(errorListener, _defer));
}
/**
* Compute the implicit constructors for all compilation units that have been
* passed to [add].
*/
void compute() {
List<List<ClassElement>> topologicalSort =
_dependencies.computeTopologicalSort();
for (List<ClassElement> classesInCycle in topologicalSort) {
// Note: a cycle could occur if there is a loop in the inheritance graph.
// Such loops are forbidden by Dart but could occur in the analysis of
// incorrect code. If this happens, we simply visit the classes
// constituting the loop in any order.
for (ClassElement classElement in classesInCycle) {
VoidFunction computation = _computations[classElement];
if (computation != null) {
computation();
}
}
}
}
/**
* Defer execution of [computation], which builds implicit constructors for
* [classElement], until after implicit constructors have been built for
* [superclassElement].
*/
void _defer(ClassElement classElement, ClassElement superclassElement,
void computation()) {
assert(!_computations.containsKey(classElement));
_computations[classElement] = computation;
_dependencies.addEdge(classElement, superclassElement);
}
}
/**
* Instances of the class `ImplicitLabelScope` represent the scope statements
* that can be the target of unlabeled break and continue statements.
@@ -7917,7 +7649,6 @@ class LibraryResolver {
_typeProvider = new TypeProviderImpl(coreElement, asyncElement);
_buildEnumMembers();
_buildTypeHierarchies();
_buildImplicitConstructors();
//
// Perform resolution and type analysis.
//
@@ -8197,22 +7928,6 @@ class LibraryResolver {
});
}
/**
* Finish steps that the [buildTypeHierarchies] could not perform, see
* [ImplicitConstructorBuilder].
*
* @throws AnalysisException if any of the type hierarchies could not be resolved
*/
void _buildImplicitConstructors() {
PerformanceStatistics.resolve.makeCurrentWhile(() {
ImplicitConstructorComputer computer = new ImplicitConstructorComputer();
for (Library library in _librariesInCycles) {
computer.add(_errorListener, library.libraryElement);
}
computer.compute();
});
}
/**
* Resolve the type hierarchy across all of the types declared in the libraries in the current
* cycle.
@@ -8653,7 +8368,6 @@ class LibraryResolver2 {
_typeProvider = new TypeProviderImpl(coreElement, asyncElement);
_buildEnumMembers();
_buildTypeHierarchies();
_buildImplicitConstructors();
//
// Perform resolution and type analysis.
//
@@ -8855,22 +8569,6 @@ class LibraryResolver2 {
});
}
/**
* Finish steps that the [buildTypeHierarchies] could not perform, see
* [ImplicitConstructorBuilder].
*
* @throws AnalysisException if any of the type hierarchies could not be resolved
*/
void _buildImplicitConstructors() {
PerformanceStatistics.resolve.makeCurrentWhile(() {
ImplicitConstructorComputer computer = new ImplicitConstructorComputer();
for (ResolvableLibrary library in _librariesInCycle) {
computer.add(_errorListener, library.libraryElement);
}
computer.compute();
});
}
HashMap<Source, ResolvableLibrary> _buildLibraryMap() {
HashMap<Source, ResolvableLibrary> libraryMap =
new HashMap<Source, ResolvableLibrary>();
@@ -268,6 +268,7 @@ class TestTypeProvider implements TypeProvider {
"iterator", false, iteratorType.substitute4(<DartType>[eType])),
ElementFactory.getterElement("last", false, eType)
]);
iterableElement.constructors = ConstructorElement.EMPTY_LIST;
_propagateTypeArguments(iterableElement);
}
return _iterableType;
@@ -282,6 +283,7 @@ class TestTypeProvider implements TypeProvider {
_setAccessors(iteratorElement, <PropertyAccessorElement>[
ElementFactory.getterElement("current", false, eType)
]);
iteratorElement.constructors = ConstructorElement.EMPTY_LIST;
_propagateTypeArguments(iteratorElement);
}
return _iteratorType;
@@ -330,6 +332,7 @@ class TestTypeProvider implements TypeProvider {
ElementFactory.methodElement(
"[]=", VoidTypeImpl.instance, [kType, vType])
];
mapElement.constructors = ConstructorElement.EMPTY_LIST;
_propagateTypeArguments(mapElement);
}
return _mapType;
@@ -356,7 +359,9 @@ class TestTypeProvider implements TypeProvider {
@override
InterfaceType get nullType {
if (_nullType == null) {
_nullType = ElementFactory.classElement2("Null").type;
ClassElementImpl nullElement = ElementFactory.classElement2("Null");
nullElement.constructors = ConstructorElement.EMPTY_LIST;
_nullType = nullElement.type;
}
return _nullType;
}
@@ -552,7 +557,9 @@ class TestTypeProvider implements TypeProvider {
];
fromEnvironment.factory = true;
fromEnvironment.isCycleFree = true;
numElement.constructors = ConstructorElement.EMPTY_LIST;
intElement.constructors = <ConstructorElement>[fromEnvironment];
doubleElement.constructors = ConstructorElement.EMPTY_LIST;
List<FieldElement> fields = <FieldElement>[
ElementFactory.fieldElement("NAN", true, false, true, _doubleType),
ElementFactory.fieldElement("INFINITY", true, false, true, _doubleType),
@@ -62,12 +62,10 @@ class EnginePlugin implements Plugin {
//
// Register Dart tasks.
//
registerExtension(taskId, BuildClassConstructorsTask.DESCRIPTOR);
registerExtension(taskId, BuildCompilationUnitElementTask.DESCRIPTOR);
registerExtension(taskId, BuildDirectiveElementsTask.DESCRIPTOR);
registerExtension(taskId, BuildEnumMemberElementsTask.DESCRIPTOR);
registerExtension(taskId, BuildExportNamespaceTask.DESCRIPTOR);
registerExtension(taskId, BuildLibraryConstructorsTask.DESCRIPTOR);
registerExtension(taskId, BuildLibraryElementTask.DESCRIPTOR);
registerExtension(taskId, BuildPublicNamespaceTask.DESCRIPTOR);
registerExtension(taskId, BuildSourceExportClosureTask.DESCRIPTOR);
+6 -346
View File
@@ -5,7 +5,6 @@
library analyzer.src.task.dart;
import 'dart:collection';
import 'dart:math' as math;
import 'package:analyzer/src/context/cache.dart';
import 'package:analyzer/src/generated/ast.dart';
@@ -58,17 +57,6 @@ final ListResultDescriptor<AnalysisError> BUILD_LIBRARY_ERRORS =
new ListResultDescriptor<AnalysisError>(
'BUILD_LIBRARY_ERRORS', AnalysisError.NO_ERRORS);
/**
* The [ClassElement]s of a [Source] representing a Dart library.
*
* The list contains the elements for all of the classes defined in the library,
* not just those in the defining compilation unit. The list will be empty if
* there are no classes, but will not be `null`.
*/
final ListResultDescriptor<ClassElement> CLASS_ELEMENTS =
new ListResultDescriptor<ClassElement>('CLASS_ELEMENTS', null,
cachingPolicy: ELEMENT_CACHING_POLICY);
/**
* A list of the [ConstantEvaluationTarget]s defined in a unit. This includes
* constants defined at top level, statically inside classes, and local to
@@ -111,23 +99,6 @@ final ResultDescriptor<ConstantEvaluationTarget> CONSTANT_VALUE =
new ResultDescriptor<ConstantEvaluationTarget>('CONSTANT_VALUE', null,
cachingPolicy: ELEMENT_CACHING_POLICY);
/**
* The [ConstructorElement]s of a [ClassElement].
*/
final ListResultDescriptor<ConstructorElement> CONSTRUCTORS =
new ListResultDescriptor<ConstructorElement>('CONSTRUCTORS', null);
/**
* The errors produced while building a [ClassElement] constructors.
*
* The list will be empty if there were no errors, but will not be `null`.
*
* The result is only available for targets representing a [ClassElement].
*/
final ListResultDescriptor<AnalysisError> CONSTRUCTORS_ERRORS =
new ListResultDescriptor<AnalysisError>(
'CONSTRUCTORS_ERRORS', AnalysisError.NO_ERRORS);
/**
* The sources representing the libraries that include a given source as a part.
*
@@ -232,17 +203,6 @@ final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT5 =
new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT5', null,
cachingPolicy: ELEMENT_CACHING_POLICY);
/**
* The partial [LibraryElement] associated with a library.
*
* [LIBRARY_ELEMENT5] plus resolved elements and types for all expressions.
*
* The result is only available for [Source]s representing a library.
*/
final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT6 =
new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT6', null,
cachingPolicy: ELEMENT_CACHING_POLICY);
/**
* The flag specifying whether all analysis errors are computed in a specific
* library.
@@ -426,234 +386,6 @@ List<AnalysisError> removeDuplicateErrors(List<AnalysisError> errors) {
return errors.toSet().toList();
}
/**
* A task that builds implicit constructors for a [ClassElement], or keeps
* the existing explicit constructors if the class has them.
*/
class BuildClassConstructorsTask extends SourceBasedAnalysisTask {
/**
* The name of the [CONSTRUCTORS] input for the superclass.
*/
static const String SUPER_CONSTRUCTORS = 'SUPER_CONSTRUCTORS';
/**
* The task descriptor describing this kind of task.
*/
static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
'BuildConstructorsForClassTask', createTask, buildInputs,
<ResultDescriptor>[CONSTRUCTORS, CONSTRUCTORS_ERRORS]);
BuildClassConstructorsTask(
InternalAnalysisContext context, AnalysisTarget target)
: super(context, target);
@override
TaskDescriptor get descriptor => DESCRIPTOR;
@override
void internalPerform() {
List<AnalysisError> errors = <AnalysisError>[];
//
// Prepare inputs.
//
ClassElementImpl classElement = this.target;
List<ConstructorElement> superConstructors = inputs[SUPER_CONSTRUCTORS];
DartType superType = classElement.supertype;
if (superType == null) {
return;
}
//
// Shortcut for ClassElement(s) without implicit constructors.
//
if (superConstructors == null) {
outputs[CONSTRUCTORS] = classElement.constructors;
outputs[CONSTRUCTORS_ERRORS] = AnalysisError.NO_ERRORS;
return;
}
//
// ClassTypeAlias
//
if (classElement.isMixinApplication) {
List<ConstructorElement> implicitConstructors =
new List<ConstructorElement>();
void callback(ConstructorElement explicitConstructor,
List<DartType> parameterTypes, List<DartType> argumentTypes) {
implicitConstructors.add(_createImplicitContructor(classElement.type,
explicitConstructor, parameterTypes, argumentTypes));
}
if (_findForwardedConstructors(classElement, superType, callback)) {
if (implicitConstructors.isEmpty) {
errors.add(new AnalysisError(classElement.source,
classElement.nameOffset, classElement.name.length,
CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS,
[superType.element.name]));
} else {
classElement.constructors = implicitConstructors;
}
}
outputs[CONSTRUCTORS] = classElement.constructors;
outputs[CONSTRUCTORS_ERRORS] = errors;
}
//
// ClassDeclaration
//
if (!classElement.isMixinApplication) {
bool constructorFound = false;
void callback(ConstructorElement explicitConstructor,
List<DartType> parameterTypes, List<DartType> argumentTypes) {
constructorFound = true;
}
if (_findForwardedConstructors(classElement, superType, callback) &&
!constructorFound) {
SourceRange withRange = classElement.withClauseRange;
errors.add(new AnalysisError(classElement.source, withRange.offset,
withRange.length, CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS,
[superType.element.name]));
classElement.mixinErrorsReported = true;
}
outputs[CONSTRUCTORS] = classElement.constructors;
outputs[CONSTRUCTORS_ERRORS] = errors;
}
}
/**
* Return a map from the names of the inputs of this kind of task to the task
* input descriptors describing those inputs for a task with the
* given [classElement].
*/
static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
ClassElement element = target;
Source librarySource = element.library.source;
DartType superType = element.supertype;
if (superType is InterfaceType) {
if (element.isMixinApplication || element.mixins.isNotEmpty) {
ClassElement superElement = superType.element;
return <String, TaskInput>{
'libraryDep': LIBRARY_ELEMENT5.of(librarySource),
SUPER_CONSTRUCTORS: CONSTRUCTORS.of(superElement)
};
}
}
// No implicit constructors.
// Depend on LIBRARY_ELEMENT5 for invalidation.
return <String, TaskInput>{
'libraryDep': LIBRARY_ELEMENT5.of(librarySource)
};
}
/**
* Create a [BuildClassConstructorsTask] based on the given
* [target] in the given [context].
*/
static BuildClassConstructorsTask createTask(
AnalysisContext context, AnalysisTarget target) {
return new BuildClassConstructorsTask(context, target);
}
/**
* Create an implicit constructor that is copied from the given
* [explicitConstructor], but that is in the given class.
*
* [classType] - the class in which the implicit constructor is defined.
* [explicitConstructor] - the constructor on which the implicit constructor
* is modeled.
* [parameterTypes] - the types to be replaced when creating parameters.
* [argumentTypes] - the types with which the parameters are to be replaced.
*/
static ConstructorElement _createImplicitContructor(InterfaceType classType,
ConstructorElement explicitConstructor, List<DartType> parameterTypes,
List<DartType> argumentTypes) {
ConstructorElementImpl implicitConstructor =
new ConstructorElementImpl(explicitConstructor.name, -1);
implicitConstructor.synthetic = true;
implicitConstructor.redirectedConstructor = explicitConstructor;
implicitConstructor.const2 = explicitConstructor.isConst;
implicitConstructor.returnType = classType;
List<ParameterElement> explicitParameters = explicitConstructor.parameters;
int count = explicitParameters.length;
if (count > 0) {
List<ParameterElement> implicitParameters =
new List<ParameterElement>(count);
for (int i = 0; i < count; i++) {
ParameterElement explicitParameter = explicitParameters[i];
ParameterElementImpl implicitParameter =
new ParameterElementImpl(explicitParameter.name, -1);
implicitParameter.const3 = explicitParameter.isConst;
implicitParameter.final2 = explicitParameter.isFinal;
implicitParameter.parameterKind = explicitParameter.parameterKind;
implicitParameter.synthetic = true;
implicitParameter.type =
explicitParameter.type.substitute2(argumentTypes, parameterTypes);
implicitParameters[i] = implicitParameter;
}
implicitConstructor.parameters = implicitParameters;
}
FunctionTypeImpl type = new FunctionTypeImpl(implicitConstructor);
type.typeArguments = classType.typeArguments;
implicitConstructor.type = type;
return implicitConstructor;
}
/**
* Find all the constructors that should be forwarded from the given
* [superType], to the class or mixin application [classElement],
* and pass information about them to [callback].
*
* Return `true` if some constructors were considered. (A `false` return value
* can only happen if the supeclass is a built-in type, in which case it
* can't be used as a mixin anyway).
*/
static bool _findForwardedConstructors(ClassElementImpl classElement,
InterfaceType superType, void callback(
ConstructorElement explicitConstructor, List<DartType> parameterTypes,
List<DartType> argumentTypes)) {
if (superType == null) {
return false;
}
ClassElement superclassElement = superType.element;
List<ConstructorElement> constructors = superclassElement.constructors;
int count = constructors.length;
if (count == 0) {
return false;
}
List<DartType> parameterTypes =
TypeParameterTypeImpl.getTypes(superType.typeParameters);
List<DartType> argumentTypes = _getArgumentTypes(superType, parameterTypes);
for (int i = 0; i < count; i++) {
ConstructorElement explicitConstructor = constructors[i];
if (!explicitConstructor.isFactory &&
classElement.isSuperConstructorAccessible(explicitConstructor)) {
callback(explicitConstructor, parameterTypes, argumentTypes);
}
}
return true;
}
/**
* Return a list of argument types that corresponds to the [parameterTypes]
* and that are derived from the type arguments of the given [superType].
*/
static List<DartType> _getArgumentTypes(
InterfaceType superType, List<DartType> parameterTypes) {
DynamicTypeImpl dynamic = DynamicTypeImpl.instance;
int parameterCount = parameterTypes.length;
List<DartType> types = new List<DartType>(parameterCount);
if (superType == null) {
types = new List<DartType>.filled(parameterCount, dynamic);
} else {
List<DartType> typeArguments = superType.typeArguments;
int argumentCount = math.min(typeArguments.length, parameterCount);
for (int i = 0; i < argumentCount; i++) {
types[i] = typeArguments[i];
}
for (int i = argumentCount; i < parameterCount; i++) {
types[i] = dynamic;
}
}
return types;
}
}
/**
* A task that builds a compilation unit element for a single compilation unit.
*/
@@ -1127,59 +859,6 @@ class BuildExportNamespaceTask extends SourceBasedAnalysisTask {
}
}
/**
* This task builds [LIBRARY_ELEMENT6] by forcing building constructors for
* all the classes of the defining and part units of a library.
*/
class BuildLibraryConstructorsTask extends SourceBasedAnalysisTask {
/**
* The name of the [LIBRARY_ELEMENT5] input.
*/
static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
/**
* The task descriptor describing this kind of task.
*/
static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
'BuildLibraryConstructorsTask', createTask, buildInputs,
<ResultDescriptor>[LIBRARY_ELEMENT6]);
BuildLibraryConstructorsTask(
InternalAnalysisContext context, AnalysisTarget target)
: super(context, target);
@override
TaskDescriptor get descriptor => DESCRIPTOR;
@override
void internalPerform() {
LibraryElement library = getRequiredInput(LIBRARY_INPUT);
outputs[LIBRARY_ELEMENT6] = library;
}
/**
* Return a map from the names of the inputs of this kind of task to the task
* input descriptors describing those inputs for a task with the
* given [target].
*/
static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
Source source = target;
return <String, TaskInput>{
LIBRARY_INPUT: LIBRARY_ELEMENT5.of(source),
'resolvedConstructors': CLASS_ELEMENTS.of(source).toListOf(CONSTRUCTORS),
};
}
/**
* Create a [BuildLibraryConstructorsTask] based on the given [target] in
* the given [context].
*/
static BuildLibraryConstructorsTask createTask(
AnalysisContext context, AnalysisTarget target) {
return new BuildLibraryConstructorsTask(context, target);
}
}
/**
* A task that builds a library element for a Dart library.
*/
@@ -1201,7 +880,6 @@ class BuildLibraryElementTask extends SourceBasedAnalysisTask {
static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
'BuildLibraryElementTask', createTask, buildInputs, <ResultDescriptor>[
BUILD_LIBRARY_ERRORS,
CLASS_ELEMENTS,
LIBRARY_ELEMENT1,
IS_LAUNCHABLE
]);
@@ -1337,17 +1015,9 @@ class BuildLibraryElementTask extends SourceBasedAnalysisTask {
_patchTopLevelAccessors(libraryElement);
}
//
// Prepare all class elements.
//
List<ClassElement> classElements = libraryElement.units
.map((CompilationUnitElement unitElement) => unitElement.types)
.expand((List<ClassElement> unitClassElements) => unitClassElements)
.toList();
//
// Record outputs.
//
outputs[BUILD_LIBRARY_ERRORS] = errors;
outputs[CLASS_ELEMENTS] = classElements;
outputs[LIBRARY_ELEMENT1] = libraryElement;
outputs[IS_LAUNCHABLE] = entryPoint != null;
}
@@ -2613,11 +2283,6 @@ class LibraryUnitErrorsTask extends SourceBasedAnalysisTask {
*/
static const String VERIFY_ERRORS_INPUT = 'VERIFY_ERRORS';
/**
* The name of the [CONSTRUCTORS_ERRORS] input.
*/
static const String CONSTRUCTORS_ERRORS_INPUT = 'CONSTRUCTORS_ERRORS';
/**
* The task descriptor describing this kind of task.
*/
@@ -2637,7 +2302,6 @@ class LibraryUnitErrorsTask extends SourceBasedAnalysisTask {
// Prepare inputs.
//
List<List<AnalysisError>> errorLists = <List<AnalysisError>>[];
errorLists.addAll(getRequiredInput(CONSTRUCTORS_ERRORS_INPUT));
errorLists.add(getRequiredInput(HINTS_INPUT));
errorLists.add(getRequiredInput(RESOLVE_REFERENCES_ERRORS_INPUT));
errorLists.add(getRequiredInput(RESOLVE_TYPE_NAMES_ERRORS_INPUT));
@@ -2657,10 +2321,6 @@ class LibraryUnitErrorsTask extends SourceBasedAnalysisTask {
static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
LibrarySpecificUnit unit = target;
return <String, TaskInput>{
CONSTRUCTORS_ERRORS_INPUT: COMPILATION_UNIT_ELEMENT
.of(unit)
.mappedToList((CompilationUnitElement element) => element.types)
.toListOf(CONSTRUCTORS_ERRORS),
HINTS_INPUT: HINTS.of(unit),
RESOLVE_REFERENCES_ERRORS_INPUT: RESOLVE_REFERENCES_ERRORS.of(unit),
RESOLVE_TYPE_NAMES_ERRORS_INPUT: RESOLVE_TYPE_NAMES_ERRORS.of(unit),
@@ -3010,7 +2670,7 @@ class ReferencedNamesBuilder extends RecursiveAstVisitor {
*/
class ResolveLibraryReferencesTask extends SourceBasedAnalysisTask {
/**
* The name of the [LIBRARY_ELEMENT6] input.
* The name of the [LIBRARY_ELEMENT5] input.
*/
static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
@@ -3060,7 +2720,7 @@ class ResolveLibraryReferencesTask extends SourceBasedAnalysisTask {
static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
Source source = target;
return <String, TaskInput>{
LIBRARY_INPUT: LIBRARY_ELEMENT6.of(source),
LIBRARY_INPUT: LIBRARY_ELEMENT5.of(source),
UNITS_INPUT: UNITS.of(source).toList((Source unit) =>
RESOLVED_UNIT5.of(new LibrarySpecificUnit(source, unit))),
'resolvedUnits': IMPORT_EXPORT_SOURCE_CLOSURE
@@ -3140,7 +2800,7 @@ class ResolveLibraryTypeNamesTask extends SourceBasedAnalysisTask {
*/
class ResolveUnitReferencesTask extends SourceBasedAnalysisTask {
/**
* The name of the [LIBRARY_ELEMENT6] input.
* The name of the [LIBRARY_ELEMENT5] input.
*/
static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
@@ -3206,8 +2866,8 @@ class ResolveUnitReferencesTask extends SourceBasedAnalysisTask {
return <String, TaskInput>{
'fullyBuiltLibraryElements': IMPORT_EXPORT_SOURCE_CLOSURE
.of(unit.library)
.toListOf(LIBRARY_ELEMENT6),
LIBRARY_INPUT: LIBRARY_ELEMENT6.of(unit.library),
.toListOf(LIBRARY_ELEMENT5),
LIBRARY_INPUT: LIBRARY_ELEMENT5.of(unit.library),
UNIT_INPUT: RESOLVED_UNIT4.of(unit),
TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request)
};
@@ -3313,7 +2973,7 @@ class ResolveUnitTypeNamesTask extends SourceBasedAnalysisTask {
*/
class ResolveVariableReferencesTask extends SourceBasedAnalysisTask {
/**
* The name of the [LIBRARY_ELEMENT6] input.
* The name of the [LIBRARY_ELEMENT1] input.
*/
static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
@@ -1061,6 +1061,8 @@ class ConstantFinderTest extends EngineTestCase {
ElementFactory.constructorElement(classElement, '', true);
constructorDeclaration.element = constructorElement;
classElement.constructors = <ConstructorElement>[constructorElement];
} else {
classElement.constructors = ConstructorElement.EMPTY_LIST;
}
return variableDeclaration;
}
@@ -8256,7 +8258,6 @@ final Map<String, LibraryInfo> LIBRARIES = const <String, LibraryInfo> {
}
}
@reflectiveTest
class StringScannerTest extends AbstractScannerTest {
@override
@@ -1912,10 +1912,7 @@ class C = a.A with M;'''
class M {}
class C = bool with M;''');
computeLibrarySourceErrors(source);
assertErrors(source, [
CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS,
CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS
]);
assertErrors(source, [CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS]);
verify([source]);
}
@@ -1933,10 +1930,7 @@ class C = double with M;''');
class M {}
class C = int with M;''');
computeLibrarySourceErrors(source);
assertErrors(source, [
CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS,
CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS
]);
assertErrors(source, [CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS]);
verify([source]);
}
@@ -1963,10 +1957,7 @@ class C = num with M;''');
class M {}
class C = String with M;''');
computeLibrarySourceErrors(source);
assertErrors(source, [
CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS,
CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS
]);
assertErrors(source, [CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS]);
verify([source]);
}
@@ -5282,6 +5273,22 @@ class M2 = Object with M1;''');
verify([source]);
}
void test_recursiveInterfaceInheritance_mixin_superclass() {
// Make sure we don't get CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS in
// addition--that would just be confusing.
Source source = addSource('''
class C = D with M;
class D = C with M;
class M {}
''');
computeLibrarySourceErrors(source);
assertErrors(source, [
CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE,
CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE
]);
verify([source]);
}
void test_recursiveInterfaceInheritance_tail() {
Source source = addSource(r'''
abstract class A implements A {}
@@ -2380,6 +2380,7 @@ class InterfaceTypeImplTest extends EngineTestCase {
void test_getConstructors_empty() {
ClassElementImpl typeElement = ElementFactory.classElement2("A");
typeElement.constructors = ConstructorElement.EMPTY_LIST;
InterfaceTypeImpl type = new InterfaceTypeImpl(typeElement);
expect(type.constructors, isEmpty);
}
@@ -13365,11 +13365,6 @@ class TypeResolverVisitorTest extends EngineTestCase {
*/
TypeResolverVisitor _visitor;
/**
* The visitor used to resolve types needed to form the type hierarchy.
*/
ImplicitConstructorBuilder _implicitConstructorBuilder;
void fail_visitConstructorDeclaration() {
fail("Not yet tested");
_listener.assertNoErrors();
@@ -13420,14 +13415,6 @@ class TypeResolverVisitorTest extends EngineTestCase {
_typeProvider = new TestTypeProvider();
_visitor =
new TypeResolverVisitor.con1(_library, librarySource, _typeProvider);
_implicitConstructorBuilder = new ImplicitConstructorBuilder(_listener,
(ClassElement classElement, ClassElement superclassElement,
void computation()) {
// For these tests, we assume the classes for which implicit
// constructors need to be built are visited in proper dependency order,
// so we just invoke the computation immediately.
computation();
});
}
void test_visitCatchClause_exception() {
@@ -13827,9 +13814,6 @@ class TypeResolverVisitorTest extends EngineTestCase {
}
}
node.accept(_visitor);
if (node is Declaration) {
node.element.accept(_implicitConstructorBuilder);
}
}
}
+1 -166
View File
@@ -28,14 +28,12 @@ import '../context/abstract_context.dart';
main() {
groupSep = ' | ';
runReflectiveTests(BuildClassConstructorsTaskTest);
runReflectiveTests(BuildCompilationUnitElementTaskTest);
runReflectiveTests(BuildDirectiveElementsTaskTest);
runReflectiveTests(BuildEnumMemberElementsTaskTest);
runReflectiveTests(BuildSourceExportClosureTaskTest);
runReflectiveTests(BuildSourceImportExportClosureTaskTest);
runReflectiveTests(BuildExportNamespaceTaskTest);
runReflectiveTests(BuildLibraryConstructorsTaskTest);
runReflectiveTests(BuildLibraryElementTaskTest);
runReflectiveTests(BuildPublicNamespaceTaskTest);
runReflectiveTests(BuildTypeProviderTaskTest);
@@ -58,112 +56,6 @@ main() {
runReflectiveTests(VerifyUnitTaskTest);
}
@reflectiveTest
class BuildClassConstructorsTaskTest extends _AbstractDartTaskTest {
test_perform_ClassDeclaration_errors_mixinHasNoConstructors() {
Source source = newSource('/test.dart', '''
class B {
B({x});
}
class M {}
class C extends B with M {}
''');
LibraryElement libraryElement;
{
computeResult(source, LIBRARY_ELEMENT5);
libraryElement = outputs[LIBRARY_ELEMENT5];
}
// prepare C
ClassElement c = libraryElement.getType('C');
expect(c, isNotNull);
// build constructors
computeResult(c, CONSTRUCTORS);
expect(task, new isInstanceOf<BuildClassConstructorsTask>());
_fillErrorListener(CONSTRUCTORS_ERRORS);
errorListener.assertErrorsWithCodes(
<ErrorCode>[CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS]);
}
test_perform_ClassDeclaration_explicitConstructors() {
Source source = newSource('/test.dart', '''
class B {
B(p);
}
class C extends B {
C(int a, String b) {}
}
''');
LibraryElement libraryElement;
{
computeResult(source, LIBRARY_ELEMENT5);
libraryElement = outputs[LIBRARY_ELEMENT5];
}
// prepare C
ClassElement c = libraryElement.getType('C');
expect(c, isNotNull);
// build constructors
computeResult(c, CONSTRUCTORS);
expect(task, new isInstanceOf<BuildClassConstructorsTask>());
// no errors
expect(outputs[CONSTRUCTORS_ERRORS], isEmpty);
// explicit constructor
List<ConstructorElement> constructors = outputs[CONSTRUCTORS];
expect(constructors, hasLength(1));
expect(constructors[0].parameters, hasLength(2));
}
test_perform_ClassTypeAlias() {
Source source = newSource('/test.dart', '''
class B {
B(int i);
}
class M1 {}
class M2 {}
class C2 = C1 with M2;
class C1 = B with M1;
''');
LibraryElement libraryElement;
{
computeResult(source, LIBRARY_ELEMENT5);
libraryElement = outputs[LIBRARY_ELEMENT5];
}
// prepare C2
ClassElement class2 = libraryElement.getType('C2');
expect(class2, isNotNull);
// build constructors
computeResult(class2, CONSTRUCTORS);
expect(task, new isInstanceOf<BuildClassConstructorsTask>());
List<ConstructorElement> constructors = outputs[CONSTRUCTORS];
expect(constructors, hasLength(1));
expect(constructors[0].parameters, hasLength(1));
}
test_perform_ClassTypeAlias_errors_mixinHasNoConstructors() {
Source source = newSource('/test.dart', '''
class B {
B({x});
}
class M {}
class C = B with M;
''');
LibraryElement libraryElement;
{
computeResult(source, LIBRARY_ELEMENT5);
libraryElement = outputs[LIBRARY_ELEMENT5];
}
// prepare C
ClassElement c = libraryElement.getType('C');
expect(c, isNotNull);
// build constructors
computeResult(c, CONSTRUCTORS);
expect(task, new isInstanceOf<BuildClassConstructorsTask>());
_fillErrorListener(CONSTRUCTORS_ERRORS);
errorListener.assertErrorsWithCodes(
<ErrorCode>[CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS]);
}
}
@reflectiveTest
class BuildCompilationUnitElementTaskTest extends _AbstractDartTaskTest {
Source source;
@@ -714,40 +606,6 @@ int topLevelB;
}
}
@reflectiveTest
class BuildLibraryConstructorsTaskTest extends _AbstractDartTaskTest {
test_perform() {
Source source = newSource('/test.dart', '''
class B {
B(int i);
}
class M1 {}
class M2 {}
class C2 = C1 with M2;
class C1 = B with M1;
class C3 = B with M2;
''');
computeResult(source, LIBRARY_ELEMENT6);
expect(task, new isInstanceOf<BuildLibraryConstructorsTask>());
LibraryElement libraryElement = outputs[LIBRARY_ELEMENT6];
// C1
{
ClassElement classElement = libraryElement.getType('C2');
List<ConstructorElement> constructors = classElement.constructors;
expect(constructors, hasLength(1));
expect(constructors[0].parameters, hasLength(1));
}
// C3
{
ClassElement classElement = libraryElement.getType('C3');
List<ConstructorElement> constructors = classElement.constructors;
expect(constructors, hasLength(1));
expect(constructors[0].parameters, hasLength(1));
}
}
}
@reflectiveTest
class BuildLibraryElementTaskTest extends _AbstractDartTaskTest {
Source librarySource;
@@ -798,7 +656,7 @@ part of lib;
part of lib;
'''
});
expect(outputs, hasLength(4));
expect(outputs, hasLength(3));
// simple outputs
expect(outputs[BUILD_LIBRARY_ERRORS], isEmpty);
expect(outputs[IS_LAUNCHABLE], isFalse);
@@ -839,28 +697,6 @@ part of lib;
(libraryUnit.directives[2] as PartDirective).element, same(secondPart));
}
test_perform_classElements() {
_performBuildTask({
'/lib.dart': '''
library lib;
part 'part1.dart';
part 'part2.dart';
class A {}
''',
'/part1.dart': '''
part of lib;
class B {}
''',
'/part2.dart': '''
part of lib;
class C {}
'''
});
List<ClassElement> classElements = outputs[CLASS_ELEMENTS];
List<String> classNames = classElements.map((c) => c.displayName).toList();
expect(classNames, unorderedEquals(['A', 'B', 'C']));
}
test_perform_error_missingLibraryDirectiveWithPart_hasCommon() {
_performBuildTask({
'/lib.dart': '''
@@ -2054,7 +1890,6 @@ class LibraryUnitErrorsTaskTest extends _AbstractDartTaskTest {
.buildInputs(new LibrarySpecificUnit(emptySource, emptySource));
expect(inputs, isNotNull);
expect(inputs.keys, unorderedEquals([
LibraryUnitErrorsTask.CONSTRUCTORS_ERRORS_INPUT,
LibraryUnitErrorsTask.HINTS_INPUT,
LibraryUnitErrorsTask.RESOLVE_REFERENCES_ERRORS_INPUT,
LibraryUnitErrorsTask.RESOLVE_TYPE_NAMES_ERRORS_INPUT,