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

Unified Diff: packages/analyzer/lib/src/summary/link.dart

Issue 2990843002: Removed fixed dependencies (Closed)
Patch Set: Created 3 years, 5 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 | « packages/analyzer/lib/src/summary/idl.dart ('k') | packages/analyzer/lib/src/summary/name_filter.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: packages/analyzer/lib/src/summary/link.dart
diff --git a/packages/analyzer/lib/src/summary/link.dart b/packages/analyzer/lib/src/summary/link.dart
new file mode 100644
index 0000000000000000000000000000000000000000..9ebc378ff40a5b99159100b428ca08bed1b617f7
--- /dev/null
+++ b/packages/analyzer/lib/src/summary/link.dart
@@ -0,0 +1,5062 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * This library is capable of producing linked summaries from unlinked
+ * ones (or prelinked ones). It functions by building a miniature
+ * element model to represent the contents of the summaries, and then
+ * scanning the element model to gather linked information and adding
+ * it to the summary data structures.
+ *
+ * The reason we use a miniature element model to do the linking
+ * (rather than resynthesizing the full element model from the
+ * summaries) is that it is expected that we will only need to
+ * traverse a small subset of the element properties in order to link.
+ * Resynthesizing only those properties that we need should save
+ * substantial CPU time.
+ *
+ * The element model implements the same interfaces as the full
+ * element model, so we can re-use code elsewhere in the analysis
+ * engine to do the linking. However, only a small subset of the
+ * methods and getters defined in the full element model are
+ * implemented here. To avoid static warnings, each element model
+ * class contains an implementation of `noSuchMethod`.
+ *
+ * The miniature element model follows the following design
+ * principles:
+ *
+ * - With few exceptions, resynthesis is done incrementally on demand,
+ * so that we don't pay the cost of resynthesizing elements (or
+ * properties of elements) that aren't referenced from a part of the
+ * element model that is relevant to linking.
+ *
+ * - Computation of values in the miniature element model is similar
+ * to the task model, but much lighter weight. Instead of declaring
+ * tasks and their relationships using classes, each task is simply
+ * a method (frequently a getter) that computes a value. Instead of
+ * using a general purpose cache, values are cached by the methods
+ * themselves in private fields (with `null` typically representing
+ * "not yet cached").
+ *
+ * - No attempt is made to detect cyclic dependencies due to bugs in
+ * the analyzer. This saves time because dependency evaluation
+ * doesn't have to be a separate step from evaluating a value; we
+ * can simply call the getter.
+ *
+ * - However, for cases where cyclic dependencies may occur in the
+ * absence of analyzer bugs (e.g. because of errors in the code
+ * being analyzed, or cycles between top level and static variables
+ * undergoing type inference), we do precompute dependencies, and we
+ * use Tarjan's strongly connected components algorithm to detect
+ * cycles.
+ *
+ * - As much as possible, bookkeeping data is pointed to directly by
+ * the element objects, rather than being stored in maps.
+ *
+ * - Where possible, we favor method dispatch instead of "is" and "as"
+ * checks. E.g. see [ReferenceableElementForLink.asConstructor].
+ */
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart' show TokenType;
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/constant/value.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/idl.dart';
+import 'package:analyzer/src/summary/prelink.dart';
+import 'package:analyzer/src/task/strong_mode.dart';
+
+bool isIncrementOrDecrement(UnlinkedExprAssignOperator operator) {
+ switch (operator) {
+ case UnlinkedExprAssignOperator.prefixDecrement:
+ case UnlinkedExprAssignOperator.prefixIncrement:
+ case UnlinkedExprAssignOperator.postfixDecrement:
+ case UnlinkedExprAssignOperator.postfixIncrement:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * Link together the build unit consisting of [libraryUris], using
+ * [getDependency] to fetch the [LinkedLibrary] objects from other
+ * build units, and [getUnit] to fetch the [UnlinkedUnit] objects from
+ * both this build unit and other build units.
+ *
+ * The [strong] flag controls whether type inference is performed in strong
+ * mode or spec mode. Note that in spec mode, the only types that are inferred
+ * are the types of initializing formals, which are inferred from the types of
+ * the corresponding fields.
+ *
+ * A map is returned whose keys are the URIs of the libraries in this
+ * build unit, and whose values are the corresponding
+ * [LinkedLibraryBuilder]s.
+ */
+Map<String, LinkedLibraryBuilder> link(
+ Set<String> libraryUris,
+ GetDependencyCallback getDependency,
+ GetUnitCallback getUnit,
+ GetDeclaredVariable getDeclaredVariable,
+ bool strong) {
+ Map<String, LinkedLibraryBuilder> linkedLibraries =
+ setupForLink(libraryUris, getUnit, getDeclaredVariable);
+ relink(linkedLibraries, getDependency, getUnit, strong);
+ return linkedLibraries;
+}
+
+/**
+ * Given [libraries] (a map from URI to [LinkedLibraryBuilder]
+ * containing correct prelinked information), rebuild linked
+ * information, using [getDependency] to fetch the [LinkedLibrary]
+ * objects from other build units, and [getUnit] to fetch the
+ * [UnlinkedUnit] objects from both this build unit and other build
+ * units.
+ *
+ * The [strong] flag controls whether type inference is performed in strong
+ * mode or spec mode. Note that in spec mode, the only types that are inferred
+ * are the types of initializing formals, which are inferred from the types of
+ * the corresponding fields.
+ */
+void relink(Map<String, LinkedLibraryBuilder> libraries,
+ GetDependencyCallback getDependency, GetUnitCallback getUnit, bool strong) {
+ new Linker(libraries, getDependency, getUnit, strong).link();
+}
+
+/**
+ * Prepare to link together the build unit consisting of [libraryUris], using
+ * [getUnit] to fetch the [UnlinkedUnit] objects from both this build unit and
+ * other build units.
+ *
+ * The libraries are prelinked, and a map is returned whose keys are the URIs of
+ * the libraries in this build unit, and whose values are the corresponding
+ * [LinkedLibraryBuilder]s.
+ */
+Map<String, LinkedLibraryBuilder> setupForLink(Set<String> libraryUris,
+ GetUnitCallback getUnit, GetDeclaredVariable getDeclaredVariable) {
+ Map<String, LinkedLibraryBuilder> linkedLibraries =
+ <String, LinkedLibraryBuilder>{};
+ for (String absoluteUri in libraryUris) {
+ Uri uri = Uri.parse(absoluteUri);
+ UnlinkedUnit getRelativeUnit(String relativeUri) =>
+ getUnit(resolveRelativeUri(uri, Uri.parse(relativeUri)).toString());
+ linkedLibraries[absoluteUri] = prelink(
+ getUnit(absoluteUri),
+ getRelativeUnit,
+ (String relativeUri) => getRelativeUnit(relativeUri)?.publicNamespace,
+ getDeclaredVariable);
+ }
+ return linkedLibraries;
+}
+
+/**
+ * Create an [EntityRefBuilder] representing the given [type], in a form
+ * suitable for inclusion in [LinkedUnit.types]. [compilationUnit] is the
+ * compilation unit in which the type will be used. If [slot] is provided, it
+ * is stored in [EntityRefBuilder.slot].
+ */
+EntityRefBuilder _createLinkedType(
+ DartType type,
+ CompilationUnitElementInBuildUnit compilationUnit,
+ TypeParameterizedElementMixin typeParameterContext,
+ {int slot}) {
+ EntityRefBuilder result = new EntityRefBuilder(slot: slot);
+ if (type is InterfaceType) {
+ ClassElementForLink element = type.element;
+ result.reference = compilationUnit.addReference(element);
+ _storeTypeArguments(
+ type.typeArguments, result, compilationUnit, typeParameterContext);
+ return result;
+ } else if (type is DynamicTypeImpl) {
+ result.reference = compilationUnit.addRawReference('dynamic');
+ return result;
+ } else if (type is VoidTypeImpl) {
+ result.reference = compilationUnit.addRawReference('void');
+ return result;
+ } else if (type is BottomTypeImpl) {
+ result.reference = compilationUnit.addRawReference('*bottom*');
+ return result;
+ } else if (type is TypeParameterType) {
+ TypeParameterElementImpl element = type.element;
+ if (typeParameterContext.isTypeParameterInScope(element)) {
+ result.paramReference =
+ typeParameterContext.typeParameterNestingLevel - element.nestingLevel;
+ } else {
+ throw new StateError('The type parameter $type (in ${element?.location}) '
+ 'is out of scope on ${typeParameterContext?.location}.');
+ }
+ return result;
+ } else if (type is FunctionType) {
+ Element element = type.element;
+ if (element is FunctionElementForLink_FunctionTypedParam) {
+ result.reference =
+ compilationUnit.addReference(element.typeParameterContext);
+ result.implicitFunctionTypeIndices = element.implicitFunctionTypeIndices;
+ _storeTypeArguments(
+ type.typeArguments, result, compilationUnit, typeParameterContext);
+ return result;
+ }
+ if (element is TopLevelFunctionElementForLink) {
+ result.reference = compilationUnit.addReference(element);
+ _storeTypeArguments(
+ type.typeArguments, result, compilationUnit, typeParameterContext);
+ return result;
+ }
+ if (element is MethodElementForLink) {
+ result.reference = compilationUnit.addReference(element);
+ _storeTypeArguments(
+ type.typeArguments, result, compilationUnit, typeParameterContext);
+ return result;
+ }
+ if (element is FunctionTypeAliasElementForLink) {
+ result.reference = compilationUnit.addReference(element);
+ _storeTypeArguments(
+ type.typeArguments, result, compilationUnit, typeParameterContext);
+ return result;
+ }
+ if (element is FunctionElement && element.enclosingElement == null) {
+ // Element is a synthetic function element that was generated on the fly
+ // to represent a type that has no associated source code location.
+ result.syntheticReturnType = _createLinkedType(
+ element.returnType, compilationUnit, typeParameterContext);
+ result.syntheticParams = element.parameters
+ .map((ParameterElement param) => _serializeSyntheticParam(
+ param, compilationUnit, typeParameterContext))
+ .toList();
+ return result;
+ }
+ if (element is FunctionElement) {
+ // Element is a local function inside another executable.
+ result.reference = compilationUnit.addReference(element);
+ // TODO(paulberry): do I need to store type arguments?
+ return result;
+ }
+ // TODO(paulberry): implement other cases.
+ throw new UnimplementedError('${element.runtimeType}');
+ }
+ // TODO(paulberry): implement other cases.
+ throw new UnimplementedError('${type.runtimeType}');
+}
+
+DartType _dynamicIfNull(DartType type) {
+ if (type == null || type.isBottom || type.isVoid) {
+ return DynamicTypeImpl.instance;
+ }
+ return type;
+}
+
+/**
+ * Create an [UnlinkedParam] representing the given [parameter], which should be
+ * a parameter of a synthetic function type (e.g. one produced during type
+ * inference as a result of computing the least upper bound of two function
+ * types).
+ */
+UnlinkedParamBuilder _serializeSyntheticParam(
+ ParameterElement parameter,
+ CompilationUnitElementInBuildUnit compilationUnit,
+ TypeParameterizedElementMixin typeParameterContext) {
+ UnlinkedParamBuilder b = new UnlinkedParamBuilder();
+ b.name = parameter.name;
+ switch (parameter.parameterKind) {
+ case ParameterKind.REQUIRED:
+ b.kind = UnlinkedParamKind.required;
+ break;
+ case ParameterKind.POSITIONAL:
+ b.kind = UnlinkedParamKind.positional;
+ break;
+ case ParameterKind.NAMED:
+ b.kind = UnlinkedParamKind.named;
+ break;
+ }
+ DartType type = parameter.type;
+ if (!parameter.hasImplicitType) {
+ if (type is FunctionType && type.element.isSynthetic) {
+ b.isFunctionTyped = true;
+ b.type = _createLinkedType(
+ type.returnType, compilationUnit, typeParameterContext);
+ b.parameters = type.parameters
+ .map((parameter) => _serializeSyntheticParam(
+ parameter, compilationUnit, typeParameterContext))
+ .toList();
+ } else {
+ b.type = _createLinkedType(type, compilationUnit, typeParameterContext);
+ }
+ }
+ return b;
+}
+
+/**
+ * Store the given [typeArguments] in [encodedType], using [compilationUnit] and
+ * [typeParameterContext] to serialize them.
+ */
+void _storeTypeArguments(
+ List<DartType> typeArguments,
+ EntityRefBuilder encodedType,
+ CompilationUnitElementInBuildUnit compilationUnit,
+ TypeParameterizedElementMixin typeParameterContext) {
+ int count = typeArguments.length;
+ List<EntityRefBuilder> encodedTypeArguments =
+ new List<EntityRefBuilder>(count);
+ for (int i = 0; i < count; i++) {
+ encodedTypeArguments[i] = _createLinkedType(
+ typeArguments[i], compilationUnit, typeParameterContext);
+ }
+ encodedType.typeArguments = encodedTypeArguments;
+}
+
+/**
+ * Type of the callback used by [link] and [relink] to request
+ * [LinkedLibrary] objects from other build units.
+ */
+typedef LinkedLibrary GetDependencyCallback(String absoluteUri);
+
+/**
+ * Type of the callback used by [link] and [relink] to request
+ * [UnlinkedUnit] objects.
+ */
+typedef UnlinkedUnit GetUnitCallback(String absoluteUri);
+
+/**
+ * Stub implementation of [AnalysisOptions] used during linking.
+ */
+class AnalysisOptionsForLink implements AnalysisOptions {
+ final Linker _linker;
+
+ AnalysisOptionsForLink(this._linker);
+
+ @override
+ bool get strongMode => _linker.strongMode;
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+/**
+ * Element representing a class or enum resynthesized from a summary
+ * during linking.
+ */
+abstract class ClassElementForLink extends Object
+ with ReferenceableElementForLink
+ implements AbstractClassElementImpl {
+ Map<String, ReferenceableElementForLink> _containedNames;
+
+ @override
+ final CompilationUnitElementForLink enclosingElement;
+
+ /// TODO(brianwilkerson) This appears to be unused and might be removable.
+ bool hasBeenInferred;
+
+ ClassElementForLink(CompilationUnitElementForLink enclosingElement)
+ : enclosingElement = enclosingElement,
+ hasBeenInferred = !enclosingElement.isInBuildUnit;
+
+ @override
+ List<PropertyAccessorElementForLink> get accessors;
+
+ @override
+ ClassElementForLink get asClass => this;
+
+ @override
+ ConstructorElementForLink get asConstructor => unnamedConstructor;
+
+ @override
+ DartType get asStaticType =>
+ enclosingElement.enclosingElement._linker.typeProvider.typeType;
+
+ @override
+ List<ConstructorElementForLink> get constructors;
+
+ @override
+ CompilationUnitElementImpl get enclosingUnit => enclosingElement;
+
+ @override
+ List<FieldElementForLink> get fields;
+
+ /**
+ * Indicates whether this is the core class `Object`.
+ */
+ bool get isObject;
+
+ @override
+ LibraryElementForLink get library => enclosingElement.library;
+
+ @override
+ List<MethodElementForLink> get methods;
+
+ @override
+ String get name;
+
+ @override
+ ConstructorElementForLink get unnamedConstructor;
+
+ @override
+ ReferenceableElementForLink getContainedName(String name) {
+ if (_containedNames == null) {
+ _containedNames = <String, ReferenceableElementForLink>{};
+ // TODO(paulberry): what's the correct way to handle name conflicts?
+ for (ConstructorElementForLink constructor in constructors) {
+ _containedNames[constructor.name] = constructor;
+ }
+ for (PropertyAccessorElementForLink accessor in accessors) {
+ _containedNames[accessor.name] = accessor;
+ }
+ for (MethodElementForLink method in methods) {
+ _containedNames[method.name] = method;
+ }
+ }
+ return _containedNames.putIfAbsent(
+ name, () => UndefinedElementForLink.instance);
+ }
+
+ /**
+ * Perform type inference and cycle detection on this class and
+ * store the resulting information in [compilationUnit].
+ */
+ void link(CompilationUnitElementInBuildUnit compilationUnit);
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+/**
+ * Element representing a class resynthesized from a summary during
+ * linking.
+ */
+class ClassElementForLink_Class extends ClassElementForLink
+ with TypeParameterizedElementMixin
+ implements ClassElementImpl {
+ /**
+ * The unlinked representation of the class in the summary.
+ */
+ final UnlinkedClass _unlinkedClass;
+
+ List<ConstructorElementForLink> _constructors;
+ ConstructorElementForLink _unnamedConstructor;
+ bool _unnamedConstructorComputed = false;
+ List<FieldElementForLink_ClassField> _fields;
+ InterfaceType _supertype;
+ InterfaceType _type;
+ List<MethodElementForLink> _methods;
+ List<InterfaceType> _mixins;
+ List<InterfaceType> _interfaces;
+ List<PropertyAccessorElementForLink> _accessors;
+
+ ClassElementForLink_Class(
+ CompilationUnitElementForLink enclosingElement, this._unlinkedClass)
+ : super(enclosingElement);
+
+ @override
+ List<PropertyAccessorElementForLink> get accessors {
+ if (_accessors == null) {
+ _accessors = <PropertyAccessorElementForLink>[];
+ Map<String, SyntheticVariableElementForLink> syntheticVariables =
+ <String, SyntheticVariableElementForLink>{};
+ for (UnlinkedExecutable unlinkedExecutable
+ in _unlinkedClass.executables) {
+ if (unlinkedExecutable.kind == UnlinkedExecutableKind.getter ||
+ unlinkedExecutable.kind == UnlinkedExecutableKind.setter) {
+ String name = unlinkedExecutable.name;
+ if (unlinkedExecutable.kind == UnlinkedExecutableKind.setter) {
+ assert(name.endsWith('='));
+ name = name.substring(0, name.length - 1);
+ }
+ SyntheticVariableElementForLink syntheticVariable = syntheticVariables
+ .putIfAbsent(name, () => new SyntheticVariableElementForLink());
+ PropertyAccessorElementForLink_Executable accessor =
+ new PropertyAccessorElementForLink_Executable(enclosingElement,
+ this, unlinkedExecutable, syntheticVariable);
+ _accessors.add(accessor);
+ if (unlinkedExecutable.kind == UnlinkedExecutableKind.getter) {
+ syntheticVariable._getter = accessor;
+ } else {
+ syntheticVariable._setter = accessor;
+ }
+ }
+ }
+ for (FieldElementForLink_ClassField field in fields) {
+ _accessors.add(field.getter);
+ if (!field.isConst && !field.isFinal) {
+ _accessors.add(field.setter);
+ }
+ }
+ }
+ return _accessors;
+ }
+
+ @override
+ List<ConstructorElementForLink> get constructors {
+ if (_constructors == null) {
+ _constructors = <ConstructorElementForLink>[];
+ for (UnlinkedExecutable unlinkedExecutable
+ in _unlinkedClass.executables) {
+ if (unlinkedExecutable.kind == UnlinkedExecutableKind.constructor) {
+ _constructors
+ .add(new ConstructorElementForLink(this, unlinkedExecutable));
+ }
+ }
+ if (_constructors.isEmpty) {
+ _unnamedConstructorComputed = true;
+ _unnamedConstructor = new ConstructorElementForLink_Synthetic(this);
+ _constructors.add(_unnamedConstructor);
+ }
+ }
+ return _constructors;
+ }
+
+ @override
+ ContextForLink get context => enclosingUnit.context;
+
+ @override
+ String get displayName => _unlinkedClass.name;
+
+ @override
+ TypeParameterizedElementMixin get enclosingTypeParameterContext => null;
+
+ @override
+ List<FieldElementForLink_ClassField> get fields {
+ if (_fields == null) {
+ _fields = <FieldElementForLink_ClassField>[];
+ for (UnlinkedVariable field in _unlinkedClass.fields) {
+ _fields.add(new FieldElementForLink_ClassField(this, field));
+ }
+ }
+ return _fields;
+ }
+
+ @override
+ String get identifier => name;
+
+ @override
+ List<InterfaceType> get interfaces => _interfaces ??=
+ _unlinkedClass.interfaces.map(_computeInterfaceType).toList();
+
+ @override
+ bool get isMixinApplication => _unlinkedClass.isMixinApplication;
+
+ @override
+ bool get isObject => _unlinkedClass.hasNoSupertype;
+
+ @override
+ LibraryElementForLink get library => enclosingElement.library;
+
+ @override
+ List<MethodElementForLink> get methods {
+ if (_methods == null) {
+ _methods = <MethodElementForLink>[];
+ for (UnlinkedExecutable unlinkedExecutable
+ in _unlinkedClass.executables) {
+ if (unlinkedExecutable.kind ==
+ UnlinkedExecutableKind.functionOrMethod) {
+ _methods.add(new MethodElementForLink(this, unlinkedExecutable));
+ }
+ }
+ }
+ return _methods;
+ }
+
+ @override
+ List<InterfaceType> get mixins =>
+ _mixins ??= _unlinkedClass.mixins.map(_computeInterfaceType).toList();
+
+ @override
+ String get name => _unlinkedClass.name;
+
+ @override
+ InterfaceType get supertype {
+ if (isObject) {
+ return null;
+ }
+ return _supertype ??= _computeInterfaceType(_unlinkedClass.supertype);
+ }
+
+ @override
+ InterfaceType get type =>
+ _type ??= buildType((int i) => typeParameterTypes[i], null);
+
+ @override
+ List<UnlinkedTypeParam> get unlinkedTypeParams =>
+ _unlinkedClass.typeParameters;
+
+ @override
+ ConstructorElementForLink get unnamedConstructor {
+ if (!_unnamedConstructorComputed) {
+ for (ConstructorElementForLink constructor in constructors) {
+ if (constructor.name.isEmpty) {
+ _unnamedConstructor = constructor;
+ break;
+ }
+ }
+ _unnamedConstructorComputed = true;
+ }
+ return _unnamedConstructor;
+ }
+
+ @override
+ int get version => 0;
+
+ @override
+ DartType buildType(
+ DartType getTypeArgument(int i), List<int> implicitFunctionTypeIndices) {
+ int numTypeParameters = _unlinkedClass.typeParameters.length;
+ if (numTypeParameters != 0) {
+ List<DartType> typeArguments =
+ new List<DartType>.generate(numTypeParameters, getTypeArgument);
+ if (typeArguments.contains(null)) {
+ return context.typeSystem.instantiateToBounds(this.type);
+ } else {
+ return new InterfaceTypeImpl.elementWithNameAndArgs(
+ this, name, () => typeArguments);
+ }
+ } else {
+ return _type ??= new InterfaceTypeImpl(this);
+ }
+ }
+
+ @override
+ PropertyAccessorElement getGetter(String getterName) {
+ for (PropertyAccessorElement accessor in accessors) {
+ if (accessor.isGetter && accessor.name == getterName) {
+ return accessor;
+ }
+ }
+ return null;
+ }
+
+ @override
+ MethodElement getMethod(String methodName) {
+ for (MethodElement method in methods) {
+ if (method.name == methodName) {
+ return method;
+ }
+ }
+ return null;
+ }
+
+ @override
+ void link(CompilationUnitElementInBuildUnit compilationUnit) {
+ for (ConstructorElementForLink constructorElement in constructors) {
+ constructorElement.link(compilationUnit);
+ }
+ if (library._linker.strongMode) {
+ for (MethodElementForLink methodElement in methods) {
+ methodElement.link(compilationUnit);
+ }
+ for (PropertyAccessorElementForLink propertyAccessorElement
+ in accessors) {
+ propertyAccessorElement.link(compilationUnit);
+ }
+ for (FieldElementForLink_ClassField fieldElement in fields) {
+ fieldElement.link(compilationUnit);
+ }
+ }
+ }
+
+ @override
+ String toString() => '$enclosingElement.$name';
+
+ /**
+ * Convert [typeRef] into an [InterfaceType].
+ */
+ InterfaceType _computeInterfaceType(EntityRef typeRef) {
+ if (typeRef != null) {
+ DartType type = enclosingElement.resolveTypeRef(typeRef, this);
+ if (type is InterfaceType) {
+ return type;
+ }
+ // In the event that the `typeRef` isn't an interface type (which may
+ // happen in the event of erroneous code) just fall through and pretend
+ // the supertype is `Object`.
+ }
+ return enclosingElement.enclosingElement._linker.typeProvider.objectType;
+ }
+}
+
+/**
+ * Element representing an enum resynthesized from a summary during
+ * linking.
+ */
+class ClassElementForLink_Enum extends ClassElementForLink
+ implements EnumElementImpl {
+ /**
+ * The unlinked representation of the enum in the summary.
+ */
+ final UnlinkedEnum _unlinkedEnum;
+
+ InterfaceType _type;
+ List<FieldElementForLink_EnumField> _fields;
+ List<PropertyAccessorElementForLink> _accessors;
+ DartType _valuesType;
+
+ ClassElementForLink_Enum(
+ CompilationUnitElementForLink enclosingElement, this._unlinkedEnum)
+ : super(enclosingElement);
+
+ @override
+ List<PropertyAccessorElementForLink> get accessors {
+ if (_accessors == null) {
+ _accessors = <PropertyAccessorElementForLink>[];
+ for (FieldElementForLink_EnumField field in fields) {
+ _accessors.add(field.getter);
+ }
+ }
+ return _accessors;
+ }
+
+ @override
+ List<ConstructorElementForLink> get constructors => const [];
+
+ @override
+ String get displayName => _unlinkedEnum.name;
+
+ @override
+ List<FieldElementForLink_EnumField> get fields {
+ if (_fields == null) {
+ _fields = <FieldElementForLink_EnumField>[];
+ _fields.add(new FieldElementForLink_EnumField(null, this));
+ for (UnlinkedEnumValue value in _unlinkedEnum.values) {
+ _fields.add(new FieldElementForLink_EnumField(value, this));
+ }
+ }
+ return _fields;
+ }
+
+ @override
+ List<InterfaceType> get interfaces => const [];
+
+ @override
+ bool get isObject => false;
+
+ @override
+ List<MethodElementForLink> get methods => const [];
+
+ @override
+ List<InterfaceType> get mixins => const [];
+
+ @override
+ String get name => _unlinkedEnum.name;
+
+ @override
+ InterfaceType get supertype => library._linker.typeProvider.objectType;
+
+ @override
+ InterfaceType get type => _type ??= new InterfaceTypeImpl(this);
+
+ @override
+ List<TypeParameterElement> get typeParameters => const [];
+
+ @override
+ ConstructorElementForLink get unnamedConstructor => null;
+
+ /**
+ * Get the type of the enum's static member `values`.
+ */
+ DartType get valuesType =>
+ _valuesType ??= library._linker.typeProvider.listType.instantiate([type]);
+
+ @override
+ DartType buildType(DartType getTypeArgument(int i),
+ List<int> implicitFunctionTypeIndices) =>
+ type;
+
+ @override
+ void link(CompilationUnitElementInBuildUnit compilationUnit) {}
+
+ @override
+ String toString() => '$enclosingElement.$name';
+}
+
+/**
+ * Element representing a compilation unit resynthesized from a
+ * summary during linking.
+ */
+abstract class CompilationUnitElementForLink
+ implements CompilationUnitElementImpl, ResynthesizerContext {
+ /**
+ * The unlinked representation of the compilation unit in the
+ * summary.
+ */
+ final UnlinkedUnit _unlinkedUnit;
+
+ /**
+ * For each entry in [UnlinkedUnit.references], the element referred
+ * to by the reference, or `null` if it hasn't been located yet.
+ */
+ final List<ReferenceableElementForLink> _references;
+
+ /**
+ * The absolute URI of this compilation unit.
+ */
+ final String _absoluteUri;
+
+ List<ClassElementForLink_Class> _types;
+ Map<String, ReferenceableElementForLink> _containedNames;
+ List<TopLevelVariableElementForLink> _topLevelVariables;
+ List<ClassElementForLink_Enum> _enums;
+ List<TopLevelFunctionElementForLink> _functions;
+ List<PropertyAccessorElementForLink> _accessors;
+ List<FunctionTypeAliasElementForLink> _functionTypeAliases;
+
+ /**
+ * Index of this unit in the list of units in the enclosing library.
+ */
+ final int unitNum;
+
+ CompilationUnitElementForLink(UnlinkedUnit unlinkedUnit, this.unitNum,
+ int numReferences, this._absoluteUri)
+ : _references = new List<ReferenceableElementForLink>(numReferences),
+ _unlinkedUnit = unlinkedUnit;
+
+ @override
+ List<PropertyAccessorElementForLink> get accessors {
+ if (_accessors == null) {
+ _accessors = <PropertyAccessorElementForLink>[];
+ Map<String, SyntheticVariableElementForLink> syntheticVariables =
+ <String, SyntheticVariableElementForLink>{};
+ for (UnlinkedExecutable unlinkedExecutable in _unlinkedUnit.executables) {
+ if (unlinkedExecutable.kind == UnlinkedExecutableKind.getter ||
+ unlinkedExecutable.kind == UnlinkedExecutableKind.setter) {
+ String name = unlinkedExecutable.name;
+ if (unlinkedExecutable.kind == UnlinkedExecutableKind.setter) {
+ assert(name.endsWith('='));
+ name = name.substring(0, name.length - 1);
+ }
+ SyntheticVariableElementForLink syntheticVariable = syntheticVariables
+ .putIfAbsent(name, () => new SyntheticVariableElementForLink());
+ PropertyAccessorElementForLink_Executable accessor =
+ new PropertyAccessorElementForLink_Executable(
+ this, null, unlinkedExecutable, syntheticVariable);
+ _accessors.add(accessor);
+ if (unlinkedExecutable.kind == UnlinkedExecutableKind.getter) {
+ syntheticVariable._getter = accessor;
+ } else {
+ syntheticVariable._setter = accessor;
+ }
+ }
+ }
+ for (TopLevelVariableElementForLink variable in topLevelVariables) {
+ _accessors.add(variable.getter);
+ if (!variable.isConst && !variable.isFinal) {
+ _accessors.add(variable.setter);
+ }
+ }
+ }
+ return _accessors;
+ }
+
+ @override
+ ContextForLink get context => library.context;
+
+ @override
+ LibraryElementForLink get enclosingElement;
+
+ @override
+ List<ClassElementForLink_Enum> get enums {
+ if (_enums == null) {
+ _enums = <ClassElementForLink_Enum>[];
+ for (UnlinkedEnum unlinkedEnum in _unlinkedUnit.enums) {
+ _enums.add(new ClassElementForLink_Enum(this, unlinkedEnum));
+ }
+ }
+ return _enums;
+ }
+
+ @override
+ List<TopLevelFunctionElementForLink> get functions {
+ if (_functions == null) {
+ _functions = <TopLevelFunctionElementForLink>[];
+ for (UnlinkedExecutable executable in _unlinkedUnit.executables) {
+ if (executable.kind == UnlinkedExecutableKind.functionOrMethod) {
+ _functions.add(new TopLevelFunctionElementForLink(this, executable));
+ }
+ }
+ }
+ return _functions;
+ }
+
+ @override
+ List<FunctionTypeAliasElementForLink> get functionTypeAliases =>
+ _functionTypeAliases ??= _unlinkedUnit.typedefs
+ .map((UnlinkedTypedef t) =>
+ new FunctionTypeAliasElementForLink(this, t))
+ .toList();
+
+ @override
+ String get identifier => _absoluteUri;
+
+ /**
+ * Indicates whether this compilation element is part of the build unit
+ * currently being linked.
+ */
+ bool get isInBuildUnit;
+
+ /**
+ * Determine whether type inference is complete in this compilation unit.
+ */
+ bool get isTypeInferenceComplete {
+ LibraryCycleForLink libraryCycleForLink = library.libraryCycleForLink;
+ if (libraryCycleForLink == null) {
+ return true;
+ } else {
+ return libraryCycleForLink._node.isEvaluated;
+ }
+ }
+
+ @override
+ LibraryElementForLink get library => enclosingElement;
+
+ @override
+ ResynthesizerContext get resynthesizerContext => this;
+
+ @override
+ List<TopLevelVariableElementForLink> get topLevelVariables {
+ if (_topLevelVariables == null) {
+ _topLevelVariables = <TopLevelVariableElementForLink>[];
+ for (UnlinkedVariable unlinkedVariable in _unlinkedUnit.variables) {
+ _topLevelVariables
+ .add(new TopLevelVariableElementForLink(this, unlinkedVariable));
+ }
+ }
+ return _topLevelVariables;
+ }
+
+ @override
+ List<ClassElementForLink_Class> get types {
+ if (_types == null) {
+ _types = <ClassElementForLink_Class>[];
+ for (UnlinkedClass unlinkedClass in _unlinkedUnit.classes) {
+ _types.add(new ClassElementForLink_Class(this, unlinkedClass));
+ }
+ }
+ return _types;
+ }
+
+ /**
+ * The linked representation of the compilation unit in the summary.
+ */
+ LinkedUnit get _linkedUnit;
+
+ /**
+ * Search the unit for a top level element with the given [name].
+ * If no name is found, return the singleton instance of
+ * [UndefinedElementForLink].
+ */
+ ReferenceableElementForLink getContainedName(name) {
+ if (_containedNames == null) {
+ _containedNames = <String, ReferenceableElementForLink>{};
+ // TODO(paulberry): what's the correct way to handle name conflicts?
+ for (ClassElementForLink_Class type in types) {
+ _containedNames[type.name] = type;
+ }
+ for (ClassElementForLink_Enum enm in enums) {
+ _containedNames[enm.name] = enm;
+ }
+ for (TopLevelFunctionElementForLink function in functions) {
+ _containedNames[function.name] = function;
+ }
+ for (PropertyAccessorElementForLink accessor in accessors) {
+ _containedNames[accessor.name] = accessor;
+ }
+ for (FunctionTypeAliasElementForLink functionTypeAlias
+ in functionTypeAliases) {
+ _containedNames[functionTypeAlias.name] = functionTypeAlias;
+ }
+ // TODO(paulberry): fill in other top level entities (typedefs
+ // and executables).
+ }
+ return _containedNames.putIfAbsent(
+ name, () => UndefinedElementForLink.instance);
+ }
+
+ /**
+ * Compute the type referred to by the given linked type [slot] (interpreted
+ * relative to [typeParameterContext]). If there is no inferred type in the
+ * given slot, `dynamic` is returned.
+ */
+ DartType getLinkedType(
+ int slot, TypeParameterizedElementMixin typeParameterContext);
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+
+ /**
+ * Return the class element for the constructor referred to by the given
+ * [index] in [UnlinkedUnit.references]. If the reference is unresolved,
+ * return [UndefinedElementForLink.instance].
+ */
+ ReferenceableElementForLink resolveConstructorClassRef(int index) {
+ LinkedReference linkedReference = _linkedUnit.references[index];
+ if (linkedReference.kind == ReferenceKind.classOrEnum) {
+ return resolveRef(index);
+ }
+ if (index < _unlinkedUnit.references.length) {
+ UnlinkedReference unlinkedReference = _unlinkedUnit.references[index];
+ return resolveRef(unlinkedReference.prefixReference);
+ }
+ return UndefinedElementForLink.instance;
+ }
+
+ /**
+ * Return the element referred to by the given [index] in
+ * [UnlinkedUnit.references]. If the reference is unresolved,
+ * return [UndefinedElementForLink.instance].
+ */
+ ReferenceableElementForLink resolveRef(int index) {
+ if (_references[index] == null) {
+ UnlinkedReference unlinkedReference =
+ index < _unlinkedUnit.references.length
+ ? _unlinkedUnit.references[index]
+ : null;
+ LinkedReference linkedReference = _linkedUnit.references[index];
+ String name = unlinkedReference == null
+ ? linkedReference.name
+ : unlinkedReference.name;
+ int containingReference = unlinkedReference == null
+ ? linkedReference.containingReference
+ : unlinkedReference.prefixReference;
+ if (containingReference != 0 &&
+ _linkedUnit.references[containingReference].kind !=
+ ReferenceKind.prefix) {
+ if (linkedReference.kind == ReferenceKind.function) {
+ // Local function
+ _references[index] = resolveRef(containingReference)
+ .getLocalFunction(linkedReference.localIndex) ??
+ UndefinedElementForLink.instance;
+ } else {
+ _references[index] =
+ resolveRef(containingReference).getContainedName(name);
+ }
+ } else if (linkedReference.dependency == 0) {
+ if (name == 'void') {
+ _references[index] = enclosingElement._linker.voidElement;
+ } else if (name == '*bottom*') {
+ _references[index] = enclosingElement._linker.bottomElement;
+ } else if (name == 'dynamic') {
+ _references[index] = enclosingElement._linker.dynamicElement;
+ } else {
+ _references[index] = enclosingElement.getContainedName(name);
+ }
+ } else {
+ LibraryElementForLink dependency =
+ enclosingElement._getDependency(linkedReference.dependency);
+ _references[index] = dependency.getContainedName(name);
+ }
+ }
+ return _references[index];
+ }
+
+ @override
+ DartType resolveTypeRef(
+ EntityRef type, TypeParameterizedElementMixin typeParameterContext,
+ {bool defaultVoid: false, bool instantiateToBoundsAllowed: true}) {
+ if (type == null) {
+ if (defaultVoid) {
+ return VoidTypeImpl.instance;
+ } else {
+ return DynamicTypeImpl.instance;
+ }
+ }
+ if (type.paramReference != 0) {
+ return typeParameterContext.getTypeParameterType(type.paramReference);
+ } else if (type.syntheticReturnType != null) {
+ // TODO(paulberry): implement.
+ throw new UnimplementedError();
+ } else if (type.implicitFunctionTypeIndices.isNotEmpty) {
+ // TODO(paulberry): implement.
+ throw new UnimplementedError();
+ } else {
+ DartType getTypeArgument(int i) {
+ if (i < type.typeArguments.length) {
+ return resolveTypeRef(type.typeArguments[i], typeParameterContext);
+ } else if (!instantiateToBoundsAllowed) {
+ // Do not allow buildType to instantiate the bounds; force dynamic.
+ return DynamicTypeImpl.instance;
+ } else {
+ return null;
+ }
+ }
+
+ ReferenceableElementForLink element = resolveRef(type.reference);
+ return element.buildType(
+ getTypeArgument, type.implicitFunctionTypeIndices);
+ }
+ }
+
+ @override
+ String toString() => enclosingElement.toString();
+}
+
+/**
+ * Element representing a compilation unit which is part of the build
+ * unit being linked.
+ */
+class CompilationUnitElementInBuildUnit extends CompilationUnitElementForLink {
+ @override
+ final LinkedUnitBuilder _linkedUnit;
+
+ @override
+ final LibraryElementInBuildUnit enclosingElement;
+
+ CompilationUnitElementInBuildUnit(
+ this.enclosingElement,
+ UnlinkedUnit unlinkedUnit,
+ this._linkedUnit,
+ int unitNum,
+ String absoluteUri)
+ : super(
+ unlinkedUnit, unitNum, unlinkedUnit.references.length, absoluteUri);
+
+ @override
+ bool get isInBuildUnit => true;
+
+ @override
+ LibraryElementInBuildUnit get library => enclosingElement;
+
+ /**
+ * If this compilation unit already has a reference in its references table
+ * matching [dependency], [name], [numTypeParameters], [unitNum],
+ * [containingReference], and [kind], return its index. Otherwise add a new reference to
+ * the table and return its index.
+ */
+ int addRawReference(String name,
+ {int dependency: 0,
+ int numTypeParameters: 0,
+ int unitNum: 0,
+ int containingReference: 0,
+ int localIndex: 0,
+ ReferenceKind kind: ReferenceKind.classOrEnum}) {
+ List<LinkedReferenceBuilder> linkedReferences = _linkedUnit.references;
+ List<UnlinkedReference> unlinkedReferences = _unlinkedUnit.references;
+ for (int i = 0; i < linkedReferences.length; i++) {
+ LinkedReferenceBuilder linkedReference = linkedReferences[i];
+ int candidateContainingReference = i < unlinkedReferences.length
+ ? unlinkedReferences[i].prefixReference
+ : linkedReference.containingReference;
+ if (candidateContainingReference != 0 &&
+ linkedReferences[candidateContainingReference].kind ==
+ ReferenceKind.prefix) {
+ // We don't need to match containing references when they are prefixes,
+ // since the relevant information is in linkedReference.dependency.
+ candidateContainingReference = 0;
+ }
+ if (linkedReference.dependency == dependency &&
+ (i < unlinkedReferences.length
+ ? unlinkedReferences[i].name
+ : linkedReference.name) ==
+ name &&
+ linkedReference.numTypeParameters == numTypeParameters &&
+ linkedReference.unit == unitNum &&
+ candidateContainingReference == containingReference &&
+ linkedReference.kind == kind &&
+ linkedReference.localIndex == localIndex) {
+ return i;
+ }
+ }
+ int result = linkedReferences.length;
+ linkedReferences.add(new LinkedReferenceBuilder(
+ dependency: dependency,
+ name: name,
+ numTypeParameters: numTypeParameters,
+ unit: unitNum,
+ containingReference: containingReference,
+ kind: kind,
+ localIndex: localIndex));
+ return result;
+ }
+
+ /**
+ * If this compilation unit already has a reference in its references table
+ * to [element], return its index. Otherwise add a new reference to the table
+ * and return its index.
+ */
+ int addReference(Element element) {
+ if (element is ClassElementForLink) {
+ return addRawReference(element.name,
+ dependency: library.addDependency(element.library),
+ numTypeParameters: element.typeParameters.length,
+ unitNum: element.enclosingElement.unitNum);
+ } else if (element is FunctionTypeAliasElementForLink) {
+ return addRawReference(element.name,
+ dependency: library.addDependency(element.library),
+ numTypeParameters: element.typeParameters.length,
+ unitNum: element.enclosingElement.unitNum,
+ kind: ReferenceKind.typedef);
+ } else if (element is FunctionElementForLink_Initializer) {
+ return addRawReference('',
+ containingReference: addReference(element.enclosingElement),
+ kind: ReferenceKind.function,
+ localIndex: 0);
+ } else if (element is FunctionElementForLink_Local_NonSynthetic) {
+ ExecutableElementForLink parent = element.enclosingElement;
+ int localIndex = parent.functions.indexOf(element);
+ assert(localIndex != -1);
+ return addRawReference(element.name,
+ containingReference: addReference(parent),
+ kind: ReferenceKind.function,
+ localIndex: localIndex);
+ } else if (element is ExecutableElementForLink_NonLocal) {
+ ClassElementForLink_Class enclosingClass = element.enclosingClass;
+ ReferenceKind kind;
+ switch (element._unlinkedExecutable.kind) {
+ case UnlinkedExecutableKind.functionOrMethod:
+ kind = enclosingClass != null
+ ? ReferenceKind.method
+ : ReferenceKind.topLevelFunction;
+ break;
+ case UnlinkedExecutableKind.setter:
+ kind = ReferenceKind.propertyAccessor;
+ break;
+ default:
+ // TODO(paulberry): implement other cases as necessary
+ throw new UnimplementedError('${element._unlinkedExecutable.kind}');
+ }
+ return addRawReference(element.name,
+ numTypeParameters: element.typeParameters.length,
+ containingReference:
+ enclosingClass != null ? addReference(enclosingClass) : null,
+ dependency: enclosingClass != null
+ ? null
+ : library.addDependency(element.library as LibraryElementForLink),
+ kind: kind);
+ } else if (element is FunctionElementForLink_Initializer) {
+ return addRawReference('',
+ containingReference: addReference(element.enclosingElement),
+ kind: ReferenceKind.function);
+ } else if (element is TopLevelVariableElementForLink) {
+ return addRawReference(element.name,
+ dependency: library.addDependency(element.library),
+ kind: ReferenceKind.topLevelPropertyAccessor);
+ } else if (element is FieldElementForLink_ClassField) {
+ ClassElementForLink_Class enclosingClass = element.enclosingElement;
+ // Note: even if the class has type parameters, we don't need to set
+ // numTypeParameters because numTypeParameters does not count type
+ // parameters of parent elements (see
+ // [LinkedReference.numTypeParameters]).
+ return addRawReference(element.name,
+ containingReference: addReference(enclosingClass),
+ kind: ReferenceKind.propertyAccessor);
+ }
+ // TODO(paulberry): implement other cases
+ throw new UnimplementedError('${element.runtimeType}');
+ }
+
+ @override
+ DartType getLinkedType(
+ int slot, TypeParameterizedElementMixin typeParameterContext) {
+ // This method should only be called on compilation units that come from
+ // dependencies, never on compilation units that are part of the current
+ // build unit.
+ throw new StateError(
+ 'Linker tried to access linked type from current build unit');
+ }
+
+ /**
+ * Perform type inference and const cycle detection on this
+ * compilation unit.
+ */
+ void link() {
+ if (library._linker.strongMode) {
+ new InstanceMemberInferrer(enclosingElement._linker.typeProvider,
+ enclosingElement.inheritanceManager)
+ .inferCompilationUnit(this);
+ for (TopLevelVariableElementForLink variable in topLevelVariables) {
+ variable.link(this);
+ }
+ }
+ for (ClassElementForLink classElement in types) {
+ classElement.link(this);
+ }
+ }
+
+ /**
+ * Throw away any information stored in the summary by a previous call to
+ * [link].
+ */
+ void unlink() {
+ _linkedUnit.constCycles.clear();
+ _linkedUnit.parametersInheritingCovariant.clear();
+ _linkedUnit.references.length = _unlinkedUnit.references.length;
+ _linkedUnit.types.clear();
+ }
+
+ /**
+ * Store the fact that the given [slot] represents a constant constructor
+ * that is part of a cycle.
+ */
+ void _storeConstCycle(int slot) {
+ _linkedUnit.constCycles.add(slot);
+ }
+
+ /**
+ * Store the fact that the given [slot] represents a parameter that inherits
+ * `@covariant` behavior.
+ */
+ void _storeInheritsCovariant(int slot) {
+ _linkedUnit.parametersInheritingCovariant.add(slot);
+ }
+
+ /**
+ * Store the given [linkedType] in the given [slot] of the this compilation
+ * unit's linked type list.
+ */
+ void _storeLinkedType(int slot, DartType linkedType,
+ TypeParameterizedElementMixin typeParameterContext) {
+ if (slot != 0) {
+ if (linkedType != null && !linkedType.isDynamic) {
+ _linkedUnit.types.add(_createLinkedType(
+ linkedType, this, typeParameterContext,
+ slot: slot));
+ }
+ }
+ }
+}
+
+/**
+ * Element representing a compilation unit which is depended upon
+ * (either directly or indirectly) by the build unit being linked.
+ *
+ * TODO(paulberry): ensure that inferred types in dependencies are properly
+ * resynthesized.
+ */
+class CompilationUnitElementInDependency extends CompilationUnitElementForLink {
+ @override
+ final LinkedUnit _linkedUnit;
+
+ List<EntityRef> _linkedTypeRefs;
+
+ @override
+ final LibraryElementInDependency enclosingElement;
+
+ CompilationUnitElementInDependency(
+ this.enclosingElement,
+ UnlinkedUnit unlinkedUnit,
+ LinkedUnit linkedUnit,
+ int unitNum,
+ String absoluteUri)
+ : _linkedUnit = linkedUnit,
+ super(
+ unlinkedUnit, unitNum, linkedUnit.references.length, absoluteUri) {
+ // Make one pass through the linked types to determine the lengths for
+ // _linkedTypeRefs and _linkedTypes. TODO(paulberry): add an int to the
+ // summary to make this unnecessary.
+ int maxLinkedTypeSlot = 0;
+ for (EntityRef ref in _linkedUnit.types) {
+ if (ref.slot > maxLinkedTypeSlot) {
+ maxLinkedTypeSlot = ref.slot;
+ }
+ }
+ // Initialize _linkedTypeRefs.
+ _linkedTypeRefs = new List<EntityRef>(maxLinkedTypeSlot + 1);
+ for (EntityRef ref in _linkedUnit.types) {
+ _linkedTypeRefs[ref.slot] = ref;
+ }
+ }
+
+ @override
+ bool get isInBuildUnit => false;
+
+ @override
+ DartType getLinkedType(
+ int slot, TypeParameterizedElementMixin typeParameterContext) {
+ if (slot < _linkedTypeRefs.length) {
+ return resolveTypeRef(_linkedTypeRefs[slot], typeParameterContext);
+ } else {
+ return DynamicTypeImpl.instance;
+ }
+ }
+}
+
+/**
+ * Instance of [ConstNode] representing a constant constructor.
+ */
+class ConstConstructorNode extends ConstNode {
+ /**
+ * The [ConstructorElement] to which this node refers.
+ */
+ final ConstructorElementForLink constructorElement;
+
+ /**
+ * Once this node has been evaluated, indicates whether the
+ * constructor is free of constant evaluation cycles.
+ */
+ bool isCycleFree = false;
+
+ ConstConstructorNode(this.constructorElement);
+
+ @override
+ List<ConstNode> computeDependencies() {
+ List<ConstNode> dependencies = <ConstNode>[];
+ void safeAddDependency(ConstNode target) {
+ if (target != null) {
+ dependencies.add(target);
+ }
+ }
+
+ UnlinkedExecutable unlinkedExecutable =
+ constructorElement._unlinkedExecutable;
+ ClassElementForLink_Class enclosingClass =
+ constructorElement.enclosingElement;
+ ConstructorElementForLink redirectedConstructor =
+ _getFactoryRedirectedConstructor();
+ if (redirectedConstructor != null) {
+ if (redirectedConstructor._constNode != null) {
+ safeAddDependency(redirectedConstructor._constNode);
+ }
+ } else if (unlinkedExecutable.isFactory) {
+ // Factory constructor, but getConstRedirectedConstructor returned
+ // null. This can happen if we're visiting one of the special external
+ // const factory constructors in the SDK, or if the code contains
+ // errors (such as delegating to a non-const constructor, or delegating
+ // to a constructor that can't be resolved). In any of these cases,
+ // we'll evaluate calls to this constructor without having to refer to
+ // any other constants. So we don't need to report any dependencies.
+ } else {
+ ClassElementForLink superClass = enclosingClass.supertype?.element;
+ bool defaultSuperInvocationNeeded = true;
+ for (UnlinkedConstructorInitializer constructorInitializer
+ in constructorElement._unlinkedExecutable.constantInitializers) {
+ if (constructorInitializer.kind ==
+ UnlinkedConstructorInitializerKind.superInvocation) {
+ defaultSuperInvocationNeeded = false;
+ if (superClass != null && !superClass.isObject) {
+ ConstructorElementForLink constructor = superClass
+ .getContainedName(constructorInitializer.name)
+ .asConstructor;
+ safeAddDependency(constructor?._constNode);
+ }
+ } else if (constructorInitializer.kind ==
+ UnlinkedConstructorInitializerKind.thisInvocation) {
+ defaultSuperInvocationNeeded = false;
+ ConstructorElementForLink constructor = constructorElement
+ .enclosingClass
+ .getContainedName(constructorInitializer.name)
+ .asConstructor;
+ safeAddDependency(constructor?._constNode);
+ }
+ CompilationUnitElementForLink compilationUnit =
+ constructorElement.enclosingElement.enclosingElement;
+ collectDependencies(
+ dependencies, constructorInitializer.expression, compilationUnit);
+ for (UnlinkedConst unlinkedConst in constructorInitializer.arguments) {
+ collectDependencies(dependencies, unlinkedConst, compilationUnit);
+ }
+ }
+
+ if (defaultSuperInvocationNeeded) {
+ // No explicit superconstructor invocation found, so we need to
+ // manually insert a reference to the implicit superconstructor.
+ if (superClass != null && !superClass.isObject) {
+ ConstructorElementForLink unnamedConstructor =
+ superClass.unnamedConstructor;
+ safeAddDependency(unnamedConstructor?._constNode);
+ }
+ }
+ for (FieldElementForLink field in enclosingClass.fields) {
+ // Note: non-static const isn't allowed but we handle it anyway so
+ // that we won't be confused by incorrect code.
+ if ((field.isFinal || field.isConst) && !field.isStatic) {
+ safeAddDependency(field.getter.asConstVariable);
+ }
+ }
+ for (ParameterElementForLink parameterElement
+ in constructorElement.parameters) {
+ safeAddDependency(parameterElement._constNode);
+ }
+ }
+ return dependencies;
+ }
+
+ /**
+ * If [constructorElement] redirects to another constructor via a factory
+ * redirect, return the constructor it redirects to.
+ */
+ ConstructorElementForLink _getFactoryRedirectedConstructor() {
+ EntityRef redirectedConstructor =
+ constructorElement._unlinkedExecutable.redirectedConstructor;
+ if (redirectedConstructor != null) {
+ return constructorElement.compilationUnit
+ .resolveRef(redirectedConstructor.reference)
+ .asConstructor;
+ } else {
+ return null;
+ }
+ }
+}
+
+/**
+ * Specialization of [DependencyWalker] for detecting constant
+ * evaluation cycles.
+ */
+class ConstDependencyWalker extends DependencyWalker<ConstNode> {
+ @override
+ void evaluate(ConstNode v) {
+ if (v is ConstConstructorNode) {
+ v.isCycleFree = true;
+ }
+ v.isEvaluated = true;
+ }
+
+ @override
+ void evaluateScc(List<ConstNode> scc) {
+ for (ConstNode v in scc) {
+ if (v is ConstConstructorNode) {
+ v.isCycleFree = false;
+ }
+ v.isEvaluated = true;
+ }
+ }
+}
+
+/**
+ * Specialization of [Node] used to construct the constant evaluation
+ * dependency graph.
+ */
+abstract class ConstNode extends Node<ConstNode> {
+ @override
+ bool isEvaluated = false;
+
+ /**
+ * Collect the dependencies in [unlinkedConst] (which should be
+ * interpreted relative to [compilationUnit]) and store them in
+ * [dependencies].
+ */
+ void collectDependencies(
+ List<ConstNode> dependencies,
+ UnlinkedConst unlinkedConst,
+ CompilationUnitElementForLink compilationUnit) {
+ if (unlinkedConst == null) {
+ return;
+ }
+ int refPtr = 0;
+ int intPtr = 0;
+ for (UnlinkedConstOperation operation in unlinkedConst.operations) {
+ switch (operation) {
+ case UnlinkedConstOperation.pushInt:
+ intPtr++;
+ break;
+ case UnlinkedConstOperation.pushLongInt:
+ int numInts = unlinkedConst.ints[intPtr++];
+ intPtr += numInts;
+ break;
+ case UnlinkedConstOperation.concatenate:
+ intPtr++;
+ break;
+ case UnlinkedConstOperation.pushReference:
+ EntityRef ref = unlinkedConst.references[refPtr++];
+ ConstVariableNode variable =
+ compilationUnit.resolveRef(ref.reference).asConstVariable;
+ if (variable != null) {
+ dependencies.add(variable);
+ }
+ break;
+ case UnlinkedConstOperation.makeUntypedList:
+ case UnlinkedConstOperation.makeUntypedMap:
+ intPtr++;
+ break;
+ case UnlinkedConstOperation.assignToRef:
+ refPtr++;
+ break;
+ case UnlinkedConstOperation.invokeMethodRef:
+ EntityRef ref = unlinkedConst.references[refPtr++];
+ ConstVariableNode variable =
+ compilationUnit.resolveRef(ref.reference).asConstVariable;
+ if (variable != null) {
+ dependencies.add(variable);
+ }
+ intPtr += 2;
+ int numTypeArguments = unlinkedConst.ints[intPtr++];
+ refPtr += numTypeArguments;
+ break;
+ case UnlinkedConstOperation.invokeMethod:
+ intPtr += 2;
+ int numTypeArguments = unlinkedConst.ints[intPtr++];
+ refPtr += numTypeArguments;
+ break;
+ case UnlinkedConstOperation.makeTypedList:
+ refPtr++;
+ intPtr++;
+ break;
+ case UnlinkedConstOperation.makeTypedMap:
+ refPtr += 2;
+ intPtr++;
+ break;
+ case UnlinkedConstOperation.invokeConstructor:
+ EntityRef ref = unlinkedConst.references[refPtr++];
+ ConstructorElementForLink element =
+ compilationUnit.resolveRef(ref.reference).asConstructor;
+ if (element?._constNode != null) {
+ dependencies.add(element._constNode);
+ }
+ intPtr += 2;
+ break;
+ case UnlinkedConstOperation.typeCast:
+ case UnlinkedConstOperation.typeCheck:
+ refPtr++;
+ break;
+ case UnlinkedConstOperation.pushLocalFunctionReference:
+ intPtr += 2;
+ break;
+ default:
+ break;
+ }
+ }
+ assert(refPtr == unlinkedConst.references.length);
+ assert(intPtr == unlinkedConst.ints.length);
+ }
+}
+
+/**
+ * Instance of [ConstNode] representing a parameter with a default
+ * value.
+ */
+class ConstParameterNode extends ConstNode {
+ /**
+ * The [ParameterElement] to which this node refers.
+ */
+ final ParameterElementForLink parameterElement;
+
+ ConstParameterNode(this.parameterElement);
+
+ @override
+ List<ConstNode> computeDependencies() {
+ List<ConstNode> dependencies = <ConstNode>[];
+ collectDependencies(
+ dependencies,
+ parameterElement._unlinkedParam.initializer?.bodyExpr,
+ parameterElement.compilationUnit);
+ return dependencies;
+ }
+}
+
+/**
+ * Element representing a constructor resynthesized from a summary
+ * during linking.
+ */
+class ConstructorElementForLink extends ExecutableElementForLink_NonLocal
+ with ReferenceableElementForLink
+ implements ConstructorElementImpl {
+ /**
+ * If this is a `const` constructor and the enclosing library is
+ * part of the build unit being linked, the constructor's node in
+ * the constant evaluation dependency graph. Otherwise `null`.
+ */
+ ConstConstructorNode _constNode;
+
+ ConstructorElementForLink(ClassElementForLink_Class enclosingClass,
+ UnlinkedExecutable unlinkedExecutable)
+ : super(enclosingClass.enclosingElement, enclosingClass,
+ unlinkedExecutable) {
+ if (enclosingClass.enclosingElement.isInBuildUnit &&
+ _unlinkedExecutable != null &&
+ _unlinkedExecutable.constCycleSlot != 0) {
+ _constNode = new ConstConstructorNode(this);
+ }
+ }
+
+ @override
+ ConstructorElementForLink get asConstructor => this;
+
+ @override
+ ClassElementImpl get enclosingElement => super.enclosingClass;
+
+ @override
+ bool get isCycleFree {
+ if (!_constNode.isEvaluated) {
+ new ConstDependencyWalker().walk(_constNode);
+ }
+ return _constNode.isCycleFree;
+ }
+
+ /**
+ * Perform const cycle detection on this constructor.
+ */
+ void link(CompilationUnitElementInBuildUnit compilationUnit) {
+ if (_constNode != null && !isCycleFree) {
+ compilationUnit._storeConstCycle(_unlinkedExecutable.constCycleSlot);
+ }
+ // TODO(paulberry): call super.
+ }
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+/**
+ * A synthetic constructor.
+ */
+class ConstructorElementForLink_Synthetic extends ConstructorElementForLink {
+ ConstructorElementForLink_Synthetic(
+ ClassElementForLink_Class enclosingElement)
+ : super(enclosingElement, null);
+
+ @override
+ String get name => '';
+
+ @override
+ List<ParameterElement> get parameters => const <ParameterElement>[];
+}
+
+/**
+ * Instance of [ConstNode] representing a constant field or constant
+ * top level variable.
+ */
+class ConstVariableNode extends ConstNode {
+ /**
+ * The [FieldElement] or [TopLevelVariableElement] to which this
+ * node refers.
+ */
+ final VariableElementForLink variableElement;
+
+ ConstVariableNode(this.variableElement);
+
+ @override
+ List<ConstNode> computeDependencies() {
+ List<ConstNode> dependencies = <ConstNode>[];
+ collectDependencies(
+ dependencies,
+ variableElement.unlinkedVariable.initializer?.bodyExpr,
+ variableElement.compilationUnit);
+ return dependencies;
+ }
+}
+
+/**
+ * Stub implementation of [AnalysisContext] which provides just those methods
+ * needed during linking.
+ */
+class ContextForLink implements AnalysisContext {
+ final Linker _linker;
+
+ ContextForLink(this._linker);
+
+ @override
+ AnalysisOptionsForLink get analysisOptions => _linker.analysisOptions;
+
+ @override
+ TypeSystem get typeSystem => _linker.typeSystem;
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+/**
+ * An instance of [DependencyWalker] contains the core algorithms for
+ * walking a dependency graph and evaluating nodes in a safe order.
+ */
+abstract class DependencyWalker<NodeType extends Node<NodeType>> {
+ /**
+ * Called by [walk] to evaluate a single non-cyclical node, after
+ * all that node's dependencies have been evaluated.
+ */
+ void evaluate(NodeType v);
+
+ /**
+ * Called by [walk] to evaluate a strongly connected component
+ * containing one or more nodes. All dependencies of the strongly
+ * connected component have been evaluated.
+ */
+ void evaluateScc(List<NodeType> scc);
+
+ /**
+ * Walk the dependency graph starting at [startingPoint], finding
+ * strongly connected components and evaluating them in a safe order
+ * by calling [evaluate] and [evaluateScc].
+ *
+ * This is an implementation of Tarjan's strongly connected
+ * components algorithm
+ * (https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm).
+ */
+ void walk(NodeType startingPoint) {
+ // TODO(paulberry): consider rewriting in a non-recursive way so
+ // that long dependency chains don't cause stack overflow.
+
+ // TODO(paulberry): in the event that an exception occurs during
+ // the walk, restore the state of the [Node] data structures so
+ // that further evaluation will be safe.
+
+ // The index which will be assigned to the next node that is
+ // freshly visited.
+ int index = 1;
+
+ // Stack of nodes which have been seen so far and whose strongly
+ // connected component is still being determined. Nodes are only
+ // popped off the stack when they are evaluated, so sometimes the
+ // stack contains nodes that were visited after the current node.
+ List<NodeType> stack = <NodeType>[];
+
+ void strongConnect(NodeType node) {
+ bool hasTrivialCycle = false;
+
+ // Assign the current node an index and add it to the stack. We
+ // haven't seen any of its dependencies yet, so set its lowLink
+ // to its index, indicating that so far it is the only node in
+ // its strongly connected component.
+ node.index = node.lowLink = index++;
+ stack.add(node);
+
+ // Consider the node's dependencies one at a time.
+ for (NodeType dependency in node.dependencies) {
+ // If the dependency has already been evaluated, it can't be
+ // part of this node's strongly connected component, so we can
+ // skip it.
+ if (dependency.isEvaluated) {
+ continue;
+ }
+ if (identical(node, dependency)) {
+ // If a node includes itself as a dependency, there is no need to
+ // explore the dependency further.
+ hasTrivialCycle = true;
+ } else if (dependency.index == 0) {
+ // The dependency hasn't been seen yet, so recurse on it.
+ strongConnect(dependency);
+ // If the dependency's lowLink refers to a node that was
+ // visited before the current node, that means that the
+ // current node, the dependency, and the node referred to by
+ // the dependency's lowLink are all part of the same
+ // strongly connected component, so we need to update the
+ // current node's lowLink accordingly.
+ if (dependency.lowLink < node.lowLink) {
+ node.lowLink = dependency.lowLink;
+ }
+ } else {
+ // The dependency has already been seen, so it is part of
+ // the current node's strongly connected component. If it
+ // was visited earlier than the current node's lowLink, then
+ // it is a new addition to the current node's strongly
+ // connected component, so we need to update the current
+ // node's lowLink accordingly.
+ if (dependency.index < node.lowLink) {
+ node.lowLink = dependency.index;
+ }
+ }
+ }
+
+ // If the current node's lowLink is the same as its index, then
+ // we have finished visiting a strongly connected component, so
+ // pop the stack and evaluate it before moving on.
+ if (node.lowLink == node.index) {
+ // The strongly connected component has only one node. If there is a
+ // cycle, it's a trivial one.
+ if (identical(stack.last, node)) {
+ stack.removeLast();
+ if (hasTrivialCycle) {
+ evaluateScc(<NodeType>[node]);
+ } else {
+ evaluate(node);
+ }
+ } else {
+ // There are multiple nodes in the strongly connected
+ // component.
+ List<NodeType> scc = <NodeType>[];
+ while (true) {
+ NodeType otherNode = stack.removeLast();
+ scc.add(otherNode);
+ if (identical(otherNode, node)) {
+ break;
+ }
+ }
+ evaluateScc(scc);
+ }
+ }
+ }
+
+ // Kick off the algorithm starting with the starting point.
+ strongConnect(startingPoint);
+ }
+}
+
+/**
+ * Base class for executable elements resynthesized from a summary during
+ * linking.
+ */
+abstract class ExecutableElementForLink extends Object
+ with TypeParameterizedElementMixin, ParameterParentElementForLink
+ implements ExecutableElementImpl {
+ /**
+ * The unlinked representation of the method in the summary.
+ */
+ final UnlinkedExecutable _unlinkedExecutable;
+
+ DartType _declaredReturnType;
+ DartType _inferredReturnType;
+ FunctionTypeImpl _type;
+ String _name;
+ String _displayName;
+
+ final CompilationUnitElementForLink compilationUnit;
+
+ ExecutableElementForLink(this.compilationUnit, this._unlinkedExecutable);
+
+ @override
+ ContextForLink get context => compilationUnit.context;
+
+ /**
+ * If the executable element had an explicitly declared return type, return
+ * it. Otherwise return `null`.
+ */
+ DartType get declaredReturnType {
+ if (_unlinkedExecutable.returnType == null) {
+ return null;
+ } else {
+ return _declaredReturnType ??=
+ compilationUnit.resolveTypeRef(_unlinkedExecutable.returnType, this);
+ }
+ }
+
+ @override
+ String get displayName {
+ if (_displayName == null) {
+ _displayName = _unlinkedExecutable.name;
+ if (_unlinkedExecutable.kind == UnlinkedExecutableKind.setter) {
+ _displayName = _displayName.substring(0, _displayName.length - 1);
+ }
+ }
+ return _displayName;
+ }
+
+ @override
+ CompilationUnitElementImpl get enclosingUnit => compilationUnit;
+
+ @override
+ bool get hasImplicitReturnType => _unlinkedExecutable.returnType == null;
+
+ @override
+ List<int> get implicitFunctionTypeIndices => const <int>[];
+
+ /**
+ * Return the inferred return type of the executable element. Should only be
+ * called if no return type was explicitly declared.
+ */
+ DartType get inferredReturnType {
+ // We should only try to infer a return type when none is explicitly
+ // declared.
+ assert(_unlinkedExecutable.returnType == null);
+ if (Linker._initializerTypeInferenceCycle != null &&
+ Linker._initializerTypeInferenceCycle ==
+ compilationUnit.library.libraryCycleForLink) {
+ // We are currently computing the type of an initializer expression in the
+ // current library cycle, so type inference results should be ignored.
+ return _computeDefaultReturnType();
+ }
+ if (_inferredReturnType == null) {
+ if (_unlinkedExecutable.kind == UnlinkedExecutableKind.constructor) {
+ // TODO(paulberry): implement.
+ throw new UnimplementedError();
+ } else if (compilationUnit.isInBuildUnit) {
+ _inferredReturnType = _computeDefaultReturnType();
+ } else {
+ _inferredReturnType = compilationUnit.getLinkedType(
+ _unlinkedExecutable.inferredReturnTypeSlot, this);
+ }
+ }
+ return _inferredReturnType;
+ }
+
+ @override
+ bool get isStatic => _unlinkedExecutable.isStatic;
+
+ @override
+ bool get isSynthetic => false;
+
+ @override
+ LibraryElement get library => enclosingElement.library;
+
+ @override
+ String get name {
+ if (_name == null) {
+ _name = _unlinkedExecutable.name;
+ if (_name == '-' && _unlinkedExecutable.parameters.isEmpty) {
+ _name = 'unary-';
+ }
+ }
+ return _name;
+ }
+
+ @override
+ DartType get returnType => declaredReturnType ?? inferredReturnType;
+
+ @override
+ void set returnType(DartType inferredType) {
+ assert(_inferredReturnType == null);
+ _inferredReturnType = inferredType;
+ }
+
+ @override
+ FunctionTypeImpl get type => _type ??= new FunctionTypeImpl(this);
+
+ @override
+ TypeParameterizedElementMixin get typeParameterContext => this;
+
+ @override
+ List<UnlinkedParam> get unlinkedParameters => _unlinkedExecutable.parameters;
+
+ @override
+ List<UnlinkedTypeParam> get unlinkedTypeParams =>
+ _unlinkedExecutable.typeParameters;
+
+ @override
+ bool isAccessibleIn(LibraryElement library) =>
+ !Identifier.isPrivateName(name) || identical(this.library, library);
+
+ /**
+ * Compute the default return type for this type of executable element (if no
+ * return type is declared and strong mode type inference cannot infer a
+ * better return type).
+ */
+ DartType _computeDefaultReturnType() {
+ if (_unlinkedExecutable.kind == UnlinkedExecutableKind.setter &&
+ (library as LibraryElementForLink)._linker.strongMode) {
+ // In strong mode, setters without an explicit return type are
+ // considered to return `void`.
+ return VoidTypeImpl.instance;
+ } else {
+ return DynamicTypeImpl.instance;
+ }
+ }
+}
+
+/**
+ * Base class for executable elements that are resynthesized from a summary
+ * during linking and are not local functions.
+ */
+abstract class ExecutableElementForLink_NonLocal
+ extends ExecutableElementForLink {
+ /**
+ * Return the class in which this executable appears, maybe `null` for a
+ * top-level function.
+ */
+ final ClassElementForLink_Class enclosingClass;
+
+ ExecutableElementForLink_NonLocal(
+ CompilationUnitElementForLink compilationUnit,
+ this.enclosingClass,
+ UnlinkedExecutable unlinkedExecutable)
+ : super(compilationUnit, unlinkedExecutable);
+
+ @override
+ Element get enclosingElement => enclosingClass ?? compilationUnit;
+
+ @override
+ TypeParameterizedElementMixin get enclosingTypeParameterContext =>
+ enclosingClass;
+
+ /**
+ * Store the results of type inference for this method in [compilationUnit].
+ */
+ void link(CompilationUnitElementInBuildUnit compilationUnit) {
+ if (_unlinkedExecutable.returnType == null) {
+ compilationUnit._storeLinkedType(
+ _unlinkedExecutable.inferredReturnTypeSlot, inferredReturnType, this);
+ }
+ for (ParameterElementForLink parameterElement in parameters) {
+ parameterElement.link(compilationUnit);
+ }
+ }
+}
+
+class ExprTypeComputer {
+ final FunctionElementForLink_Local function;
+ final CompilationUnitElementForLink unit;
+ final LibraryElementForLink library;
+ final Linker linker;
+ final TypeProvider typeProvider;
+ final UnlinkedConst unlinkedConst;
+
+ final List<DartType> stack = <DartType>[];
+ int intPtr = 0;
+ int refPtr = 0;
+ int strPtr = 0;
+ int assignmentOperatorPtr = 0;
+
+ factory ExprTypeComputer(FunctionElementForLink_Local functionElement) {
+ CompilationUnitElementForLink unit = functionElement.compilationUnit;
+ LibraryElementForLink library = unit.enclosingElement;
+ Linker linker = library._linker;
+ TypeProvider typeProvider = linker.typeProvider;
+ UnlinkedConst unlinkedConst = functionElement._unlinkedExecutable.bodyExpr;
+ return new ExprTypeComputer._(
+ functionElement, unit, library, linker, typeProvider, unlinkedConst);
+ }
+
+ ExprTypeComputer._(this.function, this.unit, this.library, this.linker,
+ this.typeProvider, this.unlinkedConst);
+
+ DartType compute() {
+ if (unlinkedConst == null) {
+ // No function body was stored for this function, so we can't infer its
+ // return type. Assume `dynamic`.
+ return DynamicTypeImpl.instance;
+ }
+ // Perform RPN evaluation of the constant, using a stack of inferred types.
+ for (UnlinkedConstOperation operation in unlinkedConst.operations) {
+ switch (operation) {
+ case UnlinkedConstOperation.pushInt:
+ intPtr++;
+ stack.add(typeProvider.intType);
+ break;
+ case UnlinkedConstOperation.pushLongInt:
+ int numInts = _getNextInt();
+ intPtr += numInts;
+ stack.add(typeProvider.intType);
+ break;
+ case UnlinkedConstOperation.pushDouble:
+ stack.add(typeProvider.doubleType);
+ break;
+ case UnlinkedConstOperation.pushTrue:
+ case UnlinkedConstOperation.pushFalse:
+ stack.add(typeProvider.boolType);
+ break;
+ case UnlinkedConstOperation.pushString:
+ strPtr++;
+ stack.add(typeProvider.stringType);
+ break;
+ case UnlinkedConstOperation.concatenate:
+ stack.length -= _getNextInt();
+ stack.add(typeProvider.stringType);
+ break;
+ case UnlinkedConstOperation.makeSymbol:
+ strPtr++;
+ stack.add(typeProvider.symbolType);
+ break;
+ case UnlinkedConstOperation.pushNull:
+ stack.add(BottomTypeImpl.instance);
+ break;
+ case UnlinkedConstOperation.pushReference:
+ _doPushReference();
+ break;
+ case UnlinkedConstOperation.extractProperty:
+ _doExtractProperty();
+ break;
+ case UnlinkedConstOperation.invokeConstructor:
+ _doInvokeConstructor();
+ break;
+ case UnlinkedConstOperation.makeUntypedList:
+ _doMakeUntypedList();
+ break;
+ case UnlinkedConstOperation.makeUntypedMap:
+ _doMakeUntypedMap();
+ break;
+ case UnlinkedConstOperation.makeTypedList:
+ _doMakeTypedList();
+ break;
+ case UnlinkedConstOperation.makeTypedMap:
+ _doMakeTypeMap();
+ break;
+ case UnlinkedConstOperation.not:
+ stack.length -= 1;
+ stack.add(typeProvider.boolType);
+ break;
+ case UnlinkedConstOperation.complement:
+ _computePrefixExpressionType('~');
+ break;
+ case UnlinkedConstOperation.negate:
+ _computePrefixExpressionType('unary-');
+ break;
+ case UnlinkedConstOperation.and:
+ case UnlinkedConstOperation.or:
+ case UnlinkedConstOperation.equal:
+ case UnlinkedConstOperation.notEqual:
+ stack.length -= 2;
+ stack.add(typeProvider.boolType);
+ break;
+ case UnlinkedConstOperation.bitXor:
+ _computeBinaryExpressionType(TokenType.CARET);
+ break;
+ case UnlinkedConstOperation.bitAnd:
+ _computeBinaryExpressionType(TokenType.AMPERSAND);
+ break;
+ case UnlinkedConstOperation.bitOr:
+ _computeBinaryExpressionType(TokenType.BAR);
+ break;
+ case UnlinkedConstOperation.bitShiftRight:
+ _computeBinaryExpressionType(TokenType.GT_GT);
+ break;
+ case UnlinkedConstOperation.bitShiftLeft:
+ _computeBinaryExpressionType(TokenType.LT_LT);
+ break;
+ case UnlinkedConstOperation.add:
+ _computeBinaryExpressionType(TokenType.PLUS);
+ break;
+ case UnlinkedConstOperation.subtract:
+ _computeBinaryExpressionType(TokenType.MINUS);
+ break;
+ case UnlinkedConstOperation.multiply:
+ _computeBinaryExpressionType(TokenType.STAR);
+ break;
+ case UnlinkedConstOperation.divide:
+ _computeBinaryExpressionType(TokenType.SLASH);
+ break;
+ case UnlinkedConstOperation.floorDivide:
+ _computeBinaryExpressionType(TokenType.TILDE_SLASH);
+ break;
+ case UnlinkedConstOperation.greater:
+ _computeBinaryExpressionType(TokenType.GT);
+ break;
+ case UnlinkedConstOperation.less:
+ _computeBinaryExpressionType(TokenType.LT);
+ break;
+ case UnlinkedConstOperation.greaterEqual:
+ _computeBinaryExpressionType(TokenType.GT_EQ);
+ break;
+ case UnlinkedConstOperation.lessEqual:
+ _computeBinaryExpressionType(TokenType.LT_EQ);
+ break;
+ case UnlinkedConstOperation.modulo:
+ _computeBinaryExpressionType(TokenType.PERCENT);
+ break;
+ case UnlinkedConstOperation.conditional:
+ _doConditional();
+ break;
+ case UnlinkedConstOperation.assignToRef:
+ _doAssignToRef();
+ break;
+ case UnlinkedConstOperation.assignToProperty:
+ _doAssignToProperty();
+ break;
+ case UnlinkedConstOperation.assignToIndex:
+ _doAssignToIndex();
+ break;
+ case UnlinkedConstOperation.extractIndex:
+ _doExtractIndex();
+ break;
+ case UnlinkedConstOperation.invokeMethodRef:
+ _doInvokeMethodRef();
+ break;
+ case UnlinkedConstOperation.invokeMethod:
+ _doInvokeMethod();
+ break;
+ case UnlinkedConstOperation.cascadeSectionBegin:
+ stack.add(stack.last);
+ break;
+ case UnlinkedConstOperation.cascadeSectionEnd:
+ stack.removeLast();
+ break;
+ case UnlinkedConstOperation.typeCast:
+ stack.removeLast();
+ DartType type = _getNextTypeRef();
+ stack.add(type);
+ break;
+ case UnlinkedConstOperation.typeCheck:
+ stack.removeLast();
+ refPtr++;
+ stack.add(typeProvider.boolType);
+ break;
+ case UnlinkedConstOperation.throwException:
+ stack.removeLast();
+ stack.add(BottomTypeImpl.instance);
+ break;
+ case UnlinkedConstOperation.pushLocalFunctionReference:
+ int popCount = _getNextInt();
+ assert(popCount == 0); // TODO(paulberry): handle the nonzero case.
+ stack.add(function.functions[_getNextInt()].type);
+ break;
+ case UnlinkedConstOperation.pushParameter:
+ stack.add(_findParameterType(_getNextString()));
+ break;
+ default:
+ // TODO(paulberry): implement.
+ throw new UnimplementedError('$operation');
+ }
+ }
+ assert(intPtr == unlinkedConst.ints.length);
+ assert(refPtr == unlinkedConst.references.length);
+ assert(strPtr == unlinkedConst.strings.length);
+ assert(assignmentOperatorPtr == unlinkedConst.assignmentOperators.length);
+ assert(stack.length == 1);
+ return stack[0];
+ }
+
+ void _computeBinaryExpressionType(TokenType operator) {
+ DartType right = stack.removeLast();
+ DartType left = stack.removeLast();
+ _pushBinaryOperatorType(left, operator, right);
+ }
+
+ void _computePrefixExpressionType(String operatorName) {
+ DartType operand = stack.removeLast();
+ if (operand is InterfaceType) {
+ MethodElement method =
+ operand.lookUpInheritedMethod(operatorName, library: library);
+ if (method != null) {
+ DartType type = method.returnType;
+ stack.add(type);
+ return;
+ }
+ }
+ stack.add(DynamicTypeImpl.instance);
+ }
+
+ void _doAssignToIndex() {
+ stack.removeLast();
+ stack.removeLast();
+ UnlinkedExprAssignOperator operator =
+ unlinkedConst.assignmentOperators[assignmentOperatorPtr++];
+ if (operator == UnlinkedExprAssignOperator.assign) {
+ // The type of the assignment is the type of the value,
+ // which is already in the stack.
+ } else if (isIncrementOrDecrement(operator)) {
+ // TODO(scheglov) implement
+ stack.add(DynamicTypeImpl.instance);
+ } else {
+ stack.removeLast();
+ // TODO(scheglov) implement
+ stack.add(DynamicTypeImpl.instance);
+ }
+ }
+
+ void _doAssignToProperty() {
+ DartType targetType = stack.removeLast();
+ String propertyName = _getNextString();
+ UnlinkedExprAssignOperator assignOperator =
+ unlinkedConst.assignmentOperators[assignmentOperatorPtr++];
+ if (assignOperator == UnlinkedExprAssignOperator.assign) {
+ // The type of the assignment is the type of the value,
+ // which is already in the stack.
+ } else if (assignOperator == UnlinkedExprAssignOperator.postfixDecrement ||
+ assignOperator == UnlinkedExprAssignOperator.postfixIncrement) {
+ DartType propertyType = _getPropertyType(targetType, propertyName);
+ stack.add(propertyType);
+ } else if (assignOperator == UnlinkedExprAssignOperator.prefixDecrement) {
+ _pushPropertyBinaryExpression(
+ targetType, propertyName, TokenType.MINUS, typeProvider.intType);
+ } else if (assignOperator == UnlinkedExprAssignOperator.prefixIncrement) {
+ _pushPropertyBinaryExpression(
+ targetType, propertyName, TokenType.PLUS, typeProvider.intType);
+ } else {
+ TokenType binaryOperator =
+ _convertAssignOperatorToTokenType(assignOperator);
+ DartType operandType = stack.removeLast();
+ _pushPropertyBinaryExpression(
+ targetType, propertyName, binaryOperator, operandType);
+ }
+ }
+
+ void _doAssignToRef() {
+ refPtr++;
+ UnlinkedExprAssignOperator operator =
+ unlinkedConst.assignmentOperators[assignmentOperatorPtr++];
+ if (operator == UnlinkedExprAssignOperator.assign) {
+ // The type of the assignment is the type of the value,
+ // which is already in the stack.
+ } else if (isIncrementOrDecrement(operator)) {
+ // TODO(scheglov) implement
+ stack.add(DynamicTypeImpl.instance);
+ } else {
+ stack.removeLast();
+ // TODO(scheglov) implement
+ stack.add(DynamicTypeImpl.instance);
+ }
+ }
+
+ void _doConditional() {
+ DartType elseType = stack.removeLast();
+ DartType thenType = stack.removeLast();
+ stack.removeLast();
+ DartType type = _leastUpperBound(thenType, elseType);
+ type = _dynamicIfNull(type);
+ stack.add(type);
+ }
+
+ void _doExtractIndex() {
+ stack.removeLast(); // index
+ DartType target = stack.removeLast();
+ stack.add(() {
+ if (target is InterfaceType) {
+ MethodElement method =
+ target.lookUpInheritedMethod('[]', library: library);
+ if (method != null) {
+ return method.returnType;
+ }
+ }
+ return DynamicTypeImpl.instance;
+ }());
+ }
+
+ void _doExtractProperty() {
+ DartType target = stack.removeLast();
+ String propertyName = _getNextString();
+ stack.add(() {
+ if (target is InterfaceType) {
+ ExecutableElement element = target
+ .lookUpInheritedGetterOrMethod(propertyName, library: library);
+ if (element != null) {
+ if (element is PropertyAccessorElement) {
+ return element.returnType;
+ } else {
+ // Method tear-off
+ return element.type;
+ }
+ }
+ }
+ return DynamicTypeImpl.instance;
+ }());
+ }
+
+ void _doInvokeConstructor() {
+ int numNamed = _getNextInt();
+ int numPositional = _getNextInt();
+ // TODO(paulberry): don't just pop the args; use their types
+ // to infer the type of type arguments.
+ stack.length -= numNamed + numPositional;
+ strPtr += numNamed;
+ EntityRef ref = _getNextRef();
+ ClassElementForLink_Class element =
+ unit.resolveConstructorClassRef(ref.reference).asClass;
+ if (element != null) {
+ stack.add(element.buildType((int i) {
+ // Type argument explicitly specified.
+ if (i < ref.typeArguments.length) {
+ return unit.resolveTypeRef(
+ ref.typeArguments[i], function.typeParameterContext);
+ } else {
+ return null;
+ }
+ }, const []));
+ } else {
+ stack.add(DynamicTypeImpl.instance);
+ }
+ }
+
+ void _doInvokeMethod() {
+ int numNamed = unlinkedConst.ints[intPtr++];
+ int numPositional = unlinkedConst.ints[intPtr++];
+ List<String> namedArgNames = _getNextStrings(numNamed);
+ List<DartType> namedArgTypeList = _popList(numNamed);
+ List<DartType> positionalArgTypes = _popList(numPositional);
+ // TODO(scheglov) if we pushed target and method name first, we might be
+ // able to move work with arguments in _inferExecutableType()
+ String methodName = _getNextString();
+ List<DartType> typeArguments = _getTypeArguments();
+ DartType target = stack.removeLast();
+ stack.add(() {
+ if (target is InterfaceType) {
+ MethodElement method =
+ target.lookUpInheritedMethod(methodName, library: library);
+ FunctionType rawType = method?.type;
+ FunctionType inferredType = _inferExecutableType(
+ rawType,
+ numNamed,
+ numPositional,
+ namedArgNames,
+ namedArgTypeList,
+ positionalArgTypes,
+ typeArguments);
+ if (inferredType != null) {
+ return inferredType.returnType;
+ }
+ }
+ return DynamicTypeImpl.instance;
+ }());
+ }
+
+ void _doInvokeMethodRef() {
+ int numNamed = _getNextInt();
+ int numPositional = _getNextInt();
+ List<String> namedArgNames = _getNextStrings(numNamed);
+ List<DartType> namedArgTypeList = _popList(numNamed);
+ List<DartType> positionalArgTypes = _popList(numPositional);
+ EntityRef ref = _getNextRef();
+ ReferenceableElementForLink element = unit.resolveRef(ref.reference);
+ List<DartType> typeArguments = _getTypeArguments();
+ stack.add(() {
+ DartType rawType = element.asStaticType;
+ if (rawType is FunctionType) {
+ FunctionType inferredType = _inferExecutableType(
+ rawType,
+ numNamed,
+ numPositional,
+ namedArgNames,
+ namedArgTypeList,
+ positionalArgTypes,
+ typeArguments);
+ if (inferredType != null) {
+ return inferredType.returnType;
+ }
+ }
+ return DynamicTypeImpl.instance;
+ }());
+ }
+
+ void _doMakeTypedList() {
+ DartType itemType = _getNextTypeRef();
+ stack.length -= _getNextInt();
+ stack.add(typeProvider.listType.instantiate(<DartType>[itemType]));
+ }
+
+ void _doMakeTypeMap() {
+ DartType keyType = _getNextTypeRef();
+ DartType valueType = _getNextTypeRef();
+ stack.length -= 2 * _getNextInt();
+ stack.add(typeProvider.mapType.instantiate(<DartType>[keyType, valueType]));
+ }
+
+ void _doMakeUntypedList() {
+ int numItems = _getNextInt();
+ DartType itemType = numItems == 0
+ ? DynamicTypeImpl.instance
+ : _popList(numItems).reduce(_leastUpperBound);
+ itemType = _dynamicIfNull(itemType);
+ stack.add(typeProvider.listType.instantiate(<DartType>[itemType]));
+ }
+
+ void _doMakeUntypedMap() {
+ int numEntries = _getNextInt();
+ List<DartType> keysValues = _popList(2 * numEntries);
+ DartType keyType = null;
+ DartType valueType = null;
+ for (int i = 0; i < 2 * numEntries; i++) {
+ DartType type = keysValues[i];
+ if (i.isEven) {
+ keyType = keyType == null ? type : _leastUpperBound(keyType, type);
+ } else {
+ valueType =
+ valueType == null ? type : _leastUpperBound(valueType, type);
+ }
+ }
+ keyType = _dynamicIfNull(keyType);
+ valueType = _dynamicIfNull(valueType);
+ stack.add(typeProvider.mapType.instantiate(<DartType>[keyType, valueType]));
+ }
+
+ void _doPushReference() {
+ EntityRef ref = _getNextRef();
+ if (ref.paramReference != 0) {
+ stack.add(typeProvider.typeType);
+ } else {
+ // Synthetic function types can't be directly referred
+ // to by expressions.
+ assert(ref.syntheticReturnType == null);
+ // Nor can implicit function types derived from
+ // function-typed parameters.
+ assert(ref.implicitFunctionTypeIndices.isEmpty);
+ ReferenceableElementForLink element = unit.resolveRef(ref.reference);
+ stack.add(element.asStaticType);
+ }
+ }
+
+ /**
+ * Find the parameter in scope called [parameterName] and return its type.
+ */
+ DartType _findParameterType(String parameterName) {
+ FunctionElementForLink_Local f = this.function;
+ while (true) {
+ for (ParameterElement parameter in f.parameters) {
+ if (parameter.name == parameterName) {
+ return parameter.type;
+ }
+ }
+ Element parent = f.enclosingElement;
+ if (parent is FunctionElementForLink_Local) {
+ f = parent;
+ } else {
+ // Parameter not found. This should never happen in a well-formed
+ // summary.
+ assert(false);
+ return DynamicTypeImpl.instance;
+ }
+ }
+ }
+
+ int _getNextInt() {
+ return unlinkedConst.ints[intPtr++];
+ }
+
+ EntityRef _getNextRef() => unlinkedConst.references[refPtr++];
+
+ String _getNextString() {
+ return unlinkedConst.strings[strPtr++];
+ }
+
+ List<String> _getNextStrings(int n) {
+ List<String> result = new List<String>(n);
+ for (int i = 0; i < n; i++) {
+ result[i] = _getNextString();
+ }
+ return result;
+ }
+
+ DartType _getNextTypeRef() {
+ EntityRef ref = _getNextRef();
+ return unit.resolveTypeRef(ref, function.typeParameterContext);
+ }
+
+ /**
+ * Return the type of the property with the given [propertyName] in the
+ * given [targetType]. May return `dynamic` if the property cannot be
+ * resolved.
+ */
+ DartType _getPropertyType(DartType targetType, String propertyName) {
+ return targetType is InterfaceType
+ ? targetType
+ .lookUpInheritedGetter(propertyName, library: library)
+ ?.returnType
+ : DynamicTypeImpl.instance;
+ }
+
+ List<DartType> _getTypeArguments() {
+ int numTypeArguments = _getNextInt();
+ List<DartType> typeArguments = new List<DartType>(numTypeArguments);
+ for (int i = 0; i < numTypeArguments; i++) {
+ typeArguments[i] = _getNextTypeRef();
+ }
+ return typeArguments;
+ }
+
+ FunctionType _inferExecutableType(
+ FunctionType rawMethodType,
+ int numNamed,
+ int numPositional,
+ List<String> namedArgNames,
+ List<DartType> namedArgTypeList,
+ List<DartType> positionalArgTypes,
+ List<DartType> typeArguments) {
+ TypeSystem ts = linker.typeSystem;
+ if (rawMethodType != null) {
+ if (rawMethodType.typeFormals.isNotEmpty && typeArguments.isNotEmpty) {
+ Element methodElement = rawMethodType.element;
+ if (methodElement is TypeParameterizedElement &&
+ methodElement.typeParameters.length == typeArguments.length) {
+ return rawMethodType.instantiate(typeArguments);
+ }
+ } else if (rawMethodType.typeFormals.isNotEmpty &&
+ ts is StrongTypeSystemImpl) {
+ List<DartType> paramTypes = <DartType>[];
+ List<DartType> argTypes = <DartType>[];
+ // Add positional parameter and argument types.
+ for (int i = 0; i < numPositional; i++) {
+ ParameterElement parameter = rawMethodType.parameters[i];
+ if (parameter != null) {
+ paramTypes.add(parameter.type);
+ argTypes.add(positionalArgTypes[i]);
+ }
+ }
+ // Prepare named argument types map.
+ Map<String, DartType> namedArgTypes = <String, DartType>{};
+ for (int i = 0; i < numNamed; i++) {
+ String name = namedArgNames[i];
+ DartType type = namedArgTypeList[i];
+ namedArgTypes[name] = type;
+ }
+ // Add named parameter and argument types.
+ Map<String, DartType> namedParameterTypes =
+ rawMethodType.namedParameterTypes;
+ namedArgTypes.forEach((String name, DartType argType) {
+ DartType parameterType = namedParameterTypes[name];
+ if (parameterType != null) {
+ paramTypes.add(parameterType);
+ argTypes.add(argType);
+ }
+ });
+ // Perform inference.
+ FunctionType inferred = ts.inferGenericFunctionCall(
+ typeProvider,
+ rawMethodType,
+ paramTypes,
+ argTypes,
+ rawMethodType.returnType,
+ null);
+ return inferred;
+ }
+ }
+ // Not a generic function type, use the raw type.
+ return rawMethodType;
+ }
+
+ DartType _leastUpperBound(DartType s, DartType t) {
+ return linker.typeSystem.getLeastUpperBound(typeProvider, s, t);
+ }
+
+ List<DartType> _popList(int n) {
+ List<DartType> result = stack.sublist(stack.length - n, stack.length);
+ stack.length -= n;
+ return result;
+ }
+
+ void _pushBinaryOperatorType(
+ DartType left, TokenType operator, DartType right) {
+ if (left is InterfaceType) {
+ MethodElement method =
+ left.lookUpInheritedMethod(operator.lexeme, library: library);
+ if (method != null) {
+ DartType type = method.returnType;
+ type = linker.typeSystem.refineBinaryExpressionType(
+ typeProvider, left, operator, right, type);
+ stack.add(type);
+ return;
+ }
+ }
+ stack.add(DynamicTypeImpl.instance);
+ }
+
+ /**
+ * Extract the property with the given [propertyName], apply the operator
+ * with the given [operandType], push the type of applying operand of the
+ * given [operandType].
+ */
+ void _pushPropertyBinaryExpression(DartType targetType, String propertyName,
+ TokenType operator, DartType operandType) {
+ DartType propertyType = _getPropertyType(targetType, propertyName);
+ _pushBinaryOperatorType(propertyType, operator, operandType);
+ }
+
+ static TokenType _convertAssignOperatorToTokenType(
+ UnlinkedExprAssignOperator o) {
+ switch (o) {
+ case UnlinkedExprAssignOperator.assign:
+ return null;
+ case UnlinkedExprAssignOperator.ifNull:
+ return TokenType.QUESTION_QUESTION;
+ case UnlinkedExprAssignOperator.multiply:
+ return TokenType.STAR;
+ case UnlinkedExprAssignOperator.divide:
+ return TokenType.SLASH;
+ case UnlinkedExprAssignOperator.floorDivide:
+ return TokenType.TILDE_SLASH;
+ case UnlinkedExprAssignOperator.modulo:
+ return TokenType.PERCENT;
+ case UnlinkedExprAssignOperator.plus:
+ return TokenType.PLUS;
+ case UnlinkedExprAssignOperator.minus:
+ return TokenType.MINUS;
+ case UnlinkedExprAssignOperator.shiftLeft:
+ return TokenType.LT_LT;
+ case UnlinkedExprAssignOperator.shiftRight:
+ return TokenType.GT_GT;
+ case UnlinkedExprAssignOperator.bitAnd:
+ return TokenType.AMPERSAND;
+ case UnlinkedExprAssignOperator.bitXor:
+ return TokenType.CARET;
+ case UnlinkedExprAssignOperator.bitOr:
+ return TokenType.BAR;
+ case UnlinkedExprAssignOperator.prefixIncrement:
+ return TokenType.PLUS_PLUS;
+ case UnlinkedExprAssignOperator.prefixDecrement:
+ return TokenType.MINUS_MINUS;
+ case UnlinkedExprAssignOperator.postfixIncrement:
+ return TokenType.PLUS_PLUS;
+ case UnlinkedExprAssignOperator.postfixDecrement:
+ return TokenType.MINUS_MINUS;
+ }
+ return null;
+ }
+}
+
+/**
+ * Element representing a field resynthesized from a summary during
+ * linking.
+ */
+abstract class FieldElementForLink implements FieldElement {
+ @override
+ PropertyAccessorElementForLink get getter;
+
+ @override
+ PropertyAccessorElementForLink get setter;
+}
+
+/**
+ * Specialization of [FieldElementForLink] for class fields.
+ */
+class FieldElementForLink_ClassField extends VariableElementForLink
+ implements FieldElementForLink {
+ @override
+ final ClassElementForLink_Class enclosingElement;
+
+ /**
+ * If this is an instance field, the type that was computed by
+ * [InstanceMemberInferrer] (if any). Otherwise `null`.
+ */
+ DartType _inferredInstanceType;
+
+ FieldElementForLink_ClassField(ClassElementForLink_Class enclosingElement,
+ UnlinkedVariable unlinkedVariable)
+ : enclosingElement = enclosingElement,
+ super(unlinkedVariable, enclosingElement.enclosingElement);
+
+ @override
+ bool get isStatic => unlinkedVariable.isStatic;
+
+ @override
+ void set type(DartType inferredType) {
+ assert(!isStatic);
+ assert(_inferredInstanceType == null);
+ _inferredInstanceType = inferredType;
+ }
+
+ @override
+ TypeParameterizedElementMixin get _typeParameterContext => enclosingElement;
+
+ /**
+ * Store the results of type inference for this field in
+ * [compilationUnit].
+ */
+ void link(CompilationUnitElementInBuildUnit compilationUnit) {
+ if (hasImplicitType) {
+ compilationUnit._storeLinkedType(
+ unlinkedVariable.inferredTypeSlot,
+ isStatic ? inferredType : _inferredInstanceType,
+ _typeParameterContext);
+ initializer?.link(compilationUnit);
+ }
+ }
+
+ @override
+ String toString() => '$enclosingElement.$name';
+}
+
+/**
+ * Specialization of [FieldElementForLink] for enum fields.
+ */
+class FieldElementForLink_EnumField extends FieldElementForLink
+ implements FieldElement {
+ /**
+ * The unlinked representation of the field in the summary, or `null` if this
+ * is an enum's `values` field.
+ */
+ final UnlinkedEnumValue unlinkedEnumValue;
+
+ PropertyAccessorElementForLink_EnumField _getter;
+
+ @override
+ final ClassElementForLink_Enum enclosingElement;
+
+ FieldElementForLink_EnumField(this.unlinkedEnumValue, this.enclosingElement);
+
+ @override
+ PropertyAccessorElementForLink_EnumField get getter =>
+ _getter ??= new PropertyAccessorElementForLink_EnumField(this);
+
+ @override
+ bool get isStatic => true;
+
+ @override
+ bool get isSynthetic => false;
+
+ @override
+ String get name =>
+ unlinkedEnumValue == null ? 'values' : unlinkedEnumValue.name;
+
+ @override
+ DartType get type => unlinkedEnumValue == null
+ ? enclosingElement.valuesType
+ : enclosingElement.type;
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+
+ @override
+ String toString() => '$enclosingElement.$name';
+}
+
+/**
+ * Element representing a function-typed parameter resynthesied from a summary
+ * during linking.
+ */
+class FunctionElementForLink_FunctionTypedParam extends Object
+ with ParameterParentElementForLink
+ implements FunctionElement {
+ @override
+ final ParameterElementForLink enclosingElement;
+
+ @override
+ final TypeParameterizedElementMixin typeParameterContext;
+
+ @override
+ final List<UnlinkedParam> unlinkedParameters;
+
+ DartType _returnType;
+ List<int> _implicitFunctionTypeIndices;
+
+ FunctionElementForLink_FunctionTypedParam(this.enclosingElement,
+ this.typeParameterContext, this.unlinkedParameters);
+
+ @override
+ List<int> get implicitFunctionTypeIndices {
+ if (_implicitFunctionTypeIndices == null) {
+ _implicitFunctionTypeIndices = enclosingElement
+ .enclosingElement.implicitFunctionTypeIndices
+ .toList();
+ _implicitFunctionTypeIndices.add(enclosingElement._parameterIndex);
+ }
+ return _implicitFunctionTypeIndices;
+ }
+
+ @override
+ DartType get returnType {
+ if (_returnType == null) {
+ if (enclosingElement._unlinkedParam.type == null) {
+ _returnType = DynamicTypeImpl.instance;
+ } else {
+ _returnType = enclosingElement.compilationUnit.resolveTypeRef(
+ enclosingElement._unlinkedParam.type, typeParameterContext);
+ }
+ }
+ return _returnType;
+ }
+
+ @override
+ List<TypeParameterElement> get typeParameters => const [];
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+/**
+ * Element representing the initializer expression of a variable.
+ */
+class FunctionElementForLink_Initializer extends Object
+ with ReferenceableElementForLink, TypeParameterizedElementMixin
+ implements FunctionElementForLink_Local {
+ /**
+ * The variable for which this element is the initializer.
+ */
+ final VariableElementForLink _variable;
+
+ /**
+ * The type inference node for this function, or `null` if it hasn't been
+ * computed yet.
+ */
+ TypeInferenceNode _typeInferenceNode;
+
+ List<FunctionElementForLink_Local_NonSynthetic> _functions;
+ DartType _inferredReturnType;
+
+ FunctionElementForLink_Initializer(this._variable);
+
+ @override
+ TypeInferenceNode get asTypeInferenceNode =>
+ _typeInferenceNode ??= new TypeInferenceNode(this);
+
+ @override
+ CompilationUnitElementForLink get compilationUnit =>
+ _variable.compilationUnit;
+
+ @override
+ VariableElementForLink get enclosingElement => _variable;
+
+ TypeParameterizedElementMixin get enclosingTypeParameterContext =>
+ _variable.enclosingElement is ClassElementForLink
+ ? _variable.enclosingElement
+ : null;
+
+ @override
+ CompilationUnitElementForLink get enclosingUnit => _variable.compilationUnit;
+
+ @override
+ List<FunctionElementForLink_Local_NonSynthetic> get functions =>
+ _functions ??= _variable.unlinkedVariable.initializer.localFunctions
+ .map((UnlinkedExecutable ex) =>
+ new FunctionElementForLink_Local_NonSynthetic(
+ _variable.compilationUnit, this, ex))
+ .toList();
+
+ @override
+ DartType get returnType {
+ // If this is a variable whose type needs inferring, infer it.
+ if (_variable.hasImplicitType) {
+ return _variable.inferredType;
+ } else {
+ // There's no reason linking should need to access the type of
+ // this FunctionElement, since the variable doesn't need its
+ // type inferred.
+ assert(false);
+ // But for robustness, return the dynamic type.
+ return DynamicTypeImpl.instance;
+ }
+ }
+
+ @override
+ void set returnType(DartType newType) {
+ // InstanceMemberInferrer stores the new type both here and on the variable
+ // element. We don't need to record both values, so we ignore it here.
+ }
+
+ @override
+ TypeParameterizedElementMixin get typeParameterContext => this;
+
+ @override
+ List<UnlinkedTypeParam> get unlinkedTypeParams => const [];
+
+ @override
+ bool get _hasTypeBeenInferred => _inferredReturnType != null;
+
+ @override
+ UnlinkedExecutable get _unlinkedExecutable =>
+ _variable.unlinkedVariable.initializer;
+
+ @override
+ FunctionElementForLink_Local getLocalFunction(int index) {
+ List<FunctionElementForLink_Local_NonSynthetic> functions = this.functions;
+ return index < functions.length ? functions[index] : null;
+ }
+
+ /**
+ * Store the results of type inference for this initializer in
+ * [compilationUnit].
+ */
+ void link(CompilationUnitElementInBuildUnit compilationUnit) {
+ compilationUnit._storeLinkedType(_unlinkedExecutable.inferredReturnTypeSlot,
+ _inferredReturnType, typeParameterContext);
+ for (FunctionElementForLink_Local_NonSynthetic function in functions) {
+ function.link(compilationUnit);
+ }
+ }
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+
+ @override
+ void _setInferredType(DartType type) {
+ assert(!_hasTypeBeenInferred);
+ _inferredReturnType = type;
+ _variable._inferredType = _dynamicIfNull(type);
+ }
+}
+
+/**
+ * Element representing a local function (possibly a closure).
+ */
+abstract class FunctionElementForLink_Local
+ implements
+ ExecutableElementForLink,
+ FunctionElementImpl,
+ ReferenceableElementForLink {
+ /**
+ * Indicates whether type inference has completed for this function.
+ */
+ bool get _hasTypeBeenInferred;
+
+ /**
+ * Stores the given [type] as the inferred return type for this function.
+ * Should only be called if [_hasTypeBeenInferred] is `false`.
+ */
+ void _setInferredType(DartType type);
+}
+
+/**
+ * Element representing a local function (possibly a closure) inside another
+ * executable.
+ */
+class FunctionElementForLink_Local_NonSynthetic extends ExecutableElementForLink
+ with ReferenceableElementForLink
+ implements FunctionElementForLink_Local {
+ @override
+ final ExecutableElementForLink enclosingElement;
+
+ List<FunctionElementForLink_Local_NonSynthetic> _functions;
+
+ /**
+ * The type inference node for this function, or `null` if it hasn't been
+ * computed yet.
+ */
+ TypeInferenceNode _typeInferenceNode;
+
+ FunctionElementForLink_Local_NonSynthetic(
+ CompilationUnitElementForLink compilationUnit,
+ this.enclosingElement,
+ UnlinkedExecutable unlinkedExecutable)
+ : super(compilationUnit, unlinkedExecutable);
+
+ @override
+ TypeInferenceNode get asTypeInferenceNode =>
+ _typeInferenceNode ??= new TypeInferenceNode(this);
+
+ @override
+ TypeParameterizedElementMixin get enclosingTypeParameterContext =>
+ enclosingElement;
+
+ @override
+ List<FunctionElementForLink_Local_NonSynthetic> get functions =>
+ _functions ??= _unlinkedExecutable.localFunctions
+ .map((UnlinkedExecutable ex) =>
+ new FunctionElementForLink_Local_NonSynthetic(
+ compilationUnit, this, ex))
+ .toList();
+
+ @override
+ bool get _hasTypeBeenInferred => _inferredReturnType != null;
+
+ @override
+ DartType buildType(
+ DartType getTypeArgument(int i), List<int> implicitFunctionTypeIndices) {
+ assert(implicitFunctionTypeIndices.isEmpty);
+ return type;
+ }
+
+ @override
+ FunctionElementForLink_Local getLocalFunction(int index) {
+ List<FunctionElementForLink_Local_NonSynthetic> functions = this.functions;
+ return index < functions.length ? functions[index] : null;
+ }
+
+ /**
+ * Store the results of type inference for this function in [compilationUnit].
+ */
+ void link(CompilationUnitElementInBuildUnit compilationUnit) {
+ compilationUnit._storeLinkedType(
+ _unlinkedExecutable.inferredReturnTypeSlot, inferredReturnType, this);
+ for (FunctionElementForLink_Local_NonSynthetic function in functions) {
+ function.link(compilationUnit);
+ }
+ }
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+
+ @override
+ void _setInferredType(DartType type) {
+ // TODO(paulberry): store the inferred return type in the summary.
+ assert(!_hasTypeBeenInferred);
+ _inferredReturnType = _dynamicIfNull(type);
+ }
+}
+
+/**
+ * Element representing a typedef resynthesized from a summary during linking.
+ */
+class FunctionTypeAliasElementForLink extends Object
+ with
+ TypeParameterizedElementMixin,
+ ParameterParentElementForLink,
+ ReferenceableElementForLink
+ implements FunctionTypeAliasElement, ElementImpl {
+ @override
+ final CompilationUnitElementForLink enclosingElement;
+
+ /**
+ * The unlinked representation of the typedef in the summary.
+ */
+ final UnlinkedTypedef _unlinkedTypedef;
+
+ FunctionTypeImpl _type;
+ DartType _returnType;
+
+ FunctionTypeAliasElementForLink(this.enclosingElement, this._unlinkedTypedef);
+
+ @override
+ DartType get asStaticType {
+ return enclosingElement.enclosingElement._linker.typeProvider.typeType;
+ }
+
+ @override
+ ContextForLink get context => enclosingElement.context;
+
+ @override
+ TypeParameterizedElementMixin get enclosingTypeParameterContext => null;
+
+ @override
+ CompilationUnitElementImpl get enclosingUnit => enclosingElement;
+
+ @override
+ String get identifier => _unlinkedTypedef.name;
+
+ @override
+ List<int> get implicitFunctionTypeIndices => const <int>[];
+
+ @override
+ bool get isSynthetic => false;
+
+ @override
+ LibraryElementForLink get library => enclosingElement.library;
+
+ @override
+ String get name => _unlinkedTypedef.name;
+
+ @override
+ DartType get returnType => _returnType ??=
+ enclosingElement.resolveTypeRef(_unlinkedTypedef.returnType, this);
+
+ @override
+ TypeParameterizedElementMixin get typeParameterContext => this;
+
+ @override
+ List<UnlinkedParam> get unlinkedParameters => _unlinkedTypedef.parameters;
+
+ @override
+ List<UnlinkedTypeParam> get unlinkedTypeParams =>
+ _unlinkedTypedef.typeParameters;
+
+ @override
+ DartType buildType(
+ DartType getTypeArgument(int i), List<int> implicitFunctionTypeIndices) {
+ int numTypeParameters = _unlinkedTypedef.typeParameters.length;
+ if (numTypeParameters != 0) {
+ List<DartType> typeArguments =
+ new List<DartType>.generate(numTypeParameters, getTypeArgument);
+ if (typeArguments.contains(null)) {
+ return context.typeSystem
+ .instantiateToBounds(new FunctionTypeImpl.forTypedef(this));
+ } else {
+ return new FunctionTypeImpl.elementWithNameAndArgs(
+ this, name, typeArguments, true);
+ }
+ } else {
+ return _type ??= new FunctionTypeImpl.forTypedef(this);
+ }
+ }
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+
+ @override
+ String toString() => '$enclosingElement.$name';
+}
+
+/**
+ * Specialization of [DependencyWalker] for linking library cycles.
+ */
+class LibraryCycleDependencyWalker extends DependencyWalker<LibraryCycleNode> {
+ @override
+ void evaluate(LibraryCycleNode v) {
+ v.link();
+ }
+
+ @override
+ void evaluateScc(List<LibraryCycleNode> scc) {
+ // There should never be a cycle among library cycles.
+ throw new StateError('Cycle among library cycles');
+ }
+}
+
+/**
+ * An instance of [LibraryCycleForLink] represents a single library cycle
+ * discovered during linking; it consists of one or more libraries in the build
+ * unit being linked.
+ */
+class LibraryCycleForLink {
+ /**
+ * The libraries in the cycle.
+ */
+ final List<LibraryElementInBuildUnit> libraries;
+
+ /**
+ * The library cycles which this library depends on.
+ */
+ final List<LibraryCycleForLink> dependencies;
+
+ /**
+ * The [LibraryCycleNode] for this library cycle.
+ */
+ LibraryCycleNode _node;
+
+ LibraryCycleForLink(this.libraries, this.dependencies) {
+ _node = new LibraryCycleNode(this);
+ }
+
+ LibraryCycleNode get node => _node;
+
+ /**
+ * Link this library cycle and any library cycles it depends on. Does
+ * nothing if this library cycle has already been linked.
+ */
+ void ensureLinked() {
+ if (!node.isEvaluated) {
+ new LibraryCycleDependencyWalker().walk(node);
+ }
+ }
+}
+
+/**
+ * Specialization of [Node] used to link library cycles in proper dependency
+ * order.
+ */
+class LibraryCycleNode extends Node<LibraryCycleNode> {
+ /**
+ * The library cycle this [Node] represents.
+ */
+ final LibraryCycleForLink libraryCycle;
+
+ /**
+ * Indicates whether this library cycle has been linked yet.
+ */
+ bool _isLinked = false;
+
+ LibraryCycleNode(this.libraryCycle);
+
+ @override
+ bool get isEvaluated => _isLinked;
+
+ @override
+ List<LibraryCycleNode> computeDependencies() => libraryCycle.dependencies
+ .map((LibraryCycleForLink cycle) => cycle.node)
+ .toList();
+
+ /**
+ * Link this library cycle.
+ */
+ void link() {
+ for (LibraryElementInBuildUnit library in libraryCycle.libraries) {
+ library.link();
+ }
+ _isLinked = true;
+ }
+}
+
+/**
+ * Specialization of [DependencyWalker] for computing library cycles.
+ */
+class LibraryDependencyWalker extends DependencyWalker<LibraryNode> {
+ @override
+ void evaluate(LibraryNode v) => evaluateScc(<LibraryNode>[v]);
+
+ @override
+ void evaluateScc(List<LibraryNode> scc) {
+ Set<LibraryCycleForLink> dependentCycles = new Set<LibraryCycleForLink>();
+ for (LibraryNode node in scc) {
+ for (LibraryNode dependency in node.dependencies) {
+ if (dependency.isEvaluated) {
+ dependentCycles.add(dependency._libraryCycle);
+ }
+ }
+ }
+ LibraryCycleForLink cycle = new LibraryCycleForLink(
+ scc.map((LibraryNode n) => n.library).toList(),
+ dependentCycles.toList());
+ for (LibraryNode node in scc) {
+ node._libraryCycle = cycle;
+ }
+ }
+}
+
+/**
+ * Element representing a library resynthesied from a summary during
+ * linking. The type parameter, [UnitElement], represents the type
+ * that will be used for the compilation unit elements.
+ */
+abstract class LibraryElementForLink<
+ UnitElement extends CompilationUnitElementForLink>
+ implements LibraryElementImpl {
+ /**
+ * Pointer back to the linker.
+ */
+ final Linker _linker;
+
+ /**
+ * The absolute URI of this library.
+ */
+ final Uri _absoluteUri;
+
+ List<UnitElement> _units;
+ final Map<String, ReferenceableElementForLink> _containedNames =
+ <String, ReferenceableElementForLink>{};
+ final List<LibraryElementForLink> _dependencies = <LibraryElementForLink>[];
+ UnlinkedUnit _definingUnlinkedUnit;
+ List<LibraryElementForLink> _importedLibraries;
+ List<LibraryElementForLink> _exportedLibraries;
+
+ LibraryElementForLink(this._linker, this._absoluteUri) {
+ if (_linkedLibrary != null) {
+ _dependencies.length = _linkedLibrary.dependencies.length;
+ }
+ }
+
+ @override
+ ContextForLink get context => _linker.context;
+
+ /**
+ * Get the [UnlinkedUnit] for the defining compilation unit of this library.
+ */
+ UnlinkedUnit get definingUnlinkedUnit =>
+ _definingUnlinkedUnit ??= _linker.getUnit(_absoluteUri.toString());
+
+ @override
+ Element get enclosingElement => null;
+
+ @override
+ List<LibraryElementForLink> get exportedLibraries => _exportedLibraries ??=
+ _linkedLibrary.exportDependencies.map(_getDependency).toList();
+
+ @override
+ String get identifier => _absoluteUri.toString();
+
+ @override
+ List<LibraryElementForLink> get importedLibraries => _importedLibraries ??=
+ _linkedLibrary.importDependencies.map(_getDependency).toList();
+
+ @override
+ bool get isDartAsync => _absoluteUri == 'dart:async';
+
+ @override
+ bool get isDartCore => _absoluteUri == 'dart:core';
+
+ /**
+ * If this library is part of the build unit being linked, return the library
+ * cycle it is part of. Otherwise return `null`.
+ */
+ LibraryCycleForLink get libraryCycleForLink;
+
+ @override
+ String get name {
+ return _definingUnlinkedUnit.libraryName;
+ }
+
+ @override
+ List<UnitElement> get units {
+ if (_units == null) {
+ UnlinkedUnit definingUnit = definingUnlinkedUnit;
+ _units = <UnitElement>[
+ _makeUnitElement(definingUnit, 0, _absoluteUri.toString())
+ ];
+ int numParts = definingUnit.parts.length;
+ for (int i = 0; i < numParts; i++) {
+ // TODO(paulberry): make sure we handle the case where Uri.parse fails.
+ // TODO(paulberry): make sure we handle the case where
+ // resolveRelativeUri fails.
+ String partAbsoluteUri = resolveRelativeUri(
+ _absoluteUri, Uri.parse(definingUnit.publicNamespace.parts[i]))
+ .toString();
+ UnlinkedUnit partUnit = _linker.getUnit(partAbsoluteUri);
+ _units.add(_makeUnitElement(
+ partUnit ?? new UnlinkedUnitBuilder(), i + 1, partAbsoluteUri));
+ }
+ }
+ return _units;
+ }
+
+ /**
+ * The linked representation of the library in the summary.
+ */
+ LinkedLibrary get _linkedLibrary;
+
+ /**
+ * Search all the units for a top level element with the given
+ * [name]. If no name is found, return the singleton instance of
+ * [UndefinedElementForLink].
+ */
+ ReferenceableElementForLink getContainedName(String name) =>
+ _containedNames.putIfAbsent(name, () {
+ for (UnitElement unit in units) {
+ ReferenceableElementForLink element = unit.getContainedName(name);
+ if (!identical(element, UndefinedElementForLink.instance)) {
+ return element;
+ }
+ }
+ return UndefinedElementForLink.instance;
+ });
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+
+ @override
+ String toString() => _absoluteUri.toString();
+
+ /**
+ * Return the [LibraryElement] corresponding to the given dependency [index].
+ */
+ LibraryElementForLink _getDependency(int index) {
+ LibraryElementForLink result = _dependencies[index];
+ if (result == null) {
+ String relativeUri = _linkedLibrary.dependencies[index].uri;
+ Uri absoluteUri = relativeUri.isEmpty
+ ? _absoluteUri
+ : resolveRelativeUri(_absoluteUri, Uri.parse(relativeUri));
+ result = _linker.getLibrary(absoluteUri);
+ _dependencies[index] = result;
+ }
+ return result;
+ }
+
+ /**
+ * Create a [UnitElement] for one of the library's compilation
+ * units.
+ */
+ UnitElement _makeUnitElement(
+ UnlinkedUnit unlinkedUnit, int i, String absoluteUri);
+}
+
+/**
+ * Element representing a library which is part of the build unit
+ * being linked.
+ */
+class LibraryElementInBuildUnit
+ extends LibraryElementForLink<CompilationUnitElementInBuildUnit> {
+ @override
+ final LinkedLibraryBuilder _linkedLibrary;
+
+ /**
+ * The [LibraryNode] representing this library in the library dependency
+ * graph.
+ */
+ LibraryNode _libraryNode;
+
+ InheritanceManager _inheritanceManager;
+
+ LibraryElementInBuildUnit(Linker linker, Uri absoluteUri, this._linkedLibrary)
+ : super(linker, absoluteUri) {
+ _libraryNode = new LibraryNode(this);
+ }
+
+ /**
+ * Get the inheritance manager for this library (creating it if necessary).
+ */
+ InheritanceManager get inheritanceManager =>
+ _inheritanceManager ??= new InheritanceManager(this);
+
+ @override
+ LibraryCycleForLink get libraryCycleForLink {
+ if (!_libraryNode.isEvaluated) {
+ new LibraryDependencyWalker().walk(_libraryNode);
+ }
+ return _libraryNode._libraryCycle;
+ }
+
+ /**
+ * If this library already has a dependency in its dependencies table matching
+ * [library], return its index. Otherwise add a new dependency to table and
+ * return its index.
+ */
+ int addDependency(LibraryElementForLink library) {
+ for (int i = 0; i < _linkedLibrary.dependencies.length; i++) {
+ if (identical(_getDependency(i), library)) {
+ return i;
+ }
+ }
+ int result = _linkedLibrary.dependencies.length;
+ _linkedLibrary.dependencies.add(new LinkedDependencyBuilder(
+ parts: library.definingUnlinkedUnit.publicNamespace.parts,
+ uri: library._absoluteUri.toString()));
+ _dependencies.add(library);
+ return result;
+ }
+
+ /**
+ * Perform type inference and const cycle detection on this library.
+ */
+ void link() {
+ for (CompilationUnitElementInBuildUnit unit in units) {
+ unit.link();
+ }
+ }
+
+ /**
+ * Throw away any information stored in the summary by a previous call to
+ * [link].
+ */
+ void unlink() {
+ _linkedLibrary.dependencies.length =
+ _linkedLibrary.numPrelinkedDependencies;
+ for (CompilationUnitElementInBuildUnit unit in units) {
+ unit.unlink();
+ }
+ }
+
+ @override
+ CompilationUnitElementInBuildUnit _makeUnitElement(
+ UnlinkedUnit unlinkedUnit, int i, String absoluteUri) =>
+ new CompilationUnitElementInBuildUnit(
+ this, unlinkedUnit, _linkedLibrary.units[i], i, absoluteUri);
+}
+
+/**
+ * Element representing a library which is depended upon (either
+ * directly or indirectly) by the build unit being linked.
+ */
+class LibraryElementInDependency
+ extends LibraryElementForLink<CompilationUnitElementInDependency> {
+ @override
+ final LinkedLibrary _linkedLibrary;
+
+ LibraryElementInDependency(
+ Linker linker, Uri absoluteUri, this._linkedLibrary)
+ : super(linker, absoluteUri);
+
+ @override
+ LibraryCycleForLink get libraryCycleForLink => null;
+
+ @override
+ CompilationUnitElementInDependency _makeUnitElement(
+ UnlinkedUnit unlinkedUnit, int i, String absoluteUri) =>
+ new CompilationUnitElementInDependency(
+ this, unlinkedUnit, _linkedLibrary.units[i], i, absoluteUri);
+}
+
+/**
+ * Specialization of [Node] used to construct the library dependency graph.
+ */
+class LibraryNode extends Node<LibraryNode> {
+ /**
+ * The library this [Node] represents.
+ */
+ final LibraryElementInBuildUnit library;
+
+ /**
+ * The library cycle to which [library] belongs, if it has been computed.
+ * Otherwise `null`.
+ */
+ LibraryCycleForLink _libraryCycle;
+
+ LibraryNode(this.library);
+
+ @override
+ bool get isEvaluated => _libraryCycle != null;
+
+ @override
+ List<LibraryNode> computeDependencies() {
+ // Note: we only need to consider dependencies within the build unit being
+ // linked; dependencies in other build units can't participate in library
+ // cycles with us.
+ List<LibraryNode> dependencies = <LibraryNode>[];
+ for (LibraryElement dependency in library.importedLibraries) {
+ if (dependency is LibraryElementInBuildUnit) {
+ dependencies.add(dependency._libraryNode);
+ }
+ }
+ for (LibraryElement dependency in library.exportedLibraries) {
+ if (dependency is LibraryElementInBuildUnit) {
+ dependencies.add(dependency._libraryNode);
+ }
+ }
+ return dependencies;
+ }
+}
+
+/**
+ * Instances of [Linker] contain the necessary information to link
+ * together a single build unit.
+ */
+class Linker {
+ /**
+ * During linking, if type inference is currently being performed on the
+ * initializer of a static or instance variable, the library cycle in
+ * which inference is being performed. Otherwise, `null`.
+ *
+ * This allows us to suppress instance member type inference results from a
+ * library cycle while doing inference on the right hand sides of static and
+ * instance variables in that same cycle.
+ */
+ static LibraryCycleForLink _initializerTypeInferenceCycle;
+
+ /**
+ * Callback to ask the client for a [LinkedLibrary] for a
+ * dependency.
+ */
+ final GetDependencyCallback getDependency;
+
+ /**
+ * Callback to ask the client for an [UnlinkedUnit].
+ */
+ final GetUnitCallback getUnit;
+
+ /**
+ * Map containing all library elements accessed during linking,
+ * whether they are part of the build unit being linked or whether
+ * they are dependencies.
+ */
+ final Map<Uri, LibraryElementForLink> _libraries =
+ <Uri, LibraryElementForLink>{};
+
+ /**
+ * List of library elements for the libraries in the build unit
+ * being linked.
+ */
+ final List<LibraryElementInBuildUnit> _librariesInBuildUnit =
+ <LibraryElementInBuildUnit>[];
+
+ /**
+ * Indicates whether type inference should use strong mode rules.
+ */
+ final bool strongMode;
+
+ LibraryElementForLink _coreLibrary;
+ LibraryElementForLink _asyncLibrary;
+ TypeProviderForLink _typeProvider;
+ TypeSystem _typeSystem;
+ SpecialTypeElementForLink _voidElement;
+ SpecialTypeElementForLink _dynamicElement;
+ SpecialTypeElementForLink _bottomElement;
+ ContextForLink _context;
+ AnalysisOptionsForLink _analysisOptions;
+
+ Linker(Map<String, LinkedLibraryBuilder> linkedLibraries, this.getDependency,
+ this.getUnit, this.strongMode) {
+ // Create elements for the libraries to be linked. The rest of
+ // the element model will be created on demand.
+ linkedLibraries
+ .forEach((String absoluteUri, LinkedLibraryBuilder linkedLibrary) {
+ Uri uri = Uri.parse(absoluteUri);
+ _librariesInBuildUnit.add(_libraries[uri] =
+ new LibraryElementInBuildUnit(this, uri, linkedLibrary));
+ });
+ }
+
+ /**
+ * Get an instance of [AnalysisOptions] for use during linking.
+ */
+ AnalysisOptionsForLink get analysisOptions =>
+ _analysisOptions ??= new AnalysisOptionsForLink(this);
+
+ /**
+ * Get the library element for `dart:async`.
+ */
+ LibraryElementForLink get asyncLibrary =>
+ _asyncLibrary ??= getLibrary(Uri.parse('dart:async'));
+
+ /**
+ * Get the element representing the "bottom" type.
+ */
+ SpecialTypeElementForLink get bottomElement => _bottomElement ??=
+ new SpecialTypeElementForLink(this, BottomTypeImpl.instance);
+
+ /**
+ * Get a stub implementation of [AnalysisContext] which can be used during
+ * linking.
+ */
+ get context => _context ??= new ContextForLink(this);
+
+ /**
+ * Get the library element for `dart:core`.
+ */
+ LibraryElementForLink get coreLibrary =>
+ _coreLibrary ??= getLibrary(Uri.parse('dart:core'));
+
+ /**
+ * Get the element representing `dynamic`.
+ */
+ SpecialTypeElementForLink get dynamicElement => _dynamicElement ??=
+ new SpecialTypeElementForLink(this, DynamicTypeImpl.instance);
+
+ /**
+ * Get an instance of [TypeProvider] for use during linking.
+ */
+ TypeProviderForLink get typeProvider =>
+ _typeProvider ??= new TypeProviderForLink(this);
+
+ /**
+ * Get an instance of [TypeSystem] for use during linking.
+ */
+ TypeSystem get typeSystem => _typeSystem ??=
+ strongMode ? new StrongTypeSystemImpl() : new TypeSystemImpl();
+
+ /**
+ * Get the element representing `void`.
+ */
+ SpecialTypeElementForLink get voidElement => _voidElement ??=
+ new SpecialTypeElementForLink(this, VoidTypeImpl.instance);
+
+ /**
+ * Get the library element for the library having the given [uri].
+ */
+ LibraryElementForLink getLibrary(Uri uri) => _libraries.putIfAbsent(
+ uri,
+ () => new LibraryElementInDependency(
+ this, uri, getDependency(uri.toString())));
+
+ /**
+ * Perform type inference and const cycle detection on all libraries
+ * in the build unit being linked.
+ */
+ void link() {
+ // Link library cycles in appropriate dependency order.
+ for (LibraryElementInBuildUnit library in _librariesInBuildUnit) {
+ library.libraryCycleForLink.ensureLinked();
+ }
+ // TODO(paulberry): set dependencies.
+ }
+
+ /**
+ * Throw away any information stored in the summary by a previous call to
+ * [link].
+ */
+ void unlink() {
+ for (LibraryElementInBuildUnit library in _librariesInBuildUnit) {
+ library.unlink();
+ }
+ }
+}
+
+/**
+ * Element representing a method resynthesized from a summary during linking.
+ */
+class MethodElementForLink extends ExecutableElementForLink_NonLocal
+ with ReferenceableElementForLink
+ implements MethodElementImpl {
+ MethodElementForLink(ClassElementForLink_Class enclosingClass,
+ UnlinkedExecutable unlinkedExecutable)
+ : super(enclosingClass.enclosingElement, enclosingClass,
+ unlinkedExecutable);
+
+ @override
+ DartType get asStaticType => type;
+
+ @override
+ ClassElementImpl get enclosingElement => super.enclosingClass;
+
+ @override
+ String get identifier => name;
+
+ @override
+ ElementKind get kind => ElementKind.METHOD;
+
+ @override
+ FunctionElementForLink_Local getLocalFunction(int index) {
+ // TODO(paulberry): implement.
+ return null;
+ }
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+
+ @override
+ String toString() => '$enclosingElement.$name';
+}
+
+/**
+ * Instances of [Node] represent nodes in a dependency graph. The
+ * type parameter, [NodeType], is the derived type (this affords some
+ * extra type safety by making it difficult to accidentally construct
+ * bridges between unrelated dependency graphs).
+ */
+abstract class Node<NodeType> {
+ /**
+ * Index used by Tarjan's strongly connected components algorithm.
+ * Zero means the node has not been visited yet; a nonzero value
+ * counts the order in which the node was visited.
+ */
+ int index = 0;
+
+ /**
+ * Low link used by Tarjan's strongly connected components
+ * algorithm. This represents the smallest [index] of all the nodes
+ * in the strongly connected component to which this node belongs.
+ */
+ int lowLink = 0;
+
+ List<NodeType> _dependencies;
+
+ /**
+ * Retrieve the dependencies of this node.
+ */
+ List<NodeType> get dependencies => _dependencies ??= computeDependencies();
+
+ /**
+ * Indicates whether this node has been evaluated yet.
+ */
+ bool get isEvaluated;
+
+ /**
+ * Compute the dependencies of this node.
+ */
+ List<NodeType> computeDependencies();
+}
+
+/**
+ * Element used for references that result from trying to access a non-static
+ * member of an element that is not a container (e.g. accessing the "length"
+ * property of a constant).
+ *
+ * Accesses to a chain of non-static members separated by '.' are andled by
+ * creating a [NonstaticMemberElementForLink] that points to another
+ * [NonstaticMemberElementForLink], to whatever nesting level is necessary.
+ */
+class NonstaticMemberElementForLink extends Object
+ with ReferenceableElementForLink {
+ /**
+ * The [ReferenceableElementForLink] which is the target of the non-static
+ * reference.
+ */
+ final ReferenceableElementForLink _target;
+
+ /**
+ * The name of the non-static members that is being accessed.
+ */
+ final String _name;
+
+ /**
+ * The library in which the access occurs. This determines whether private
+ * names are accessible.
+ */
+ final LibraryElementForLink _library;
+
+ NonstaticMemberElementForLink(this._library, this._target, this._name);
+
+ @override
+ ConstVariableNode get asConstVariable => _target.asConstVariable;
+
+ @override
+ DartType get asStaticType {
+ if (_library._linker.strongMode) {
+ DartType targetType = _target.asStaticType;
+ if (targetType is InterfaceType) {
+ ExecutableElement element =
+ targetType.lookUpInheritedGetterOrMethod(_name, library: _library);
+ if (element != null) {
+ if (element is PropertyAccessorElement) {
+ return element.returnType;
+ } else {
+ // Method tear-off
+ return element.type;
+ }
+ }
+ }
+ // TODO(paulberry): handle .call on function types and .toString or
+ // .hashCode on all types.
+ }
+ return DynamicTypeImpl.instance;
+ }
+
+ @override
+ TypeInferenceNode get asTypeInferenceNode => _target.asTypeInferenceNode;
+
+ @override
+ ReferenceableElementForLink getContainedName(String name) {
+ return new NonstaticMemberElementForLink(_library, this, name);
+ }
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+
+ @override
+ String toString() => '$_target.(dynamic)$_name';
+}
+
+/**
+ * Element representing a function or method parameter resynthesized
+ * from a summary during linking.
+ */
+class ParameterElementForLink implements ParameterElementImpl {
+ /**
+ * The unlinked representation of the parameter in the summary.
+ */
+ final UnlinkedParam _unlinkedParam;
+
+ /**
+ * The innermost enclosing element that can declare type parameters.
+ */
+ final TypeParameterizedElementMixin _typeParameterContext;
+
+ /**
+ * If this parameter has a default value and the enclosing library
+ * is part of the build unit being linked, the parameter's node in
+ * the constant evaluation dependency graph. Otherwise `null`.
+ */
+ ConstNode _constNode;
+
+ /**
+ * The compilation unit in which this parameter appears.
+ */
+ final CompilationUnitElementForLink compilationUnit;
+
+ /**
+ * The index of this parameter within [enclosingElement]'s parameter list.
+ */
+ final int _parameterIndex;
+
+ @override
+ final ParameterParentElementForLink enclosingElement;
+
+ DartType _inferredType;
+ DartType _declaredType;
+ bool _inheritsCovariant = false;
+
+ ParameterElementForLink(this.enclosingElement, this._unlinkedParam,
+ this._typeParameterContext, this.compilationUnit, this._parameterIndex) {
+ if (_unlinkedParam.initializer?.bodyExpr != null) {
+ _constNode = new ConstParameterNode(this);
+ }
+ }
+
+ @override
+ String get displayName => _unlinkedParam.name;
+
+ @override
+ bool get hasImplicitType =>
+ !_unlinkedParam.isFunctionTyped && _unlinkedParam.type == null;
+
+ @override
+ bool get inheritsCovariant => _inheritsCovariant;
+
+ @override
+ void set inheritsCovariant(bool value) {
+ _inheritsCovariant = value;
+ }
+
+ @override
+ bool get isCovariant {
+ if (inheritsCovariant) {
+ return true;
+ }
+ for (UnlinkedConst annotation in _unlinkedParam.annotations) {
+ if (annotation.operations.length == 1 &&
+ annotation.operations[0] == UnlinkedConstOperation.pushReference) {
+ ReferenceableElementForLink element =
+ this.compilationUnit.resolveRef(annotation.references[0].reference);
+ if (element is PropertyAccessorElementForLink &&
+ element.name == 'checked' &&
+ element.library.name == 'meta') {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @override
+ String get name => _unlinkedParam.name;
+
+ @override
+ ParameterKind get parameterKind {
+ switch (_unlinkedParam.kind) {
+ case UnlinkedParamKind.required:
+ return ParameterKind.REQUIRED;
+ case UnlinkedParamKind.positional:
+ return ParameterKind.POSITIONAL;
+ case UnlinkedParamKind.named:
+ return ParameterKind.NAMED;
+ }
+ return null;
+ }
+
+ @override
+ DartType get type {
+ if (_inferredType != null) {
+ return _inferredType;
+ } else if (_declaredType == null) {
+ if (_unlinkedParam.isFunctionTyped) {
+ _declaredType = new FunctionTypeImpl(
+ new FunctionElementForLink_FunctionTypedParam(
+ this, _typeParameterContext, _unlinkedParam.parameters));
+ } else if (_unlinkedParam.type == null) {
+ if (!compilationUnit.isInBuildUnit) {
+ _inferredType = compilationUnit.getLinkedType(
+ _unlinkedParam.inferredTypeSlot, _typeParameterContext);
+ return _inferredType;
+ } else {
+ _declaredType = DynamicTypeImpl.instance;
+ }
+ } else {
+ _declaredType = compilationUnit.resolveTypeRef(
+ _unlinkedParam.type, _typeParameterContext);
+ }
+ }
+ return _declaredType;
+ }
+
+ @override
+ void set type(DartType inferredType) {
+ assert(_inferredType == null);
+ _inferredType = inferredType;
+ }
+
+ /**
+ * Store the results of type inference for this parameter in
+ * [compilationUnit].
+ */
+ void link(CompilationUnitElementInBuildUnit compilationUnit) {
+ compilationUnit._storeLinkedType(
+ _unlinkedParam.inferredTypeSlot, _inferredType, _typeParameterContext);
+ if (inheritsCovariant) {
+ compilationUnit
+ ._storeInheritsCovariant(_unlinkedParam.inheritsCovariantSlot);
+ }
+ }
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+/**
+ * Element representing the parameter of a synthetic setter for a variable
+ * resynthesized during linking.
+ */
+class ParameterElementForLink_VariableSetter implements ParameterElementImpl {
+ @override
+ final PropertyAccessorElementForLink_Variable enclosingElement;
+
+ @override
+ bool inheritsCovariant = false;
+
+ ParameterElementForLink_VariableSetter(this.enclosingElement);
+
+ @override
+ bool get isCovariant => false;
+
+ @override
+ bool get isSynthetic => true;
+
+ @override
+ String get name => 'x';
+
+ @override
+ ParameterKind get parameterKind => ParameterKind.REQUIRED;
+
+ @override
+ DartType get type => enclosingElement.computeVariableType();
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+/**
+ * Mixin used by elements that can have parameters.
+ */
+abstract class ParameterParentElementForLink implements Element {
+ List<ParameterElement> _parameters;
+
+ /**
+ * Get the appropriate integer list to store in
+ * [EntityRef.implicitFunctionTypeIndices] to refer to this element. For an
+ * element representing a function-typed parameter, this should return a
+ * non-empty list. For an element representing an executable, this should
+ * return the empty list.
+ */
+ List<int> get implicitFunctionTypeIndices;
+
+ /**
+ * Get all the parameters of this element.
+ */
+ List<ParameterElement> get parameters {
+ if (_parameters == null) {
+ List<UnlinkedParam> unlinkedParameters = this.unlinkedParameters;
+ int numParameters = unlinkedParameters.length;
+ _parameters = new List<ParameterElement>(numParameters);
+ for (int i = 0; i < numParameters; i++) {
+ UnlinkedParam unlinkedParam = unlinkedParameters[i];
+ _parameters[i] = new ParameterElementForLink(
+ this,
+ unlinkedParam,
+ typeParameterContext,
+ typeParameterContext.enclosingUnit.resynthesizerContext
+ as CompilationUnitElementForLink,
+ i);
+ }
+ }
+ return _parameters;
+ }
+
+ /**
+ * Get the innermost enclosing element that can declare type parameters (which
+ * may be [this], or may be a parent when there are function-typed
+ * parameters).
+ */
+ TypeParameterizedElementMixin get typeParameterContext;
+
+ /**
+ * Get the list of unlinked parameters of this element.
+ */
+ List<UnlinkedParam> get unlinkedParameters;
+}
+
+/**
+ * Element representing a getter or setter resynthesized from a summary during
+ * linking.
+ */
+abstract class PropertyAccessorElementForLink
+ implements PropertyAccessorElementImpl, ReferenceableElementForLink {
+ void link(CompilationUnitElementInBuildUnit compilationUnit);
+}
+
+/**
+ * Specialization of [PropertyAccessorElementForLink] for synthetic accessors
+ * implied by the synthetic fields of an enum declaration.
+ */
+class PropertyAccessorElementForLink_EnumField extends Object
+ with ReferenceableElementForLink
+ implements PropertyAccessorElementForLink {
+ @override
+ final FieldElementForLink_EnumField variable;
+
+ FunctionTypeImpl _type;
+
+ PropertyAccessorElementForLink_EnumField(this.variable);
+
+ @override
+ DartType get asStaticType => returnType;
+
+ @override
+ Element get enclosingElement => variable.enclosingElement;
+
+ @override
+ bool get isGetter => true;
+
+ @override
+ bool get isSetter => false;
+
+ @override
+ bool get isStatic => variable.isStatic;
+
+ @override
+ bool get isSynthetic => true;
+
+ @override
+ ElementKind get kind => ElementKind.GETTER;
+
+ @override
+ LibraryElementForLink get library =>
+ variable.enclosingElement.enclosingElement.enclosingElement;
+
+ @override
+ String get name => variable.name;
+
+ @override
+ List<ParameterElement> get parameters => const [];
+
+ @override
+ DartType get returnType => variable.type;
+
+ @override
+ FunctionTypeImpl get type => _type ??= new FunctionTypeImpl(this);
+
+ @override
+ List<TypeParameterElement> get typeParameters => const [];
+
+ @override
+ ReferenceableElementForLink getContainedName(String name) {
+ return new NonstaticMemberElementForLink(library, this, name);
+ }
+
+ @override
+ FunctionElementForLink_Local getLocalFunction(int index) {
+ // TODO(paulberry): implement (should return the synthetic function element
+ // for the enum field's initializer).
+ return null;
+ }
+
+ @override
+ bool isAccessibleIn(LibraryElement library) =>
+ !Identifier.isPrivateName(name) || identical(this.library, library);
+
+ @override
+ void link(CompilationUnitElementInBuildUnit compilationUnit) {}
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+
+ @override
+ String toString() => '$enclosingElement.$name';
+}
+
+/**
+ * Specialization of [PropertyAccessorElementForLink] for non-synthetic
+ * accessors explicitly declared in the source code.
+ */
+class PropertyAccessorElementForLink_Executable
+ extends ExecutableElementForLink_NonLocal
+ with ReferenceableElementForLink
+ implements PropertyAccessorElementForLink {
+ @override
+ PropertyInducingElement variable;
+
+ PropertyAccessorElementForLink_Executable(
+ CompilationUnitElementForLink enclosingUnit,
+ ClassElementForLink_Class enclosingClass,
+ UnlinkedExecutable unlinkedExecutable,
+ this.variable)
+ : super(enclosingUnit, enclosingClass, unlinkedExecutable);
+
+ @override
+ DartType get asStaticType => returnType;
+
+ @override
+ PropertyAccessorElementForLink_Executable get correspondingGetter =>
+ variable.getter;
+
+ @override
+ bool get isGetter =>
+ _unlinkedExecutable.kind == UnlinkedExecutableKind.getter;
+
+ @override
+ bool get isSetter =>
+ _unlinkedExecutable.kind == UnlinkedExecutableKind.setter;
+
+ @override
+ bool get isStatic => enclosingClass == null || super.isStatic;
+
+ @override
+ ElementKind get kind =>
+ _unlinkedExecutable.kind == UnlinkedExecutableKind.getter
+ ? ElementKind.GETTER
+ : ElementKind.SETTER;
+
+ @override
+ ReferenceableElementForLink getContainedName(String name) {
+ return new NonstaticMemberElementForLink(
+ library as LibraryElementForLink, this, name);
+ }
+
+ @override
+ FunctionElementForLink_Local getLocalFunction(int index) {
+ // TODO(paulberry): implement
+ return null;
+ }
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+
+ @override
+ String toString() => '$enclosingElement.$name';
+}
+
+/**
+ * Specialization of [PropertyAccessorElementForLink] for synthetic accessors
+ * implied by a field or variable declaration.
+ */
+class PropertyAccessorElementForLink_Variable extends Object
+ with ReferenceableElementForLink
+ implements PropertyAccessorElementForLink {
+ @override
+ final bool isSetter;
+
+ final VariableElementForLink variable;
+ FunctionTypeImpl _type;
+ List<ParameterElement> _parameters;
+
+ PropertyAccessorElementForLink_Variable(this.variable, this.isSetter);
+
+ @override
+ ConstVariableNode get asConstVariable => variable._constNode;
+
+ @override
+ DartType get asStaticType => returnType;
+
+ @override
+ TypeInferenceNode get asTypeInferenceNode => variable._typeInferenceNode;
+
+ @override
+ Element get enclosingElement => variable.enclosingElement;
+
+ @override
+ bool get isGetter => !isSetter;
+
+ @override
+ bool get isStatic => variable.isStatic;
+
+ @override
+ bool get isSynthetic => true;
+
+ @override
+ ElementKind get kind => isSetter ? ElementKind.SETTER : ElementKind.GETTER;
+
+ @override
+ LibraryElementForLink get library =>
+ variable.compilationUnit.enclosingElement;
+
+ @override
+ String get name => isSetter ? '${variable.name}=' : variable.name;
+
+ @override
+ List<ParameterElement> get parameters {
+ if (_parameters == null) {
+ _parameters = <ParameterElementForLink_VariableSetter>[];
+ if (isSetter) {
+ _parameters.add(new ParameterElementForLink_VariableSetter(this));
+ }
+ }
+ return _parameters;
+ }
+
+ @override
+ DartType get returnType {
+ if (isSetter) {
+ return VoidTypeImpl.instance;
+ } else {
+ return computeVariableType();
+ }
+ }
+
+ @override
+ FunctionTypeImpl get type => _type ??= new FunctionTypeImpl(this);
+
+ @override
+ List<TypeParameterElement> get typeParameters {
+ // TODO(paulberry): is this correct for fields in generic classes?
+ return const [];
+ }
+
+ /**
+ * Compute the type of the corresponding variable, which may depend on the
+ * progress of type inference.
+ */
+ DartType computeVariableType() {
+ if (variable.hasImplicitType &&
+ !isStatic &&
+ !variable.compilationUnit.isTypeInferenceComplete) {
+ // This is an instance field and we are currently inferring types in the
+ // library cycle containing it. So we shouldn't use the inferred type
+ // (even if we have already computed it), since that would lead to
+ // non-deterministic type inference results.
+ return DynamicTypeImpl.instance;
+ } else {
+ return variable.type;
+ }
+ }
+
+ @override
+ ReferenceableElementForLink getContainedName(String name) {
+ return new NonstaticMemberElementForLink(library, this, name);
+ }
+
+ @override
+ FunctionElementForLink_Local getLocalFunction(int index) {
+ if (index == 0) {
+ return variable.initializer;
+ } else {
+ return null;
+ }
+ }
+
+ @override
+ bool isAccessibleIn(LibraryElement library) =>
+ !Identifier.isPrivateName(name) || identical(this.library, library);
+
+ @override
+ void link(CompilationUnitElementInBuildUnit compilationUnit) {}
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+
+ @override
+ String toString() => '$enclosingElement.$name';
+}
+
+/**
+ * Base class representing an element which can be the target of a reference.
+ * When used as a mixin, implements the default behavior shared by most
+ * elements.
+ */
+abstract class ReferenceableElementForLink implements Element {
+ /**
+ * If this element is a class reference, return it. Otherwise return `null`.
+ */
+ ClassElementForLink get asClass => null;
+
+ /**
+ * If this element can be used in a constructor invocation context,
+ * return the associated constructor (which may be `this` or some
+ * other element). Otherwise return `null`.
+ */
+ ConstructorElementForLink get asConstructor => null;
+
+ /**
+ * If this element can be used in a getter context to refer to a
+ * constant variable, return the [ConstVariableNode] for the
+ * constant value. Otherwise return `null`.
+ */
+ ConstVariableNode get asConstVariable => null;
+
+ /**
+ * Return the static type (possibly inferred) of the entity referred to by
+ * this element.
+ */
+ DartType get asStaticType => DynamicTypeImpl.instance;
+
+ /**
+ * If this element can be used in a getter context as a type inference
+ * dependency, return the [TypeInferenceNode] for the inferred type.
+ * Otherwise return `null`.
+ */
+ TypeInferenceNode get asTypeInferenceNode => null;
+
+ @override
+ ElementLocation get location => new ElementLocationImpl.con1(this);
+
+ /**
+ * Return the type indicated by this element when it is used in a
+ * type instantiation context. If this element can't legally be
+ * instantiated as a type, return the dynamic type.
+ *
+ * If the type is parameterized, [getTypeArgument] will be called to retrieve
+ * the type parameters. It should return `null` for unspecified type
+ * parameters.
+ */
+ DartType buildType(DartType getTypeArgument(int i),
+ List<int> implicitFunctionTypeIndices) =>
+ DynamicTypeImpl.instance;
+
+ /**
+ * If this element contains other named elements, return the
+ * contained element having the given [name]. If this element can't
+ * contain other named elements, or it doesn't contain an element
+ * with the given name, return the singleton of
+ * [UndefinedElementForLink].
+ */
+ ReferenceableElementForLink getContainedName(String name) {
+ // TODO(paulberry): handle references to `call` for function types.
+ return UndefinedElementForLink.instance;
+ }
+
+ /**
+ * If this element contains local functions, return the contained local
+ * function having the given [index]. If this element doesn't contain local
+ * functions, or the index is out of range, return `null`.
+ */
+ FunctionElementForLink_Local getLocalFunction(int index) => null;
+}
+
+/**
+ * Element used for references to special types such as `void`.
+ */
+class SpecialTypeElementForLink extends Object
+ with ReferenceableElementForLink {
+ final Linker linker;
+ final DartType type;
+
+ SpecialTypeElementForLink(this.linker, this.type);
+
+ @override
+ DartType get asStaticType => linker.typeProvider.typeType;
+
+ @override
+ DartType buildType(
+ DartType getTypeArgument(int i), List<int> implicitFunctionTypeIndices) {
+ return type;
+ }
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+
+ @override
+ String toString() => type.toString();
+}
+
+/**
+ * Element representing a synthetic variable resynthesized from a summary during
+ * linking.
+ */
+class SyntheticVariableElementForLink implements PropertyInducingElementImpl {
+ PropertyAccessorElementForLink_Executable _getter;
+ PropertyAccessorElementForLink_Executable _setter;
+
+ @override
+ PropertyAccessorElementForLink_Executable get getter => _getter;
+
+ @override
+ bool get isSynthetic => true;
+
+ @override
+ PropertyAccessorElementForLink_Executable get setter => _setter;
+
+ @override
+ void set type(DartType inferredType) {}
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+/**
+ * Element representing a top-level function.
+ */
+class TopLevelFunctionElementForLink extends ExecutableElementForLink_NonLocal
+ with ReferenceableElementForLink
+ implements FunctionElementImpl {
+ DartType _returnType;
+
+ TopLevelFunctionElementForLink(
+ CompilationUnitElementForLink enclosingUnit, UnlinkedExecutable _buf)
+ : super(enclosingUnit, null, _buf);
+
+ @override
+ DartType get asStaticType => type;
+
+ @override
+ String get identifier => _unlinkedExecutable.name;
+
+ @override
+ bool get isStatic => true;
+
+ @override
+ ElementKind get kind => ElementKind.FUNCTION;
+
+ @override
+ FunctionElementForLink_Local getLocalFunction(int index) {
+ // TODO(paulberry): implement.
+ return null;
+ }
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+
+ @override
+ String toString() => '$enclosingElement.$name';
+}
+
+/**
+ * Element representing a top level variable resynthesized from a
+ * summary during linking.
+ */
+class TopLevelVariableElementForLink extends VariableElementForLink
+ implements TopLevelVariableElement {
+ TopLevelVariableElementForLink(CompilationUnitElementForLink enclosingElement,
+ UnlinkedVariable unlinkedVariable)
+ : super(unlinkedVariable, enclosingElement);
+
+ @override
+ CompilationUnitElementForLink get enclosingElement => compilationUnit;
+
+ @override
+ bool get isStatic => true;
+
+ @override
+ LibraryElementForLink get library => compilationUnit.library;
+
+ @override
+ TypeParameterizedElementMixin get _typeParameterContext => null;
+
+ /**
+ * Store the results of type inference for this variable in
+ * [compilationUnit].
+ */
+ void link(CompilationUnitElementInBuildUnit compilationUnit) {
+ if (hasImplicitType) {
+ TypeInferenceNode typeInferenceNode = this._typeInferenceNode;
+ if (typeInferenceNode != null) {
+ compilationUnit._storeLinkedType(
+ unlinkedVariable.inferredTypeSlot, inferredType, null);
+ }
+ initializer?.link(compilationUnit);
+ }
+ }
+}
+
+/**
+ * Specialization of [DependencyWalker] for performing type inferrence
+ * on static and top level variables.
+ */
+class TypeInferenceDependencyWalker
+ extends DependencyWalker<TypeInferenceNode> {
+ @override
+ void evaluate(TypeInferenceNode v) {
+ v.evaluate(false);
+ }
+
+ @override
+ void evaluateScc(List<TypeInferenceNode> scc) {
+ for (TypeInferenceNode v in scc) {
+ v.evaluate(true);
+ }
+ }
+}
+
+/**
+ * Specialization of [Node] used to construct the type inference dependency
+ * graph.
+ */
+class TypeInferenceNode extends Node<TypeInferenceNode> {
+ /**
+ * The [FunctionElementForLink_Local] to which this node refers.
+ */
+ final FunctionElementForLink_Local functionElement;
+
+ TypeInferenceNode(this.functionElement);
+
+ @override
+ bool get isEvaluated => functionElement._hasTypeBeenInferred;
+
+ /**
+ * Collect the type inference dependencies in [unlinkedExecutable] (which
+ * should be interpreted relative to [compilationUnit]) and store them in
+ * [dependencies].
+ */
+ void collectDependencies(
+ List<TypeInferenceNode> dependencies,
+ UnlinkedExecutable unlinkedExecutable,
+ CompilationUnitElementForLink compilationUnit) {
+ UnlinkedConst unlinkedConst = unlinkedExecutable?.bodyExpr;
+ if (unlinkedConst == null) {
+ return;
+ }
+ int refPtr = 0;
+ int intPtr = 0;
+
+ for (UnlinkedConstOperation operation in unlinkedConst.operations) {
+ switch (operation) {
+ case UnlinkedConstOperation.pushInt:
+ intPtr++;
+ break;
+ case UnlinkedConstOperation.pushLongInt:
+ int numInts = unlinkedConst.ints[intPtr++];
+ intPtr += numInts;
+ break;
+ case UnlinkedConstOperation.concatenate:
+ intPtr++;
+ break;
+ case UnlinkedConstOperation.pushReference:
+ EntityRef ref = unlinkedConst.references[refPtr++];
+ // TODO(paulberry): cache these resolved references for
+ // later use by evaluate().
+ TypeInferenceNode dependency =
+ compilationUnit.resolveRef(ref.reference).asTypeInferenceNode;
+ if (dependency != null) {
+ dependencies.add(dependency);
+ }
+ break;
+ case UnlinkedConstOperation.invokeConstructor:
+ refPtr++;
+ intPtr += 2;
+ break;
+ case UnlinkedConstOperation.makeUntypedList:
+ case UnlinkedConstOperation.makeUntypedMap:
+ intPtr++;
+ break;
+ case UnlinkedConstOperation.makeTypedList:
+ refPtr++;
+ intPtr++;
+ break;
+ case UnlinkedConstOperation.makeTypedMap:
+ refPtr += 2;
+ intPtr++;
+ break;
+ case UnlinkedConstOperation.assignToRef:
+ // TODO(paulberry): if this reference refers to a variable, should it
+ // be considered a type inference dependency?
+ refPtr++;
+ break;
+ case UnlinkedConstOperation.invokeMethodRef:
+ // TODO(paulberry): if this reference refers to a variable, should it
+ // be considered a type inference dependency?
+ refPtr++;
+ intPtr += 2;
+ int numTypeArguments = unlinkedConst.ints[intPtr++];
+ refPtr += numTypeArguments;
+ break;
+ case UnlinkedConstOperation.invokeMethod:
+ intPtr += 2;
+ int numTypeArguments = unlinkedConst.ints[intPtr++];
+ refPtr += numTypeArguments;
+ break;
+ case UnlinkedConstOperation.typeCast:
+ case UnlinkedConstOperation.typeCheck:
+ refPtr++;
+ break;
+ case UnlinkedConstOperation.pushLocalFunctionReference:
+ int popCount = unlinkedConst.ints[intPtr++];
+ assert(popCount == 0); // TODO(paulberry): handle the nonzero case.
+ dependencies.add(functionElement
+ .getLocalFunction(unlinkedConst.ints[intPtr++])
+ .asTypeInferenceNode);
+ break;
+ default:
+ break;
+ }
+ }
+ assert(refPtr == unlinkedConst.references.length);
+ assert(intPtr == unlinkedConst.ints.length);
+ }
+
+ @override
+ List<TypeInferenceNode> computeDependencies() {
+ List<TypeInferenceNode> dependencies = <TypeInferenceNode>[];
+ collectDependencies(dependencies, functionElement._unlinkedExecutable,
+ functionElement.compilationUnit);
+ return dependencies;
+ }
+
+ void evaluate(bool inCycle) {
+ if (inCycle) {
+ functionElement._setInferredType(DynamicTypeImpl.instance);
+ } else {
+ functionElement
+ ._setInferredType(new ExprTypeComputer(functionElement).compute());
+ }
+ }
+
+ @override
+ String toString() => 'TypeInferenceNode($functionElement)';
+}
+
+class TypeProviderForLink extends TypeProviderBase {
+ final Linker _linker;
+
+ InterfaceType _boolType;
+ InterfaceType _deprecatedType;
+ InterfaceType _doubleType;
+ InterfaceType _functionType;
+ InterfaceType _futureDynamicType;
+ InterfaceType _futureNullType;
+ InterfaceType _futureType;
+ InterfaceType _intType;
+ InterfaceType _iterableDynamicType;
+ InterfaceType _iterableType;
+ InterfaceType _listType;
+ InterfaceType _mapType;
+ InterfaceType _nullType;
+ InterfaceType _numType;
+ InterfaceType _objectType;
+ InterfaceType _stackTraceType;
+ InterfaceType _streamDynamicType;
+ InterfaceType _streamType;
+ InterfaceType _stringType;
+ InterfaceType _symbolType;
+ InterfaceType _typeType;
+
+ TypeProviderForLink(this._linker);
+
+ @override
+ InterfaceType get boolType =>
+ _boolType ??= _buildInterfaceType(_linker.coreLibrary, 'bool');
+
+ @override
+ DartType get bottomType => BottomTypeImpl.instance;
+
+ @override
+ InterfaceType get deprecatedType => _deprecatedType ??=
+ _buildInterfaceType(_linker.coreLibrary, 'Deprecated');
+
+ @override
+ InterfaceType get doubleType =>
+ _doubleType ??= _buildInterfaceType(_linker.coreLibrary, 'double');
+
+ @override
+ DartType get dynamicType => DynamicTypeImpl.instance;
+
+ @override
+ InterfaceType get functionType =>
+ _functionType ??= _buildInterfaceType(_linker.coreLibrary, 'Function');
+
+ @override
+ InterfaceType get futureDynamicType =>
+ _futureDynamicType ??= futureType.instantiate(<DartType>[dynamicType]);
+
+ @override
+ InterfaceType get futureNullType =>
+ _futureNullType ??= futureType.instantiate(<DartType>[nullType]);
+
+ @override
+ InterfaceType get futureType =>
+ _futureType ??= _buildInterfaceType(_linker.asyncLibrary, 'Future');
+
+ @override
+ InterfaceType get intType =>
+ _intType ??= _buildInterfaceType(_linker.coreLibrary, 'int');
+
+ @override
+ InterfaceType get iterableDynamicType => _iterableDynamicType ??=
+ iterableType.instantiate(<DartType>[dynamicType]);
+
+ @override
+ InterfaceType get iterableType =>
+ _iterableType ??= _buildInterfaceType(_linker.coreLibrary, 'Iterable');
+
+ @override
+ InterfaceType get listType =>
+ _listType ??= _buildInterfaceType(_linker.coreLibrary, 'List');
+
+ @override
+ InterfaceType get mapType =>
+ _mapType ??= _buildInterfaceType(_linker.coreLibrary, 'Map');
+
+ @override
+ DartObjectImpl get nullObject {
+ // TODO(paulberry): implement if needed
+ throw new UnimplementedError();
+ }
+
+ @override
+ InterfaceType get nullType =>
+ _nullType ??= _buildInterfaceType(_linker.coreLibrary, 'Null');
+
+ @override
+ InterfaceType get numType =>
+ _numType ??= _buildInterfaceType(_linker.coreLibrary, 'num');
+
+ @override
+ InterfaceType get objectType =>
+ _objectType ??= _buildInterfaceType(_linker.coreLibrary, 'Object');
+
+ @override
+ InterfaceType get stackTraceType => _stackTraceType ??=
+ _buildInterfaceType(_linker.coreLibrary, 'StackTrace');
+
+ @override
+ InterfaceType get streamDynamicType =>
+ _streamDynamicType ??= streamType.instantiate(<DartType>[dynamicType]);
+
+ @override
+ InterfaceType get streamType =>
+ _streamType ??= _buildInterfaceType(_linker.asyncLibrary, 'Stream');
+
+ @override
+ InterfaceType get stringType =>
+ _stringType ??= _buildInterfaceType(_linker.coreLibrary, 'String');
+
+ @override
+ InterfaceType get symbolType =>
+ _symbolType ??= _buildInterfaceType(_linker.coreLibrary, 'Symbol');
+
+ @override
+ InterfaceType get typeType =>
+ _typeType ??= _buildInterfaceType(_linker.coreLibrary, 'Type');
+
+ @override
+ DartType get undefinedType => UndefinedTypeImpl.instance;
+
+ InterfaceType _buildInterfaceType(
+ LibraryElementForLink library, String name) {
+ return library.getContainedName(name).buildType((int i) {
+ // TODO(scheglov) accept type parameter names
+ var element = new TypeParameterElementImpl('T$i', -1);
+ return new TypeParameterTypeImpl(element);
+ }, const []);
+ }
+}
+
+/**
+ * Singleton element used for unresolved references.
+ */
+class UndefinedElementForLink extends Object with ReferenceableElementForLink {
+ static final UndefinedElementForLink instance =
+ new UndefinedElementForLink._();
+
+ UndefinedElementForLink._();
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+/**
+ * Element representing a top level variable resynthesized from a
+ * summary during linking.
+ */
+abstract class VariableElementForLink
+ implements NonParameterVariableElementImpl, PropertyInducingElement {
+ /**
+ * The unlinked representation of the variable in the summary.
+ */
+ final UnlinkedVariable unlinkedVariable;
+
+ /**
+ * If this variable is declared `const` and the enclosing library is
+ * part of the build unit being linked, the variable's node in the
+ * constant evaluation dependency graph. Otherwise `null`.
+ */
+ ConstNode _constNode;
+
+ /**
+ * If this variable has an initializer and an implicit type, and the enclosing
+ * library is part of the build unit being linked, the variable's node in the
+ * type inference dependency graph. Otherwise `null`.
+ */
+ TypeInferenceNode _typeInferenceNode;
+
+ FunctionElementForLink_Initializer _initializer;
+ DartType _inferredType;
+ DartType _declaredType;
+ PropertyAccessorElementForLink_Variable _getter;
+ PropertyAccessorElementForLink_Variable _setter;
+
+ /**
+ * The compilation unit in which this variable appears.
+ */
+ final CompilationUnitElementForLink compilationUnit;
+
+ VariableElementForLink(this.unlinkedVariable, this.compilationUnit) {
+ if (compilationUnit.isInBuildUnit &&
+ unlinkedVariable.initializer?.bodyExpr != null) {
+ _constNode = new ConstVariableNode(this);
+ if (unlinkedVariable.type == null) {
+ _typeInferenceNode = initializer.asTypeInferenceNode;
+ }
+ }
+ }
+
+ /**
+ * If the variable has an explicitly declared return type, return it.
+ * Otherwise return `null`.
+ */
+ DartType get declaredType {
+ if (unlinkedVariable.type == null) {
+ return null;
+ } else {
+ return _declaredType ??= compilationUnit.resolveTypeRef(
+ unlinkedVariable.type, _typeParameterContext);
+ }
+ }
+
+ @override
+ PropertyAccessorElementForLink_Variable get getter =>
+ _getter ??= new PropertyAccessorElementForLink_Variable(this, false);
+
+ @override
+ bool get hasImplicitType => unlinkedVariable.type == null;
+
+ /**
+ * Return the inferred type of the variable element. Should only be called if
+ * no type was explicitly declared.
+ */
+ DartType get inferredType {
+ // We should only try to infer a type when none is explicitly declared.
+ assert(unlinkedVariable.type == null);
+ if (_inferredType == null) {
+ if (_typeInferenceNode != null) {
+ assert(Linker._initializerTypeInferenceCycle == null);
+ Linker._initializerTypeInferenceCycle =
+ compilationUnit.library.libraryCycleForLink;
+ try {
+ new TypeInferenceDependencyWalker().walk(_typeInferenceNode);
+ assert(_inferredType != null);
+ } finally {
+ Linker._initializerTypeInferenceCycle = null;
+ }
+ } else if (compilationUnit.isInBuildUnit) {
+ _inferredType = DynamicTypeImpl.instance;
+ } else {
+ _inferredType = compilationUnit.getLinkedType(
+ unlinkedVariable.inferredTypeSlot, _typeParameterContext);
+ }
+ }
+ return _inferredType;
+ }
+
+ @override
+ FunctionElementForLink_Initializer get initializer {
+ if (unlinkedVariable.initializer == null) {
+ return null;
+ } else {
+ return _initializer ??= new FunctionElementForLink_Initializer(this);
+ }
+ }
+
+ @override
+ bool get isConst => unlinkedVariable.isConst;
+
+ @override
+ bool get isFinal => unlinkedVariable.isFinal;
+
+ @override
+ bool get isStatic;
+
+ @override
+ bool get isSynthetic => false;
+
+ @override
+ String get name => unlinkedVariable.name;
+
+ @override
+ DartType get propagatedType {
+ return DynamicTypeImpl.instance;
+ }
+
+ @override
+ PropertyAccessorElementForLink_Variable get setter {
+ if (!isConst && !isFinal) {
+ return _setter ??=
+ new PropertyAccessorElementForLink_Variable(this, true);
+ } else {
+ return null;
+ }
+ }
+
+ @override
+ DartType get type => declaredType ?? inferredType;
+
+ @override
+ void set type(DartType newType) {
+ // TODO(paulberry): store inferred type.
+ }
+
+ /**
+ * The context in which type parameters should be interpreted, or `null` if
+ * there are no type parameters in scope.
+ */
+ TypeParameterizedElementMixin get _typeParameterContext;
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+
+ @override
+ String toString() => '$enclosingElement.$name';
+}
« no previous file with comments | « packages/analyzer/lib/src/summary/idl.dart ('k') | packages/analyzer/lib/src/summary/name_filter.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698