Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(140)

Unified Diff: pkg/analyzer/lib/src/generated/element.dart

Issue 1215053003: Compute mixin application constructors in the ClassElement.constructors getter. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/analyzer/lib/src/context/context.dart ('k') | pkg/analyzer/lib/src/generated/element_resolver.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/analyzer/lib/src/generated/element.dart
diff --git a/pkg/analyzer/lib/src/generated/element.dart b/pkg/analyzer/lib/src/generated/element.dart
index 52ef4f5df925a7d692fc6c70a484ba84cba1d5c0..24344aae432ecac820252d7241b5f33c41a4f541 100644
--- a/pkg/analyzer/lib/src/generated/element.dart
+++ b/pkg/analyzer/lib/src/generated/element.dart
@@ -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,12 +592,24 @@ 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;
}
@@ -599,6 +617,50 @@ class ClassElementImpl extends ElementImpl implements ClassElement {
}
/**
+ * 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.
*/
void set enum2(bool isEnum) {
@@ -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 =
@@ -8073,41 +8222,34 @@ class Modifier extends Enum<Modifier> {
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,
« no previous file with comments | « pkg/analyzer/lib/src/context/context.dart ('k') | pkg/analyzer/lib/src/generated/element_resolver.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698