| // 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/standard_ast_factory.dart'; |
| import 'package:analyzer/dart/element/element.dart'; |
| import 'package:analyzer/dart/element/type.dart'; |
| import 'package:analyzer/error/listener.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/source.dart'; |
| import 'package:analyzer/src/generated/utilities_dart.dart'; |
| import 'package:analyzer/src/summary/expr_builder.dart'; |
| import 'package:analyzer/src/summary/format.dart'; |
| import 'package:analyzer/src/summary/idl.dart'; |
| import 'package:analyzer/src/summary/package_bundle_reader.dart'; |
| import 'package:analyzer/src/summary/prelink.dart'; |
| import 'package:analyzer/src/summary/resynthesize.dart'; |
| import 'package:analyzer/src/task/strong_mode.dart'; |
| import 'package:front_end/src/dependency_walker.dart'; |
| |
| final _typesWithImplicitArguments = new Expando(); |
| |
| 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) { |
| linkedLibraries[absoluteUri] = prelink( |
| absoluteUri, |
| getUnit(absoluteUri), |
| getUnit, |
| (String absoluteUri) => getUnit(absoluteUri)?.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 != null && |
| 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) { |
| // We store all function elements by value. Synthetic elements, e.g. |
| // created for LUB, don't have actual elements; and local functions |
| // are not exposed from element model. |
| _storeFunctionElementByValue(result, element, compilationUnit); |
| // TODO(paulberry): do I need to store type arguments? |
| return result; |
| } |
| if (element is GenericFunctionTypeElementImpl) { |
| // Function types are their own type parameter context |
| typeParameterContext = element; |
| result.entityKind = EntityRefKind.genericFunctionType; |
| result.syntheticReturnType = _createLinkedType( |
| type.returnType, compilationUnit, typeParameterContext); |
| result.syntheticParams = type.parameters |
| .map((ParameterElement param) => _serializeSyntheticParam( |
| param, compilationUnit, typeParameterContext)) |
| .toList(); |
| _storeTypeArguments( |
| type.typeArguments, result, compilationUnit, typeParameterContext); |
| return result; |
| } |
| // TODO(paulberry): implement other cases. |
| throw new UnimplementedError('${element.runtimeType}'); |
| } |
| // TODO(paulberry): implement other cases. |
| throw new UnimplementedError('${type.runtimeType}'); |
| } |
| |
| DartType _dynamicIfBottom(DartType type) { |
| if (type == null || type.isBottom) { |
| return DynamicTypeImpl.instance; |
| } |
| return type; |
| } |
| |
| DartType _dynamicIfNull(DartType type) { |
| if (type == null || type.isBottom || type.isDartCoreNull) { |
| 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; |
| if (parameter.isNotOptional) { |
| b.kind = UnlinkedParamKind.required; |
| } else if (parameter.isOptionalPositional) { |
| b.kind = UnlinkedParamKind.positional; |
| } else if (parameter.isNamed) { |
| b.kind = UnlinkedParamKind.named; |
| } |
| 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; |
| } |
| |
| /** |
| * Create an [UnlinkedTypeParamBuilder] representing the given [typeParameter], |
| * which should be a type 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). |
| */ |
| UnlinkedTypeParamBuilder _serializeSyntheticTypeParameter( |
| TypeParameterElement typeParameter, |
| CompilationUnitElementInBuildUnit compilationUnit, |
| TypeParameterizedElementMixin typeParameterContext) { |
| TypeParameterElementImpl impl = typeParameter as TypeParameterElementImpl; |
| EntityRefBuilder boundBuilder = typeParameter.bound != null |
| ? _createLinkedType( |
| typeParameter.bound, compilationUnit, typeParameterContext) |
| : null; |
| CodeRangeBuilder codeRangeBuilder = |
| new CodeRangeBuilder(offset: impl.codeOffset, length: impl.codeLength); |
| return new UnlinkedTypeParamBuilder( |
| name: typeParameter.name, |
| nameOffset: typeParameter.nameOffset, |
| bound: boundBuilder, |
| codeRange: codeRangeBuilder); |
| } |
| |
| /** |
| * Store the given function [element] into the [entity] by value. |
| */ |
| void _storeFunctionElementByValue( |
| EntityRefBuilder entity, |
| FunctionElement element, |
| CompilationUnitElementInBuildUnit compilationUnit) { |
| // Element is a local function, or a synthetic function element that was |
| // generated on the fly to represent a type that has no associated source |
| // code location. Store it as value. |
| if (element is FunctionElementImpl) { |
| entity.syntheticReturnType = |
| _createLinkedType(element.returnType, compilationUnit, element); |
| entity.entityKind = EntityRefKind.syntheticFunction; |
| entity.syntheticParams = element.parameters |
| .map((ParameterElement param) => |
| _serializeSyntheticParam(param, compilationUnit, element)) |
| .toList(); |
| entity.typeParameters = element.typeParameters |
| .map((TypeParameterElement e) => |
| _serializeSyntheticTypeParameter(e, compilationUnit, element)) |
| .toList(); |
| } |
| } |
| |
| /** |
| * 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 hint => false; |
| |
| @override |
| bool get previewDart2 => true; |
| |
| @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; |
| |
| DartType _typeWithDefaultBounds; |
| |
| 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; |
| |
| DartType get typeWithDefaultBounds => _typeWithDefaultBounds ??= |
| enclosingElement.library._linker.typeSystem.instantiateToBounds(type); |
| |
| @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); |
| } |
| |
| @override |
| FieldElement getField(String name) { |
| for (FieldElement fieldElement in fields) { |
| if (name == fieldElement.name) { |
| return fieldElement; |
| } |
| } |
| return null; |
| } |
| |
| @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; |
| } |
| |
| /** |
| * Perform type inference and cycle detection on this class and |
| * store the resulting information in [compilationUnit]. |
| */ |
| void link(CompilationUnitElementInBuildUnit compilationUnit); |
| |
| @override |
| MethodElement lookUpMethod(String methodName, LibraryElement library) { |
| return AbstractClassElementImpl.lookUpMethodInClass( |
| this, methodName, library); |
| } |
| |
| @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 isEnum => false; |
| |
| @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 { |
| if (_mixins == null) { |
| // Note: in the event of a loop in the class hierarchy, the calls to |
| // collectAllSupertypes below will wind up reentrantly calling |
| // this.mixins. So to prevent infinite recursion we need to set _mixins |
| // to non-null now. It's ok that we populate it gradually; in the event |
| // of a reentrant call, the user's code is known to have errors, so it's |
| // ok if the reentrant call doesn't return the complete set of mixins; we |
| // just need to ensure that analysis terminates. |
| _mixins = <InterfaceType>[]; |
| List<InterfaceType> supertypesForMixinInference; // populated lazily |
| for (var entity in _unlinkedClass.mixins) { |
| var mixin = _computeInterfaceType(entity); |
| var mixinElement = mixin.element; |
| var slot = entity.refinedSlot; |
| if (slot != 0 && |
| mixinElement.typeParameters.isNotEmpty && |
| library._linker.strongMode) { |
| CompilationUnitElementForLink enclosingElement = |
| this.enclosingElement; |
| if (enclosingElement is CompilationUnitElementInBuildUnit) { |
| var mixinSupertypeConstraints = context.typeSystem |
| .gatherMixinSupertypeConstraints(mixinElement); |
| if (mixinSupertypeConstraints.isNotEmpty) { |
| if (supertypesForMixinInference == null) { |
| supertypesForMixinInference = <InterfaceType>[]; |
| ClassElementImpl.collectAllSupertypes( |
| supertypesForMixinInference, supertype, type); |
| for (var previousMixin in _mixins) { |
| ClassElementImpl.collectAllSupertypes( |
| supertypesForMixinInference, previousMixin, type); |
| } |
| } |
| var matchingInterfaceTypes = _findInterfaceTypesForConstraints( |
| mixinSupertypeConstraints, supertypesForMixinInference); |
| // Note: if matchingInterfaceType is null, that's an error. Also, |
| // if there are multiple matching interface types that use |
| // different type parameters, that's also an error. But we can't |
| // report errors from the linker, so we just use the |
| // first matching interface type (if there is one). The error |
| // detection logic is implemented in the ErrorVerifier. |
| if (matchingInterfaceTypes != null) { |
| // Try to pattern match matchingInterfaceTypes against |
| // mixinSupertypeConstraints to find the correct set of type |
| // parameters to apply to the mixin. |
| var inferredMixin = context.typeSystem |
| .matchSupertypeConstraints(mixinElement, |
| mixinSupertypeConstraints, matchingInterfaceTypes); |
| if (inferredMixin != null) { |
| mixin = inferredMixin; |
| enclosingElement._storeLinkedType(slot, mixin, this); |
| } |
| } |
| } |
| } else { |
| var refinedMixin = enclosingElement.getLinkedType(this, slot); |
| if (refinedMixin is InterfaceType) { |
| mixin = refinedMixin; |
| } |
| } |
| } |
| _mixins.add(mixin); |
| if (supertypesForMixinInference != null) { |
| ClassElementImpl.collectAllSupertypes( |
| supertypesForMixinInference, mixin, type); |
| } |
| } |
| } |
| return _mixins; |
| } |
| |
| @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 |
| ConstructorElement getNamedConstructor(String name) => |
| ClassElementImpl.getNamedConstructorFromList(name, constructors); |
| |
| @override |
| PropertyAccessorElement getSetter(String setterName) => |
| AbstractClassElementImpl.getSetterFromAccessors(setterName, accessors); |
| |
| @override |
| void link(CompilationUnitElementInBuildUnit compilationUnit) { |
| // Force mixins to be inferred by calling this.mixins. We don't need the |
| // return value from the getter; we just need it to execute and record the |
| // mixin inference results as a side effect. |
| this.mixins; |
| |
| 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(this, typeRef); |
| if (type is InterfaceType && !type.element.isEnum) { |
| 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; |
| } |
| |
| InterfaceType _findInterfaceTypeForElement( |
| ClassElement element, List<InterfaceType> interfaceTypes) { |
| for (var interfaceType in interfaceTypes) { |
| if (interfaceType.element == element) return interfaceType; |
| } |
| return null; |
| } |
| |
| List<InterfaceType> _findInterfaceTypesForConstraints( |
| List<InterfaceType> constraints, List<InterfaceType> interfaceTypes) { |
| var result = <InterfaceType>[]; |
| for (var constraint in constraints) { |
| var interfaceType = |
| _findInterfaceTypeForElement(constraint.element, interfaceTypes); |
| if (interfaceType == null) { |
| // No matching interface type found, so inference fails. |
| return null; |
| } |
| result.add(interfaceType); |
| } |
| return result; |
| } |
| } |
| |
| /** |
| * 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> _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 field in fields) { |
| _accessors.add(field.getter); |
| } |
| } |
| return _accessors; |
| } |
| |
| @override |
| List<ConstructorElementForLink> get constructors => const []; |
| |
| @override |
| String get displayName => _unlinkedEnum.name; |
| |
| @override |
| List<FieldElementForLink> get fields { |
| if (_fields == null) { |
| _fields = <FieldElementForLink>[]; |
| _fields.add(new FieldElementForLink_EnumField_values(this)); |
| for (UnlinkedEnumValue value in _unlinkedEnum.values) { |
| _fields.add(new FieldElementForLink_EnumField_value(this, value)); |
| } |
| _fields.add(new FieldElementForLink_EnumField_index(this)); |
| } |
| return _fields; |
| } |
| |
| @override |
| List<InterfaceType> get interfaces => const []; |
| |
| @override |
| bool get isEnum => true; |
| |
| @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 |
| ConstructorElement getNamedConstructor(String name) => null; |
| |
| @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 { |
| final _UnitResynthesizer _unitResynthesizer; |
| |
| /** |
| * 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<_ReferenceInfo> _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; |
| |
| @override |
| final Source source; |
| |
| CompilationUnitElementForLink(UnlinkedUnit unlinkedUnit, this.unitNum, |
| int numReferences, this._absoluteUri) |
| : _references = new List<_ReferenceInfo>(numReferences), |
| _unlinkedUnit = unlinkedUnit, |
| source = new InSummarySource(Uri.parse(_absoluteUri), null), |
| _unitResynthesizer = new _UnitResynthesizer() { |
| _unitResynthesizer._unit = this; |
| } |
| |
| @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) { |
| if (t.style == TypedefStyle.functionType) { |
| return new FunctionTypeAliasElementForLink(this, t); |
| } else if (t.style == TypedefStyle.genericFunctionType) { |
| return new GenericTypeAliasElementForLink(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 |
| * in [context]). If there is no inferred type in the |
| * given slot, `dynamic` is returned. |
| */ |
| DartType getLinkedType(ElementImpl context, int slot); |
| |
| @override |
| ClassElement getType(String className) => |
| CompilationUnitElementImpl.getTypeFromTypes(className, types); |
| |
| @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) => |
| resolveRefToInfo(index).element; |
| |
| _ReferenceInfo resolveRefToInfo(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; |
| _ReferenceInfo enclosingInfo = containingReference != 0 |
| ? resolveRefToInfo(containingReference) |
| : null; |
| ReferenceableElementForLink element; |
| if (containingReference != 0 && |
| _linkedUnit.references[containingReference].kind != |
| ReferenceKind.prefix) { |
| element = enclosingInfo.element.getContainedName(name); |
| } else if (linkedReference.dependency == 0) { |
| if (linkedReference.kind == ReferenceKind.unresolved) { |
| element = UndefinedElementForLink.instance; |
| } else if (name == 'void') { |
| element = enclosingElement._linker.voidElement; |
| } else if (name == '*bottom*') { |
| element = enclosingElement._linker.bottomElement; |
| } else if (name == 'dynamic') { |
| element = enclosingElement._linker.dynamicElement; |
| } else { |
| element = enclosingElement.getContainedName(name); |
| } |
| } else { |
| LibraryElementForLink dependency = |
| enclosingElement.buildImportedLibrary(linkedReference.dependency); |
| element = dependency.getContainedName(name); |
| } |
| _references[index] = new _ReferenceInfo( |
| enclosingInfo, element, name, linkedReference.numTypeParameters != 0); |
| } |
| return _references[index]; |
| } |
| |
| @override |
| DartType resolveTypeRef(ElementImpl context, EntityRef entity, |
| {bool defaultVoid: false, |
| bool instantiateToBoundsAllowed: true, |
| bool declaredType: false}) { |
| if (entity == null) { |
| if (defaultVoid) { |
| return VoidTypeImpl.instance; |
| } else { |
| return DynamicTypeImpl.instance; |
| } |
| } |
| if (entity.paramReference != 0) { |
| return context.typeParameterContext |
| .getTypeParameterType(entity.paramReference); |
| } else if (entity.entityKind == EntityRefKind.genericFunctionType) { |
| return new GenericFunctionTypeElementForLink(this, context, entity).type; |
| } else if (entity.syntheticReturnType != null) { |
| FunctionElementImpl element = |
| new FunctionElementForLink_Synthetic(this, context, entity); |
| return element.type; |
| } else if (entity.implicitFunctionTypeIndices.isNotEmpty) { |
| DartType type = resolveRef(entity.reference).asStaticType; |
| for (int index in entity.implicitFunctionTypeIndices) { |
| type = (type as FunctionType).parameters[index].type; |
| } |
| return type; |
| } else { |
| ReferenceableElementForLink element = resolveRef(entity.reference); |
| bool implicitTypeArgumentsInUse = false; |
| |
| DartType getTypeArgument(int i) { |
| if (i < entity.typeArguments.length) { |
| return resolveTypeRef(context, entity.typeArguments[i]); |
| } else { |
| implicitTypeArgumentsInUse = true; |
| if (!instantiateToBoundsAllowed) { |
| // Do not allow buildType to instantiate the bounds; force dynamic. |
| return DynamicTypeImpl.instance; |
| } else { |
| return null; |
| } |
| } |
| } |
| |
| var type = element.buildType( |
| getTypeArgument, entity.implicitFunctionTypeIndices); |
| if (implicitTypeArgumentsInUse) { |
| _typesWithImplicitArguments[type] = true; |
| } |
| return type; |
| } |
| } |
| |
| @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, |
| 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) { |
| return i; |
| } |
| } |
| int result = linkedReferences.length; |
| linkedReferences.add(new LinkedReferenceBuilder( |
| dependency: dependency, |
| name: name, |
| numTypeParameters: numTypeParameters, |
| unit: unitNum, |
| containingReference: containingReference, |
| kind: kind)); |
| 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 ExecutableElementForLink_NonLocal) { |
| ClassElementForLink_Class enclosingClass = element.enclosingClass; |
| ReferenceKind kind; |
| switch (element.serializedExecutable.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.serializedExecutable.kind}'); |
| } |
| if (enclosingClass == null) { |
| return addRawReference(element.name, |
| numTypeParameters: element.typeParameters.length, |
| dependency: |
| library.addDependency(element.library as LibraryElementForLink), |
| unitNum: element.compilationUnit.unitNum, |
| kind: kind); |
| } else { |
| return addRawReference(element.name, |
| numTypeParameters: element.typeParameters.length, |
| containingReference: addReference(enclosingClass), |
| 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), |
| unitNum: element.compilationUnit.unitNum, |
| 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(ElementImpl context, int slot) { |
| // 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, |
| (clazz) => (clazz.library as LibraryElementInBuildUnit) |
| .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)); |
| } |
| } |
| } |
| |
| /** |
| * Store the given error [error] in the given [slot]. |
| */ |
| void _storeLinkedTypeError(int slot, TopLevelInferenceErrorBuilder error) { |
| if (slot != 0) { |
| if (error != null) { |
| error.slot = slot; |
| _linkedUnit.topLevelInferenceErrors.add(error); |
| } |
| } |
| } |
| } |
| |
| /** |
| * 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; |
| |
| /** |
| * Set of slot ids corresponding to parameters that inherit `covariant`. |
| */ |
| Set<int> parametersInheritingCovariant; |
| |
| 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) { |
| parametersInheritingCovariant = |
| _linkedUnit.parametersInheritingCovariant.toSet(); |
| // 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(ElementImpl context, int slot) { |
| if (slot < _linkedTypeRefs.length) { |
| return resolveTypeRef(context, _linkedTypeRefs[slot]); |
| } 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.serializedExecutable; |
| 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.serializedExecutable.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 (UnlinkedExpr 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.serializedExecutable.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, |
| UnlinkedExpr unlinkedConst, |
| CompilationUnitElementForLink compilationUnit) { |
| if (unlinkedConst == null) { |
| return; |
| } |
| int refPtr = 0; |
| int intPtr = 0; |
| for (UnlinkedExprOperation operation in unlinkedConst.operations) { |
| switch (operation) { |
| case UnlinkedExprOperation.pushInt: |
| intPtr++; |
| break; |
| case UnlinkedExprOperation.pushLongInt: |
| int numInts = unlinkedConst.ints[intPtr++]; |
| intPtr += numInts; |
| break; |
| case UnlinkedExprOperation.concatenate: |
| intPtr++; |
| break; |
| case UnlinkedExprOperation.pushReference: |
| EntityRef ref = unlinkedConst.references[refPtr++]; |
| ConstVariableNode variable = |
| compilationUnit.resolveRef(ref.reference).asConstVariable; |
| if (variable != null) { |
| dependencies.add(variable); |
| } |
| break; |
| case UnlinkedExprOperation.makeUntypedList: |
| case UnlinkedExprOperation.makeUntypedMap: |
| intPtr++; |
| break; |
| case UnlinkedExprOperation.assignToRef: |
| refPtr++; |
| break; |
| case UnlinkedExprOperation.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 UnlinkedExprOperation.invokeMethod: |
| intPtr += 2; |
| int numTypeArguments = unlinkedConst.ints[intPtr++]; |
| refPtr += numTypeArguments; |
| break; |
| case UnlinkedExprOperation.makeTypedList: |
| refPtr++; |
| intPtr++; |
| break; |
| case UnlinkedExprOperation.makeTypedMap: |
| refPtr += 2; |
| intPtr++; |
| break; |
| case UnlinkedExprOperation.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 UnlinkedExprOperation.typeCast: |
| case UnlinkedExprOperation.typeCheck: |
| refPtr++; |
| break; |
| case UnlinkedExprOperation.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 && |
| serializedExecutable != null && |
| serializedExecutable.constCycleSlot != 0) { |
| _constNode = new ConstConstructorNode(this); |
| } |
| } |
| |
| @override |
| ConstructorElementForLink get asConstructor => this; |
| |
| @override |
| ClassElementImpl get enclosingElement => super.enclosingClass; |
| |
| @override |
| String get identifier => name; |
| |
| @override |
| bool get isConst => serializedExecutable.isConst; |
| |
| @override |
| bool get isCycleFree { |
| if (!_constNode.isEvaluated) { |
| new ConstDependencyWalker().walk(_constNode); |
| } |
| return _constNode.isCycleFree; |
| } |
| |
| @override |
| DartType get returnType => enclosingElement.type; |
| |
| @override |
| List<TypeParameterElement> get typeParameters => const []; |
| |
| /** |
| * Perform const cycle detection on this constructor. |
| */ |
| void link(CompilationUnitElementInBuildUnit compilationUnit) { |
| if (_constNode != null && !isCycleFree) { |
| compilationUnit._storeConstCycle(serializedExecutable.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); |
| } |
| |
| /** |
| * 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 serializedExecutable; |
| |
| DartType _declaredReturnType; |
| DartType _inferredReturnType; |
| FunctionTypeImpl _type; |
| String _name; |
| String _displayName; |
| |
| final CompilationUnitElementForLink compilationUnit; |
| |
| ExecutableElementForLink(this.compilationUnit, this.serializedExecutable); |
| |
| @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 (serializedExecutable.returnType == null) { |
| return null; |
| } else { |
| return _declaredReturnType ??= |
| compilationUnit.resolveTypeRef(this, serializedExecutable.returnType); |
| } |
| } |
| |
| @override |
| String get displayName { |
| if (_displayName == null) { |
| _displayName = serializedExecutable.name; |
| if (serializedExecutable.kind == UnlinkedExecutableKind.setter) { |
| _displayName = _displayName.substring(0, _displayName.length - 1); |
| } |
| } |
| return _displayName; |
| } |
| |
| @override |
| CompilationUnitElementImpl get enclosingUnit => compilationUnit; |
| |
| /** |
| * Return a list containing all of the functions defined within this |
| * executable element. |
| */ |
| List<FunctionElement> get functions { |
| return []; |
| } |
| |
| @override |
| bool get hasImplicitReturnType => serializedExecutable.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(serializedExecutable.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 (serializedExecutable.kind == UnlinkedExecutableKind.constructor) { |
| // TODO(paulberry): implement. |
| throw new UnimplementedError(); |
| } else if (compilationUnit.isInBuildUnit) { |
| _inferredReturnType = _computeDefaultReturnType(); |
| } else { |
| _inferredReturnType = compilationUnit.getLinkedType( |
| this, serializedExecutable.inferredReturnTypeSlot); |
| } |
| } |
| return _inferredReturnType; |
| } |
| |
| @override |
| bool get isGenerator => serializedExecutable.isGenerator; |
| |
| @override |
| bool get isStatic => serializedExecutable.isStatic; |
| |
| @override |
| bool get isSynthetic => false; |
| |
| @override |
| LibraryElement get library => enclosingElement.library; |
| |
| @override |
| String get name { |
| if (_name == null) { |
| _name = serializedExecutable.name; |
| if (_name == '-' && serializedExecutable.parameters.isEmpty) { |
| _name = 'unary-'; |
| } |
| } |
| return _name; |
| } |
| |
| @override |
| DartType get returnType => declaredReturnType ?? inferredReturnType; |
| |
| @override |
| void set returnType(DartType inferredType) { |
| _inferredReturnType = inferredType; |
| } |
| |
| @override |
| FunctionTypeImpl get type => _type ??= new FunctionTypeImpl(this); |
| |
| @override |
| TypeParameterizedElementMixin get typeParameterContext => this; |
| |
| @override |
| List<UnlinkedParam> get unlinkedParameters => serializedExecutable.parameters; |
| |
| @override |
| List<UnlinkedTypeParam> get unlinkedTypeParams => |
| serializedExecutable.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() { |
| var kind = serializedExecutable.kind; |
| var isMethod = kind == UnlinkedExecutableKind.functionOrMethod; |
| var isSetter = kind == UnlinkedExecutableKind.setter; |
| if ((isSetter || isMethod && serializedExecutable.name == '[]=') && |
| (library as LibraryElementForLink)._linker.strongMode) { |
| // In strong mode, setters and `[]=` operators 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 (serializedExecutable.returnType == null) { |
| compilationUnit._storeLinkedType( |
| serializedExecutable.inferredReturnTypeSlot, |
| inferredReturnType, |
| this); |
| } |
| for (ParameterElementForLink parameterElement in parameters) { |
| parameterElement.link(compilationUnit); |
| } |
| } |
| } |
| |
| class ExprTypeComputer { |
| final ExprBuilder _builder; |
| |
| final AstRewriteVisitor _astRewriteVisitor; |
| |
| final ResolverVisitor _resolverVisitor; |
| |
| factory ExprTypeComputer(FunctionElementForLink_Local functionElement) { |
| CompilationUnitElementForLink unit = functionElement.compilationUnit; |
| LibraryElementForLink library = unit.enclosingElement; |
| Linker linker = library._linker; |
| TypeProvider typeProvider = linker.typeProvider; |
| var unlinkedExecutable = functionElement.serializedExecutable; |
| UnlinkedExpr unlinkedConst = unlinkedExecutable.bodyExpr; |
| var errorListener = AnalysisErrorListener.NULL_LISTENER; |
| var astRewriteVisitor = new AstRewriteVisitor( |
| linker.typeSystem, library, unit.source, typeProvider, errorListener); |
| // TODO(paulberry): Do we need to pass a nameScope to |
| // resolverVisitor to get type variables to resolve properly? |
| var resolverVisitor = new ResolverVisitor( |
| library, unit.source, typeProvider, errorListener, |
| propagateTypes: false, reportConstEvaluationErrors: false); |
| return new ExprTypeComputer._( |
| unit._unitResynthesizer, |
| astRewriteVisitor, |
| resolverVisitor, |
| errorListener, |
| functionElement, |
| unlinkedConst, |
| unlinkedExecutable.localFunctions); |
| } |
| |
| ExprTypeComputer._( |
| UnitResynthesizer unitResynthesizer, |
| this._astRewriteVisitor, |
| this._resolverVisitor, |
| AnalysisErrorListener _errorListener, |
| ElementImpl context, |
| UnlinkedExpr unlinkedConst, |
| List<UnlinkedExecutable> localFunctions) |
| : _builder = new ExprBuilder(unitResynthesizer, context, unlinkedConst, |
| requireValidConst: false, localFunctions: localFunctions); |
| |
| TopLevelInferenceErrorKind get errorKind { |
| // TODO(paulberry): should we return TopLevelInferenceErrorKind.assignment |
| // sometimes? |
| return null; |
| } |
| |
| DartType compute() { |
| if (_builder.uc == null) { |
| // No function body was stored for this function, so we can't infer its |
| // return type. Assume `dynamic`. |
| return DynamicTypeImpl.instance; |
| } |
| // If no operations, we cannot compute the type. Assume `dynamic`. |
| if (_builder.uc.operations.isEmpty) { |
| return DynamicTypeImpl.instance; |
| } |
| var expression = _builder.build(); |
| var container = |
| astFactory.expressionFunctionBody(null, null, expression, null); |
| expression.accept(_astRewriteVisitor); |
| expression = container.expression; |
| expression.accept(_resolverVisitor); |
| return expression.staticType; |
| } |
| } |
| |
| /** |
| * 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; |
| |
| TopLevelInferenceErrorBuilder _inferenceError; |
| |
| 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); |
| compilationUnit._storeLinkedTypeError( |
| unlinkedVariable.inferredTypeSlot, _inferenceError); |
| if (initializer != null) { |
| compilationUnit._storeLinkedTypeError( |
| unlinkedVariable.inferredTypeSlot, initializer._inferenceError); |
| initializer.link(compilationUnit); |
| } |
| } |
| } |
| |
| void setInferenceError(TopLevelInferenceErrorBuilder error) { |
| assert(_inferenceError == null); |
| _inferenceError = error; |
| } |
| |
| @override |
| String toString() => '$enclosingElement.$name'; |
| } |
| |
| /** |
| * Specialization of [FieldElementForLink] for enum fields. |
| */ |
| class FieldElementForLink_EnumField extends FieldElementForLink |
| implements FieldElement { |
| PropertyAccessorElementForLink_EnumField _getter; |
| |
| @override |
| final ClassElementForLink_Enum enclosingElement; |
| |
| FieldElementForLink_EnumField(this.enclosingElement); |
| |
| @override |
| PropertyAccessorElementForLink_EnumField get getter => |
| _getter ??= new PropertyAccessorElementForLink_EnumField(this); |
| |
| @override |
| bool get isSynthetic => false; |
| |
| @override |
| noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); |
| |
| @override |
| String toString() => '$enclosingElement.$name'; |
| } |
| |
| /** |
| * Specialization of [FieldElementForLink] for the 'index' enum field. |
| */ |
| class FieldElementForLink_EnumField_index |
| extends FieldElementForLink_EnumField { |
| FieldElementForLink_EnumField_index(ClassElementForLink_Enum enclosingElement) |
| : super(enclosingElement); |
| |
| @override |
| bool get isStatic => false; |
| |
| @override |
| String get name => 'index'; |
| |
| @override |
| DartType get type => |
| enclosingElement.enclosingElement.library._linker.typeProvider.intType; |
| } |
| |
| /** |
| * Specialization of [FieldElementForLink] for enum fields. |
| */ |
| class FieldElementForLink_EnumField_value |
| extends FieldElementForLink_EnumField { |
| /** |
| * The unlinked representation of the field in the summary. |
| */ |
| final UnlinkedEnumValue unlinkedEnumValue; |
| |
| FieldElementForLink_EnumField_value( |
| ClassElementForLink_Enum enclosingElement, this.unlinkedEnumValue) |
| : super(enclosingElement); |
| |
| @override |
| bool get isStatic => true; |
| |
| @override |
| String get name => unlinkedEnumValue.name; |
| |
| @override |
| DartType get type => enclosingElement.type; |
| } |
| |
| /** |
| * Specialization of [FieldElementForLink] for the 'values' enum field. |
| */ |
| class FieldElementForLink_EnumField_values |
| extends FieldElementForLink_EnumField { |
| FieldElementForLink_EnumField_values( |
| ClassElementForLink_Enum enclosingElement) |
| : super(enclosingElement); |
| |
| @override |
| bool get isStatic => true; |
| |
| @override |
| String get name => 'values'; |
| |
| @override |
| DartType get type => enclosingElement.valuesType; |
| } |
| |
| class FieldFormalParameterElementForLink extends ParameterElementForLink |
| implements FieldFormalParameterElement { |
| FieldElement _field; |
| DartType _type; |
| |
| FieldFormalParameterElementForLink( |
| ParameterParentElementForLink enclosingElement, |
| UnlinkedParam unlinkedParam, |
| TypeParameterizedElementMixin typeParameterContext, |
| CompilationUnitElementForLink compilationUnit, |
| int parameterIndex) |
| : super(enclosingElement, unlinkedParam, typeParameterContext, |
| compilationUnit, parameterIndex); |
| |
| @override |
| FieldElement get field { |
| if (_field == null) { |
| Element enclosingConstructor = enclosingElement; |
| if (enclosingConstructor is ConstructorElement) { |
| Element enclosingClass = enclosingConstructor.enclosingElement; |
| if (enclosingClass is ClassElement) { |
| FieldElement field = enclosingClass.getField(unlinkedParam.name); |
| if (field != null && !field.isSynthetic) { |
| _field = field; |
| } |
| } |
| } |
| } |
| return _field; |
| } |
| |
| @override |
| bool get isInitializingFormal => true; |
| |
| @override |
| DartType get type { |
| return _type ??= field?.type ?? DynamicTypeImpl.instance; |
| } |
| } |
| |
| /** |
| * 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 |
| bool get isSynthetic => true; |
| |
| @override |
| DartType get returnType { |
| if (_returnType == null) { |
| if (enclosingElement.unlinkedParam.type == null) { |
| _returnType = DynamicTypeImpl.instance; |
| } else { |
| _returnType = enclosingElement.compilationUnit.resolveTypeRef( |
| enclosingElement, enclosingElement.unlinkedParam.type); |
| } |
| } |
| 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; |
| TopLevelInferenceErrorBuilder _inferenceError; |
| |
| 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 |
| String get identifier => ''; |
| |
| @override |
| bool get isAsynchronous => serializedExecutable.isAsynchronous; |
| |
| @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 |
| UnlinkedExecutable get serializedExecutable => |
| _variable.unlinkedVariable.initializer; |
| |
| @override |
| TypeParameterizedElementMixin get typeParameterContext => this; |
| |
| @override |
| List<UnlinkedTypeParam> get unlinkedTypeParams => const []; |
| |
| @override |
| bool get _hasTypeBeenInferred => _inferredReturnType != null; |
| |
| @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( |
| serializedExecutable.inferredReturnTypeSlot, |
| _inferredReturnType, |
| typeParameterContext); |
| for (FunctionElementForLink_Local_NonSynthetic function in functions) { |
| function.link(compilationUnit); |
| } |
| } |
| |
| @override |
| noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); |
| |
| @override |
| String toString() => _variable.toString(); |
| |
| @override |
| void _setInferenceError(TopLevelInferenceErrorBuilder error) { |
| assert(!_hasTypeBeenInferred); |
| _inferenceError = error; |
| } |
| |
| @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 [error] as the type inference error for this function. |
| * Should only be called if [_hasTypeBeenInferred] is `false`. |
| */ |
| void _setInferenceError(TopLevelInferenceErrorBuilder error); |
| |
| /** |
| * 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 ??= serializedExecutable.localFunctions |
| .map((UnlinkedExecutable ex) => |
| new FunctionElementForLink_Local_NonSynthetic( |
| compilationUnit, this, ex)) |
| .toList(); |
| |
| @override |
| String get identifier { |
| String identifier = serializedExecutable.name; |
| Element enclosing = this.enclosingElement; |
| if (enclosing is ExecutableElementForLink) { |
| int id = |
| ElementImpl.findElementIndexUsingIdentical(enclosing.functions, this); |
| identifier += "@$id"; |
| } |
| return identifier; |
| } |
| |
| @override |
| bool get isAsynchronous => serializedExecutable.isAsynchronous; |
| |
| @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) { |
| if (serializedExecutable.returnType == null) { |
| compilationUnit._storeLinkedType( |
| serializedExecutable.inferredReturnTypeSlot, |
| inferredReturnType, |
| this); |
| } |
| for (FunctionElementForLink_Local_NonSynthetic function in functions) { |
| function.link(compilationUnit); |
| } |
| } |
| |
| @override |
| noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); |
| |
| @override |
| String toString() => enclosingElement.toString(); |
| |
| @override |
| void _setInferenceError(TopLevelInferenceErrorBuilder error) {} |
| |
| @override |
| void _setInferredType(DartType type) { |
| // TODO(paulberry): store the inferred return type in the summary. |
| assert(!_hasTypeBeenInferred); |
| _inferredReturnType = _dynamicIfBottom(type); |
| } |
| } |
| |
| /** |
| * Synthetic function element which is created for local functions. |
| */ |
| class FunctionElementForLink_Synthetic extends ExecutableElementForLink |
| with ReferenceableElementForLink |
| implements FunctionElementForLink_Local { |
| @override |
| final Element enclosingElement; |
| |
| final EntityRef _entityRef; |
| |
| FunctionElementForLink_Synthetic( |
| CompilationUnitElementForLink compilationUnit, |
| this.enclosingElement, |
| this._entityRef) |
| : super(compilationUnit, null); |
| |
| @override |
| TypeParameterizedElementMixin get enclosingTypeParameterContext { |
| if (enclosingElement is TypeParameterizedElementMixin) { |
| return enclosingElement; |
| } |
| return null; |
| } |
| |
| @override |
| DartType get returnType { |
| return _declaredReturnType ??= enclosingUnit.resynthesizerContext |
| .resolveTypeRef(this, _entityRef.syntheticReturnType); |
| } |
| |
| @override |
| List<UnlinkedParam> get unlinkedParameters => _entityRef.syntheticParams; |
| |
| @override |
| List<UnlinkedTypeParam> get unlinkedTypeParams => _entityRef.typeParameters; |
| |
| @override |
| noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); |
| } |
| |
| /** |
| * 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(this, _unlinkedTypedef.returnType); |
| |
| @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.forTypedef(this, |
| typeArguments: typeArguments); |
| } |
| } else { |
| return _type ??= new FunctionTypeImpl.forTypedef(this); |
| } |
| } |
| |
| @override |
| noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); |
| |
| @override |
| String toString() => '$enclosingElement.$name'; |
| } |
| |
| /** |
| * Element representing a generic function resynthesized from a summary during |
| * linking. |
| */ |
| class GenericFunctionTypeElementForLink extends Object |
| with |
| TypeParameterizedElementMixin, |
| ParameterParentElementForLink, |
| ReferenceableElementForLink |
| implements GenericFunctionTypeElementImpl, ElementImpl { |
| @override |
| final CompilationUnitElementForLink enclosingUnit; |
| |
| @override |
| final ElementImpl enclosingElement; |
| |
| /** |
| * The linked representation of the generic function in the summary. |
| */ |
| final EntityRef _entity; |
| |
| DartType _returnType; |
| FunctionTypeImpl _type; |
| |
| GenericFunctionTypeElementForLink( |
| this.enclosingUnit, this.enclosingElement, this._entity); |
| |
| @override |
| DartType get asStaticType { |
| return enclosingUnit.enclosingElement._linker.typeProvider.typeType; |
| } |
| |
| @override |
| ContextForLink get context => enclosingElement.context; |
| |
| @override |
| TypeParameterizedElementMixin get enclosingTypeParameterContext { |
| return enclosingElement.typeParameterContext; |
| } |
| |
| @override |
| String get identifier => name; |
| |
| @override |
| List<int> get implicitFunctionTypeIndices => const <int>[]; |
| |
| @override |
| bool get isSynthetic => false; |
| |
| @override |
| LibraryElementForLink get library => enclosingElement.library; |
| |
| @override |
| String get name => '-'; |
| |
| @override |
| DartType get returnType => _returnType ??= |
| enclosingUnit.resolveTypeRef(this, _entity.syntheticReturnType); |
| |
| @override |
| FunctionType get type { |
| return _type ??= new FunctionTypeImpl(this); |
| } |
| |
| @override |
| TypeParameterizedElementMixin get typeParameterContext => this; |
| |
| @override |
| List<UnlinkedParam> get unlinkedParameters => _entity.syntheticParams; |
| |
| @override |
| List<UnlinkedTypeParam> get unlinkedTypeParams => _entity.typeParameters; |
| |
| @override |
| noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); |
| |
| @override |
| String toString() => '$enclosingElement.$name'; |
| } |
| |
| /** |
| * Element representing a generic typedef resynthesized from a summary during |
| * linking. |
| */ |
| class GenericTypeAliasElementForLink extends Object |
| with |
| TypeParameterizedElementMixin, |
| ParameterParentElementForLink, |
| ReferenceableElementForLink |
| implements FunctionTypeAliasElementForLink, ElementImpl { |
| @override |
| final CompilationUnitElementForLink enclosingElement; |
| |
| /** |
| * The unlinked representation of the typedef in the summary. |
| */ |
| final UnlinkedTypedef _unlinkedTypedef; |
| |
| GenericTypeAliasElementForLink(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 => enclosingElement.resolveTypeRef( |
| this, _unlinkedTypedef.returnType.syntheticReturnType); |
| |
| @override |
| TypeParameterizedElementMixin get typeParameterContext => this; |
| |
| @override |
| List<UnlinkedParam> get unlinkedParameters => |
| _unlinkedTypedef.returnType.syntheticParams; |
| |
| @override |
| List<UnlinkedTypeParam> get unlinkedTypeParams { |
| var result = _unlinkedTypedef.typeParameters.toList(); |
| result.addAll(_unlinkedTypedef.returnType.typeParameters); |
| return result; |
| } |
| |
| @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.forTypedef(this, |
| typeArguments: typeArguments); |
| } |
| } else { |
| return 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.getDependencies(node)) { |
| 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> |
| extends LibraryResynthesizerContextMixin implements LibraryElementImpl { |
| final _LibraryResynthesizer resynthesizer; |
| |
| /** |
| * Pointer back to the linker. |
| */ |
| final Linker _linker; |
| |
| /** |
| * The absolute URI of this library. |
| */ |
| final Uri _absoluteUri; |
| |
| List<UnitElement> _units; |
| List<UnitElement> _parts; |
| final Map<String, ReferenceableElementForLink> _containedNames = |
| <String, ReferenceableElementForLink>{}; |
| final List<LibraryElementForLink> _dependencies = <LibraryElementForLink>[]; |
| UnlinkedUnit _unlinkedDefiningUnit; |
| List<LibraryElementForLink> _importedLibraries; |
| List<LibraryElementForLink> _exportedLibraries; |
| |
| Namespace _exportNamespace; |
| |
| Namespace _publicNamespace; |
| |
| FunctionElement _loadLibraryFunction; |
| |
| LibraryElementForLink(this._linker, this._absoluteUri) |
| : resynthesizer = new _LibraryResynthesizer() { |
| resynthesizer._library = this; |
| if (_linkedLibrary != null) { |
| _dependencies.length = _linkedLibrary.dependencies.length; |
| } |
| } |
| |
| @override |
| ContextForLink get context => _linker.context; |
| |
| @override |
| UnitElement get definingCompilationUnit => units[0]; |
| |
| @override |
| Element get enclosingElement => null; |
| |
| @override |
| List<LibraryElementForLink> get exportedLibraries => |
| _exportedLibraries ??= _linkedLibrary.exportDependencies |
| .map(buildImportedLibrary) |
| .where((library) => library != null) |
| .toList(); |
| |
| @override |
| Namespace get exportNamespace => |
| _exportNamespace ??= resynthesizerContext.buildExportNamespace(); |
| |
| @override |
| String get identifier => _absoluteUri.toString(); |
| |
| @override |
| List<LibraryElementForLink> get importedLibraries => _importedLibraries ??= |
| _linkedLibrary.importDependencies.map(buildImportedLibrary).toList(); |
| |
| @override |
| bool get isDartAsync => _absoluteUri.toString() == 'dart:async'; |
| |
| @override |
| bool get isDartCore => _absoluteUri.toString() == 'dart:core'; |
| |
| @override |
| bool get isInSdk => _absoluteUri.scheme == 'dart'; |
| |
| @override |
| bool get isSynthetic => _linkedLibrary == null; |
| |
| /** |
| * 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 |
| FunctionElement get loadLibraryFunction => |
| _loadLibraryFunction ??= LibraryElementImpl |
| .createLoadLibraryFunctionForLibrary(_linker.typeProvider, this); |
| |
| @override |
| String get name { |
| return _unlinkedDefiningUnit.libraryName; |
| } |
| |
| List<UnitElement> get parts => _parts ??= units.sublist(1); |
| |
| @override |
| Namespace get publicNamespace => |
| _publicNamespace ??= resynthesizerContext.buildPublicNamespace(); |
| |
| @override |
| LibraryResynthesizerContext get resynthesizerContext => this; |
| |
| @override |
| Source get source => definingCompilationUnit.source; |
| |
| @override |
| List<UnitElement> get units { |
| if (_units == null) { |
| UnlinkedUnit definingUnit = unlinkedDefiningUnit; |
| _units = <UnitElement>[ |
| _makeUnitElement(definingUnit, 0, _absoluteUri.toString()) |
| ]; |
| int numParts = definingUnit.parts.length; |
| for (int i = 0; i < numParts; i++) { |
| String partRelativeUriStr = definingUnit.publicNamespace.parts[i]; |
| |
| if (partRelativeUriStr.isEmpty) { |
| continue; |
| } |
| |
| Uri partRelativeUri; |
| try { |
| partRelativeUri = Uri.parse(partRelativeUriStr); |
| } on FormatException { |
| continue; |
| } |
| |
| String partAbsoluteUri = |
| resolveRelativeUri(_absoluteUri, partRelativeUri).toString(); |
| UnlinkedUnit partUnit = _linker.getUnit(partAbsoluteUri); |
| _units.add(_makeUnitElement( |
| partUnit ?? new UnlinkedUnitBuilder(), i + 1, partAbsoluteUri)); |
| } |
| } |
| return _units; |
| } |
| |
| @override |
| UnlinkedUnit get unlinkedDefiningUnit => _unlinkedDefiningUnit ??= |
| _linker.getUnit(_absoluteUri.toString()) ?? new UnlinkedUnitBuilder(); |
| |
| List<LinkedExportName> get _linkedExportNames => |
| _linkedLibrary == null ? [] : _linkedLibrary.exportNames; |
| |
| /** |
| * The linked representation of the library in the summary. |
| */ |
| LinkedLibrary get _linkedLibrary; |
| |
| /** |
| * Return the [LibraryElement] corresponding to the given dependency [index]. |
| */ |
| LibraryElementForLink buildImportedLibrary(int index) { |
| LibraryElementForLink result = _dependencies[index]; |
| if (result == null) { |
| Uri uri; |
| String uriStr = _linkedLibrary.dependencies[index].uri; |
| if (uriStr.isEmpty) { |
| uri = _absoluteUri; |
| } else { |
| try { |
| uri = Uri.parse(uriStr); |
| } on FormatException { |
| return null; |
| } |
| } |
| |
| result = _linker.getLibrary(uri); |
| _dependencies[index] = result; |
| } |
| return result; |
| } |
| |
| /** |
| * 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 |
| List<ImportElement> getImportsWithPrefix(PrefixElement prefixElement) => |
| LibraryElementImpl.getImportsWithPrefixFromImports( |
| prefixElement, imports); |
| |
| @override |
| ClassElement getType(String className) => LibraryElementImpl.getTypeFromParts( |
| className, definingCompilationUnit, parts); |
| |
| @override |
| noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); |
| |
| @override |
| String toString() => _absoluteUri.toString(); |
| |
| /** |
| * 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; |
| |
| List<ImportElement> _imports; |
| |
| List<PrefixElement> _prefixes; |
| |
| LibraryElementInBuildUnit(Linker linker, Uri absoluteUri, this._linkedLibrary) |
| : super(linker, absoluteUri) { |
| _libraryNode = new LibraryNode(this); |
| } |
| |
| @override |
| List<ImportElement> get imports => |
| _imports ??= LibraryElementImpl.buildImportsFromSummary(this, |
| _unlinkedDefiningUnit.imports, _linkedLibrary.importDependencies); |
| |
| /** |
| * Get the inheritance manager for this library (creating it if necessary). |
| */ |
| InheritanceManager get inheritanceManager => |
| _inheritanceManager ??= new InheritanceManager(this, ignoreErrors: true); |
| |
| @override |
| LibraryCycleForLink get libraryCycleForLink { |
| if (!_libraryNode.isEvaluated) { |
| new LibraryDependencyWalker().walk(_libraryNode); |
| } |
| return _libraryNode._libraryCycle; |
| } |
| |
| @override |
| List<PrefixElement> get prefixes => |
| _prefixes ??= LibraryElementImpl.buildPrefixesFromImports(imports); |
| |
| /** |
| * 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(buildImportedLibrary(i), library)) { |
| return i; |
| } |
| } |
| int result = _linkedLibrary.dependencies.length; |
| Uri libraryUri = library._absoluteUri; |
| List<String> partsRelativeToDependency = |
| library.unlinkedDefiningUnit.publicNamespace.parts; |
| List<String> partsAbsolute = partsRelativeToDependency |
| .map((partUri) => |
| resolveRelativeUri(libraryUri, Uri.parse(partUri)).toString()) |
| .toList(); |
| _linkedLibrary.dependencies.add(new LinkedDependencyBuilder( |
| parts: partsAbsolute, uri: libraryUri.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 == null |
| ? new LinkedUnitBuilder() |
| : _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(typeProvider) |
| : new TypeSystemImpl(typeProvider); |
| |
| /** |
| * 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'; |
| } |
| |
| /** |
| * 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 handled 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; |
| |
| /** |
| * Whether the [_element] was computed (even if to `null`). |
| */ |
| bool _elementReady = false; |
| |
| /** |
| * The cached [ExecutableElement] represented by this element. |
| */ |
| ExecutableElement _element; |
| |
| NonstaticMemberElementForLink(this._library, this._target, this._name); |
| |
| @override |
| ConstVariableNode get asConstVariable => _target.asConstVariable; |
| |
| /** |
| * Return the [ExecutableElement] represented by this element. |
| */ |
| ExecutableElement get asExecutableElement { |
| if (!_elementReady) { |
| _elementReady = true; |
| DartType targetType = _target.asStaticType; |
| if (targetType.isDynamic) { |
| targetType = _library._linker.typeProvider.objectType; |
| } |
| if (targetType is InterfaceType) { |
| _element = |
| targetType.lookUpInheritedGetterOrMethod(_name, library: _library); |
| } |
| // TODO(paulberry): handle .call on function types and .toString or |
| // .hashCode on all types. |
| } |
| return _element; |
| } |
| |
| @override |
| DartType get asStaticType { |
| if (_library._linker.strongMode) { |
| ExecutableElement element = asExecutableElement; |
| if (element != null) { |
| if (element is PropertyAccessorElement) { |
| return element.returnType; |
| } else { |
| // Method tear-off |
| return element.type; |
| } |
| } |
| } |
| 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; |
| TopLevelInferenceErrorBuilder _inferenceError; |
| 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); |
| } |
| if (compilationUnit is CompilationUnitElementInDependency) { |
| _inheritsCovariant = |
| (compilationUnit as CompilationUnitElementInDependency) |
| .parametersInheritingCovariant |
| .contains(unlinkedParam.inheritsCovariantSlot); |
| } |
| } |
| |
| factory ParameterElementForLink.forFactory( |
| ParameterParentElementForLink enclosingElement, |
| UnlinkedParam unlinkedParameter, |
| TypeParameterizedElementMixin typeParameterContext, |
| CompilationUnitElementForLink compilationUnit, |
| int parameterIndex) { |
| if (unlinkedParameter.isInitializingFormal) { |
| return new FieldFormalParameterElementForLink( |
| enclosingElement, |
| unlinkedParameter, |
| typeParameterContext, |
| typeParameterContext.enclosingUnit.resynthesizerContext |
| as CompilationUnitElementForLink, |
| parameterIndex); |
| } else { |
| return new ParameterElementForLink( |
| enclosingElement, |
| unlinkedParameter, |
| typeParameterContext, |
| typeParameterContext.enclosingUnit.resynthesizerContext |
| as CompilationUnitElementForLink, |
| parameterIndex); |
| } |
| } |
| |
| @override |
| String get displayName => unlinkedParam.name; |
| |
| @override |
| bool get hasImplicitType => |
| !unlinkedParam.isFunctionTyped && unlinkedParam.type == null; |
| |
| @override |
| String get identifier => name; |
| |
| @override |
| bool get inheritsCovariant => _inheritsCovariant; |
| |
| @override |
| void set inheritsCovariant(bool value) { |
| _inheritsCovariant = value; |
| } |
| |
| @override |
| FunctionElement get initializer => null; |
| |
| @override |
| bool get isCovariant { |
| if (isExplicitlyCovariant || inheritsCovariant) { |
| return true; |
| } |
| for (UnlinkedExpr annotation in unlinkedParam.annotations) { |
| if (annotation.operations.length == 1 && |
| annotation.operations[0] == UnlinkedExprOperation.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 |
| bool get isExplicitlyCovariant => unlinkedParam.isExplicitlyCovariant; |
| |
| @override |
| bool get isInitializingFormal => unlinkedParam.isInitializingFormal; |
| |
| @override |
| bool get isNamed => parameterKind == ParameterKind.NAMED; |
| |
| @override |
| bool get isNotOptional => parameterKind == ParameterKind.REQUIRED; |
| |
| @override |
| bool get isOptional => |
| parameterKind == ParameterKind.NAMED || |
| parameterKind == ParameterKind.POSITIONAL; |
| |
| @override |
| bool get isOptionalPositional => parameterKind == ParameterKind.POSITIONAL; |
| |
| @override |
| bool get isPositional => |
| parameterKind == ParameterKind.POSITIONAL || |
| parameterKind == ParameterKind.REQUIRED; |
| |
| @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( |
| this, unlinkedParam.inferredTypeSlot); |
| return _inferredType; |
| } else { |
| _declaredType = DynamicTypeImpl.instance; |
| } |
| } else { |
| _declaredType = |
| compilationUnit.resolveTypeRef(this, unlinkedParam.type); |
| } |
| } |
| return _declaredType; |
| } |
| |
| @override |
| void set type(DartType inferredType) { |
| assert(_inferredType == null); |
| _inferredType = inferredType; |
| } |
| |
| @override |
| TypeParameterizedElementMixin get typeParameterContext { |
| return _typeParameterContext; |
| } |
| |
| /** |
| * Store the results of type inference for this parameter in |
| * [compilationUnit]. |
| */ |
| void link(CompilationUnitElementInBuildUnit compilationUnit) { |
| compilationUnit._storeLinkedType( |
| unlinkedParam.inferredTypeSlot, _inferredType, _typeParameterContext); |
| compilationUnit._storeLinkedTypeError( |
| unlinkedParam.inferredTypeSlot, _inferenceError); |
| if (inheritsCovariant) { |
| compilationUnit |
| ._storeInheritsCovariant(unlinkedParam.inheritsCovariantSlot); |
| } |
| } |
| |
| @override |
| noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); |
| |
| void setInferenceError(TopLevelInferenceErrorBuilder error) { |
| assert(_inferenceError == null); |
| _inferenceError = error; |
| } |
| } |
| |
| /** |
| * 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 => isExplicitlyCovariant || inheritsCovariant; |
| |
| @override |
| bool get isExplicitlyCovariant => enclosingElement.variable.isCovariant; |
| |
| bool get isInitializingFormal => unlinkedParam.isInitializingFormal; |
| |
| @override |
| bool get isNamed => parameterKind == ParameterKind.NAMED; |
| |
| @override |
| bool get isNotOptional => parameterKind == ParameterKind.REQUIRED; |
| |
| @override |
| bool get isOptional => |
| parameterKind == ParameterKind.NAMED || |
| parameterKind == ParameterKind.POSITIONAL; |
| |
| @override |
| bool get isOptionalPositional => parameterKind == ParameterKind.POSITIONAL; |
| |
| @override |
| bool get isPositional => |
| parameterKind == ParameterKind.POSITIONAL || |
| parameterKind == ParameterKind.REQUIRED; |
| |
| @override |
| bool get isSynthetic => true; |
| |
| @override |
| String get name => 'x'; |
| |
| @override |
| ParameterKind get parameterKind => ParameterKind.REQUIRED; |
| |
| @override |
| DartType get type => enclosingElement.variable.type; |
| |
| @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.forFactory( |
| 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 => |
| serializedExecutable.kind == UnlinkedExecutableKind.getter; |
| |
| @override |
| bool get isSetter => |
| serializedExecutable.kind == UnlinkedExecutableKind.setter; |
| |
| @override |
| bool get isStatic => enclosingClass == null || super.isStatic; |
| |
| @override |
| ElementKind get kind => |
| serializedExecutable.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; |
| ParameterElementForLink_VariableSetter _parameter; |
| 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 |
| String get displayName => variable.displayName; |
| |
| @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) { |
| _parameter = new ParameterElementForLink_VariableSetter(this); |
| _parameters.add(_parameter); |
| } |
| } |
| return _parameters; |
| } |
| |
| @override |
| DartType get returnType { |
| if (isSetter) { |
| return VoidTypeImpl.instance; |
| } else { |
| return variable.type; |
| } |
| } |
| |
| @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 []; |
| } |
| |
| @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) { |
| if (isSetter && _parameter != null) { |
| if (_parameter.inheritsCovariant) { |
| compilationUnit._storeInheritsCovariant( |
| variable.unlinkedVariable.inheritsCovariantSlot); |
| } |
| } |
| } |
| |
| @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 isFinal => _setter == null; |
| |
| @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 => serializedExecutable.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); |
| compilationUnit._storeLinkedTypeError( |
| unlinkedVariable.inferredTypeSlot, initializer._inferenceError); |
| } |
| initializer?.link(compilationUnit); |
| } |
| } |
| } |
| |
| /** |
| * Specialization of [DependencyWalker] for performing type inference on static |
| * and top level variables. |
| */ |
| class TypeInferenceDependencyWalker |
| extends DependencyWalker<TypeInferenceNode> { |
| @override |
| void evaluate(TypeInferenceNode v) { |
| v.evaluate(null); |
| } |
| |
| @override |
| void evaluateScc(List<TypeInferenceNode> scc) { |
| for (TypeInferenceNode v in scc) { |
| v.evaluate(scc); |
| } |
| } |
| } |
| |
| /** |
| * 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) { |
| UnlinkedExpr unlinkedConst = unlinkedExecutable?.bodyExpr; |
| if (unlinkedConst == null) { |
| return; |
| } |
| int refPtr = 0; |
| int intPtr = 0; |
| |
| for (UnlinkedExprOperation operation in unlinkedConst.operations) { |
| switch (operation) { |
| case UnlinkedExprOperation.pushInt: |
| intPtr++; |
| break; |
| case UnlinkedExprOperation.pushLongInt: |
| int numInts = unlinkedConst.ints[intPtr++]; |
| intPtr += numInts; |
| break; |
| case UnlinkedExprOperation.concatenate: |
| intPtr++; |
| break; |
| case UnlinkedExprOperation.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 UnlinkedExprOperation.invokeConstructor: |
| refPtr++; |
| intPtr += 2; |
| break; |
| case UnlinkedExprOperation.makeUntypedList: |
| case UnlinkedExprOperation.makeUntypedMap: |
| intPtr++; |
| break; |
| case UnlinkedExprOperation.makeTypedList: |
| refPtr++; |
| intPtr++; |
| break; |
| case UnlinkedExprOperation.makeTypedMap: |
| refPtr += 2; |
| intPtr++; |
| break; |
| case UnlinkedExprOperation.assignToRef: |
| 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 UnlinkedExprOperation.invokeMethodRef: |
| EntityRef ref = unlinkedConst.references[refPtr++]; |
| TypeInferenceNode dependency = |
| compilationUnit.resolveRef(ref.reference).asTypeInferenceNode; |
| if (dependency != null) { |
| dependencies.add(dependency); |
| } |
| intPtr += 2; |
| int numTypeArguments = unlinkedConst.ints[intPtr++]; |
| refPtr += numTypeArguments; |
| break; |
| case UnlinkedExprOperation.invokeMethod: |
| intPtr += 2; |
| int numTypeArguments = unlinkedConst.ints[intPtr++]; |
| refPtr += numTypeArguments; |
| break; |
| case UnlinkedExprOperation.typeCast: |
| case UnlinkedExprOperation.typeCheck: |
| refPtr++; |
| break; |
| case UnlinkedExprOperation.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.serializedExecutable, |
| functionElement.compilationUnit); |
| return dependencies; |
| } |
| |
| void evaluate(List<TypeInferenceNode> cycle) { |
| if (cycle != null) { |
| List<String> cycleNames = cycle |
| .map((node) { |
| Element e = node.functionElement; |
| while (e != null) { |
| if (e is VariableElement) { |
| return e.name; |
| } |
| e = e.enclosingElement; |
| } |
| return '<unknown>'; |
| }) |
| .toSet() |
| .toList(); |
| functionElement._setInferenceError(new TopLevelInferenceErrorBuilder( |
| kind: TopLevelInferenceErrorKind.dependencyCycle, |
| arguments: cycleNames)); |
| functionElement._setInferredType(DynamicTypeImpl.instance); |
| } else { |
| var computer = new ExprTypeComputer(functionElement); |
| DartType bodyType = computer.compute(); |
| if (computer.errorKind != null) { |
| functionElement._setInferenceError( |
| new TopLevelInferenceErrorBuilder(kind: computer.errorKind)); |
| functionElement._setInferredType(DynamicTypeImpl.instance); |
| } else { |
| if (functionElement.isAsynchronous) { |
| var linker = functionElement.compilationUnit.library._linker; |
| var typeProvider = linker.typeProvider; |
| var typeSystem = linker.typeSystem; |
| if (bodyType.isDartAsyncFutureOr) { |
| bodyType = (bodyType as InterfaceType).typeArguments[0]; |
| } |
| bodyType = typeProvider.futureType |
| .instantiate([bodyType.flattenFutures(typeSystem)]); |
| } |
| functionElement._setInferredType(bodyType); |
| } |
| } |
| } |
| |
| @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 _futureOrNullType; |
| InterfaceType _futureOrType; |
| 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 futureOrNullType => |
| _futureOrNullType ??= futureOrType.instantiate(<DartType>[nullType]); |
| |
| @override |
| InterfaceType get futureOrType => |
| _futureOrType ??= _buildInterfaceType(_linker.asyncLibrary, 'FutureOr'); |
| |
| @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(this, unlinkedVariable.type); |
| } |
| } |
| |
| @override |
| String get displayName => unlinkedVariable.name; |
| |
| @override |
| PropertyAccessorElementForLink_Variable get getter => |
| _getter ??= new PropertyAccessorElementForLink_Variable(this, false); |
| |
| @override |
| bool get hasImplicitType => unlinkedVariable.type == null; |
| |
| @override |
| String get identifier => unlinkedVariable.name; |
| |
| /** |
| * 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( |
| this, unlinkedVariable.inferredTypeSlot); |
| } |
| } |
| 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; |
| |
| /** |
| * Return `true` if this variable is a field that was explicitly marked as |
| * being covariant (in the setter's parameter). |
| */ |
| bool get isCovariant => unlinkedVariable.isCovariant; |
| |
| @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. |
| } |
| |
| @override |
| TypeParameterizedElementMixin get typeParameterContext { |
| return _typeParameterContext; |
| } |
| |
| /** |
| * 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'; |
| } |
| |
| /// Specialization of [LibraryResynthesizer] for resynthesis during linking. |
| class _LibraryResynthesizer extends LibraryResynthesizerMixin { |
| LibraryElementForLink _library; |
| |
| @override |
| LibraryElement get library => _library; |
| |
| @override |
| List<LinkedExportName> get linkedExportNames => _library._linkedExportNames; |
| |
| @override |
| Element buildExportName(LinkedExportName exportName) { |
| LibraryElementForLink dependency = |
| _library.buildImportedLibrary(exportName.dependency); |
| return dependency.getContainedName(exportName.name); |
| } |
| } |
| |
| /// Specialization of [ReferenceInfo] for resynthesis during linking. |
| class _ReferenceInfo extends ReferenceInfo { |
| @override |
| final ReferenceableElementForLink element; |
| |
| @override |
| final ReferenceInfo enclosing; |
| |
| @override |
| final String name; |
| |
| @override |
| final bool hasTypeParameters; |
| |
| _ReferenceInfo( |
| this.enclosing, this.element, this.name, this.hasTypeParameters); |
| |
| /// TODO(paulberry): this method doesn't seem to be used. Investigate whether |
| /// it is needed. |
| @override |
| DartType get type => throw new UnimplementedError(); |
| } |
| |
| /// Specialization of [UnitResynthesizer] for resynthesis during linking. |
| class _UnitResynthesizer extends UnitResynthesizer with UnitResynthesizerMixin { |
| CompilationUnitElementForLink _unit; |
| |
| @override |
| TypeProvider get typeProvider => _unit.library._linker.typeProvider; |
| |
| @override |
| DartType buildType(ElementImpl context, EntityRef type) => |
| _unit.resolveTypeRef(context, type); |
| |
| @override |
| DartType buildTypeForClassInfo( |
| info, int numTypeArguments, DartType Function(int i) getTypeArgument) { |
| ClassElementForLink class_ = info.element; |
| if (numTypeArguments == 0) { |
| DartType type = class_.typeWithDefaultBounds; |
| _typesWithImplicitArguments[type] = true; |
| return type; |
| } |
| return class_.buildType(getTypeArgument, const []); |
| } |
| |
| @override |
| bool doesTypeHaveImplicitArguments(ParameterizedType type) => |
| _typesWithImplicitArguments[type] != null; |
| |
| @override |
| _ReferenceInfo getReferenceInfo(int index) { |
| return _unit.resolveRefToInfo(index); |
| } |
| } |