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

Side by Side Diff: packages/analyzer/lib/src/summary/link.dart

Issue 2990843002: Removed fixed dependencies (Closed)
Patch Set: Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 /**
6 * This library is capable of producing linked summaries from unlinked
7 * ones (or prelinked ones). It functions by building a miniature
8 * element model to represent the contents of the summaries, and then
9 * scanning the element model to gather linked information and adding
10 * it to the summary data structures.
11 *
12 * The reason we use a miniature element model to do the linking
13 * (rather than resynthesizing the full element model from the
14 * summaries) is that it is expected that we will only need to
15 * traverse a small subset of the element properties in order to link.
16 * Resynthesizing only those properties that we need should save
17 * substantial CPU time.
18 *
19 * The element model implements the same interfaces as the full
20 * element model, so we can re-use code elsewhere in the analysis
21 * engine to do the linking. However, only a small subset of the
22 * methods and getters defined in the full element model are
23 * implemented here. To avoid static warnings, each element model
24 * class contains an implementation of `noSuchMethod`.
25 *
26 * The miniature element model follows the following design
27 * principles:
28 *
29 * - With few exceptions, resynthesis is done incrementally on demand,
30 * so that we don't pay the cost of resynthesizing elements (or
31 * properties of elements) that aren't referenced from a part of the
32 * element model that is relevant to linking.
33 *
34 * - Computation of values in the miniature element model is similar
35 * to the task model, but much lighter weight. Instead of declaring
36 * tasks and their relationships using classes, each task is simply
37 * a method (frequently a getter) that computes a value. Instead of
38 * using a general purpose cache, values are cached by the methods
39 * themselves in private fields (with `null` typically representing
40 * "not yet cached").
41 *
42 * - No attempt is made to detect cyclic dependencies due to bugs in
43 * the analyzer. This saves time because dependency evaluation
44 * doesn't have to be a separate step from evaluating a value; we
45 * can simply call the getter.
46 *
47 * - However, for cases where cyclic dependencies may occur in the
48 * absence of analyzer bugs (e.g. because of errors in the code
49 * being analyzed, or cycles between top level and static variables
50 * undergoing type inference), we do precompute dependencies, and we
51 * use Tarjan's strongly connected components algorithm to detect
52 * cycles.
53 *
54 * - As much as possible, bookkeeping data is pointed to directly by
55 * the element objects, rather than being stored in maps.
56 *
57 * - Where possible, we favor method dispatch instead of "is" and "as"
58 * checks. E.g. see [ReferenceableElementForLink.asConstructor].
59 */
60 import 'package:analyzer/dart/ast/ast.dart';
61 import 'package:analyzer/dart/ast/token.dart' show TokenType;
62 import 'package:analyzer/dart/element/element.dart';
63 import 'package:analyzer/dart/element/type.dart';
64 import 'package:analyzer/src/dart/constant/value.dart';
65 import 'package:analyzer/src/dart/element/element.dart';
66 import 'package:analyzer/src/dart/element/type.dart';
67 import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
68 import 'package:analyzer/src/generated/engine.dart';
69 import 'package:analyzer/src/generated/resolver.dart';
70 import 'package:analyzer/src/generated/utilities_dart.dart';
71 import 'package:analyzer/src/summary/format.dart';
72 import 'package:analyzer/src/summary/idl.dart';
73 import 'package:analyzer/src/summary/prelink.dart';
74 import 'package:analyzer/src/task/strong_mode.dart';
75
76 bool isIncrementOrDecrement(UnlinkedExprAssignOperator operator) {
77 switch (operator) {
78 case UnlinkedExprAssignOperator.prefixDecrement:
79 case UnlinkedExprAssignOperator.prefixIncrement:
80 case UnlinkedExprAssignOperator.postfixDecrement:
81 case UnlinkedExprAssignOperator.postfixIncrement:
82 return true;
83 default:
84 return false;
85 }
86 }
87
88 /**
89 * Link together the build unit consisting of [libraryUris], using
90 * [getDependency] to fetch the [LinkedLibrary] objects from other
91 * build units, and [getUnit] to fetch the [UnlinkedUnit] objects from
92 * both this build unit and other build units.
93 *
94 * The [strong] flag controls whether type inference is performed in strong
95 * mode or spec mode. Note that in spec mode, the only types that are inferred
96 * are the types of initializing formals, which are inferred from the types of
97 * the corresponding fields.
98 *
99 * A map is returned whose keys are the URIs of the libraries in this
100 * build unit, and whose values are the corresponding
101 * [LinkedLibraryBuilder]s.
102 */
103 Map<String, LinkedLibraryBuilder> link(
104 Set<String> libraryUris,
105 GetDependencyCallback getDependency,
106 GetUnitCallback getUnit,
107 GetDeclaredVariable getDeclaredVariable,
108 bool strong) {
109 Map<String, LinkedLibraryBuilder> linkedLibraries =
110 setupForLink(libraryUris, getUnit, getDeclaredVariable);
111 relink(linkedLibraries, getDependency, getUnit, strong);
112 return linkedLibraries;
113 }
114
115 /**
116 * Given [libraries] (a map from URI to [LinkedLibraryBuilder]
117 * containing correct prelinked information), rebuild linked
118 * information, using [getDependency] to fetch the [LinkedLibrary]
119 * objects from other build units, and [getUnit] to fetch the
120 * [UnlinkedUnit] objects from both this build unit and other build
121 * units.
122 *
123 * The [strong] flag controls whether type inference is performed in strong
124 * mode or spec mode. Note that in spec mode, the only types that are inferred
125 * are the types of initializing formals, which are inferred from the types of
126 * the corresponding fields.
127 */
128 void relink(Map<String, LinkedLibraryBuilder> libraries,
129 GetDependencyCallback getDependency, GetUnitCallback getUnit, bool strong) {
130 new Linker(libraries, getDependency, getUnit, strong).link();
131 }
132
133 /**
134 * Prepare to link together the build unit consisting of [libraryUris], using
135 * [getUnit] to fetch the [UnlinkedUnit] objects from both this build unit and
136 * other build units.
137 *
138 * The libraries are prelinked, and a map is returned whose keys are the URIs of
139 * the libraries in this build unit, and whose values are the corresponding
140 * [LinkedLibraryBuilder]s.
141 */
142 Map<String, LinkedLibraryBuilder> setupForLink(Set<String> libraryUris,
143 GetUnitCallback getUnit, GetDeclaredVariable getDeclaredVariable) {
144 Map<String, LinkedLibraryBuilder> linkedLibraries =
145 <String, LinkedLibraryBuilder>{};
146 for (String absoluteUri in libraryUris) {
147 Uri uri = Uri.parse(absoluteUri);
148 UnlinkedUnit getRelativeUnit(String relativeUri) =>
149 getUnit(resolveRelativeUri(uri, Uri.parse(relativeUri)).toString());
150 linkedLibraries[absoluteUri] = prelink(
151 getUnit(absoluteUri),
152 getRelativeUnit,
153 (String relativeUri) => getRelativeUnit(relativeUri)?.publicNamespace,
154 getDeclaredVariable);
155 }
156 return linkedLibraries;
157 }
158
159 /**
160 * Create an [EntityRefBuilder] representing the given [type], in a form
161 * suitable for inclusion in [LinkedUnit.types]. [compilationUnit] is the
162 * compilation unit in which the type will be used. If [slot] is provided, it
163 * is stored in [EntityRefBuilder.slot].
164 */
165 EntityRefBuilder _createLinkedType(
166 DartType type,
167 CompilationUnitElementInBuildUnit compilationUnit,
168 TypeParameterizedElementMixin typeParameterContext,
169 {int slot}) {
170 EntityRefBuilder result = new EntityRefBuilder(slot: slot);
171 if (type is InterfaceType) {
172 ClassElementForLink element = type.element;
173 result.reference = compilationUnit.addReference(element);
174 _storeTypeArguments(
175 type.typeArguments, result, compilationUnit, typeParameterContext);
176 return result;
177 } else if (type is DynamicTypeImpl) {
178 result.reference = compilationUnit.addRawReference('dynamic');
179 return result;
180 } else if (type is VoidTypeImpl) {
181 result.reference = compilationUnit.addRawReference('void');
182 return result;
183 } else if (type is BottomTypeImpl) {
184 result.reference = compilationUnit.addRawReference('*bottom*');
185 return result;
186 } else if (type is TypeParameterType) {
187 TypeParameterElementImpl element = type.element;
188 if (typeParameterContext.isTypeParameterInScope(element)) {
189 result.paramReference =
190 typeParameterContext.typeParameterNestingLevel - element.nestingLevel;
191 } else {
192 throw new StateError('The type parameter $type (in ${element?.location}) '
193 'is out of scope on ${typeParameterContext?.location}.');
194 }
195 return result;
196 } else if (type is FunctionType) {
197 Element element = type.element;
198 if (element is FunctionElementForLink_FunctionTypedParam) {
199 result.reference =
200 compilationUnit.addReference(element.typeParameterContext);
201 result.implicitFunctionTypeIndices = element.implicitFunctionTypeIndices;
202 _storeTypeArguments(
203 type.typeArguments, result, compilationUnit, typeParameterContext);
204 return result;
205 }
206 if (element is TopLevelFunctionElementForLink) {
207 result.reference = compilationUnit.addReference(element);
208 _storeTypeArguments(
209 type.typeArguments, result, compilationUnit, typeParameterContext);
210 return result;
211 }
212 if (element is MethodElementForLink) {
213 result.reference = compilationUnit.addReference(element);
214 _storeTypeArguments(
215 type.typeArguments, result, compilationUnit, typeParameterContext);
216 return result;
217 }
218 if (element is FunctionTypeAliasElementForLink) {
219 result.reference = compilationUnit.addReference(element);
220 _storeTypeArguments(
221 type.typeArguments, result, compilationUnit, typeParameterContext);
222 return result;
223 }
224 if (element is FunctionElement && element.enclosingElement == null) {
225 // Element is a synthetic function element that was generated on the fly
226 // to represent a type that has no associated source code location.
227 result.syntheticReturnType = _createLinkedType(
228 element.returnType, compilationUnit, typeParameterContext);
229 result.syntheticParams = element.parameters
230 .map((ParameterElement param) => _serializeSyntheticParam(
231 param, compilationUnit, typeParameterContext))
232 .toList();
233 return result;
234 }
235 if (element is FunctionElement) {
236 // Element is a local function inside another executable.
237 result.reference = compilationUnit.addReference(element);
238 // TODO(paulberry): do I need to store type arguments?
239 return result;
240 }
241 // TODO(paulberry): implement other cases.
242 throw new UnimplementedError('${element.runtimeType}');
243 }
244 // TODO(paulberry): implement other cases.
245 throw new UnimplementedError('${type.runtimeType}');
246 }
247
248 DartType _dynamicIfNull(DartType type) {
249 if (type == null || type.isBottom || type.isVoid) {
250 return DynamicTypeImpl.instance;
251 }
252 return type;
253 }
254
255 /**
256 * Create an [UnlinkedParam] representing the given [parameter], which should be
257 * a parameter of a synthetic function type (e.g. one produced during type
258 * inference as a result of computing the least upper bound of two function
259 * types).
260 */
261 UnlinkedParamBuilder _serializeSyntheticParam(
262 ParameterElement parameter,
263 CompilationUnitElementInBuildUnit compilationUnit,
264 TypeParameterizedElementMixin typeParameterContext) {
265 UnlinkedParamBuilder b = new UnlinkedParamBuilder();
266 b.name = parameter.name;
267 switch (parameter.parameterKind) {
268 case ParameterKind.REQUIRED:
269 b.kind = UnlinkedParamKind.required;
270 break;
271 case ParameterKind.POSITIONAL:
272 b.kind = UnlinkedParamKind.positional;
273 break;
274 case ParameterKind.NAMED:
275 b.kind = UnlinkedParamKind.named;
276 break;
277 }
278 DartType type = parameter.type;
279 if (!parameter.hasImplicitType) {
280 if (type is FunctionType && type.element.isSynthetic) {
281 b.isFunctionTyped = true;
282 b.type = _createLinkedType(
283 type.returnType, compilationUnit, typeParameterContext);
284 b.parameters = type.parameters
285 .map((parameter) => _serializeSyntheticParam(
286 parameter, compilationUnit, typeParameterContext))
287 .toList();
288 } else {
289 b.type = _createLinkedType(type, compilationUnit, typeParameterContext);
290 }
291 }
292 return b;
293 }
294
295 /**
296 * Store the given [typeArguments] in [encodedType], using [compilationUnit] and
297 * [typeParameterContext] to serialize them.
298 */
299 void _storeTypeArguments(
300 List<DartType> typeArguments,
301 EntityRefBuilder encodedType,
302 CompilationUnitElementInBuildUnit compilationUnit,
303 TypeParameterizedElementMixin typeParameterContext) {
304 int count = typeArguments.length;
305 List<EntityRefBuilder> encodedTypeArguments =
306 new List<EntityRefBuilder>(count);
307 for (int i = 0; i < count; i++) {
308 encodedTypeArguments[i] = _createLinkedType(
309 typeArguments[i], compilationUnit, typeParameterContext);
310 }
311 encodedType.typeArguments = encodedTypeArguments;
312 }
313
314 /**
315 * Type of the callback used by [link] and [relink] to request
316 * [LinkedLibrary] objects from other build units.
317 */
318 typedef LinkedLibrary GetDependencyCallback(String absoluteUri);
319
320 /**
321 * Type of the callback used by [link] and [relink] to request
322 * [UnlinkedUnit] objects.
323 */
324 typedef UnlinkedUnit GetUnitCallback(String absoluteUri);
325
326 /**
327 * Stub implementation of [AnalysisOptions] used during linking.
328 */
329 class AnalysisOptionsForLink implements AnalysisOptions {
330 final Linker _linker;
331
332 AnalysisOptionsForLink(this._linker);
333
334 @override
335 bool get strongMode => _linker.strongMode;
336
337 @override
338 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
339 }
340
341 /**
342 * Element representing a class or enum resynthesized from a summary
343 * during linking.
344 */
345 abstract class ClassElementForLink extends Object
346 with ReferenceableElementForLink
347 implements AbstractClassElementImpl {
348 Map<String, ReferenceableElementForLink> _containedNames;
349
350 @override
351 final CompilationUnitElementForLink enclosingElement;
352
353 /// TODO(brianwilkerson) This appears to be unused and might be removable.
354 bool hasBeenInferred;
355
356 ClassElementForLink(CompilationUnitElementForLink enclosingElement)
357 : enclosingElement = enclosingElement,
358 hasBeenInferred = !enclosingElement.isInBuildUnit;
359
360 @override
361 List<PropertyAccessorElementForLink> get accessors;
362
363 @override
364 ClassElementForLink get asClass => this;
365
366 @override
367 ConstructorElementForLink get asConstructor => unnamedConstructor;
368
369 @override
370 DartType get asStaticType =>
371 enclosingElement.enclosingElement._linker.typeProvider.typeType;
372
373 @override
374 List<ConstructorElementForLink> get constructors;
375
376 @override
377 CompilationUnitElementImpl get enclosingUnit => enclosingElement;
378
379 @override
380 List<FieldElementForLink> get fields;
381
382 /**
383 * Indicates whether this is the core class `Object`.
384 */
385 bool get isObject;
386
387 @override
388 LibraryElementForLink get library => enclosingElement.library;
389
390 @override
391 List<MethodElementForLink> get methods;
392
393 @override
394 String get name;
395
396 @override
397 ConstructorElementForLink get unnamedConstructor;
398
399 @override
400 ReferenceableElementForLink getContainedName(String name) {
401 if (_containedNames == null) {
402 _containedNames = <String, ReferenceableElementForLink>{};
403 // TODO(paulberry): what's the correct way to handle name conflicts?
404 for (ConstructorElementForLink constructor in constructors) {
405 _containedNames[constructor.name] = constructor;
406 }
407 for (PropertyAccessorElementForLink accessor in accessors) {
408 _containedNames[accessor.name] = accessor;
409 }
410 for (MethodElementForLink method in methods) {
411 _containedNames[method.name] = method;
412 }
413 }
414 return _containedNames.putIfAbsent(
415 name, () => UndefinedElementForLink.instance);
416 }
417
418 /**
419 * Perform type inference and cycle detection on this class and
420 * store the resulting information in [compilationUnit].
421 */
422 void link(CompilationUnitElementInBuildUnit compilationUnit);
423
424 @override
425 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
426 }
427
428 /**
429 * Element representing a class resynthesized from a summary during
430 * linking.
431 */
432 class ClassElementForLink_Class extends ClassElementForLink
433 with TypeParameterizedElementMixin
434 implements ClassElementImpl {
435 /**
436 * The unlinked representation of the class in the summary.
437 */
438 final UnlinkedClass _unlinkedClass;
439
440 List<ConstructorElementForLink> _constructors;
441 ConstructorElementForLink _unnamedConstructor;
442 bool _unnamedConstructorComputed = false;
443 List<FieldElementForLink_ClassField> _fields;
444 InterfaceType _supertype;
445 InterfaceType _type;
446 List<MethodElementForLink> _methods;
447 List<InterfaceType> _mixins;
448 List<InterfaceType> _interfaces;
449 List<PropertyAccessorElementForLink> _accessors;
450
451 ClassElementForLink_Class(
452 CompilationUnitElementForLink enclosingElement, this._unlinkedClass)
453 : super(enclosingElement);
454
455 @override
456 List<PropertyAccessorElementForLink> get accessors {
457 if (_accessors == null) {
458 _accessors = <PropertyAccessorElementForLink>[];
459 Map<String, SyntheticVariableElementForLink> syntheticVariables =
460 <String, SyntheticVariableElementForLink>{};
461 for (UnlinkedExecutable unlinkedExecutable
462 in _unlinkedClass.executables) {
463 if (unlinkedExecutable.kind == UnlinkedExecutableKind.getter ||
464 unlinkedExecutable.kind == UnlinkedExecutableKind.setter) {
465 String name = unlinkedExecutable.name;
466 if (unlinkedExecutable.kind == UnlinkedExecutableKind.setter) {
467 assert(name.endsWith('='));
468 name = name.substring(0, name.length - 1);
469 }
470 SyntheticVariableElementForLink syntheticVariable = syntheticVariables
471 .putIfAbsent(name, () => new SyntheticVariableElementForLink());
472 PropertyAccessorElementForLink_Executable accessor =
473 new PropertyAccessorElementForLink_Executable(enclosingElement,
474 this, unlinkedExecutable, syntheticVariable);
475 _accessors.add(accessor);
476 if (unlinkedExecutable.kind == UnlinkedExecutableKind.getter) {
477 syntheticVariable._getter = accessor;
478 } else {
479 syntheticVariable._setter = accessor;
480 }
481 }
482 }
483 for (FieldElementForLink_ClassField field in fields) {
484 _accessors.add(field.getter);
485 if (!field.isConst && !field.isFinal) {
486 _accessors.add(field.setter);
487 }
488 }
489 }
490 return _accessors;
491 }
492
493 @override
494 List<ConstructorElementForLink> get constructors {
495 if (_constructors == null) {
496 _constructors = <ConstructorElementForLink>[];
497 for (UnlinkedExecutable unlinkedExecutable
498 in _unlinkedClass.executables) {
499 if (unlinkedExecutable.kind == UnlinkedExecutableKind.constructor) {
500 _constructors
501 .add(new ConstructorElementForLink(this, unlinkedExecutable));
502 }
503 }
504 if (_constructors.isEmpty) {
505 _unnamedConstructorComputed = true;
506 _unnamedConstructor = new ConstructorElementForLink_Synthetic(this);
507 _constructors.add(_unnamedConstructor);
508 }
509 }
510 return _constructors;
511 }
512
513 @override
514 ContextForLink get context => enclosingUnit.context;
515
516 @override
517 String get displayName => _unlinkedClass.name;
518
519 @override
520 TypeParameterizedElementMixin get enclosingTypeParameterContext => null;
521
522 @override
523 List<FieldElementForLink_ClassField> get fields {
524 if (_fields == null) {
525 _fields = <FieldElementForLink_ClassField>[];
526 for (UnlinkedVariable field in _unlinkedClass.fields) {
527 _fields.add(new FieldElementForLink_ClassField(this, field));
528 }
529 }
530 return _fields;
531 }
532
533 @override
534 String get identifier => name;
535
536 @override
537 List<InterfaceType> get interfaces => _interfaces ??=
538 _unlinkedClass.interfaces.map(_computeInterfaceType).toList();
539
540 @override
541 bool get isMixinApplication => _unlinkedClass.isMixinApplication;
542
543 @override
544 bool get isObject => _unlinkedClass.hasNoSupertype;
545
546 @override
547 LibraryElementForLink get library => enclosingElement.library;
548
549 @override
550 List<MethodElementForLink> get methods {
551 if (_methods == null) {
552 _methods = <MethodElementForLink>[];
553 for (UnlinkedExecutable unlinkedExecutable
554 in _unlinkedClass.executables) {
555 if (unlinkedExecutable.kind ==
556 UnlinkedExecutableKind.functionOrMethod) {
557 _methods.add(new MethodElementForLink(this, unlinkedExecutable));
558 }
559 }
560 }
561 return _methods;
562 }
563
564 @override
565 List<InterfaceType> get mixins =>
566 _mixins ??= _unlinkedClass.mixins.map(_computeInterfaceType).toList();
567
568 @override
569 String get name => _unlinkedClass.name;
570
571 @override
572 InterfaceType get supertype {
573 if (isObject) {
574 return null;
575 }
576 return _supertype ??= _computeInterfaceType(_unlinkedClass.supertype);
577 }
578
579 @override
580 InterfaceType get type =>
581 _type ??= buildType((int i) => typeParameterTypes[i], null);
582
583 @override
584 List<UnlinkedTypeParam> get unlinkedTypeParams =>
585 _unlinkedClass.typeParameters;
586
587 @override
588 ConstructorElementForLink get unnamedConstructor {
589 if (!_unnamedConstructorComputed) {
590 for (ConstructorElementForLink constructor in constructors) {
591 if (constructor.name.isEmpty) {
592 _unnamedConstructor = constructor;
593 break;
594 }
595 }
596 _unnamedConstructorComputed = true;
597 }
598 return _unnamedConstructor;
599 }
600
601 @override
602 int get version => 0;
603
604 @override
605 DartType buildType(
606 DartType getTypeArgument(int i), List<int> implicitFunctionTypeIndices) {
607 int numTypeParameters = _unlinkedClass.typeParameters.length;
608 if (numTypeParameters != 0) {
609 List<DartType> typeArguments =
610 new List<DartType>.generate(numTypeParameters, getTypeArgument);
611 if (typeArguments.contains(null)) {
612 return context.typeSystem.instantiateToBounds(this.type);
613 } else {
614 return new InterfaceTypeImpl.elementWithNameAndArgs(
615 this, name, () => typeArguments);
616 }
617 } else {
618 return _type ??= new InterfaceTypeImpl(this);
619 }
620 }
621
622 @override
623 PropertyAccessorElement getGetter(String getterName) {
624 for (PropertyAccessorElement accessor in accessors) {
625 if (accessor.isGetter && accessor.name == getterName) {
626 return accessor;
627 }
628 }
629 return null;
630 }
631
632 @override
633 MethodElement getMethod(String methodName) {
634 for (MethodElement method in methods) {
635 if (method.name == methodName) {
636 return method;
637 }
638 }
639 return null;
640 }
641
642 @override
643 void link(CompilationUnitElementInBuildUnit compilationUnit) {
644 for (ConstructorElementForLink constructorElement in constructors) {
645 constructorElement.link(compilationUnit);
646 }
647 if (library._linker.strongMode) {
648 for (MethodElementForLink methodElement in methods) {
649 methodElement.link(compilationUnit);
650 }
651 for (PropertyAccessorElementForLink propertyAccessorElement
652 in accessors) {
653 propertyAccessorElement.link(compilationUnit);
654 }
655 for (FieldElementForLink_ClassField fieldElement in fields) {
656 fieldElement.link(compilationUnit);
657 }
658 }
659 }
660
661 @override
662 String toString() => '$enclosingElement.$name';
663
664 /**
665 * Convert [typeRef] into an [InterfaceType].
666 */
667 InterfaceType _computeInterfaceType(EntityRef typeRef) {
668 if (typeRef != null) {
669 DartType type = enclosingElement.resolveTypeRef(typeRef, this);
670 if (type is InterfaceType) {
671 return type;
672 }
673 // In the event that the `typeRef` isn't an interface type (which may
674 // happen in the event of erroneous code) just fall through and pretend
675 // the supertype is `Object`.
676 }
677 return enclosingElement.enclosingElement._linker.typeProvider.objectType;
678 }
679 }
680
681 /**
682 * Element representing an enum resynthesized from a summary during
683 * linking.
684 */
685 class ClassElementForLink_Enum extends ClassElementForLink
686 implements EnumElementImpl {
687 /**
688 * The unlinked representation of the enum in the summary.
689 */
690 final UnlinkedEnum _unlinkedEnum;
691
692 InterfaceType _type;
693 List<FieldElementForLink_EnumField> _fields;
694 List<PropertyAccessorElementForLink> _accessors;
695 DartType _valuesType;
696
697 ClassElementForLink_Enum(
698 CompilationUnitElementForLink enclosingElement, this._unlinkedEnum)
699 : super(enclosingElement);
700
701 @override
702 List<PropertyAccessorElementForLink> get accessors {
703 if (_accessors == null) {
704 _accessors = <PropertyAccessorElementForLink>[];
705 for (FieldElementForLink_EnumField field in fields) {
706 _accessors.add(field.getter);
707 }
708 }
709 return _accessors;
710 }
711
712 @override
713 List<ConstructorElementForLink> get constructors => const [];
714
715 @override
716 String get displayName => _unlinkedEnum.name;
717
718 @override
719 List<FieldElementForLink_EnumField> get fields {
720 if (_fields == null) {
721 _fields = <FieldElementForLink_EnumField>[];
722 _fields.add(new FieldElementForLink_EnumField(null, this));
723 for (UnlinkedEnumValue value in _unlinkedEnum.values) {
724 _fields.add(new FieldElementForLink_EnumField(value, this));
725 }
726 }
727 return _fields;
728 }
729
730 @override
731 List<InterfaceType> get interfaces => const [];
732
733 @override
734 bool get isObject => false;
735
736 @override
737 List<MethodElementForLink> get methods => const [];
738
739 @override
740 List<InterfaceType> get mixins => const [];
741
742 @override
743 String get name => _unlinkedEnum.name;
744
745 @override
746 InterfaceType get supertype => library._linker.typeProvider.objectType;
747
748 @override
749 InterfaceType get type => _type ??= new InterfaceTypeImpl(this);
750
751 @override
752 List<TypeParameterElement> get typeParameters => const [];
753
754 @override
755 ConstructorElementForLink get unnamedConstructor => null;
756
757 /**
758 * Get the type of the enum's static member `values`.
759 */
760 DartType get valuesType =>
761 _valuesType ??= library._linker.typeProvider.listType.instantiate([type]);
762
763 @override
764 DartType buildType(DartType getTypeArgument(int i),
765 List<int> implicitFunctionTypeIndices) =>
766 type;
767
768 @override
769 void link(CompilationUnitElementInBuildUnit compilationUnit) {}
770
771 @override
772 String toString() => '$enclosingElement.$name';
773 }
774
775 /**
776 * Element representing a compilation unit resynthesized from a
777 * summary during linking.
778 */
779 abstract class CompilationUnitElementForLink
780 implements CompilationUnitElementImpl, ResynthesizerContext {
781 /**
782 * The unlinked representation of the compilation unit in the
783 * summary.
784 */
785 final UnlinkedUnit _unlinkedUnit;
786
787 /**
788 * For each entry in [UnlinkedUnit.references], the element referred
789 * to by the reference, or `null` if it hasn't been located yet.
790 */
791 final List<ReferenceableElementForLink> _references;
792
793 /**
794 * The absolute URI of this compilation unit.
795 */
796 final String _absoluteUri;
797
798 List<ClassElementForLink_Class> _types;
799 Map<String, ReferenceableElementForLink> _containedNames;
800 List<TopLevelVariableElementForLink> _topLevelVariables;
801 List<ClassElementForLink_Enum> _enums;
802 List<TopLevelFunctionElementForLink> _functions;
803 List<PropertyAccessorElementForLink> _accessors;
804 List<FunctionTypeAliasElementForLink> _functionTypeAliases;
805
806 /**
807 * Index of this unit in the list of units in the enclosing library.
808 */
809 final int unitNum;
810
811 CompilationUnitElementForLink(UnlinkedUnit unlinkedUnit, this.unitNum,
812 int numReferences, this._absoluteUri)
813 : _references = new List<ReferenceableElementForLink>(numReferences),
814 _unlinkedUnit = unlinkedUnit;
815
816 @override
817 List<PropertyAccessorElementForLink> get accessors {
818 if (_accessors == null) {
819 _accessors = <PropertyAccessorElementForLink>[];
820 Map<String, SyntheticVariableElementForLink> syntheticVariables =
821 <String, SyntheticVariableElementForLink>{};
822 for (UnlinkedExecutable unlinkedExecutable in _unlinkedUnit.executables) {
823 if (unlinkedExecutable.kind == UnlinkedExecutableKind.getter ||
824 unlinkedExecutable.kind == UnlinkedExecutableKind.setter) {
825 String name = unlinkedExecutable.name;
826 if (unlinkedExecutable.kind == UnlinkedExecutableKind.setter) {
827 assert(name.endsWith('='));
828 name = name.substring(0, name.length - 1);
829 }
830 SyntheticVariableElementForLink syntheticVariable = syntheticVariables
831 .putIfAbsent(name, () => new SyntheticVariableElementForLink());
832 PropertyAccessorElementForLink_Executable accessor =
833 new PropertyAccessorElementForLink_Executable(
834 this, null, unlinkedExecutable, syntheticVariable);
835 _accessors.add(accessor);
836 if (unlinkedExecutable.kind == UnlinkedExecutableKind.getter) {
837 syntheticVariable._getter = accessor;
838 } else {
839 syntheticVariable._setter = accessor;
840 }
841 }
842 }
843 for (TopLevelVariableElementForLink variable in topLevelVariables) {
844 _accessors.add(variable.getter);
845 if (!variable.isConst && !variable.isFinal) {
846 _accessors.add(variable.setter);
847 }
848 }
849 }
850 return _accessors;
851 }
852
853 @override
854 ContextForLink get context => library.context;
855
856 @override
857 LibraryElementForLink get enclosingElement;
858
859 @override
860 List<ClassElementForLink_Enum> get enums {
861 if (_enums == null) {
862 _enums = <ClassElementForLink_Enum>[];
863 for (UnlinkedEnum unlinkedEnum in _unlinkedUnit.enums) {
864 _enums.add(new ClassElementForLink_Enum(this, unlinkedEnum));
865 }
866 }
867 return _enums;
868 }
869
870 @override
871 List<TopLevelFunctionElementForLink> get functions {
872 if (_functions == null) {
873 _functions = <TopLevelFunctionElementForLink>[];
874 for (UnlinkedExecutable executable in _unlinkedUnit.executables) {
875 if (executable.kind == UnlinkedExecutableKind.functionOrMethod) {
876 _functions.add(new TopLevelFunctionElementForLink(this, executable));
877 }
878 }
879 }
880 return _functions;
881 }
882
883 @override
884 List<FunctionTypeAliasElementForLink> get functionTypeAliases =>
885 _functionTypeAliases ??= _unlinkedUnit.typedefs
886 .map((UnlinkedTypedef t) =>
887 new FunctionTypeAliasElementForLink(this, t))
888 .toList();
889
890 @override
891 String get identifier => _absoluteUri;
892
893 /**
894 * Indicates whether this compilation element is part of the build unit
895 * currently being linked.
896 */
897 bool get isInBuildUnit;
898
899 /**
900 * Determine whether type inference is complete in this compilation unit.
901 */
902 bool get isTypeInferenceComplete {
903 LibraryCycleForLink libraryCycleForLink = library.libraryCycleForLink;
904 if (libraryCycleForLink == null) {
905 return true;
906 } else {
907 return libraryCycleForLink._node.isEvaluated;
908 }
909 }
910
911 @override
912 LibraryElementForLink get library => enclosingElement;
913
914 @override
915 ResynthesizerContext get resynthesizerContext => this;
916
917 @override
918 List<TopLevelVariableElementForLink> get topLevelVariables {
919 if (_topLevelVariables == null) {
920 _topLevelVariables = <TopLevelVariableElementForLink>[];
921 for (UnlinkedVariable unlinkedVariable in _unlinkedUnit.variables) {
922 _topLevelVariables
923 .add(new TopLevelVariableElementForLink(this, unlinkedVariable));
924 }
925 }
926 return _topLevelVariables;
927 }
928
929 @override
930 List<ClassElementForLink_Class> get types {
931 if (_types == null) {
932 _types = <ClassElementForLink_Class>[];
933 for (UnlinkedClass unlinkedClass in _unlinkedUnit.classes) {
934 _types.add(new ClassElementForLink_Class(this, unlinkedClass));
935 }
936 }
937 return _types;
938 }
939
940 /**
941 * The linked representation of the compilation unit in the summary.
942 */
943 LinkedUnit get _linkedUnit;
944
945 /**
946 * Search the unit for a top level element with the given [name].
947 * If no name is found, return the singleton instance of
948 * [UndefinedElementForLink].
949 */
950 ReferenceableElementForLink getContainedName(name) {
951 if (_containedNames == null) {
952 _containedNames = <String, ReferenceableElementForLink>{};
953 // TODO(paulberry): what's the correct way to handle name conflicts?
954 for (ClassElementForLink_Class type in types) {
955 _containedNames[type.name] = type;
956 }
957 for (ClassElementForLink_Enum enm in enums) {
958 _containedNames[enm.name] = enm;
959 }
960 for (TopLevelFunctionElementForLink function in functions) {
961 _containedNames[function.name] = function;
962 }
963 for (PropertyAccessorElementForLink accessor in accessors) {
964 _containedNames[accessor.name] = accessor;
965 }
966 for (FunctionTypeAliasElementForLink functionTypeAlias
967 in functionTypeAliases) {
968 _containedNames[functionTypeAlias.name] = functionTypeAlias;
969 }
970 // TODO(paulberry): fill in other top level entities (typedefs
971 // and executables).
972 }
973 return _containedNames.putIfAbsent(
974 name, () => UndefinedElementForLink.instance);
975 }
976
977 /**
978 * Compute the type referred to by the given linked type [slot] (interpreted
979 * relative to [typeParameterContext]). If there is no inferred type in the
980 * given slot, `dynamic` is returned.
981 */
982 DartType getLinkedType(
983 int slot, TypeParameterizedElementMixin typeParameterContext);
984
985 @override
986 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
987
988 /**
989 * Return the class element for the constructor referred to by the given
990 * [index] in [UnlinkedUnit.references]. If the reference is unresolved,
991 * return [UndefinedElementForLink.instance].
992 */
993 ReferenceableElementForLink resolveConstructorClassRef(int index) {
994 LinkedReference linkedReference = _linkedUnit.references[index];
995 if (linkedReference.kind == ReferenceKind.classOrEnum) {
996 return resolveRef(index);
997 }
998 if (index < _unlinkedUnit.references.length) {
999 UnlinkedReference unlinkedReference = _unlinkedUnit.references[index];
1000 return resolveRef(unlinkedReference.prefixReference);
1001 }
1002 return UndefinedElementForLink.instance;
1003 }
1004
1005 /**
1006 * Return the element referred to by the given [index] in
1007 * [UnlinkedUnit.references]. If the reference is unresolved,
1008 * return [UndefinedElementForLink.instance].
1009 */
1010 ReferenceableElementForLink resolveRef(int index) {
1011 if (_references[index] == null) {
1012 UnlinkedReference unlinkedReference =
1013 index < _unlinkedUnit.references.length
1014 ? _unlinkedUnit.references[index]
1015 : null;
1016 LinkedReference linkedReference = _linkedUnit.references[index];
1017 String name = unlinkedReference == null
1018 ? linkedReference.name
1019 : unlinkedReference.name;
1020 int containingReference = unlinkedReference == null
1021 ? linkedReference.containingReference
1022 : unlinkedReference.prefixReference;
1023 if (containingReference != 0 &&
1024 _linkedUnit.references[containingReference].kind !=
1025 ReferenceKind.prefix) {
1026 if (linkedReference.kind == ReferenceKind.function) {
1027 // Local function
1028 _references[index] = resolveRef(containingReference)
1029 .getLocalFunction(linkedReference.localIndex) ??
1030 UndefinedElementForLink.instance;
1031 } else {
1032 _references[index] =
1033 resolveRef(containingReference).getContainedName(name);
1034 }
1035 } else if (linkedReference.dependency == 0) {
1036 if (name == 'void') {
1037 _references[index] = enclosingElement._linker.voidElement;
1038 } else if (name == '*bottom*') {
1039 _references[index] = enclosingElement._linker.bottomElement;
1040 } else if (name == 'dynamic') {
1041 _references[index] = enclosingElement._linker.dynamicElement;
1042 } else {
1043 _references[index] = enclosingElement.getContainedName(name);
1044 }
1045 } else {
1046 LibraryElementForLink dependency =
1047 enclosingElement._getDependency(linkedReference.dependency);
1048 _references[index] = dependency.getContainedName(name);
1049 }
1050 }
1051 return _references[index];
1052 }
1053
1054 @override
1055 DartType resolveTypeRef(
1056 EntityRef type, TypeParameterizedElementMixin typeParameterContext,
1057 {bool defaultVoid: false, bool instantiateToBoundsAllowed: true}) {
1058 if (type == null) {
1059 if (defaultVoid) {
1060 return VoidTypeImpl.instance;
1061 } else {
1062 return DynamicTypeImpl.instance;
1063 }
1064 }
1065 if (type.paramReference != 0) {
1066 return typeParameterContext.getTypeParameterType(type.paramReference);
1067 } else if (type.syntheticReturnType != null) {
1068 // TODO(paulberry): implement.
1069 throw new UnimplementedError();
1070 } else if (type.implicitFunctionTypeIndices.isNotEmpty) {
1071 // TODO(paulberry): implement.
1072 throw new UnimplementedError();
1073 } else {
1074 DartType getTypeArgument(int i) {
1075 if (i < type.typeArguments.length) {
1076 return resolveTypeRef(type.typeArguments[i], typeParameterContext);
1077 } else if (!instantiateToBoundsAllowed) {
1078 // Do not allow buildType to instantiate the bounds; force dynamic.
1079 return DynamicTypeImpl.instance;
1080 } else {
1081 return null;
1082 }
1083 }
1084
1085 ReferenceableElementForLink element = resolveRef(type.reference);
1086 return element.buildType(
1087 getTypeArgument, type.implicitFunctionTypeIndices);
1088 }
1089 }
1090
1091 @override
1092 String toString() => enclosingElement.toString();
1093 }
1094
1095 /**
1096 * Element representing a compilation unit which is part of the build
1097 * unit being linked.
1098 */
1099 class CompilationUnitElementInBuildUnit extends CompilationUnitElementForLink {
1100 @override
1101 final LinkedUnitBuilder _linkedUnit;
1102
1103 @override
1104 final LibraryElementInBuildUnit enclosingElement;
1105
1106 CompilationUnitElementInBuildUnit(
1107 this.enclosingElement,
1108 UnlinkedUnit unlinkedUnit,
1109 this._linkedUnit,
1110 int unitNum,
1111 String absoluteUri)
1112 : super(
1113 unlinkedUnit, unitNum, unlinkedUnit.references.length, absoluteUri);
1114
1115 @override
1116 bool get isInBuildUnit => true;
1117
1118 @override
1119 LibraryElementInBuildUnit get library => enclosingElement;
1120
1121 /**
1122 * If this compilation unit already has a reference in its references table
1123 * matching [dependency], [name], [numTypeParameters], [unitNum],
1124 * [containingReference], and [kind], return its index. Otherwise add a new r eference to
1125 * the table and return its index.
1126 */
1127 int addRawReference(String name,
1128 {int dependency: 0,
1129 int numTypeParameters: 0,
1130 int unitNum: 0,
1131 int containingReference: 0,
1132 int localIndex: 0,
1133 ReferenceKind kind: ReferenceKind.classOrEnum}) {
1134 List<LinkedReferenceBuilder> linkedReferences = _linkedUnit.references;
1135 List<UnlinkedReference> unlinkedReferences = _unlinkedUnit.references;
1136 for (int i = 0; i < linkedReferences.length; i++) {
1137 LinkedReferenceBuilder linkedReference = linkedReferences[i];
1138 int candidateContainingReference = i < unlinkedReferences.length
1139 ? unlinkedReferences[i].prefixReference
1140 : linkedReference.containingReference;
1141 if (candidateContainingReference != 0 &&
1142 linkedReferences[candidateContainingReference].kind ==
1143 ReferenceKind.prefix) {
1144 // We don't need to match containing references when they are prefixes,
1145 // since the relevant information is in linkedReference.dependency.
1146 candidateContainingReference = 0;
1147 }
1148 if (linkedReference.dependency == dependency &&
1149 (i < unlinkedReferences.length
1150 ? unlinkedReferences[i].name
1151 : linkedReference.name) ==
1152 name &&
1153 linkedReference.numTypeParameters == numTypeParameters &&
1154 linkedReference.unit == unitNum &&
1155 candidateContainingReference == containingReference &&
1156 linkedReference.kind == kind &&
1157 linkedReference.localIndex == localIndex) {
1158 return i;
1159 }
1160 }
1161 int result = linkedReferences.length;
1162 linkedReferences.add(new LinkedReferenceBuilder(
1163 dependency: dependency,
1164 name: name,
1165 numTypeParameters: numTypeParameters,
1166 unit: unitNum,
1167 containingReference: containingReference,
1168 kind: kind,
1169 localIndex: localIndex));
1170 return result;
1171 }
1172
1173 /**
1174 * If this compilation unit already has a reference in its references table
1175 * to [element], return its index. Otherwise add a new reference to the table
1176 * and return its index.
1177 */
1178 int addReference(Element element) {
1179 if (element is ClassElementForLink) {
1180 return addRawReference(element.name,
1181 dependency: library.addDependency(element.library),
1182 numTypeParameters: element.typeParameters.length,
1183 unitNum: element.enclosingElement.unitNum);
1184 } else if (element is FunctionTypeAliasElementForLink) {
1185 return addRawReference(element.name,
1186 dependency: library.addDependency(element.library),
1187 numTypeParameters: element.typeParameters.length,
1188 unitNum: element.enclosingElement.unitNum,
1189 kind: ReferenceKind.typedef);
1190 } else if (element is FunctionElementForLink_Initializer) {
1191 return addRawReference('',
1192 containingReference: addReference(element.enclosingElement),
1193 kind: ReferenceKind.function,
1194 localIndex: 0);
1195 } else if (element is FunctionElementForLink_Local_NonSynthetic) {
1196 ExecutableElementForLink parent = element.enclosingElement;
1197 int localIndex = parent.functions.indexOf(element);
1198 assert(localIndex != -1);
1199 return addRawReference(element.name,
1200 containingReference: addReference(parent),
1201 kind: ReferenceKind.function,
1202 localIndex: localIndex);
1203 } else if (element is ExecutableElementForLink_NonLocal) {
1204 ClassElementForLink_Class enclosingClass = element.enclosingClass;
1205 ReferenceKind kind;
1206 switch (element._unlinkedExecutable.kind) {
1207 case UnlinkedExecutableKind.functionOrMethod:
1208 kind = enclosingClass != null
1209 ? ReferenceKind.method
1210 : ReferenceKind.topLevelFunction;
1211 break;
1212 case UnlinkedExecutableKind.setter:
1213 kind = ReferenceKind.propertyAccessor;
1214 break;
1215 default:
1216 // TODO(paulberry): implement other cases as necessary
1217 throw new UnimplementedError('${element._unlinkedExecutable.kind}');
1218 }
1219 return addRawReference(element.name,
1220 numTypeParameters: element.typeParameters.length,
1221 containingReference:
1222 enclosingClass != null ? addReference(enclosingClass) : null,
1223 dependency: enclosingClass != null
1224 ? null
1225 : library.addDependency(element.library as LibraryElementForLink),
1226 kind: kind);
1227 } else if (element is FunctionElementForLink_Initializer) {
1228 return addRawReference('',
1229 containingReference: addReference(element.enclosingElement),
1230 kind: ReferenceKind.function);
1231 } else if (element is TopLevelVariableElementForLink) {
1232 return addRawReference(element.name,
1233 dependency: library.addDependency(element.library),
1234 kind: ReferenceKind.topLevelPropertyAccessor);
1235 } else if (element is FieldElementForLink_ClassField) {
1236 ClassElementForLink_Class enclosingClass = element.enclosingElement;
1237 // Note: even if the class has type parameters, we don't need to set
1238 // numTypeParameters because numTypeParameters does not count type
1239 // parameters of parent elements (see
1240 // [LinkedReference.numTypeParameters]).
1241 return addRawReference(element.name,
1242 containingReference: addReference(enclosingClass),
1243 kind: ReferenceKind.propertyAccessor);
1244 }
1245 // TODO(paulberry): implement other cases
1246 throw new UnimplementedError('${element.runtimeType}');
1247 }
1248
1249 @override
1250 DartType getLinkedType(
1251 int slot, TypeParameterizedElementMixin typeParameterContext) {
1252 // This method should only be called on compilation units that come from
1253 // dependencies, never on compilation units that are part of the current
1254 // build unit.
1255 throw new StateError(
1256 'Linker tried to access linked type from current build unit');
1257 }
1258
1259 /**
1260 * Perform type inference and const cycle detection on this
1261 * compilation unit.
1262 */
1263 void link() {
1264 if (library._linker.strongMode) {
1265 new InstanceMemberInferrer(enclosingElement._linker.typeProvider,
1266 enclosingElement.inheritanceManager)
1267 .inferCompilationUnit(this);
1268 for (TopLevelVariableElementForLink variable in topLevelVariables) {
1269 variable.link(this);
1270 }
1271 }
1272 for (ClassElementForLink classElement in types) {
1273 classElement.link(this);
1274 }
1275 }
1276
1277 /**
1278 * Throw away any information stored in the summary by a previous call to
1279 * [link].
1280 */
1281 void unlink() {
1282 _linkedUnit.constCycles.clear();
1283 _linkedUnit.parametersInheritingCovariant.clear();
1284 _linkedUnit.references.length = _unlinkedUnit.references.length;
1285 _linkedUnit.types.clear();
1286 }
1287
1288 /**
1289 * Store the fact that the given [slot] represents a constant constructor
1290 * that is part of a cycle.
1291 */
1292 void _storeConstCycle(int slot) {
1293 _linkedUnit.constCycles.add(slot);
1294 }
1295
1296 /**
1297 * Store the fact that the given [slot] represents a parameter that inherits
1298 * `@covariant` behavior.
1299 */
1300 void _storeInheritsCovariant(int slot) {
1301 _linkedUnit.parametersInheritingCovariant.add(slot);
1302 }
1303
1304 /**
1305 * Store the given [linkedType] in the given [slot] of the this compilation
1306 * unit's linked type list.
1307 */
1308 void _storeLinkedType(int slot, DartType linkedType,
1309 TypeParameterizedElementMixin typeParameterContext) {
1310 if (slot != 0) {
1311 if (linkedType != null && !linkedType.isDynamic) {
1312 _linkedUnit.types.add(_createLinkedType(
1313 linkedType, this, typeParameterContext,
1314 slot: slot));
1315 }
1316 }
1317 }
1318 }
1319
1320 /**
1321 * Element representing a compilation unit which is depended upon
1322 * (either directly or indirectly) by the build unit being linked.
1323 *
1324 * TODO(paulberry): ensure that inferred types in dependencies are properly
1325 * resynthesized.
1326 */
1327 class CompilationUnitElementInDependency extends CompilationUnitElementForLink {
1328 @override
1329 final LinkedUnit _linkedUnit;
1330
1331 List<EntityRef> _linkedTypeRefs;
1332
1333 @override
1334 final LibraryElementInDependency enclosingElement;
1335
1336 CompilationUnitElementInDependency(
1337 this.enclosingElement,
1338 UnlinkedUnit unlinkedUnit,
1339 LinkedUnit linkedUnit,
1340 int unitNum,
1341 String absoluteUri)
1342 : _linkedUnit = linkedUnit,
1343 super(
1344 unlinkedUnit, unitNum, linkedUnit.references.length, absoluteUri) {
1345 // Make one pass through the linked types to determine the lengths for
1346 // _linkedTypeRefs and _linkedTypes. TODO(paulberry): add an int to the
1347 // summary to make this unnecessary.
1348 int maxLinkedTypeSlot = 0;
1349 for (EntityRef ref in _linkedUnit.types) {
1350 if (ref.slot > maxLinkedTypeSlot) {
1351 maxLinkedTypeSlot = ref.slot;
1352 }
1353 }
1354 // Initialize _linkedTypeRefs.
1355 _linkedTypeRefs = new List<EntityRef>(maxLinkedTypeSlot + 1);
1356 for (EntityRef ref in _linkedUnit.types) {
1357 _linkedTypeRefs[ref.slot] = ref;
1358 }
1359 }
1360
1361 @override
1362 bool get isInBuildUnit => false;
1363
1364 @override
1365 DartType getLinkedType(
1366 int slot, TypeParameterizedElementMixin typeParameterContext) {
1367 if (slot < _linkedTypeRefs.length) {
1368 return resolveTypeRef(_linkedTypeRefs[slot], typeParameterContext);
1369 } else {
1370 return DynamicTypeImpl.instance;
1371 }
1372 }
1373 }
1374
1375 /**
1376 * Instance of [ConstNode] representing a constant constructor.
1377 */
1378 class ConstConstructorNode extends ConstNode {
1379 /**
1380 * The [ConstructorElement] to which this node refers.
1381 */
1382 final ConstructorElementForLink constructorElement;
1383
1384 /**
1385 * Once this node has been evaluated, indicates whether the
1386 * constructor is free of constant evaluation cycles.
1387 */
1388 bool isCycleFree = false;
1389
1390 ConstConstructorNode(this.constructorElement);
1391
1392 @override
1393 List<ConstNode> computeDependencies() {
1394 List<ConstNode> dependencies = <ConstNode>[];
1395 void safeAddDependency(ConstNode target) {
1396 if (target != null) {
1397 dependencies.add(target);
1398 }
1399 }
1400
1401 UnlinkedExecutable unlinkedExecutable =
1402 constructorElement._unlinkedExecutable;
1403 ClassElementForLink_Class enclosingClass =
1404 constructorElement.enclosingElement;
1405 ConstructorElementForLink redirectedConstructor =
1406 _getFactoryRedirectedConstructor();
1407 if (redirectedConstructor != null) {
1408 if (redirectedConstructor._constNode != null) {
1409 safeAddDependency(redirectedConstructor._constNode);
1410 }
1411 } else if (unlinkedExecutable.isFactory) {
1412 // Factory constructor, but getConstRedirectedConstructor returned
1413 // null. This can happen if we're visiting one of the special external
1414 // const factory constructors in the SDK, or if the code contains
1415 // errors (such as delegating to a non-const constructor, or delegating
1416 // to a constructor that can't be resolved). In any of these cases,
1417 // we'll evaluate calls to this constructor without having to refer to
1418 // any other constants. So we don't need to report any dependencies.
1419 } else {
1420 ClassElementForLink superClass = enclosingClass.supertype?.element;
1421 bool defaultSuperInvocationNeeded = true;
1422 for (UnlinkedConstructorInitializer constructorInitializer
1423 in constructorElement._unlinkedExecutable.constantInitializers) {
1424 if (constructorInitializer.kind ==
1425 UnlinkedConstructorInitializerKind.superInvocation) {
1426 defaultSuperInvocationNeeded = false;
1427 if (superClass != null && !superClass.isObject) {
1428 ConstructorElementForLink constructor = superClass
1429 .getContainedName(constructorInitializer.name)
1430 .asConstructor;
1431 safeAddDependency(constructor?._constNode);
1432 }
1433 } else if (constructorInitializer.kind ==
1434 UnlinkedConstructorInitializerKind.thisInvocation) {
1435 defaultSuperInvocationNeeded = false;
1436 ConstructorElementForLink constructor = constructorElement
1437 .enclosingClass
1438 .getContainedName(constructorInitializer.name)
1439 .asConstructor;
1440 safeAddDependency(constructor?._constNode);
1441 }
1442 CompilationUnitElementForLink compilationUnit =
1443 constructorElement.enclosingElement.enclosingElement;
1444 collectDependencies(
1445 dependencies, constructorInitializer.expression, compilationUnit);
1446 for (UnlinkedConst unlinkedConst in constructorInitializer.arguments) {
1447 collectDependencies(dependencies, unlinkedConst, compilationUnit);
1448 }
1449 }
1450
1451 if (defaultSuperInvocationNeeded) {
1452 // No explicit superconstructor invocation found, so we need to
1453 // manually insert a reference to the implicit superconstructor.
1454 if (superClass != null && !superClass.isObject) {
1455 ConstructorElementForLink unnamedConstructor =
1456 superClass.unnamedConstructor;
1457 safeAddDependency(unnamedConstructor?._constNode);
1458 }
1459 }
1460 for (FieldElementForLink field in enclosingClass.fields) {
1461 // Note: non-static const isn't allowed but we handle it anyway so
1462 // that we won't be confused by incorrect code.
1463 if ((field.isFinal || field.isConst) && !field.isStatic) {
1464 safeAddDependency(field.getter.asConstVariable);
1465 }
1466 }
1467 for (ParameterElementForLink parameterElement
1468 in constructorElement.parameters) {
1469 safeAddDependency(parameterElement._constNode);
1470 }
1471 }
1472 return dependencies;
1473 }
1474
1475 /**
1476 * If [constructorElement] redirects to another constructor via a factory
1477 * redirect, return the constructor it redirects to.
1478 */
1479 ConstructorElementForLink _getFactoryRedirectedConstructor() {
1480 EntityRef redirectedConstructor =
1481 constructorElement._unlinkedExecutable.redirectedConstructor;
1482 if (redirectedConstructor != null) {
1483 return constructorElement.compilationUnit
1484 .resolveRef(redirectedConstructor.reference)
1485 .asConstructor;
1486 } else {
1487 return null;
1488 }
1489 }
1490 }
1491
1492 /**
1493 * Specialization of [DependencyWalker] for detecting constant
1494 * evaluation cycles.
1495 */
1496 class ConstDependencyWalker extends DependencyWalker<ConstNode> {
1497 @override
1498 void evaluate(ConstNode v) {
1499 if (v is ConstConstructorNode) {
1500 v.isCycleFree = true;
1501 }
1502 v.isEvaluated = true;
1503 }
1504
1505 @override
1506 void evaluateScc(List<ConstNode> scc) {
1507 for (ConstNode v in scc) {
1508 if (v is ConstConstructorNode) {
1509 v.isCycleFree = false;
1510 }
1511 v.isEvaluated = true;
1512 }
1513 }
1514 }
1515
1516 /**
1517 * Specialization of [Node] used to construct the constant evaluation
1518 * dependency graph.
1519 */
1520 abstract class ConstNode extends Node<ConstNode> {
1521 @override
1522 bool isEvaluated = false;
1523
1524 /**
1525 * Collect the dependencies in [unlinkedConst] (which should be
1526 * interpreted relative to [compilationUnit]) and store them in
1527 * [dependencies].
1528 */
1529 void collectDependencies(
1530 List<ConstNode> dependencies,
1531 UnlinkedConst unlinkedConst,
1532 CompilationUnitElementForLink compilationUnit) {
1533 if (unlinkedConst == null) {
1534 return;
1535 }
1536 int refPtr = 0;
1537 int intPtr = 0;
1538 for (UnlinkedConstOperation operation in unlinkedConst.operations) {
1539 switch (operation) {
1540 case UnlinkedConstOperation.pushInt:
1541 intPtr++;
1542 break;
1543 case UnlinkedConstOperation.pushLongInt:
1544 int numInts = unlinkedConst.ints[intPtr++];
1545 intPtr += numInts;
1546 break;
1547 case UnlinkedConstOperation.concatenate:
1548 intPtr++;
1549 break;
1550 case UnlinkedConstOperation.pushReference:
1551 EntityRef ref = unlinkedConst.references[refPtr++];
1552 ConstVariableNode variable =
1553 compilationUnit.resolveRef(ref.reference).asConstVariable;
1554 if (variable != null) {
1555 dependencies.add(variable);
1556 }
1557 break;
1558 case UnlinkedConstOperation.makeUntypedList:
1559 case UnlinkedConstOperation.makeUntypedMap:
1560 intPtr++;
1561 break;
1562 case UnlinkedConstOperation.assignToRef:
1563 refPtr++;
1564 break;
1565 case UnlinkedConstOperation.invokeMethodRef:
1566 EntityRef ref = unlinkedConst.references[refPtr++];
1567 ConstVariableNode variable =
1568 compilationUnit.resolveRef(ref.reference).asConstVariable;
1569 if (variable != null) {
1570 dependencies.add(variable);
1571 }
1572 intPtr += 2;
1573 int numTypeArguments = unlinkedConst.ints[intPtr++];
1574 refPtr += numTypeArguments;
1575 break;
1576 case UnlinkedConstOperation.invokeMethod:
1577 intPtr += 2;
1578 int numTypeArguments = unlinkedConst.ints[intPtr++];
1579 refPtr += numTypeArguments;
1580 break;
1581 case UnlinkedConstOperation.makeTypedList:
1582 refPtr++;
1583 intPtr++;
1584 break;
1585 case UnlinkedConstOperation.makeTypedMap:
1586 refPtr += 2;
1587 intPtr++;
1588 break;
1589 case UnlinkedConstOperation.invokeConstructor:
1590 EntityRef ref = unlinkedConst.references[refPtr++];
1591 ConstructorElementForLink element =
1592 compilationUnit.resolveRef(ref.reference).asConstructor;
1593 if (element?._constNode != null) {
1594 dependencies.add(element._constNode);
1595 }
1596 intPtr += 2;
1597 break;
1598 case UnlinkedConstOperation.typeCast:
1599 case UnlinkedConstOperation.typeCheck:
1600 refPtr++;
1601 break;
1602 case UnlinkedConstOperation.pushLocalFunctionReference:
1603 intPtr += 2;
1604 break;
1605 default:
1606 break;
1607 }
1608 }
1609 assert(refPtr == unlinkedConst.references.length);
1610 assert(intPtr == unlinkedConst.ints.length);
1611 }
1612 }
1613
1614 /**
1615 * Instance of [ConstNode] representing a parameter with a default
1616 * value.
1617 */
1618 class ConstParameterNode extends ConstNode {
1619 /**
1620 * The [ParameterElement] to which this node refers.
1621 */
1622 final ParameterElementForLink parameterElement;
1623
1624 ConstParameterNode(this.parameterElement);
1625
1626 @override
1627 List<ConstNode> computeDependencies() {
1628 List<ConstNode> dependencies = <ConstNode>[];
1629 collectDependencies(
1630 dependencies,
1631 parameterElement._unlinkedParam.initializer?.bodyExpr,
1632 parameterElement.compilationUnit);
1633 return dependencies;
1634 }
1635 }
1636
1637 /**
1638 * Element representing a constructor resynthesized from a summary
1639 * during linking.
1640 */
1641 class ConstructorElementForLink extends ExecutableElementForLink_NonLocal
1642 with ReferenceableElementForLink
1643 implements ConstructorElementImpl {
1644 /**
1645 * If this is a `const` constructor and the enclosing library is
1646 * part of the build unit being linked, the constructor's node in
1647 * the constant evaluation dependency graph. Otherwise `null`.
1648 */
1649 ConstConstructorNode _constNode;
1650
1651 ConstructorElementForLink(ClassElementForLink_Class enclosingClass,
1652 UnlinkedExecutable unlinkedExecutable)
1653 : super(enclosingClass.enclosingElement, enclosingClass,
1654 unlinkedExecutable) {
1655 if (enclosingClass.enclosingElement.isInBuildUnit &&
1656 _unlinkedExecutable != null &&
1657 _unlinkedExecutable.constCycleSlot != 0) {
1658 _constNode = new ConstConstructorNode(this);
1659 }
1660 }
1661
1662 @override
1663 ConstructorElementForLink get asConstructor => this;
1664
1665 @override
1666 ClassElementImpl get enclosingElement => super.enclosingClass;
1667
1668 @override
1669 bool get isCycleFree {
1670 if (!_constNode.isEvaluated) {
1671 new ConstDependencyWalker().walk(_constNode);
1672 }
1673 return _constNode.isCycleFree;
1674 }
1675
1676 /**
1677 * Perform const cycle detection on this constructor.
1678 */
1679 void link(CompilationUnitElementInBuildUnit compilationUnit) {
1680 if (_constNode != null && !isCycleFree) {
1681 compilationUnit._storeConstCycle(_unlinkedExecutable.constCycleSlot);
1682 }
1683 // TODO(paulberry): call super.
1684 }
1685
1686 @override
1687 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
1688 }
1689
1690 /**
1691 * A synthetic constructor.
1692 */
1693 class ConstructorElementForLink_Synthetic extends ConstructorElementForLink {
1694 ConstructorElementForLink_Synthetic(
1695 ClassElementForLink_Class enclosingElement)
1696 : super(enclosingElement, null);
1697
1698 @override
1699 String get name => '';
1700
1701 @override
1702 List<ParameterElement> get parameters => const <ParameterElement>[];
1703 }
1704
1705 /**
1706 * Instance of [ConstNode] representing a constant field or constant
1707 * top level variable.
1708 */
1709 class ConstVariableNode extends ConstNode {
1710 /**
1711 * The [FieldElement] or [TopLevelVariableElement] to which this
1712 * node refers.
1713 */
1714 final VariableElementForLink variableElement;
1715
1716 ConstVariableNode(this.variableElement);
1717
1718 @override
1719 List<ConstNode> computeDependencies() {
1720 List<ConstNode> dependencies = <ConstNode>[];
1721 collectDependencies(
1722 dependencies,
1723 variableElement.unlinkedVariable.initializer?.bodyExpr,
1724 variableElement.compilationUnit);
1725 return dependencies;
1726 }
1727 }
1728
1729 /**
1730 * Stub implementation of [AnalysisContext] which provides just those methods
1731 * needed during linking.
1732 */
1733 class ContextForLink implements AnalysisContext {
1734 final Linker _linker;
1735
1736 ContextForLink(this._linker);
1737
1738 @override
1739 AnalysisOptionsForLink get analysisOptions => _linker.analysisOptions;
1740
1741 @override
1742 TypeSystem get typeSystem => _linker.typeSystem;
1743
1744 @override
1745 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
1746 }
1747
1748 /**
1749 * An instance of [DependencyWalker] contains the core algorithms for
1750 * walking a dependency graph and evaluating nodes in a safe order.
1751 */
1752 abstract class DependencyWalker<NodeType extends Node<NodeType>> {
1753 /**
1754 * Called by [walk] to evaluate a single non-cyclical node, after
1755 * all that node's dependencies have been evaluated.
1756 */
1757 void evaluate(NodeType v);
1758
1759 /**
1760 * Called by [walk] to evaluate a strongly connected component
1761 * containing one or more nodes. All dependencies of the strongly
1762 * connected component have been evaluated.
1763 */
1764 void evaluateScc(List<NodeType> scc);
1765
1766 /**
1767 * Walk the dependency graph starting at [startingPoint], finding
1768 * strongly connected components and evaluating them in a safe order
1769 * by calling [evaluate] and [evaluateScc].
1770 *
1771 * This is an implementation of Tarjan's strongly connected
1772 * components algorithm
1773 * (https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_alg orithm).
1774 */
1775 void walk(NodeType startingPoint) {
1776 // TODO(paulberry): consider rewriting in a non-recursive way so
1777 // that long dependency chains don't cause stack overflow.
1778
1779 // TODO(paulberry): in the event that an exception occurs during
1780 // the walk, restore the state of the [Node] data structures so
1781 // that further evaluation will be safe.
1782
1783 // The index which will be assigned to the next node that is
1784 // freshly visited.
1785 int index = 1;
1786
1787 // Stack of nodes which have been seen so far and whose strongly
1788 // connected component is still being determined. Nodes are only
1789 // popped off the stack when they are evaluated, so sometimes the
1790 // stack contains nodes that were visited after the current node.
1791 List<NodeType> stack = <NodeType>[];
1792
1793 void strongConnect(NodeType node) {
1794 bool hasTrivialCycle = false;
1795
1796 // Assign the current node an index and add it to the stack. We
1797 // haven't seen any of its dependencies yet, so set its lowLink
1798 // to its index, indicating that so far it is the only node in
1799 // its strongly connected component.
1800 node.index = node.lowLink = index++;
1801 stack.add(node);
1802
1803 // Consider the node's dependencies one at a time.
1804 for (NodeType dependency in node.dependencies) {
1805 // If the dependency has already been evaluated, it can't be
1806 // part of this node's strongly connected component, so we can
1807 // skip it.
1808 if (dependency.isEvaluated) {
1809 continue;
1810 }
1811 if (identical(node, dependency)) {
1812 // If a node includes itself as a dependency, there is no need to
1813 // explore the dependency further.
1814 hasTrivialCycle = true;
1815 } else if (dependency.index == 0) {
1816 // The dependency hasn't been seen yet, so recurse on it.
1817 strongConnect(dependency);
1818 // If the dependency's lowLink refers to a node that was
1819 // visited before the current node, that means that the
1820 // current node, the dependency, and the node referred to by
1821 // the dependency's lowLink are all part of the same
1822 // strongly connected component, so we need to update the
1823 // current node's lowLink accordingly.
1824 if (dependency.lowLink < node.lowLink) {
1825 node.lowLink = dependency.lowLink;
1826 }
1827 } else {
1828 // The dependency has already been seen, so it is part of
1829 // the current node's strongly connected component. If it
1830 // was visited earlier than the current node's lowLink, then
1831 // it is a new addition to the current node's strongly
1832 // connected component, so we need to update the current
1833 // node's lowLink accordingly.
1834 if (dependency.index < node.lowLink) {
1835 node.lowLink = dependency.index;
1836 }
1837 }
1838 }
1839
1840 // If the current node's lowLink is the same as its index, then
1841 // we have finished visiting a strongly connected component, so
1842 // pop the stack and evaluate it before moving on.
1843 if (node.lowLink == node.index) {
1844 // The strongly connected component has only one node. If there is a
1845 // cycle, it's a trivial one.
1846 if (identical(stack.last, node)) {
1847 stack.removeLast();
1848 if (hasTrivialCycle) {
1849 evaluateScc(<NodeType>[node]);
1850 } else {
1851 evaluate(node);
1852 }
1853 } else {
1854 // There are multiple nodes in the strongly connected
1855 // component.
1856 List<NodeType> scc = <NodeType>[];
1857 while (true) {
1858 NodeType otherNode = stack.removeLast();
1859 scc.add(otherNode);
1860 if (identical(otherNode, node)) {
1861 break;
1862 }
1863 }
1864 evaluateScc(scc);
1865 }
1866 }
1867 }
1868
1869 // Kick off the algorithm starting with the starting point.
1870 strongConnect(startingPoint);
1871 }
1872 }
1873
1874 /**
1875 * Base class for executable elements resynthesized from a summary during
1876 * linking.
1877 */
1878 abstract class ExecutableElementForLink extends Object
1879 with TypeParameterizedElementMixin, ParameterParentElementForLink
1880 implements ExecutableElementImpl {
1881 /**
1882 * The unlinked representation of the method in the summary.
1883 */
1884 final UnlinkedExecutable _unlinkedExecutable;
1885
1886 DartType _declaredReturnType;
1887 DartType _inferredReturnType;
1888 FunctionTypeImpl _type;
1889 String _name;
1890 String _displayName;
1891
1892 final CompilationUnitElementForLink compilationUnit;
1893
1894 ExecutableElementForLink(this.compilationUnit, this._unlinkedExecutable);
1895
1896 @override
1897 ContextForLink get context => compilationUnit.context;
1898
1899 /**
1900 * If the executable element had an explicitly declared return type, return
1901 * it. Otherwise return `null`.
1902 */
1903 DartType get declaredReturnType {
1904 if (_unlinkedExecutable.returnType == null) {
1905 return null;
1906 } else {
1907 return _declaredReturnType ??=
1908 compilationUnit.resolveTypeRef(_unlinkedExecutable.returnType, this);
1909 }
1910 }
1911
1912 @override
1913 String get displayName {
1914 if (_displayName == null) {
1915 _displayName = _unlinkedExecutable.name;
1916 if (_unlinkedExecutable.kind == UnlinkedExecutableKind.setter) {
1917 _displayName = _displayName.substring(0, _displayName.length - 1);
1918 }
1919 }
1920 return _displayName;
1921 }
1922
1923 @override
1924 CompilationUnitElementImpl get enclosingUnit => compilationUnit;
1925
1926 @override
1927 bool get hasImplicitReturnType => _unlinkedExecutable.returnType == null;
1928
1929 @override
1930 List<int> get implicitFunctionTypeIndices => const <int>[];
1931
1932 /**
1933 * Return the inferred return type of the executable element. Should only be
1934 * called if no return type was explicitly declared.
1935 */
1936 DartType get inferredReturnType {
1937 // We should only try to infer a return type when none is explicitly
1938 // declared.
1939 assert(_unlinkedExecutable.returnType == null);
1940 if (Linker._initializerTypeInferenceCycle != null &&
1941 Linker._initializerTypeInferenceCycle ==
1942 compilationUnit.library.libraryCycleForLink) {
1943 // We are currently computing the type of an initializer expression in the
1944 // current library cycle, so type inference results should be ignored.
1945 return _computeDefaultReturnType();
1946 }
1947 if (_inferredReturnType == null) {
1948 if (_unlinkedExecutable.kind == UnlinkedExecutableKind.constructor) {
1949 // TODO(paulberry): implement.
1950 throw new UnimplementedError();
1951 } else if (compilationUnit.isInBuildUnit) {
1952 _inferredReturnType = _computeDefaultReturnType();
1953 } else {
1954 _inferredReturnType = compilationUnit.getLinkedType(
1955 _unlinkedExecutable.inferredReturnTypeSlot, this);
1956 }
1957 }
1958 return _inferredReturnType;
1959 }
1960
1961 @override
1962 bool get isStatic => _unlinkedExecutable.isStatic;
1963
1964 @override
1965 bool get isSynthetic => false;
1966
1967 @override
1968 LibraryElement get library => enclosingElement.library;
1969
1970 @override
1971 String get name {
1972 if (_name == null) {
1973 _name = _unlinkedExecutable.name;
1974 if (_name == '-' && _unlinkedExecutable.parameters.isEmpty) {
1975 _name = 'unary-';
1976 }
1977 }
1978 return _name;
1979 }
1980
1981 @override
1982 DartType get returnType => declaredReturnType ?? inferredReturnType;
1983
1984 @override
1985 void set returnType(DartType inferredType) {
1986 assert(_inferredReturnType == null);
1987 _inferredReturnType = inferredType;
1988 }
1989
1990 @override
1991 FunctionTypeImpl get type => _type ??= new FunctionTypeImpl(this);
1992
1993 @override
1994 TypeParameterizedElementMixin get typeParameterContext => this;
1995
1996 @override
1997 List<UnlinkedParam> get unlinkedParameters => _unlinkedExecutable.parameters;
1998
1999 @override
2000 List<UnlinkedTypeParam> get unlinkedTypeParams =>
2001 _unlinkedExecutable.typeParameters;
2002
2003 @override
2004 bool isAccessibleIn(LibraryElement library) =>
2005 !Identifier.isPrivateName(name) || identical(this.library, library);
2006
2007 /**
2008 * Compute the default return type for this type of executable element (if no
2009 * return type is declared and strong mode type inference cannot infer a
2010 * better return type).
2011 */
2012 DartType _computeDefaultReturnType() {
2013 if (_unlinkedExecutable.kind == UnlinkedExecutableKind.setter &&
2014 (library as LibraryElementForLink)._linker.strongMode) {
2015 // In strong mode, setters without an explicit return type are
2016 // considered to return `void`.
2017 return VoidTypeImpl.instance;
2018 } else {
2019 return DynamicTypeImpl.instance;
2020 }
2021 }
2022 }
2023
2024 /**
2025 * Base class for executable elements that are resynthesized from a summary
2026 * during linking and are not local functions.
2027 */
2028 abstract class ExecutableElementForLink_NonLocal
2029 extends ExecutableElementForLink {
2030 /**
2031 * Return the class in which this executable appears, maybe `null` for a
2032 * top-level function.
2033 */
2034 final ClassElementForLink_Class enclosingClass;
2035
2036 ExecutableElementForLink_NonLocal(
2037 CompilationUnitElementForLink compilationUnit,
2038 this.enclosingClass,
2039 UnlinkedExecutable unlinkedExecutable)
2040 : super(compilationUnit, unlinkedExecutable);
2041
2042 @override
2043 Element get enclosingElement => enclosingClass ?? compilationUnit;
2044
2045 @override
2046 TypeParameterizedElementMixin get enclosingTypeParameterContext =>
2047 enclosingClass;
2048
2049 /**
2050 * Store the results of type inference for this method in [compilationUnit].
2051 */
2052 void link(CompilationUnitElementInBuildUnit compilationUnit) {
2053 if (_unlinkedExecutable.returnType == null) {
2054 compilationUnit._storeLinkedType(
2055 _unlinkedExecutable.inferredReturnTypeSlot, inferredReturnType, this);
2056 }
2057 for (ParameterElementForLink parameterElement in parameters) {
2058 parameterElement.link(compilationUnit);
2059 }
2060 }
2061 }
2062
2063 class ExprTypeComputer {
2064 final FunctionElementForLink_Local function;
2065 final CompilationUnitElementForLink unit;
2066 final LibraryElementForLink library;
2067 final Linker linker;
2068 final TypeProvider typeProvider;
2069 final UnlinkedConst unlinkedConst;
2070
2071 final List<DartType> stack = <DartType>[];
2072 int intPtr = 0;
2073 int refPtr = 0;
2074 int strPtr = 0;
2075 int assignmentOperatorPtr = 0;
2076
2077 factory ExprTypeComputer(FunctionElementForLink_Local functionElement) {
2078 CompilationUnitElementForLink unit = functionElement.compilationUnit;
2079 LibraryElementForLink library = unit.enclosingElement;
2080 Linker linker = library._linker;
2081 TypeProvider typeProvider = linker.typeProvider;
2082 UnlinkedConst unlinkedConst = functionElement._unlinkedExecutable.bodyExpr;
2083 return new ExprTypeComputer._(
2084 functionElement, unit, library, linker, typeProvider, unlinkedConst);
2085 }
2086
2087 ExprTypeComputer._(this.function, this.unit, this.library, this.linker,
2088 this.typeProvider, this.unlinkedConst);
2089
2090 DartType compute() {
2091 if (unlinkedConst == null) {
2092 // No function body was stored for this function, so we can't infer its
2093 // return type. Assume `dynamic`.
2094 return DynamicTypeImpl.instance;
2095 }
2096 // Perform RPN evaluation of the constant, using a stack of inferred types.
2097 for (UnlinkedConstOperation operation in unlinkedConst.operations) {
2098 switch (operation) {
2099 case UnlinkedConstOperation.pushInt:
2100 intPtr++;
2101 stack.add(typeProvider.intType);
2102 break;
2103 case UnlinkedConstOperation.pushLongInt:
2104 int numInts = _getNextInt();
2105 intPtr += numInts;
2106 stack.add(typeProvider.intType);
2107 break;
2108 case UnlinkedConstOperation.pushDouble:
2109 stack.add(typeProvider.doubleType);
2110 break;
2111 case UnlinkedConstOperation.pushTrue:
2112 case UnlinkedConstOperation.pushFalse:
2113 stack.add(typeProvider.boolType);
2114 break;
2115 case UnlinkedConstOperation.pushString:
2116 strPtr++;
2117 stack.add(typeProvider.stringType);
2118 break;
2119 case UnlinkedConstOperation.concatenate:
2120 stack.length -= _getNextInt();
2121 stack.add(typeProvider.stringType);
2122 break;
2123 case UnlinkedConstOperation.makeSymbol:
2124 strPtr++;
2125 stack.add(typeProvider.symbolType);
2126 break;
2127 case UnlinkedConstOperation.pushNull:
2128 stack.add(BottomTypeImpl.instance);
2129 break;
2130 case UnlinkedConstOperation.pushReference:
2131 _doPushReference();
2132 break;
2133 case UnlinkedConstOperation.extractProperty:
2134 _doExtractProperty();
2135 break;
2136 case UnlinkedConstOperation.invokeConstructor:
2137 _doInvokeConstructor();
2138 break;
2139 case UnlinkedConstOperation.makeUntypedList:
2140 _doMakeUntypedList();
2141 break;
2142 case UnlinkedConstOperation.makeUntypedMap:
2143 _doMakeUntypedMap();
2144 break;
2145 case UnlinkedConstOperation.makeTypedList:
2146 _doMakeTypedList();
2147 break;
2148 case UnlinkedConstOperation.makeTypedMap:
2149 _doMakeTypeMap();
2150 break;
2151 case UnlinkedConstOperation.not:
2152 stack.length -= 1;
2153 stack.add(typeProvider.boolType);
2154 break;
2155 case UnlinkedConstOperation.complement:
2156 _computePrefixExpressionType('~');
2157 break;
2158 case UnlinkedConstOperation.negate:
2159 _computePrefixExpressionType('unary-');
2160 break;
2161 case UnlinkedConstOperation.and:
2162 case UnlinkedConstOperation.or:
2163 case UnlinkedConstOperation.equal:
2164 case UnlinkedConstOperation.notEqual:
2165 stack.length -= 2;
2166 stack.add(typeProvider.boolType);
2167 break;
2168 case UnlinkedConstOperation.bitXor:
2169 _computeBinaryExpressionType(TokenType.CARET);
2170 break;
2171 case UnlinkedConstOperation.bitAnd:
2172 _computeBinaryExpressionType(TokenType.AMPERSAND);
2173 break;
2174 case UnlinkedConstOperation.bitOr:
2175 _computeBinaryExpressionType(TokenType.BAR);
2176 break;
2177 case UnlinkedConstOperation.bitShiftRight:
2178 _computeBinaryExpressionType(TokenType.GT_GT);
2179 break;
2180 case UnlinkedConstOperation.bitShiftLeft:
2181 _computeBinaryExpressionType(TokenType.LT_LT);
2182 break;
2183 case UnlinkedConstOperation.add:
2184 _computeBinaryExpressionType(TokenType.PLUS);
2185 break;
2186 case UnlinkedConstOperation.subtract:
2187 _computeBinaryExpressionType(TokenType.MINUS);
2188 break;
2189 case UnlinkedConstOperation.multiply:
2190 _computeBinaryExpressionType(TokenType.STAR);
2191 break;
2192 case UnlinkedConstOperation.divide:
2193 _computeBinaryExpressionType(TokenType.SLASH);
2194 break;
2195 case UnlinkedConstOperation.floorDivide:
2196 _computeBinaryExpressionType(TokenType.TILDE_SLASH);
2197 break;
2198 case UnlinkedConstOperation.greater:
2199 _computeBinaryExpressionType(TokenType.GT);
2200 break;
2201 case UnlinkedConstOperation.less:
2202 _computeBinaryExpressionType(TokenType.LT);
2203 break;
2204 case UnlinkedConstOperation.greaterEqual:
2205 _computeBinaryExpressionType(TokenType.GT_EQ);
2206 break;
2207 case UnlinkedConstOperation.lessEqual:
2208 _computeBinaryExpressionType(TokenType.LT_EQ);
2209 break;
2210 case UnlinkedConstOperation.modulo:
2211 _computeBinaryExpressionType(TokenType.PERCENT);
2212 break;
2213 case UnlinkedConstOperation.conditional:
2214 _doConditional();
2215 break;
2216 case UnlinkedConstOperation.assignToRef:
2217 _doAssignToRef();
2218 break;
2219 case UnlinkedConstOperation.assignToProperty:
2220 _doAssignToProperty();
2221 break;
2222 case UnlinkedConstOperation.assignToIndex:
2223 _doAssignToIndex();
2224 break;
2225 case UnlinkedConstOperation.extractIndex:
2226 _doExtractIndex();
2227 break;
2228 case UnlinkedConstOperation.invokeMethodRef:
2229 _doInvokeMethodRef();
2230 break;
2231 case UnlinkedConstOperation.invokeMethod:
2232 _doInvokeMethod();
2233 break;
2234 case UnlinkedConstOperation.cascadeSectionBegin:
2235 stack.add(stack.last);
2236 break;
2237 case UnlinkedConstOperation.cascadeSectionEnd:
2238 stack.removeLast();
2239 break;
2240 case UnlinkedConstOperation.typeCast:
2241 stack.removeLast();
2242 DartType type = _getNextTypeRef();
2243 stack.add(type);
2244 break;
2245 case UnlinkedConstOperation.typeCheck:
2246 stack.removeLast();
2247 refPtr++;
2248 stack.add(typeProvider.boolType);
2249 break;
2250 case UnlinkedConstOperation.throwException:
2251 stack.removeLast();
2252 stack.add(BottomTypeImpl.instance);
2253 break;
2254 case UnlinkedConstOperation.pushLocalFunctionReference:
2255 int popCount = _getNextInt();
2256 assert(popCount == 0); // TODO(paulberry): handle the nonzero case.
2257 stack.add(function.functions[_getNextInt()].type);
2258 break;
2259 case UnlinkedConstOperation.pushParameter:
2260 stack.add(_findParameterType(_getNextString()));
2261 break;
2262 default:
2263 // TODO(paulberry): implement.
2264 throw new UnimplementedError('$operation');
2265 }
2266 }
2267 assert(intPtr == unlinkedConst.ints.length);
2268 assert(refPtr == unlinkedConst.references.length);
2269 assert(strPtr == unlinkedConst.strings.length);
2270 assert(assignmentOperatorPtr == unlinkedConst.assignmentOperators.length);
2271 assert(stack.length == 1);
2272 return stack[0];
2273 }
2274
2275 void _computeBinaryExpressionType(TokenType operator) {
2276 DartType right = stack.removeLast();
2277 DartType left = stack.removeLast();
2278 _pushBinaryOperatorType(left, operator, right);
2279 }
2280
2281 void _computePrefixExpressionType(String operatorName) {
2282 DartType operand = stack.removeLast();
2283 if (operand is InterfaceType) {
2284 MethodElement method =
2285 operand.lookUpInheritedMethod(operatorName, library: library);
2286 if (method != null) {
2287 DartType type = method.returnType;
2288 stack.add(type);
2289 return;
2290 }
2291 }
2292 stack.add(DynamicTypeImpl.instance);
2293 }
2294
2295 void _doAssignToIndex() {
2296 stack.removeLast();
2297 stack.removeLast();
2298 UnlinkedExprAssignOperator operator =
2299 unlinkedConst.assignmentOperators[assignmentOperatorPtr++];
2300 if (operator == UnlinkedExprAssignOperator.assign) {
2301 // The type of the assignment is the type of the value,
2302 // which is already in the stack.
2303 } else if (isIncrementOrDecrement(operator)) {
2304 // TODO(scheglov) implement
2305 stack.add(DynamicTypeImpl.instance);
2306 } else {
2307 stack.removeLast();
2308 // TODO(scheglov) implement
2309 stack.add(DynamicTypeImpl.instance);
2310 }
2311 }
2312
2313 void _doAssignToProperty() {
2314 DartType targetType = stack.removeLast();
2315 String propertyName = _getNextString();
2316 UnlinkedExprAssignOperator assignOperator =
2317 unlinkedConst.assignmentOperators[assignmentOperatorPtr++];
2318 if (assignOperator == UnlinkedExprAssignOperator.assign) {
2319 // The type of the assignment is the type of the value,
2320 // which is already in the stack.
2321 } else if (assignOperator == UnlinkedExprAssignOperator.postfixDecrement ||
2322 assignOperator == UnlinkedExprAssignOperator.postfixIncrement) {
2323 DartType propertyType = _getPropertyType(targetType, propertyName);
2324 stack.add(propertyType);
2325 } else if (assignOperator == UnlinkedExprAssignOperator.prefixDecrement) {
2326 _pushPropertyBinaryExpression(
2327 targetType, propertyName, TokenType.MINUS, typeProvider.intType);
2328 } else if (assignOperator == UnlinkedExprAssignOperator.prefixIncrement) {
2329 _pushPropertyBinaryExpression(
2330 targetType, propertyName, TokenType.PLUS, typeProvider.intType);
2331 } else {
2332 TokenType binaryOperator =
2333 _convertAssignOperatorToTokenType(assignOperator);
2334 DartType operandType = stack.removeLast();
2335 _pushPropertyBinaryExpression(
2336 targetType, propertyName, binaryOperator, operandType);
2337 }
2338 }
2339
2340 void _doAssignToRef() {
2341 refPtr++;
2342 UnlinkedExprAssignOperator operator =
2343 unlinkedConst.assignmentOperators[assignmentOperatorPtr++];
2344 if (operator == UnlinkedExprAssignOperator.assign) {
2345 // The type of the assignment is the type of the value,
2346 // which is already in the stack.
2347 } else if (isIncrementOrDecrement(operator)) {
2348 // TODO(scheglov) implement
2349 stack.add(DynamicTypeImpl.instance);
2350 } else {
2351 stack.removeLast();
2352 // TODO(scheglov) implement
2353 stack.add(DynamicTypeImpl.instance);
2354 }
2355 }
2356
2357 void _doConditional() {
2358 DartType elseType = stack.removeLast();
2359 DartType thenType = stack.removeLast();
2360 stack.removeLast();
2361 DartType type = _leastUpperBound(thenType, elseType);
2362 type = _dynamicIfNull(type);
2363 stack.add(type);
2364 }
2365
2366 void _doExtractIndex() {
2367 stack.removeLast(); // index
2368 DartType target = stack.removeLast();
2369 stack.add(() {
2370 if (target is InterfaceType) {
2371 MethodElement method =
2372 target.lookUpInheritedMethod('[]', library: library);
2373 if (method != null) {
2374 return method.returnType;
2375 }
2376 }
2377 return DynamicTypeImpl.instance;
2378 }());
2379 }
2380
2381 void _doExtractProperty() {
2382 DartType target = stack.removeLast();
2383 String propertyName = _getNextString();
2384 stack.add(() {
2385 if (target is InterfaceType) {
2386 ExecutableElement element = target
2387 .lookUpInheritedGetterOrMethod(propertyName, library: library);
2388 if (element != null) {
2389 if (element is PropertyAccessorElement) {
2390 return element.returnType;
2391 } else {
2392 // Method tear-off
2393 return element.type;
2394 }
2395 }
2396 }
2397 return DynamicTypeImpl.instance;
2398 }());
2399 }
2400
2401 void _doInvokeConstructor() {
2402 int numNamed = _getNextInt();
2403 int numPositional = _getNextInt();
2404 // TODO(paulberry): don't just pop the args; use their types
2405 // to infer the type of type arguments.
2406 stack.length -= numNamed + numPositional;
2407 strPtr += numNamed;
2408 EntityRef ref = _getNextRef();
2409 ClassElementForLink_Class element =
2410 unit.resolveConstructorClassRef(ref.reference).asClass;
2411 if (element != null) {
2412 stack.add(element.buildType((int i) {
2413 // Type argument explicitly specified.
2414 if (i < ref.typeArguments.length) {
2415 return unit.resolveTypeRef(
2416 ref.typeArguments[i], function.typeParameterContext);
2417 } else {
2418 return null;
2419 }
2420 }, const []));
2421 } else {
2422 stack.add(DynamicTypeImpl.instance);
2423 }
2424 }
2425
2426 void _doInvokeMethod() {
2427 int numNamed = unlinkedConst.ints[intPtr++];
2428 int numPositional = unlinkedConst.ints[intPtr++];
2429 List<String> namedArgNames = _getNextStrings(numNamed);
2430 List<DartType> namedArgTypeList = _popList(numNamed);
2431 List<DartType> positionalArgTypes = _popList(numPositional);
2432 // TODO(scheglov) if we pushed target and method name first, we might be
2433 // able to move work with arguments in _inferExecutableType()
2434 String methodName = _getNextString();
2435 List<DartType> typeArguments = _getTypeArguments();
2436 DartType target = stack.removeLast();
2437 stack.add(() {
2438 if (target is InterfaceType) {
2439 MethodElement method =
2440 target.lookUpInheritedMethod(methodName, library: library);
2441 FunctionType rawType = method?.type;
2442 FunctionType inferredType = _inferExecutableType(
2443 rawType,
2444 numNamed,
2445 numPositional,
2446 namedArgNames,
2447 namedArgTypeList,
2448 positionalArgTypes,
2449 typeArguments);
2450 if (inferredType != null) {
2451 return inferredType.returnType;
2452 }
2453 }
2454 return DynamicTypeImpl.instance;
2455 }());
2456 }
2457
2458 void _doInvokeMethodRef() {
2459 int numNamed = _getNextInt();
2460 int numPositional = _getNextInt();
2461 List<String> namedArgNames = _getNextStrings(numNamed);
2462 List<DartType> namedArgTypeList = _popList(numNamed);
2463 List<DartType> positionalArgTypes = _popList(numPositional);
2464 EntityRef ref = _getNextRef();
2465 ReferenceableElementForLink element = unit.resolveRef(ref.reference);
2466 List<DartType> typeArguments = _getTypeArguments();
2467 stack.add(() {
2468 DartType rawType = element.asStaticType;
2469 if (rawType is FunctionType) {
2470 FunctionType inferredType = _inferExecutableType(
2471 rawType,
2472 numNamed,
2473 numPositional,
2474 namedArgNames,
2475 namedArgTypeList,
2476 positionalArgTypes,
2477 typeArguments);
2478 if (inferredType != null) {
2479 return inferredType.returnType;
2480 }
2481 }
2482 return DynamicTypeImpl.instance;
2483 }());
2484 }
2485
2486 void _doMakeTypedList() {
2487 DartType itemType = _getNextTypeRef();
2488 stack.length -= _getNextInt();
2489 stack.add(typeProvider.listType.instantiate(<DartType>[itemType]));
2490 }
2491
2492 void _doMakeTypeMap() {
2493 DartType keyType = _getNextTypeRef();
2494 DartType valueType = _getNextTypeRef();
2495 stack.length -= 2 * _getNextInt();
2496 stack.add(typeProvider.mapType.instantiate(<DartType>[keyType, valueType]));
2497 }
2498
2499 void _doMakeUntypedList() {
2500 int numItems = _getNextInt();
2501 DartType itemType = numItems == 0
2502 ? DynamicTypeImpl.instance
2503 : _popList(numItems).reduce(_leastUpperBound);
2504 itemType = _dynamicIfNull(itemType);
2505 stack.add(typeProvider.listType.instantiate(<DartType>[itemType]));
2506 }
2507
2508 void _doMakeUntypedMap() {
2509 int numEntries = _getNextInt();
2510 List<DartType> keysValues = _popList(2 * numEntries);
2511 DartType keyType = null;
2512 DartType valueType = null;
2513 for (int i = 0; i < 2 * numEntries; i++) {
2514 DartType type = keysValues[i];
2515 if (i.isEven) {
2516 keyType = keyType == null ? type : _leastUpperBound(keyType, type);
2517 } else {
2518 valueType =
2519 valueType == null ? type : _leastUpperBound(valueType, type);
2520 }
2521 }
2522 keyType = _dynamicIfNull(keyType);
2523 valueType = _dynamicIfNull(valueType);
2524 stack.add(typeProvider.mapType.instantiate(<DartType>[keyType, valueType]));
2525 }
2526
2527 void _doPushReference() {
2528 EntityRef ref = _getNextRef();
2529 if (ref.paramReference != 0) {
2530 stack.add(typeProvider.typeType);
2531 } else {
2532 // Synthetic function types can't be directly referred
2533 // to by expressions.
2534 assert(ref.syntheticReturnType == null);
2535 // Nor can implicit function types derived from
2536 // function-typed parameters.
2537 assert(ref.implicitFunctionTypeIndices.isEmpty);
2538 ReferenceableElementForLink element = unit.resolveRef(ref.reference);
2539 stack.add(element.asStaticType);
2540 }
2541 }
2542
2543 /**
2544 * Find the parameter in scope called [parameterName] and return its type.
2545 */
2546 DartType _findParameterType(String parameterName) {
2547 FunctionElementForLink_Local f = this.function;
2548 while (true) {
2549 for (ParameterElement parameter in f.parameters) {
2550 if (parameter.name == parameterName) {
2551 return parameter.type;
2552 }
2553 }
2554 Element parent = f.enclosingElement;
2555 if (parent is FunctionElementForLink_Local) {
2556 f = parent;
2557 } else {
2558 // Parameter not found. This should never happen in a well-formed
2559 // summary.
2560 assert(false);
2561 return DynamicTypeImpl.instance;
2562 }
2563 }
2564 }
2565
2566 int _getNextInt() {
2567 return unlinkedConst.ints[intPtr++];
2568 }
2569
2570 EntityRef _getNextRef() => unlinkedConst.references[refPtr++];
2571
2572 String _getNextString() {
2573 return unlinkedConst.strings[strPtr++];
2574 }
2575
2576 List<String> _getNextStrings(int n) {
2577 List<String> result = new List<String>(n);
2578 for (int i = 0; i < n; i++) {
2579 result[i] = _getNextString();
2580 }
2581 return result;
2582 }
2583
2584 DartType _getNextTypeRef() {
2585 EntityRef ref = _getNextRef();
2586 return unit.resolveTypeRef(ref, function.typeParameterContext);
2587 }
2588
2589 /**
2590 * Return the type of the property with the given [propertyName] in the
2591 * given [targetType]. May return `dynamic` if the property cannot be
2592 * resolved.
2593 */
2594 DartType _getPropertyType(DartType targetType, String propertyName) {
2595 return targetType is InterfaceType
2596 ? targetType
2597 .lookUpInheritedGetter(propertyName, library: library)
2598 ?.returnType
2599 : DynamicTypeImpl.instance;
2600 }
2601
2602 List<DartType> _getTypeArguments() {
2603 int numTypeArguments = _getNextInt();
2604 List<DartType> typeArguments = new List<DartType>(numTypeArguments);
2605 for (int i = 0; i < numTypeArguments; i++) {
2606 typeArguments[i] = _getNextTypeRef();
2607 }
2608 return typeArguments;
2609 }
2610
2611 FunctionType _inferExecutableType(
2612 FunctionType rawMethodType,
2613 int numNamed,
2614 int numPositional,
2615 List<String> namedArgNames,
2616 List<DartType> namedArgTypeList,
2617 List<DartType> positionalArgTypes,
2618 List<DartType> typeArguments) {
2619 TypeSystem ts = linker.typeSystem;
2620 if (rawMethodType != null) {
2621 if (rawMethodType.typeFormals.isNotEmpty && typeArguments.isNotEmpty) {
2622 Element methodElement = rawMethodType.element;
2623 if (methodElement is TypeParameterizedElement &&
2624 methodElement.typeParameters.length == typeArguments.length) {
2625 return rawMethodType.instantiate(typeArguments);
2626 }
2627 } else if (rawMethodType.typeFormals.isNotEmpty &&
2628 ts is StrongTypeSystemImpl) {
2629 List<DartType> paramTypes = <DartType>[];
2630 List<DartType> argTypes = <DartType>[];
2631 // Add positional parameter and argument types.
2632 for (int i = 0; i < numPositional; i++) {
2633 ParameterElement parameter = rawMethodType.parameters[i];
2634 if (parameter != null) {
2635 paramTypes.add(parameter.type);
2636 argTypes.add(positionalArgTypes[i]);
2637 }
2638 }
2639 // Prepare named argument types map.
2640 Map<String, DartType> namedArgTypes = <String, DartType>{};
2641 for (int i = 0; i < numNamed; i++) {
2642 String name = namedArgNames[i];
2643 DartType type = namedArgTypeList[i];
2644 namedArgTypes[name] = type;
2645 }
2646 // Add named parameter and argument types.
2647 Map<String, DartType> namedParameterTypes =
2648 rawMethodType.namedParameterTypes;
2649 namedArgTypes.forEach((String name, DartType argType) {
2650 DartType parameterType = namedParameterTypes[name];
2651 if (parameterType != null) {
2652 paramTypes.add(parameterType);
2653 argTypes.add(argType);
2654 }
2655 });
2656 // Perform inference.
2657 FunctionType inferred = ts.inferGenericFunctionCall(
2658 typeProvider,
2659 rawMethodType,
2660 paramTypes,
2661 argTypes,
2662 rawMethodType.returnType,
2663 null);
2664 return inferred;
2665 }
2666 }
2667 // Not a generic function type, use the raw type.
2668 return rawMethodType;
2669 }
2670
2671 DartType _leastUpperBound(DartType s, DartType t) {
2672 return linker.typeSystem.getLeastUpperBound(typeProvider, s, t);
2673 }
2674
2675 List<DartType> _popList(int n) {
2676 List<DartType> result = stack.sublist(stack.length - n, stack.length);
2677 stack.length -= n;
2678 return result;
2679 }
2680
2681 void _pushBinaryOperatorType(
2682 DartType left, TokenType operator, DartType right) {
2683 if (left is InterfaceType) {
2684 MethodElement method =
2685 left.lookUpInheritedMethod(operator.lexeme, library: library);
2686 if (method != null) {
2687 DartType type = method.returnType;
2688 type = linker.typeSystem.refineBinaryExpressionType(
2689 typeProvider, left, operator, right, type);
2690 stack.add(type);
2691 return;
2692 }
2693 }
2694 stack.add(DynamicTypeImpl.instance);
2695 }
2696
2697 /**
2698 * Extract the property with the given [propertyName], apply the operator
2699 * with the given [operandType], push the type of applying operand of the
2700 * given [operandType].
2701 */
2702 void _pushPropertyBinaryExpression(DartType targetType, String propertyName,
2703 TokenType operator, DartType operandType) {
2704 DartType propertyType = _getPropertyType(targetType, propertyName);
2705 _pushBinaryOperatorType(propertyType, operator, operandType);
2706 }
2707
2708 static TokenType _convertAssignOperatorToTokenType(
2709 UnlinkedExprAssignOperator o) {
2710 switch (o) {
2711 case UnlinkedExprAssignOperator.assign:
2712 return null;
2713 case UnlinkedExprAssignOperator.ifNull:
2714 return TokenType.QUESTION_QUESTION;
2715 case UnlinkedExprAssignOperator.multiply:
2716 return TokenType.STAR;
2717 case UnlinkedExprAssignOperator.divide:
2718 return TokenType.SLASH;
2719 case UnlinkedExprAssignOperator.floorDivide:
2720 return TokenType.TILDE_SLASH;
2721 case UnlinkedExprAssignOperator.modulo:
2722 return TokenType.PERCENT;
2723 case UnlinkedExprAssignOperator.plus:
2724 return TokenType.PLUS;
2725 case UnlinkedExprAssignOperator.minus:
2726 return TokenType.MINUS;
2727 case UnlinkedExprAssignOperator.shiftLeft:
2728 return TokenType.LT_LT;
2729 case UnlinkedExprAssignOperator.shiftRight:
2730 return TokenType.GT_GT;
2731 case UnlinkedExprAssignOperator.bitAnd:
2732 return TokenType.AMPERSAND;
2733 case UnlinkedExprAssignOperator.bitXor:
2734 return TokenType.CARET;
2735 case UnlinkedExprAssignOperator.bitOr:
2736 return TokenType.BAR;
2737 case UnlinkedExprAssignOperator.prefixIncrement:
2738 return TokenType.PLUS_PLUS;
2739 case UnlinkedExprAssignOperator.prefixDecrement:
2740 return TokenType.MINUS_MINUS;
2741 case UnlinkedExprAssignOperator.postfixIncrement:
2742 return TokenType.PLUS_PLUS;
2743 case UnlinkedExprAssignOperator.postfixDecrement:
2744 return TokenType.MINUS_MINUS;
2745 }
2746 return null;
2747 }
2748 }
2749
2750 /**
2751 * Element representing a field resynthesized from a summary during
2752 * linking.
2753 */
2754 abstract class FieldElementForLink implements FieldElement {
2755 @override
2756 PropertyAccessorElementForLink get getter;
2757
2758 @override
2759 PropertyAccessorElementForLink get setter;
2760 }
2761
2762 /**
2763 * Specialization of [FieldElementForLink] for class fields.
2764 */
2765 class FieldElementForLink_ClassField extends VariableElementForLink
2766 implements FieldElementForLink {
2767 @override
2768 final ClassElementForLink_Class enclosingElement;
2769
2770 /**
2771 * If this is an instance field, the type that was computed by
2772 * [InstanceMemberInferrer] (if any). Otherwise `null`.
2773 */
2774 DartType _inferredInstanceType;
2775
2776 FieldElementForLink_ClassField(ClassElementForLink_Class enclosingElement,
2777 UnlinkedVariable unlinkedVariable)
2778 : enclosingElement = enclosingElement,
2779 super(unlinkedVariable, enclosingElement.enclosingElement);
2780
2781 @override
2782 bool get isStatic => unlinkedVariable.isStatic;
2783
2784 @override
2785 void set type(DartType inferredType) {
2786 assert(!isStatic);
2787 assert(_inferredInstanceType == null);
2788 _inferredInstanceType = inferredType;
2789 }
2790
2791 @override
2792 TypeParameterizedElementMixin get _typeParameterContext => enclosingElement;
2793
2794 /**
2795 * Store the results of type inference for this field in
2796 * [compilationUnit].
2797 */
2798 void link(CompilationUnitElementInBuildUnit compilationUnit) {
2799 if (hasImplicitType) {
2800 compilationUnit._storeLinkedType(
2801 unlinkedVariable.inferredTypeSlot,
2802 isStatic ? inferredType : _inferredInstanceType,
2803 _typeParameterContext);
2804 initializer?.link(compilationUnit);
2805 }
2806 }
2807
2808 @override
2809 String toString() => '$enclosingElement.$name';
2810 }
2811
2812 /**
2813 * Specialization of [FieldElementForLink] for enum fields.
2814 */
2815 class FieldElementForLink_EnumField extends FieldElementForLink
2816 implements FieldElement {
2817 /**
2818 * The unlinked representation of the field in the summary, or `null` if this
2819 * is an enum's `values` field.
2820 */
2821 final UnlinkedEnumValue unlinkedEnumValue;
2822
2823 PropertyAccessorElementForLink_EnumField _getter;
2824
2825 @override
2826 final ClassElementForLink_Enum enclosingElement;
2827
2828 FieldElementForLink_EnumField(this.unlinkedEnumValue, this.enclosingElement);
2829
2830 @override
2831 PropertyAccessorElementForLink_EnumField get getter =>
2832 _getter ??= new PropertyAccessorElementForLink_EnumField(this);
2833
2834 @override
2835 bool get isStatic => true;
2836
2837 @override
2838 bool get isSynthetic => false;
2839
2840 @override
2841 String get name =>
2842 unlinkedEnumValue == null ? 'values' : unlinkedEnumValue.name;
2843
2844 @override
2845 DartType get type => unlinkedEnumValue == null
2846 ? enclosingElement.valuesType
2847 : enclosingElement.type;
2848
2849 @override
2850 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
2851
2852 @override
2853 String toString() => '$enclosingElement.$name';
2854 }
2855
2856 /**
2857 * Element representing a function-typed parameter resynthesied from a summary
2858 * during linking.
2859 */
2860 class FunctionElementForLink_FunctionTypedParam extends Object
2861 with ParameterParentElementForLink
2862 implements FunctionElement {
2863 @override
2864 final ParameterElementForLink enclosingElement;
2865
2866 @override
2867 final TypeParameterizedElementMixin typeParameterContext;
2868
2869 @override
2870 final List<UnlinkedParam> unlinkedParameters;
2871
2872 DartType _returnType;
2873 List<int> _implicitFunctionTypeIndices;
2874
2875 FunctionElementForLink_FunctionTypedParam(this.enclosingElement,
2876 this.typeParameterContext, this.unlinkedParameters);
2877
2878 @override
2879 List<int> get implicitFunctionTypeIndices {
2880 if (_implicitFunctionTypeIndices == null) {
2881 _implicitFunctionTypeIndices = enclosingElement
2882 .enclosingElement.implicitFunctionTypeIndices
2883 .toList();
2884 _implicitFunctionTypeIndices.add(enclosingElement._parameterIndex);
2885 }
2886 return _implicitFunctionTypeIndices;
2887 }
2888
2889 @override
2890 DartType get returnType {
2891 if (_returnType == null) {
2892 if (enclosingElement._unlinkedParam.type == null) {
2893 _returnType = DynamicTypeImpl.instance;
2894 } else {
2895 _returnType = enclosingElement.compilationUnit.resolveTypeRef(
2896 enclosingElement._unlinkedParam.type, typeParameterContext);
2897 }
2898 }
2899 return _returnType;
2900 }
2901
2902 @override
2903 List<TypeParameterElement> get typeParameters => const [];
2904
2905 @override
2906 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
2907 }
2908
2909 /**
2910 * Element representing the initializer expression of a variable.
2911 */
2912 class FunctionElementForLink_Initializer extends Object
2913 with ReferenceableElementForLink, TypeParameterizedElementMixin
2914 implements FunctionElementForLink_Local {
2915 /**
2916 * The variable for which this element is the initializer.
2917 */
2918 final VariableElementForLink _variable;
2919
2920 /**
2921 * The type inference node for this function, or `null` if it hasn't been
2922 * computed yet.
2923 */
2924 TypeInferenceNode _typeInferenceNode;
2925
2926 List<FunctionElementForLink_Local_NonSynthetic> _functions;
2927 DartType _inferredReturnType;
2928
2929 FunctionElementForLink_Initializer(this._variable);
2930
2931 @override
2932 TypeInferenceNode get asTypeInferenceNode =>
2933 _typeInferenceNode ??= new TypeInferenceNode(this);
2934
2935 @override
2936 CompilationUnitElementForLink get compilationUnit =>
2937 _variable.compilationUnit;
2938
2939 @override
2940 VariableElementForLink get enclosingElement => _variable;
2941
2942 TypeParameterizedElementMixin get enclosingTypeParameterContext =>
2943 _variable.enclosingElement is ClassElementForLink
2944 ? _variable.enclosingElement
2945 : null;
2946
2947 @override
2948 CompilationUnitElementForLink get enclosingUnit => _variable.compilationUnit;
2949
2950 @override
2951 List<FunctionElementForLink_Local_NonSynthetic> get functions =>
2952 _functions ??= _variable.unlinkedVariable.initializer.localFunctions
2953 .map((UnlinkedExecutable ex) =>
2954 new FunctionElementForLink_Local_NonSynthetic(
2955 _variable.compilationUnit, this, ex))
2956 .toList();
2957
2958 @override
2959 DartType get returnType {
2960 // If this is a variable whose type needs inferring, infer it.
2961 if (_variable.hasImplicitType) {
2962 return _variable.inferredType;
2963 } else {
2964 // There's no reason linking should need to access the type of
2965 // this FunctionElement, since the variable doesn't need its
2966 // type inferred.
2967 assert(false);
2968 // But for robustness, return the dynamic type.
2969 return DynamicTypeImpl.instance;
2970 }
2971 }
2972
2973 @override
2974 void set returnType(DartType newType) {
2975 // InstanceMemberInferrer stores the new type both here and on the variable
2976 // element. We don't need to record both values, so we ignore it here.
2977 }
2978
2979 @override
2980 TypeParameterizedElementMixin get typeParameterContext => this;
2981
2982 @override
2983 List<UnlinkedTypeParam> get unlinkedTypeParams => const [];
2984
2985 @override
2986 bool get _hasTypeBeenInferred => _inferredReturnType != null;
2987
2988 @override
2989 UnlinkedExecutable get _unlinkedExecutable =>
2990 _variable.unlinkedVariable.initializer;
2991
2992 @override
2993 FunctionElementForLink_Local getLocalFunction(int index) {
2994 List<FunctionElementForLink_Local_NonSynthetic> functions = this.functions;
2995 return index < functions.length ? functions[index] : null;
2996 }
2997
2998 /**
2999 * Store the results of type inference for this initializer in
3000 * [compilationUnit].
3001 */
3002 void link(CompilationUnitElementInBuildUnit compilationUnit) {
3003 compilationUnit._storeLinkedType(_unlinkedExecutable.inferredReturnTypeSlot,
3004 _inferredReturnType, typeParameterContext);
3005 for (FunctionElementForLink_Local_NonSynthetic function in functions) {
3006 function.link(compilationUnit);
3007 }
3008 }
3009
3010 @override
3011 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
3012
3013 @override
3014 void _setInferredType(DartType type) {
3015 assert(!_hasTypeBeenInferred);
3016 _inferredReturnType = type;
3017 _variable._inferredType = _dynamicIfNull(type);
3018 }
3019 }
3020
3021 /**
3022 * Element representing a local function (possibly a closure).
3023 */
3024 abstract class FunctionElementForLink_Local
3025 implements
3026 ExecutableElementForLink,
3027 FunctionElementImpl,
3028 ReferenceableElementForLink {
3029 /**
3030 * Indicates whether type inference has completed for this function.
3031 */
3032 bool get _hasTypeBeenInferred;
3033
3034 /**
3035 * Stores the given [type] as the inferred return type for this function.
3036 * Should only be called if [_hasTypeBeenInferred] is `false`.
3037 */
3038 void _setInferredType(DartType type);
3039 }
3040
3041 /**
3042 * Element representing a local function (possibly a closure) inside another
3043 * executable.
3044 */
3045 class FunctionElementForLink_Local_NonSynthetic extends ExecutableElementForLink
3046 with ReferenceableElementForLink
3047 implements FunctionElementForLink_Local {
3048 @override
3049 final ExecutableElementForLink enclosingElement;
3050
3051 List<FunctionElementForLink_Local_NonSynthetic> _functions;
3052
3053 /**
3054 * The type inference node for this function, or `null` if it hasn't been
3055 * computed yet.
3056 */
3057 TypeInferenceNode _typeInferenceNode;
3058
3059 FunctionElementForLink_Local_NonSynthetic(
3060 CompilationUnitElementForLink compilationUnit,
3061 this.enclosingElement,
3062 UnlinkedExecutable unlinkedExecutable)
3063 : super(compilationUnit, unlinkedExecutable);
3064
3065 @override
3066 TypeInferenceNode get asTypeInferenceNode =>
3067 _typeInferenceNode ??= new TypeInferenceNode(this);
3068
3069 @override
3070 TypeParameterizedElementMixin get enclosingTypeParameterContext =>
3071 enclosingElement;
3072
3073 @override
3074 List<FunctionElementForLink_Local_NonSynthetic> get functions =>
3075 _functions ??= _unlinkedExecutable.localFunctions
3076 .map((UnlinkedExecutable ex) =>
3077 new FunctionElementForLink_Local_NonSynthetic(
3078 compilationUnit, this, ex))
3079 .toList();
3080
3081 @override
3082 bool get _hasTypeBeenInferred => _inferredReturnType != null;
3083
3084 @override
3085 DartType buildType(
3086 DartType getTypeArgument(int i), List<int> implicitFunctionTypeIndices) {
3087 assert(implicitFunctionTypeIndices.isEmpty);
3088 return type;
3089 }
3090
3091 @override
3092 FunctionElementForLink_Local getLocalFunction(int index) {
3093 List<FunctionElementForLink_Local_NonSynthetic> functions = this.functions;
3094 return index < functions.length ? functions[index] : null;
3095 }
3096
3097 /**
3098 * Store the results of type inference for this function in [compilationUnit].
3099 */
3100 void link(CompilationUnitElementInBuildUnit compilationUnit) {
3101 compilationUnit._storeLinkedType(
3102 _unlinkedExecutable.inferredReturnTypeSlot, inferredReturnType, this);
3103 for (FunctionElementForLink_Local_NonSynthetic function in functions) {
3104 function.link(compilationUnit);
3105 }
3106 }
3107
3108 @override
3109 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
3110
3111 @override
3112 void _setInferredType(DartType type) {
3113 // TODO(paulberry): store the inferred return type in the summary.
3114 assert(!_hasTypeBeenInferred);
3115 _inferredReturnType = _dynamicIfNull(type);
3116 }
3117 }
3118
3119 /**
3120 * Element representing a typedef resynthesized from a summary during linking.
3121 */
3122 class FunctionTypeAliasElementForLink extends Object
3123 with
3124 TypeParameterizedElementMixin,
3125 ParameterParentElementForLink,
3126 ReferenceableElementForLink
3127 implements FunctionTypeAliasElement, ElementImpl {
3128 @override
3129 final CompilationUnitElementForLink enclosingElement;
3130
3131 /**
3132 * The unlinked representation of the typedef in the summary.
3133 */
3134 final UnlinkedTypedef _unlinkedTypedef;
3135
3136 FunctionTypeImpl _type;
3137 DartType _returnType;
3138
3139 FunctionTypeAliasElementForLink(this.enclosingElement, this._unlinkedTypedef);
3140
3141 @override
3142 DartType get asStaticType {
3143 return enclosingElement.enclosingElement._linker.typeProvider.typeType;
3144 }
3145
3146 @override
3147 ContextForLink get context => enclosingElement.context;
3148
3149 @override
3150 TypeParameterizedElementMixin get enclosingTypeParameterContext => null;
3151
3152 @override
3153 CompilationUnitElementImpl get enclosingUnit => enclosingElement;
3154
3155 @override
3156 String get identifier => _unlinkedTypedef.name;
3157
3158 @override
3159 List<int> get implicitFunctionTypeIndices => const <int>[];
3160
3161 @override
3162 bool get isSynthetic => false;
3163
3164 @override
3165 LibraryElementForLink get library => enclosingElement.library;
3166
3167 @override
3168 String get name => _unlinkedTypedef.name;
3169
3170 @override
3171 DartType get returnType => _returnType ??=
3172 enclosingElement.resolveTypeRef(_unlinkedTypedef.returnType, this);
3173
3174 @override
3175 TypeParameterizedElementMixin get typeParameterContext => this;
3176
3177 @override
3178 List<UnlinkedParam> get unlinkedParameters => _unlinkedTypedef.parameters;
3179
3180 @override
3181 List<UnlinkedTypeParam> get unlinkedTypeParams =>
3182 _unlinkedTypedef.typeParameters;
3183
3184 @override
3185 DartType buildType(
3186 DartType getTypeArgument(int i), List<int> implicitFunctionTypeIndices) {
3187 int numTypeParameters = _unlinkedTypedef.typeParameters.length;
3188 if (numTypeParameters != 0) {
3189 List<DartType> typeArguments =
3190 new List<DartType>.generate(numTypeParameters, getTypeArgument);
3191 if (typeArguments.contains(null)) {
3192 return context.typeSystem
3193 .instantiateToBounds(new FunctionTypeImpl.forTypedef(this));
3194 } else {
3195 return new FunctionTypeImpl.elementWithNameAndArgs(
3196 this, name, typeArguments, true);
3197 }
3198 } else {
3199 return _type ??= new FunctionTypeImpl.forTypedef(this);
3200 }
3201 }
3202
3203 @override
3204 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
3205
3206 @override
3207 String toString() => '$enclosingElement.$name';
3208 }
3209
3210 /**
3211 * Specialization of [DependencyWalker] for linking library cycles.
3212 */
3213 class LibraryCycleDependencyWalker extends DependencyWalker<LibraryCycleNode> {
3214 @override
3215 void evaluate(LibraryCycleNode v) {
3216 v.link();
3217 }
3218
3219 @override
3220 void evaluateScc(List<LibraryCycleNode> scc) {
3221 // There should never be a cycle among library cycles.
3222 throw new StateError('Cycle among library cycles');
3223 }
3224 }
3225
3226 /**
3227 * An instance of [LibraryCycleForLink] represents a single library cycle
3228 * discovered during linking; it consists of one or more libraries in the build
3229 * unit being linked.
3230 */
3231 class LibraryCycleForLink {
3232 /**
3233 * The libraries in the cycle.
3234 */
3235 final List<LibraryElementInBuildUnit> libraries;
3236
3237 /**
3238 * The library cycles which this library depends on.
3239 */
3240 final List<LibraryCycleForLink> dependencies;
3241
3242 /**
3243 * The [LibraryCycleNode] for this library cycle.
3244 */
3245 LibraryCycleNode _node;
3246
3247 LibraryCycleForLink(this.libraries, this.dependencies) {
3248 _node = new LibraryCycleNode(this);
3249 }
3250
3251 LibraryCycleNode get node => _node;
3252
3253 /**
3254 * Link this library cycle and any library cycles it depends on. Does
3255 * nothing if this library cycle has already been linked.
3256 */
3257 void ensureLinked() {
3258 if (!node.isEvaluated) {
3259 new LibraryCycleDependencyWalker().walk(node);
3260 }
3261 }
3262 }
3263
3264 /**
3265 * Specialization of [Node] used to link library cycles in proper dependency
3266 * order.
3267 */
3268 class LibraryCycleNode extends Node<LibraryCycleNode> {
3269 /**
3270 * The library cycle this [Node] represents.
3271 */
3272 final LibraryCycleForLink libraryCycle;
3273
3274 /**
3275 * Indicates whether this library cycle has been linked yet.
3276 */
3277 bool _isLinked = false;
3278
3279 LibraryCycleNode(this.libraryCycle);
3280
3281 @override
3282 bool get isEvaluated => _isLinked;
3283
3284 @override
3285 List<LibraryCycleNode> computeDependencies() => libraryCycle.dependencies
3286 .map((LibraryCycleForLink cycle) => cycle.node)
3287 .toList();
3288
3289 /**
3290 * Link this library cycle.
3291 */
3292 void link() {
3293 for (LibraryElementInBuildUnit library in libraryCycle.libraries) {
3294 library.link();
3295 }
3296 _isLinked = true;
3297 }
3298 }
3299
3300 /**
3301 * Specialization of [DependencyWalker] for computing library cycles.
3302 */
3303 class LibraryDependencyWalker extends DependencyWalker<LibraryNode> {
3304 @override
3305 void evaluate(LibraryNode v) => evaluateScc(<LibraryNode>[v]);
3306
3307 @override
3308 void evaluateScc(List<LibraryNode> scc) {
3309 Set<LibraryCycleForLink> dependentCycles = new Set<LibraryCycleForLink>();
3310 for (LibraryNode node in scc) {
3311 for (LibraryNode dependency in node.dependencies) {
3312 if (dependency.isEvaluated) {
3313 dependentCycles.add(dependency._libraryCycle);
3314 }
3315 }
3316 }
3317 LibraryCycleForLink cycle = new LibraryCycleForLink(
3318 scc.map((LibraryNode n) => n.library).toList(),
3319 dependentCycles.toList());
3320 for (LibraryNode node in scc) {
3321 node._libraryCycle = cycle;
3322 }
3323 }
3324 }
3325
3326 /**
3327 * Element representing a library resynthesied from a summary during
3328 * linking. The type parameter, [UnitElement], represents the type
3329 * that will be used for the compilation unit elements.
3330 */
3331 abstract class LibraryElementForLink<
3332 UnitElement extends CompilationUnitElementForLink>
3333 implements LibraryElementImpl {
3334 /**
3335 * Pointer back to the linker.
3336 */
3337 final Linker _linker;
3338
3339 /**
3340 * The absolute URI of this library.
3341 */
3342 final Uri _absoluteUri;
3343
3344 List<UnitElement> _units;
3345 final Map<String, ReferenceableElementForLink> _containedNames =
3346 <String, ReferenceableElementForLink>{};
3347 final List<LibraryElementForLink> _dependencies = <LibraryElementForLink>[];
3348 UnlinkedUnit _definingUnlinkedUnit;
3349 List<LibraryElementForLink> _importedLibraries;
3350 List<LibraryElementForLink> _exportedLibraries;
3351
3352 LibraryElementForLink(this._linker, this._absoluteUri) {
3353 if (_linkedLibrary != null) {
3354 _dependencies.length = _linkedLibrary.dependencies.length;
3355 }
3356 }
3357
3358 @override
3359 ContextForLink get context => _linker.context;
3360
3361 /**
3362 * Get the [UnlinkedUnit] for the defining compilation unit of this library.
3363 */
3364 UnlinkedUnit get definingUnlinkedUnit =>
3365 _definingUnlinkedUnit ??= _linker.getUnit(_absoluteUri.toString());
3366
3367 @override
3368 Element get enclosingElement => null;
3369
3370 @override
3371 List<LibraryElementForLink> get exportedLibraries => _exportedLibraries ??=
3372 _linkedLibrary.exportDependencies.map(_getDependency).toList();
3373
3374 @override
3375 String get identifier => _absoluteUri.toString();
3376
3377 @override
3378 List<LibraryElementForLink> get importedLibraries => _importedLibraries ??=
3379 _linkedLibrary.importDependencies.map(_getDependency).toList();
3380
3381 @override
3382 bool get isDartAsync => _absoluteUri == 'dart:async';
3383
3384 @override
3385 bool get isDartCore => _absoluteUri == 'dart:core';
3386
3387 /**
3388 * If this library is part of the build unit being linked, return the library
3389 * cycle it is part of. Otherwise return `null`.
3390 */
3391 LibraryCycleForLink get libraryCycleForLink;
3392
3393 @override
3394 String get name {
3395 return _definingUnlinkedUnit.libraryName;
3396 }
3397
3398 @override
3399 List<UnitElement> get units {
3400 if (_units == null) {
3401 UnlinkedUnit definingUnit = definingUnlinkedUnit;
3402 _units = <UnitElement>[
3403 _makeUnitElement(definingUnit, 0, _absoluteUri.toString())
3404 ];
3405 int numParts = definingUnit.parts.length;
3406 for (int i = 0; i < numParts; i++) {
3407 // TODO(paulberry): make sure we handle the case where Uri.parse fails.
3408 // TODO(paulberry): make sure we handle the case where
3409 // resolveRelativeUri fails.
3410 String partAbsoluteUri = resolveRelativeUri(
3411 _absoluteUri, Uri.parse(definingUnit.publicNamespace.parts[i]))
3412 .toString();
3413 UnlinkedUnit partUnit = _linker.getUnit(partAbsoluteUri);
3414 _units.add(_makeUnitElement(
3415 partUnit ?? new UnlinkedUnitBuilder(), i + 1, partAbsoluteUri));
3416 }
3417 }
3418 return _units;
3419 }
3420
3421 /**
3422 * The linked representation of the library in the summary.
3423 */
3424 LinkedLibrary get _linkedLibrary;
3425
3426 /**
3427 * Search all the units for a top level element with the given
3428 * [name]. If no name is found, return the singleton instance of
3429 * [UndefinedElementForLink].
3430 */
3431 ReferenceableElementForLink getContainedName(String name) =>
3432 _containedNames.putIfAbsent(name, () {
3433 for (UnitElement unit in units) {
3434 ReferenceableElementForLink element = unit.getContainedName(name);
3435 if (!identical(element, UndefinedElementForLink.instance)) {
3436 return element;
3437 }
3438 }
3439 return UndefinedElementForLink.instance;
3440 });
3441
3442 @override
3443 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
3444
3445 @override
3446 String toString() => _absoluteUri.toString();
3447
3448 /**
3449 * Return the [LibraryElement] corresponding to the given dependency [index].
3450 */
3451 LibraryElementForLink _getDependency(int index) {
3452 LibraryElementForLink result = _dependencies[index];
3453 if (result == null) {
3454 String relativeUri = _linkedLibrary.dependencies[index].uri;
3455 Uri absoluteUri = relativeUri.isEmpty
3456 ? _absoluteUri
3457 : resolveRelativeUri(_absoluteUri, Uri.parse(relativeUri));
3458 result = _linker.getLibrary(absoluteUri);
3459 _dependencies[index] = result;
3460 }
3461 return result;
3462 }
3463
3464 /**
3465 * Create a [UnitElement] for one of the library's compilation
3466 * units.
3467 */
3468 UnitElement _makeUnitElement(
3469 UnlinkedUnit unlinkedUnit, int i, String absoluteUri);
3470 }
3471
3472 /**
3473 * Element representing a library which is part of the build unit
3474 * being linked.
3475 */
3476 class LibraryElementInBuildUnit
3477 extends LibraryElementForLink<CompilationUnitElementInBuildUnit> {
3478 @override
3479 final LinkedLibraryBuilder _linkedLibrary;
3480
3481 /**
3482 * The [LibraryNode] representing this library in the library dependency
3483 * graph.
3484 */
3485 LibraryNode _libraryNode;
3486
3487 InheritanceManager _inheritanceManager;
3488
3489 LibraryElementInBuildUnit(Linker linker, Uri absoluteUri, this._linkedLibrary)
3490 : super(linker, absoluteUri) {
3491 _libraryNode = new LibraryNode(this);
3492 }
3493
3494 /**
3495 * Get the inheritance manager for this library (creating it if necessary).
3496 */
3497 InheritanceManager get inheritanceManager =>
3498 _inheritanceManager ??= new InheritanceManager(this);
3499
3500 @override
3501 LibraryCycleForLink get libraryCycleForLink {
3502 if (!_libraryNode.isEvaluated) {
3503 new LibraryDependencyWalker().walk(_libraryNode);
3504 }
3505 return _libraryNode._libraryCycle;
3506 }
3507
3508 /**
3509 * If this library already has a dependency in its dependencies table matching
3510 * [library], return its index. Otherwise add a new dependency to table and
3511 * return its index.
3512 */
3513 int addDependency(LibraryElementForLink library) {
3514 for (int i = 0; i < _linkedLibrary.dependencies.length; i++) {
3515 if (identical(_getDependency(i), library)) {
3516 return i;
3517 }
3518 }
3519 int result = _linkedLibrary.dependencies.length;
3520 _linkedLibrary.dependencies.add(new LinkedDependencyBuilder(
3521 parts: library.definingUnlinkedUnit.publicNamespace.parts,
3522 uri: library._absoluteUri.toString()));
3523 _dependencies.add(library);
3524 return result;
3525 }
3526
3527 /**
3528 * Perform type inference and const cycle detection on this library.
3529 */
3530 void link() {
3531 for (CompilationUnitElementInBuildUnit unit in units) {
3532 unit.link();
3533 }
3534 }
3535
3536 /**
3537 * Throw away any information stored in the summary by a previous call to
3538 * [link].
3539 */
3540 void unlink() {
3541 _linkedLibrary.dependencies.length =
3542 _linkedLibrary.numPrelinkedDependencies;
3543 for (CompilationUnitElementInBuildUnit unit in units) {
3544 unit.unlink();
3545 }
3546 }
3547
3548 @override
3549 CompilationUnitElementInBuildUnit _makeUnitElement(
3550 UnlinkedUnit unlinkedUnit, int i, String absoluteUri) =>
3551 new CompilationUnitElementInBuildUnit(
3552 this, unlinkedUnit, _linkedLibrary.units[i], i, absoluteUri);
3553 }
3554
3555 /**
3556 * Element representing a library which is depended upon (either
3557 * directly or indirectly) by the build unit being linked.
3558 */
3559 class LibraryElementInDependency
3560 extends LibraryElementForLink<CompilationUnitElementInDependency> {
3561 @override
3562 final LinkedLibrary _linkedLibrary;
3563
3564 LibraryElementInDependency(
3565 Linker linker, Uri absoluteUri, this._linkedLibrary)
3566 : super(linker, absoluteUri);
3567
3568 @override
3569 LibraryCycleForLink get libraryCycleForLink => null;
3570
3571 @override
3572 CompilationUnitElementInDependency _makeUnitElement(
3573 UnlinkedUnit unlinkedUnit, int i, String absoluteUri) =>
3574 new CompilationUnitElementInDependency(
3575 this, unlinkedUnit, _linkedLibrary.units[i], i, absoluteUri);
3576 }
3577
3578 /**
3579 * Specialization of [Node] used to construct the library dependency graph.
3580 */
3581 class LibraryNode extends Node<LibraryNode> {
3582 /**
3583 * The library this [Node] represents.
3584 */
3585 final LibraryElementInBuildUnit library;
3586
3587 /**
3588 * The library cycle to which [library] belongs, if it has been computed.
3589 * Otherwise `null`.
3590 */
3591 LibraryCycleForLink _libraryCycle;
3592
3593 LibraryNode(this.library);
3594
3595 @override
3596 bool get isEvaluated => _libraryCycle != null;
3597
3598 @override
3599 List<LibraryNode> computeDependencies() {
3600 // Note: we only need to consider dependencies within the build unit being
3601 // linked; dependencies in other build units can't participate in library
3602 // cycles with us.
3603 List<LibraryNode> dependencies = <LibraryNode>[];
3604 for (LibraryElement dependency in library.importedLibraries) {
3605 if (dependency is LibraryElementInBuildUnit) {
3606 dependencies.add(dependency._libraryNode);
3607 }
3608 }
3609 for (LibraryElement dependency in library.exportedLibraries) {
3610 if (dependency is LibraryElementInBuildUnit) {
3611 dependencies.add(dependency._libraryNode);
3612 }
3613 }
3614 return dependencies;
3615 }
3616 }
3617
3618 /**
3619 * Instances of [Linker] contain the necessary information to link
3620 * together a single build unit.
3621 */
3622 class Linker {
3623 /**
3624 * During linking, if type inference is currently being performed on the
3625 * initializer of a static or instance variable, the library cycle in
3626 * which inference is being performed. Otherwise, `null`.
3627 *
3628 * This allows us to suppress instance member type inference results from a
3629 * library cycle while doing inference on the right hand sides of static and
3630 * instance variables in that same cycle.
3631 */
3632 static LibraryCycleForLink _initializerTypeInferenceCycle;
3633
3634 /**
3635 * Callback to ask the client for a [LinkedLibrary] for a
3636 * dependency.
3637 */
3638 final GetDependencyCallback getDependency;
3639
3640 /**
3641 * Callback to ask the client for an [UnlinkedUnit].
3642 */
3643 final GetUnitCallback getUnit;
3644
3645 /**
3646 * Map containing all library elements accessed during linking,
3647 * whether they are part of the build unit being linked or whether
3648 * they are dependencies.
3649 */
3650 final Map<Uri, LibraryElementForLink> _libraries =
3651 <Uri, LibraryElementForLink>{};
3652
3653 /**
3654 * List of library elements for the libraries in the build unit
3655 * being linked.
3656 */
3657 final List<LibraryElementInBuildUnit> _librariesInBuildUnit =
3658 <LibraryElementInBuildUnit>[];
3659
3660 /**
3661 * Indicates whether type inference should use strong mode rules.
3662 */
3663 final bool strongMode;
3664
3665 LibraryElementForLink _coreLibrary;
3666 LibraryElementForLink _asyncLibrary;
3667 TypeProviderForLink _typeProvider;
3668 TypeSystem _typeSystem;
3669 SpecialTypeElementForLink _voidElement;
3670 SpecialTypeElementForLink _dynamicElement;
3671 SpecialTypeElementForLink _bottomElement;
3672 ContextForLink _context;
3673 AnalysisOptionsForLink _analysisOptions;
3674
3675 Linker(Map<String, LinkedLibraryBuilder> linkedLibraries, this.getDependency,
3676 this.getUnit, this.strongMode) {
3677 // Create elements for the libraries to be linked. The rest of
3678 // the element model will be created on demand.
3679 linkedLibraries
3680 .forEach((String absoluteUri, LinkedLibraryBuilder linkedLibrary) {
3681 Uri uri = Uri.parse(absoluteUri);
3682 _librariesInBuildUnit.add(_libraries[uri] =
3683 new LibraryElementInBuildUnit(this, uri, linkedLibrary));
3684 });
3685 }
3686
3687 /**
3688 * Get an instance of [AnalysisOptions] for use during linking.
3689 */
3690 AnalysisOptionsForLink get analysisOptions =>
3691 _analysisOptions ??= new AnalysisOptionsForLink(this);
3692
3693 /**
3694 * Get the library element for `dart:async`.
3695 */
3696 LibraryElementForLink get asyncLibrary =>
3697 _asyncLibrary ??= getLibrary(Uri.parse('dart:async'));
3698
3699 /**
3700 * Get the element representing the "bottom" type.
3701 */
3702 SpecialTypeElementForLink get bottomElement => _bottomElement ??=
3703 new SpecialTypeElementForLink(this, BottomTypeImpl.instance);
3704
3705 /**
3706 * Get a stub implementation of [AnalysisContext] which can be used during
3707 * linking.
3708 */
3709 get context => _context ??= new ContextForLink(this);
3710
3711 /**
3712 * Get the library element for `dart:core`.
3713 */
3714 LibraryElementForLink get coreLibrary =>
3715 _coreLibrary ??= getLibrary(Uri.parse('dart:core'));
3716
3717 /**
3718 * Get the element representing `dynamic`.
3719 */
3720 SpecialTypeElementForLink get dynamicElement => _dynamicElement ??=
3721 new SpecialTypeElementForLink(this, DynamicTypeImpl.instance);
3722
3723 /**
3724 * Get an instance of [TypeProvider] for use during linking.
3725 */
3726 TypeProviderForLink get typeProvider =>
3727 _typeProvider ??= new TypeProviderForLink(this);
3728
3729 /**
3730 * Get an instance of [TypeSystem] for use during linking.
3731 */
3732 TypeSystem get typeSystem => _typeSystem ??=
3733 strongMode ? new StrongTypeSystemImpl() : new TypeSystemImpl();
3734
3735 /**
3736 * Get the element representing `void`.
3737 */
3738 SpecialTypeElementForLink get voidElement => _voidElement ??=
3739 new SpecialTypeElementForLink(this, VoidTypeImpl.instance);
3740
3741 /**
3742 * Get the library element for the library having the given [uri].
3743 */
3744 LibraryElementForLink getLibrary(Uri uri) => _libraries.putIfAbsent(
3745 uri,
3746 () => new LibraryElementInDependency(
3747 this, uri, getDependency(uri.toString())));
3748
3749 /**
3750 * Perform type inference and const cycle detection on all libraries
3751 * in the build unit being linked.
3752 */
3753 void link() {
3754 // Link library cycles in appropriate dependency order.
3755 for (LibraryElementInBuildUnit library in _librariesInBuildUnit) {
3756 library.libraryCycleForLink.ensureLinked();
3757 }
3758 // TODO(paulberry): set dependencies.
3759 }
3760
3761 /**
3762 * Throw away any information stored in the summary by a previous call to
3763 * [link].
3764 */
3765 void unlink() {
3766 for (LibraryElementInBuildUnit library in _librariesInBuildUnit) {
3767 library.unlink();
3768 }
3769 }
3770 }
3771
3772 /**
3773 * Element representing a method resynthesized from a summary during linking.
3774 */
3775 class MethodElementForLink extends ExecutableElementForLink_NonLocal
3776 with ReferenceableElementForLink
3777 implements MethodElementImpl {
3778 MethodElementForLink(ClassElementForLink_Class enclosingClass,
3779 UnlinkedExecutable unlinkedExecutable)
3780 : super(enclosingClass.enclosingElement, enclosingClass,
3781 unlinkedExecutable);
3782
3783 @override
3784 DartType get asStaticType => type;
3785
3786 @override
3787 ClassElementImpl get enclosingElement => super.enclosingClass;
3788
3789 @override
3790 String get identifier => name;
3791
3792 @override
3793 ElementKind get kind => ElementKind.METHOD;
3794
3795 @override
3796 FunctionElementForLink_Local getLocalFunction(int index) {
3797 // TODO(paulberry): implement.
3798 return null;
3799 }
3800
3801 @override
3802 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
3803
3804 @override
3805 String toString() => '$enclosingElement.$name';
3806 }
3807
3808 /**
3809 * Instances of [Node] represent nodes in a dependency graph. The
3810 * type parameter, [NodeType], is the derived type (this affords some
3811 * extra type safety by making it difficult to accidentally construct
3812 * bridges between unrelated dependency graphs).
3813 */
3814 abstract class Node<NodeType> {
3815 /**
3816 * Index used by Tarjan's strongly connected components algorithm.
3817 * Zero means the node has not been visited yet; a nonzero value
3818 * counts the order in which the node was visited.
3819 */
3820 int index = 0;
3821
3822 /**
3823 * Low link used by Tarjan's strongly connected components
3824 * algorithm. This represents the smallest [index] of all the nodes
3825 * in the strongly connected component to which this node belongs.
3826 */
3827 int lowLink = 0;
3828
3829 List<NodeType> _dependencies;
3830
3831 /**
3832 * Retrieve the dependencies of this node.
3833 */
3834 List<NodeType> get dependencies => _dependencies ??= computeDependencies();
3835
3836 /**
3837 * Indicates whether this node has been evaluated yet.
3838 */
3839 bool get isEvaluated;
3840
3841 /**
3842 * Compute the dependencies of this node.
3843 */
3844 List<NodeType> computeDependencies();
3845 }
3846
3847 /**
3848 * Element used for references that result from trying to access a non-static
3849 * member of an element that is not a container (e.g. accessing the "length"
3850 * property of a constant).
3851 *
3852 * Accesses to a chain of non-static members separated by '.' are andled by
3853 * creating a [NonstaticMemberElementForLink] that points to another
3854 * [NonstaticMemberElementForLink], to whatever nesting level is necessary.
3855 */
3856 class NonstaticMemberElementForLink extends Object
3857 with ReferenceableElementForLink {
3858 /**
3859 * The [ReferenceableElementForLink] which is the target of the non-static
3860 * reference.
3861 */
3862 final ReferenceableElementForLink _target;
3863
3864 /**
3865 * The name of the non-static members that is being accessed.
3866 */
3867 final String _name;
3868
3869 /**
3870 * The library in which the access occurs. This determines whether private
3871 * names are accessible.
3872 */
3873 final LibraryElementForLink _library;
3874
3875 NonstaticMemberElementForLink(this._library, this._target, this._name);
3876
3877 @override
3878 ConstVariableNode get asConstVariable => _target.asConstVariable;
3879
3880 @override
3881 DartType get asStaticType {
3882 if (_library._linker.strongMode) {
3883 DartType targetType = _target.asStaticType;
3884 if (targetType is InterfaceType) {
3885 ExecutableElement element =
3886 targetType.lookUpInheritedGetterOrMethod(_name, library: _library);
3887 if (element != null) {
3888 if (element is PropertyAccessorElement) {
3889 return element.returnType;
3890 } else {
3891 // Method tear-off
3892 return element.type;
3893 }
3894 }
3895 }
3896 // TODO(paulberry): handle .call on function types and .toString or
3897 // .hashCode on all types.
3898 }
3899 return DynamicTypeImpl.instance;
3900 }
3901
3902 @override
3903 TypeInferenceNode get asTypeInferenceNode => _target.asTypeInferenceNode;
3904
3905 @override
3906 ReferenceableElementForLink getContainedName(String name) {
3907 return new NonstaticMemberElementForLink(_library, this, name);
3908 }
3909
3910 @override
3911 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
3912
3913 @override
3914 String toString() => '$_target.(dynamic)$_name';
3915 }
3916
3917 /**
3918 * Element representing a function or method parameter resynthesized
3919 * from a summary during linking.
3920 */
3921 class ParameterElementForLink implements ParameterElementImpl {
3922 /**
3923 * The unlinked representation of the parameter in the summary.
3924 */
3925 final UnlinkedParam _unlinkedParam;
3926
3927 /**
3928 * The innermost enclosing element that can declare type parameters.
3929 */
3930 final TypeParameterizedElementMixin _typeParameterContext;
3931
3932 /**
3933 * If this parameter has a default value and the enclosing library
3934 * is part of the build unit being linked, the parameter's node in
3935 * the constant evaluation dependency graph. Otherwise `null`.
3936 */
3937 ConstNode _constNode;
3938
3939 /**
3940 * The compilation unit in which this parameter appears.
3941 */
3942 final CompilationUnitElementForLink compilationUnit;
3943
3944 /**
3945 * The index of this parameter within [enclosingElement]'s parameter list.
3946 */
3947 final int _parameterIndex;
3948
3949 @override
3950 final ParameterParentElementForLink enclosingElement;
3951
3952 DartType _inferredType;
3953 DartType _declaredType;
3954 bool _inheritsCovariant = false;
3955
3956 ParameterElementForLink(this.enclosingElement, this._unlinkedParam,
3957 this._typeParameterContext, this.compilationUnit, this._parameterIndex) {
3958 if (_unlinkedParam.initializer?.bodyExpr != null) {
3959 _constNode = new ConstParameterNode(this);
3960 }
3961 }
3962
3963 @override
3964 String get displayName => _unlinkedParam.name;
3965
3966 @override
3967 bool get hasImplicitType =>
3968 !_unlinkedParam.isFunctionTyped && _unlinkedParam.type == null;
3969
3970 @override
3971 bool get inheritsCovariant => _inheritsCovariant;
3972
3973 @override
3974 void set inheritsCovariant(bool value) {
3975 _inheritsCovariant = value;
3976 }
3977
3978 @override
3979 bool get isCovariant {
3980 if (inheritsCovariant) {
3981 return true;
3982 }
3983 for (UnlinkedConst annotation in _unlinkedParam.annotations) {
3984 if (annotation.operations.length == 1 &&
3985 annotation.operations[0] == UnlinkedConstOperation.pushReference) {
3986 ReferenceableElementForLink element =
3987 this.compilationUnit.resolveRef(annotation.references[0].reference);
3988 if (element is PropertyAccessorElementForLink &&
3989 element.name == 'checked' &&
3990 element.library.name == 'meta') {
3991 return true;
3992 }
3993 }
3994 }
3995 return false;
3996 }
3997
3998 @override
3999 String get name => _unlinkedParam.name;
4000
4001 @override
4002 ParameterKind get parameterKind {
4003 switch (_unlinkedParam.kind) {
4004 case UnlinkedParamKind.required:
4005 return ParameterKind.REQUIRED;
4006 case UnlinkedParamKind.positional:
4007 return ParameterKind.POSITIONAL;
4008 case UnlinkedParamKind.named:
4009 return ParameterKind.NAMED;
4010 }
4011 return null;
4012 }
4013
4014 @override
4015 DartType get type {
4016 if (_inferredType != null) {
4017 return _inferredType;
4018 } else if (_declaredType == null) {
4019 if (_unlinkedParam.isFunctionTyped) {
4020 _declaredType = new FunctionTypeImpl(
4021 new FunctionElementForLink_FunctionTypedParam(
4022 this, _typeParameterContext, _unlinkedParam.parameters));
4023 } else if (_unlinkedParam.type == null) {
4024 if (!compilationUnit.isInBuildUnit) {
4025 _inferredType = compilationUnit.getLinkedType(
4026 _unlinkedParam.inferredTypeSlot, _typeParameterContext);
4027 return _inferredType;
4028 } else {
4029 _declaredType = DynamicTypeImpl.instance;
4030 }
4031 } else {
4032 _declaredType = compilationUnit.resolveTypeRef(
4033 _unlinkedParam.type, _typeParameterContext);
4034 }
4035 }
4036 return _declaredType;
4037 }
4038
4039 @override
4040 void set type(DartType inferredType) {
4041 assert(_inferredType == null);
4042 _inferredType = inferredType;
4043 }
4044
4045 /**
4046 * Store the results of type inference for this parameter in
4047 * [compilationUnit].
4048 */
4049 void link(CompilationUnitElementInBuildUnit compilationUnit) {
4050 compilationUnit._storeLinkedType(
4051 _unlinkedParam.inferredTypeSlot, _inferredType, _typeParameterContext);
4052 if (inheritsCovariant) {
4053 compilationUnit
4054 ._storeInheritsCovariant(_unlinkedParam.inheritsCovariantSlot);
4055 }
4056 }
4057
4058 @override
4059 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
4060 }
4061
4062 /**
4063 * Element representing the parameter of a synthetic setter for a variable
4064 * resynthesized during linking.
4065 */
4066 class ParameterElementForLink_VariableSetter implements ParameterElementImpl {
4067 @override
4068 final PropertyAccessorElementForLink_Variable enclosingElement;
4069
4070 @override
4071 bool inheritsCovariant = false;
4072
4073 ParameterElementForLink_VariableSetter(this.enclosingElement);
4074
4075 @override
4076 bool get isCovariant => false;
4077
4078 @override
4079 bool get isSynthetic => true;
4080
4081 @override
4082 String get name => 'x';
4083
4084 @override
4085 ParameterKind get parameterKind => ParameterKind.REQUIRED;
4086
4087 @override
4088 DartType get type => enclosingElement.computeVariableType();
4089
4090 @override
4091 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
4092 }
4093
4094 /**
4095 * Mixin used by elements that can have parameters.
4096 */
4097 abstract class ParameterParentElementForLink implements Element {
4098 List<ParameterElement> _parameters;
4099
4100 /**
4101 * Get the appropriate integer list to store in
4102 * [EntityRef.implicitFunctionTypeIndices] to refer to this element. For an
4103 * element representing a function-typed parameter, this should return a
4104 * non-empty list. For an element representing an executable, this should
4105 * return the empty list.
4106 */
4107 List<int> get implicitFunctionTypeIndices;
4108
4109 /**
4110 * Get all the parameters of this element.
4111 */
4112 List<ParameterElement> get parameters {
4113 if (_parameters == null) {
4114 List<UnlinkedParam> unlinkedParameters = this.unlinkedParameters;
4115 int numParameters = unlinkedParameters.length;
4116 _parameters = new List<ParameterElement>(numParameters);
4117 for (int i = 0; i < numParameters; i++) {
4118 UnlinkedParam unlinkedParam = unlinkedParameters[i];
4119 _parameters[i] = new ParameterElementForLink(
4120 this,
4121 unlinkedParam,
4122 typeParameterContext,
4123 typeParameterContext.enclosingUnit.resynthesizerContext
4124 as CompilationUnitElementForLink,
4125 i);
4126 }
4127 }
4128 return _parameters;
4129 }
4130
4131 /**
4132 * Get the innermost enclosing element that can declare type parameters (which
4133 * may be [this], or may be a parent when there are function-typed
4134 * parameters).
4135 */
4136 TypeParameterizedElementMixin get typeParameterContext;
4137
4138 /**
4139 * Get the list of unlinked parameters of this element.
4140 */
4141 List<UnlinkedParam> get unlinkedParameters;
4142 }
4143
4144 /**
4145 * Element representing a getter or setter resynthesized from a summary during
4146 * linking.
4147 */
4148 abstract class PropertyAccessorElementForLink
4149 implements PropertyAccessorElementImpl, ReferenceableElementForLink {
4150 void link(CompilationUnitElementInBuildUnit compilationUnit);
4151 }
4152
4153 /**
4154 * Specialization of [PropertyAccessorElementForLink] for synthetic accessors
4155 * implied by the synthetic fields of an enum declaration.
4156 */
4157 class PropertyAccessorElementForLink_EnumField extends Object
4158 with ReferenceableElementForLink
4159 implements PropertyAccessorElementForLink {
4160 @override
4161 final FieldElementForLink_EnumField variable;
4162
4163 FunctionTypeImpl _type;
4164
4165 PropertyAccessorElementForLink_EnumField(this.variable);
4166
4167 @override
4168 DartType get asStaticType => returnType;
4169
4170 @override
4171 Element get enclosingElement => variable.enclosingElement;
4172
4173 @override
4174 bool get isGetter => true;
4175
4176 @override
4177 bool get isSetter => false;
4178
4179 @override
4180 bool get isStatic => variable.isStatic;
4181
4182 @override
4183 bool get isSynthetic => true;
4184
4185 @override
4186 ElementKind get kind => ElementKind.GETTER;
4187
4188 @override
4189 LibraryElementForLink get library =>
4190 variable.enclosingElement.enclosingElement.enclosingElement;
4191
4192 @override
4193 String get name => variable.name;
4194
4195 @override
4196 List<ParameterElement> get parameters => const [];
4197
4198 @override
4199 DartType get returnType => variable.type;
4200
4201 @override
4202 FunctionTypeImpl get type => _type ??= new FunctionTypeImpl(this);
4203
4204 @override
4205 List<TypeParameterElement> get typeParameters => const [];
4206
4207 @override
4208 ReferenceableElementForLink getContainedName(String name) {
4209 return new NonstaticMemberElementForLink(library, this, name);
4210 }
4211
4212 @override
4213 FunctionElementForLink_Local getLocalFunction(int index) {
4214 // TODO(paulberry): implement (should return the synthetic function element
4215 // for the enum field's initializer).
4216 return null;
4217 }
4218
4219 @override
4220 bool isAccessibleIn(LibraryElement library) =>
4221 !Identifier.isPrivateName(name) || identical(this.library, library);
4222
4223 @override
4224 void link(CompilationUnitElementInBuildUnit compilationUnit) {}
4225
4226 @override
4227 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
4228
4229 @override
4230 String toString() => '$enclosingElement.$name';
4231 }
4232
4233 /**
4234 * Specialization of [PropertyAccessorElementForLink] for non-synthetic
4235 * accessors explicitly declared in the source code.
4236 */
4237 class PropertyAccessorElementForLink_Executable
4238 extends ExecutableElementForLink_NonLocal
4239 with ReferenceableElementForLink
4240 implements PropertyAccessorElementForLink {
4241 @override
4242 PropertyInducingElement variable;
4243
4244 PropertyAccessorElementForLink_Executable(
4245 CompilationUnitElementForLink enclosingUnit,
4246 ClassElementForLink_Class enclosingClass,
4247 UnlinkedExecutable unlinkedExecutable,
4248 this.variable)
4249 : super(enclosingUnit, enclosingClass, unlinkedExecutable);
4250
4251 @override
4252 DartType get asStaticType => returnType;
4253
4254 @override
4255 PropertyAccessorElementForLink_Executable get correspondingGetter =>
4256 variable.getter;
4257
4258 @override
4259 bool get isGetter =>
4260 _unlinkedExecutable.kind == UnlinkedExecutableKind.getter;
4261
4262 @override
4263 bool get isSetter =>
4264 _unlinkedExecutable.kind == UnlinkedExecutableKind.setter;
4265
4266 @override
4267 bool get isStatic => enclosingClass == null || super.isStatic;
4268
4269 @override
4270 ElementKind get kind =>
4271 _unlinkedExecutable.kind == UnlinkedExecutableKind.getter
4272 ? ElementKind.GETTER
4273 : ElementKind.SETTER;
4274
4275 @override
4276 ReferenceableElementForLink getContainedName(String name) {
4277 return new NonstaticMemberElementForLink(
4278 library as LibraryElementForLink, this, name);
4279 }
4280
4281 @override
4282 FunctionElementForLink_Local getLocalFunction(int index) {
4283 // TODO(paulberry): implement
4284 return null;
4285 }
4286
4287 @override
4288 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
4289
4290 @override
4291 String toString() => '$enclosingElement.$name';
4292 }
4293
4294 /**
4295 * Specialization of [PropertyAccessorElementForLink] for synthetic accessors
4296 * implied by a field or variable declaration.
4297 */
4298 class PropertyAccessorElementForLink_Variable extends Object
4299 with ReferenceableElementForLink
4300 implements PropertyAccessorElementForLink {
4301 @override
4302 final bool isSetter;
4303
4304 final VariableElementForLink variable;
4305 FunctionTypeImpl _type;
4306 List<ParameterElement> _parameters;
4307
4308 PropertyAccessorElementForLink_Variable(this.variable, this.isSetter);
4309
4310 @override
4311 ConstVariableNode get asConstVariable => variable._constNode;
4312
4313 @override
4314 DartType get asStaticType => returnType;
4315
4316 @override
4317 TypeInferenceNode get asTypeInferenceNode => variable._typeInferenceNode;
4318
4319 @override
4320 Element get enclosingElement => variable.enclosingElement;
4321
4322 @override
4323 bool get isGetter => !isSetter;
4324
4325 @override
4326 bool get isStatic => variable.isStatic;
4327
4328 @override
4329 bool get isSynthetic => true;
4330
4331 @override
4332 ElementKind get kind => isSetter ? ElementKind.SETTER : ElementKind.GETTER;
4333
4334 @override
4335 LibraryElementForLink get library =>
4336 variable.compilationUnit.enclosingElement;
4337
4338 @override
4339 String get name => isSetter ? '${variable.name}=' : variable.name;
4340
4341 @override
4342 List<ParameterElement> get parameters {
4343 if (_parameters == null) {
4344 _parameters = <ParameterElementForLink_VariableSetter>[];
4345 if (isSetter) {
4346 _parameters.add(new ParameterElementForLink_VariableSetter(this));
4347 }
4348 }
4349 return _parameters;
4350 }
4351
4352 @override
4353 DartType get returnType {
4354 if (isSetter) {
4355 return VoidTypeImpl.instance;
4356 } else {
4357 return computeVariableType();
4358 }
4359 }
4360
4361 @override
4362 FunctionTypeImpl get type => _type ??= new FunctionTypeImpl(this);
4363
4364 @override
4365 List<TypeParameterElement> get typeParameters {
4366 // TODO(paulberry): is this correct for fields in generic classes?
4367 return const [];
4368 }
4369
4370 /**
4371 * Compute the type of the corresponding variable, which may depend on the
4372 * progress of type inference.
4373 */
4374 DartType computeVariableType() {
4375 if (variable.hasImplicitType &&
4376 !isStatic &&
4377 !variable.compilationUnit.isTypeInferenceComplete) {
4378 // This is an instance field and we are currently inferring types in the
4379 // library cycle containing it. So we shouldn't use the inferred type
4380 // (even if we have already computed it), since that would lead to
4381 // non-deterministic type inference results.
4382 return DynamicTypeImpl.instance;
4383 } else {
4384 return variable.type;
4385 }
4386 }
4387
4388 @override
4389 ReferenceableElementForLink getContainedName(String name) {
4390 return new NonstaticMemberElementForLink(library, this, name);
4391 }
4392
4393 @override
4394 FunctionElementForLink_Local getLocalFunction(int index) {
4395 if (index == 0) {
4396 return variable.initializer;
4397 } else {
4398 return null;
4399 }
4400 }
4401
4402 @override
4403 bool isAccessibleIn(LibraryElement library) =>
4404 !Identifier.isPrivateName(name) || identical(this.library, library);
4405
4406 @override
4407 void link(CompilationUnitElementInBuildUnit compilationUnit) {}
4408
4409 @override
4410 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
4411
4412 @override
4413 String toString() => '$enclosingElement.$name';
4414 }
4415
4416 /**
4417 * Base class representing an element which can be the target of a reference.
4418 * When used as a mixin, implements the default behavior shared by most
4419 * elements.
4420 */
4421 abstract class ReferenceableElementForLink implements Element {
4422 /**
4423 * If this element is a class reference, return it. Otherwise return `null`.
4424 */
4425 ClassElementForLink get asClass => null;
4426
4427 /**
4428 * If this element can be used in a constructor invocation context,
4429 * return the associated constructor (which may be `this` or some
4430 * other element). Otherwise return `null`.
4431 */
4432 ConstructorElementForLink get asConstructor => null;
4433
4434 /**
4435 * If this element can be used in a getter context to refer to a
4436 * constant variable, return the [ConstVariableNode] for the
4437 * constant value. Otherwise return `null`.
4438 */
4439 ConstVariableNode get asConstVariable => null;
4440
4441 /**
4442 * Return the static type (possibly inferred) of the entity referred to by
4443 * this element.
4444 */
4445 DartType get asStaticType => DynamicTypeImpl.instance;
4446
4447 /**
4448 * If this element can be used in a getter context as a type inference
4449 * dependency, return the [TypeInferenceNode] for the inferred type.
4450 * Otherwise return `null`.
4451 */
4452 TypeInferenceNode get asTypeInferenceNode => null;
4453
4454 @override
4455 ElementLocation get location => new ElementLocationImpl.con1(this);
4456
4457 /**
4458 * Return the type indicated by this element when it is used in a
4459 * type instantiation context. If this element can't legally be
4460 * instantiated as a type, return the dynamic type.
4461 *
4462 * If the type is parameterized, [getTypeArgument] will be called to retrieve
4463 * the type parameters. It should return `null` for unspecified type
4464 * parameters.
4465 */
4466 DartType buildType(DartType getTypeArgument(int i),
4467 List<int> implicitFunctionTypeIndices) =>
4468 DynamicTypeImpl.instance;
4469
4470 /**
4471 * If this element contains other named elements, return the
4472 * contained element having the given [name]. If this element can't
4473 * contain other named elements, or it doesn't contain an element
4474 * with the given name, return the singleton of
4475 * [UndefinedElementForLink].
4476 */
4477 ReferenceableElementForLink getContainedName(String name) {
4478 // TODO(paulberry): handle references to `call` for function types.
4479 return UndefinedElementForLink.instance;
4480 }
4481
4482 /**
4483 * If this element contains local functions, return the contained local
4484 * function having the given [index]. If this element doesn't contain local
4485 * functions, or the index is out of range, return `null`.
4486 */
4487 FunctionElementForLink_Local getLocalFunction(int index) => null;
4488 }
4489
4490 /**
4491 * Element used for references to special types such as `void`.
4492 */
4493 class SpecialTypeElementForLink extends Object
4494 with ReferenceableElementForLink {
4495 final Linker linker;
4496 final DartType type;
4497
4498 SpecialTypeElementForLink(this.linker, this.type);
4499
4500 @override
4501 DartType get asStaticType => linker.typeProvider.typeType;
4502
4503 @override
4504 DartType buildType(
4505 DartType getTypeArgument(int i), List<int> implicitFunctionTypeIndices) {
4506 return type;
4507 }
4508
4509 @override
4510 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
4511
4512 @override
4513 String toString() => type.toString();
4514 }
4515
4516 /**
4517 * Element representing a synthetic variable resynthesized from a summary during
4518 * linking.
4519 */
4520 class SyntheticVariableElementForLink implements PropertyInducingElementImpl {
4521 PropertyAccessorElementForLink_Executable _getter;
4522 PropertyAccessorElementForLink_Executable _setter;
4523
4524 @override
4525 PropertyAccessorElementForLink_Executable get getter => _getter;
4526
4527 @override
4528 bool get isSynthetic => true;
4529
4530 @override
4531 PropertyAccessorElementForLink_Executable get setter => _setter;
4532
4533 @override
4534 void set type(DartType inferredType) {}
4535
4536 @override
4537 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
4538 }
4539
4540 /**
4541 * Element representing a top-level function.
4542 */
4543 class TopLevelFunctionElementForLink extends ExecutableElementForLink_NonLocal
4544 with ReferenceableElementForLink
4545 implements FunctionElementImpl {
4546 DartType _returnType;
4547
4548 TopLevelFunctionElementForLink(
4549 CompilationUnitElementForLink enclosingUnit, UnlinkedExecutable _buf)
4550 : super(enclosingUnit, null, _buf);
4551
4552 @override
4553 DartType get asStaticType => type;
4554
4555 @override
4556 String get identifier => _unlinkedExecutable.name;
4557
4558 @override
4559 bool get isStatic => true;
4560
4561 @override
4562 ElementKind get kind => ElementKind.FUNCTION;
4563
4564 @override
4565 FunctionElementForLink_Local getLocalFunction(int index) {
4566 // TODO(paulberry): implement.
4567 return null;
4568 }
4569
4570 @override
4571 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
4572
4573 @override
4574 String toString() => '$enclosingElement.$name';
4575 }
4576
4577 /**
4578 * Element representing a top level variable resynthesized from a
4579 * summary during linking.
4580 */
4581 class TopLevelVariableElementForLink extends VariableElementForLink
4582 implements TopLevelVariableElement {
4583 TopLevelVariableElementForLink(CompilationUnitElementForLink enclosingElement,
4584 UnlinkedVariable unlinkedVariable)
4585 : super(unlinkedVariable, enclosingElement);
4586
4587 @override
4588 CompilationUnitElementForLink get enclosingElement => compilationUnit;
4589
4590 @override
4591 bool get isStatic => true;
4592
4593 @override
4594 LibraryElementForLink get library => compilationUnit.library;
4595
4596 @override
4597 TypeParameterizedElementMixin get _typeParameterContext => null;
4598
4599 /**
4600 * Store the results of type inference for this variable in
4601 * [compilationUnit].
4602 */
4603 void link(CompilationUnitElementInBuildUnit compilationUnit) {
4604 if (hasImplicitType) {
4605 TypeInferenceNode typeInferenceNode = this._typeInferenceNode;
4606 if (typeInferenceNode != null) {
4607 compilationUnit._storeLinkedType(
4608 unlinkedVariable.inferredTypeSlot, inferredType, null);
4609 }
4610 initializer?.link(compilationUnit);
4611 }
4612 }
4613 }
4614
4615 /**
4616 * Specialization of [DependencyWalker] for performing type inferrence
4617 * on static and top level variables.
4618 */
4619 class TypeInferenceDependencyWalker
4620 extends DependencyWalker<TypeInferenceNode> {
4621 @override
4622 void evaluate(TypeInferenceNode v) {
4623 v.evaluate(false);
4624 }
4625
4626 @override
4627 void evaluateScc(List<TypeInferenceNode> scc) {
4628 for (TypeInferenceNode v in scc) {
4629 v.evaluate(true);
4630 }
4631 }
4632 }
4633
4634 /**
4635 * Specialization of [Node] used to construct the type inference dependency
4636 * graph.
4637 */
4638 class TypeInferenceNode extends Node<TypeInferenceNode> {
4639 /**
4640 * The [FunctionElementForLink_Local] to which this node refers.
4641 */
4642 final FunctionElementForLink_Local functionElement;
4643
4644 TypeInferenceNode(this.functionElement);
4645
4646 @override
4647 bool get isEvaluated => functionElement._hasTypeBeenInferred;
4648
4649 /**
4650 * Collect the type inference dependencies in [unlinkedExecutable] (which
4651 * should be interpreted relative to [compilationUnit]) and store them in
4652 * [dependencies].
4653 */
4654 void collectDependencies(
4655 List<TypeInferenceNode> dependencies,
4656 UnlinkedExecutable unlinkedExecutable,
4657 CompilationUnitElementForLink compilationUnit) {
4658 UnlinkedConst unlinkedConst = unlinkedExecutable?.bodyExpr;
4659 if (unlinkedConst == null) {
4660 return;
4661 }
4662 int refPtr = 0;
4663 int intPtr = 0;
4664
4665 for (UnlinkedConstOperation operation in unlinkedConst.operations) {
4666 switch (operation) {
4667 case UnlinkedConstOperation.pushInt:
4668 intPtr++;
4669 break;
4670 case UnlinkedConstOperation.pushLongInt:
4671 int numInts = unlinkedConst.ints[intPtr++];
4672 intPtr += numInts;
4673 break;
4674 case UnlinkedConstOperation.concatenate:
4675 intPtr++;
4676 break;
4677 case UnlinkedConstOperation.pushReference:
4678 EntityRef ref = unlinkedConst.references[refPtr++];
4679 // TODO(paulberry): cache these resolved references for
4680 // later use by evaluate().
4681 TypeInferenceNode dependency =
4682 compilationUnit.resolveRef(ref.reference).asTypeInferenceNode;
4683 if (dependency != null) {
4684 dependencies.add(dependency);
4685 }
4686 break;
4687 case UnlinkedConstOperation.invokeConstructor:
4688 refPtr++;
4689 intPtr += 2;
4690 break;
4691 case UnlinkedConstOperation.makeUntypedList:
4692 case UnlinkedConstOperation.makeUntypedMap:
4693 intPtr++;
4694 break;
4695 case UnlinkedConstOperation.makeTypedList:
4696 refPtr++;
4697 intPtr++;
4698 break;
4699 case UnlinkedConstOperation.makeTypedMap:
4700 refPtr += 2;
4701 intPtr++;
4702 break;
4703 case UnlinkedConstOperation.assignToRef:
4704 // TODO(paulberry): if this reference refers to a variable, should it
4705 // be considered a type inference dependency?
4706 refPtr++;
4707 break;
4708 case UnlinkedConstOperation.invokeMethodRef:
4709 // TODO(paulberry): if this reference refers to a variable, should it
4710 // be considered a type inference dependency?
4711 refPtr++;
4712 intPtr += 2;
4713 int numTypeArguments = unlinkedConst.ints[intPtr++];
4714 refPtr += numTypeArguments;
4715 break;
4716 case UnlinkedConstOperation.invokeMethod:
4717 intPtr += 2;
4718 int numTypeArguments = unlinkedConst.ints[intPtr++];
4719 refPtr += numTypeArguments;
4720 break;
4721 case UnlinkedConstOperation.typeCast:
4722 case UnlinkedConstOperation.typeCheck:
4723 refPtr++;
4724 break;
4725 case UnlinkedConstOperation.pushLocalFunctionReference:
4726 int popCount = unlinkedConst.ints[intPtr++];
4727 assert(popCount == 0); // TODO(paulberry): handle the nonzero case.
4728 dependencies.add(functionElement
4729 .getLocalFunction(unlinkedConst.ints[intPtr++])
4730 .asTypeInferenceNode);
4731 break;
4732 default:
4733 break;
4734 }
4735 }
4736 assert(refPtr == unlinkedConst.references.length);
4737 assert(intPtr == unlinkedConst.ints.length);
4738 }
4739
4740 @override
4741 List<TypeInferenceNode> computeDependencies() {
4742 List<TypeInferenceNode> dependencies = <TypeInferenceNode>[];
4743 collectDependencies(dependencies, functionElement._unlinkedExecutable,
4744 functionElement.compilationUnit);
4745 return dependencies;
4746 }
4747
4748 void evaluate(bool inCycle) {
4749 if (inCycle) {
4750 functionElement._setInferredType(DynamicTypeImpl.instance);
4751 } else {
4752 functionElement
4753 ._setInferredType(new ExprTypeComputer(functionElement).compute());
4754 }
4755 }
4756
4757 @override
4758 String toString() => 'TypeInferenceNode($functionElement)';
4759 }
4760
4761 class TypeProviderForLink extends TypeProviderBase {
4762 final Linker _linker;
4763
4764 InterfaceType _boolType;
4765 InterfaceType _deprecatedType;
4766 InterfaceType _doubleType;
4767 InterfaceType _functionType;
4768 InterfaceType _futureDynamicType;
4769 InterfaceType _futureNullType;
4770 InterfaceType _futureType;
4771 InterfaceType _intType;
4772 InterfaceType _iterableDynamicType;
4773 InterfaceType _iterableType;
4774 InterfaceType _listType;
4775 InterfaceType _mapType;
4776 InterfaceType _nullType;
4777 InterfaceType _numType;
4778 InterfaceType _objectType;
4779 InterfaceType _stackTraceType;
4780 InterfaceType _streamDynamicType;
4781 InterfaceType _streamType;
4782 InterfaceType _stringType;
4783 InterfaceType _symbolType;
4784 InterfaceType _typeType;
4785
4786 TypeProviderForLink(this._linker);
4787
4788 @override
4789 InterfaceType get boolType =>
4790 _boolType ??= _buildInterfaceType(_linker.coreLibrary, 'bool');
4791
4792 @override
4793 DartType get bottomType => BottomTypeImpl.instance;
4794
4795 @override
4796 InterfaceType get deprecatedType => _deprecatedType ??=
4797 _buildInterfaceType(_linker.coreLibrary, 'Deprecated');
4798
4799 @override
4800 InterfaceType get doubleType =>
4801 _doubleType ??= _buildInterfaceType(_linker.coreLibrary, 'double');
4802
4803 @override
4804 DartType get dynamicType => DynamicTypeImpl.instance;
4805
4806 @override
4807 InterfaceType get functionType =>
4808 _functionType ??= _buildInterfaceType(_linker.coreLibrary, 'Function');
4809
4810 @override
4811 InterfaceType get futureDynamicType =>
4812 _futureDynamicType ??= futureType.instantiate(<DartType>[dynamicType]);
4813
4814 @override
4815 InterfaceType get futureNullType =>
4816 _futureNullType ??= futureType.instantiate(<DartType>[nullType]);
4817
4818 @override
4819 InterfaceType get futureType =>
4820 _futureType ??= _buildInterfaceType(_linker.asyncLibrary, 'Future');
4821
4822 @override
4823 InterfaceType get intType =>
4824 _intType ??= _buildInterfaceType(_linker.coreLibrary, 'int');
4825
4826 @override
4827 InterfaceType get iterableDynamicType => _iterableDynamicType ??=
4828 iterableType.instantiate(<DartType>[dynamicType]);
4829
4830 @override
4831 InterfaceType get iterableType =>
4832 _iterableType ??= _buildInterfaceType(_linker.coreLibrary, 'Iterable');
4833
4834 @override
4835 InterfaceType get listType =>
4836 _listType ??= _buildInterfaceType(_linker.coreLibrary, 'List');
4837
4838 @override
4839 InterfaceType get mapType =>
4840 _mapType ??= _buildInterfaceType(_linker.coreLibrary, 'Map');
4841
4842 @override
4843 DartObjectImpl get nullObject {
4844 // TODO(paulberry): implement if needed
4845 throw new UnimplementedError();
4846 }
4847
4848 @override
4849 InterfaceType get nullType =>
4850 _nullType ??= _buildInterfaceType(_linker.coreLibrary, 'Null');
4851
4852 @override
4853 InterfaceType get numType =>
4854 _numType ??= _buildInterfaceType(_linker.coreLibrary, 'num');
4855
4856 @override
4857 InterfaceType get objectType =>
4858 _objectType ??= _buildInterfaceType(_linker.coreLibrary, 'Object');
4859
4860 @override
4861 InterfaceType get stackTraceType => _stackTraceType ??=
4862 _buildInterfaceType(_linker.coreLibrary, 'StackTrace');
4863
4864 @override
4865 InterfaceType get streamDynamicType =>
4866 _streamDynamicType ??= streamType.instantiate(<DartType>[dynamicType]);
4867
4868 @override
4869 InterfaceType get streamType =>
4870 _streamType ??= _buildInterfaceType(_linker.asyncLibrary, 'Stream');
4871
4872 @override
4873 InterfaceType get stringType =>
4874 _stringType ??= _buildInterfaceType(_linker.coreLibrary, 'String');
4875
4876 @override
4877 InterfaceType get symbolType =>
4878 _symbolType ??= _buildInterfaceType(_linker.coreLibrary, 'Symbol');
4879
4880 @override
4881 InterfaceType get typeType =>
4882 _typeType ??= _buildInterfaceType(_linker.coreLibrary, 'Type');
4883
4884 @override
4885 DartType get undefinedType => UndefinedTypeImpl.instance;
4886
4887 InterfaceType _buildInterfaceType(
4888 LibraryElementForLink library, String name) {
4889 return library.getContainedName(name).buildType((int i) {
4890 // TODO(scheglov) accept type parameter names
4891 var element = new TypeParameterElementImpl('T$i', -1);
4892 return new TypeParameterTypeImpl(element);
4893 }, const []);
4894 }
4895 }
4896
4897 /**
4898 * Singleton element used for unresolved references.
4899 */
4900 class UndefinedElementForLink extends Object with ReferenceableElementForLink {
4901 static final UndefinedElementForLink instance =
4902 new UndefinedElementForLink._();
4903
4904 UndefinedElementForLink._();
4905
4906 @override
4907 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
4908 }
4909
4910 /**
4911 * Element representing a top level variable resynthesized from a
4912 * summary during linking.
4913 */
4914 abstract class VariableElementForLink
4915 implements NonParameterVariableElementImpl, PropertyInducingElement {
4916 /**
4917 * The unlinked representation of the variable in the summary.
4918 */
4919 final UnlinkedVariable unlinkedVariable;
4920
4921 /**
4922 * If this variable is declared `const` and the enclosing library is
4923 * part of the build unit being linked, the variable's node in the
4924 * constant evaluation dependency graph. Otherwise `null`.
4925 */
4926 ConstNode _constNode;
4927
4928 /**
4929 * If this variable has an initializer and an implicit type, and the enclosing
4930 * library is part of the build unit being linked, the variable's node in the
4931 * type inference dependency graph. Otherwise `null`.
4932 */
4933 TypeInferenceNode _typeInferenceNode;
4934
4935 FunctionElementForLink_Initializer _initializer;
4936 DartType _inferredType;
4937 DartType _declaredType;
4938 PropertyAccessorElementForLink_Variable _getter;
4939 PropertyAccessorElementForLink_Variable _setter;
4940
4941 /**
4942 * The compilation unit in which this variable appears.
4943 */
4944 final CompilationUnitElementForLink compilationUnit;
4945
4946 VariableElementForLink(this.unlinkedVariable, this.compilationUnit) {
4947 if (compilationUnit.isInBuildUnit &&
4948 unlinkedVariable.initializer?.bodyExpr != null) {
4949 _constNode = new ConstVariableNode(this);
4950 if (unlinkedVariable.type == null) {
4951 _typeInferenceNode = initializer.asTypeInferenceNode;
4952 }
4953 }
4954 }
4955
4956 /**
4957 * If the variable has an explicitly declared return type, return it.
4958 * Otherwise return `null`.
4959 */
4960 DartType get declaredType {
4961 if (unlinkedVariable.type == null) {
4962 return null;
4963 } else {
4964 return _declaredType ??= compilationUnit.resolveTypeRef(
4965 unlinkedVariable.type, _typeParameterContext);
4966 }
4967 }
4968
4969 @override
4970 PropertyAccessorElementForLink_Variable get getter =>
4971 _getter ??= new PropertyAccessorElementForLink_Variable(this, false);
4972
4973 @override
4974 bool get hasImplicitType => unlinkedVariable.type == null;
4975
4976 /**
4977 * Return the inferred type of the variable element. Should only be called if
4978 * no type was explicitly declared.
4979 */
4980 DartType get inferredType {
4981 // We should only try to infer a type when none is explicitly declared.
4982 assert(unlinkedVariable.type == null);
4983 if (_inferredType == null) {
4984 if (_typeInferenceNode != null) {
4985 assert(Linker._initializerTypeInferenceCycle == null);
4986 Linker._initializerTypeInferenceCycle =
4987 compilationUnit.library.libraryCycleForLink;
4988 try {
4989 new TypeInferenceDependencyWalker().walk(_typeInferenceNode);
4990 assert(_inferredType != null);
4991 } finally {
4992 Linker._initializerTypeInferenceCycle = null;
4993 }
4994 } else if (compilationUnit.isInBuildUnit) {
4995 _inferredType = DynamicTypeImpl.instance;
4996 } else {
4997 _inferredType = compilationUnit.getLinkedType(
4998 unlinkedVariable.inferredTypeSlot, _typeParameterContext);
4999 }
5000 }
5001 return _inferredType;
5002 }
5003
5004 @override
5005 FunctionElementForLink_Initializer get initializer {
5006 if (unlinkedVariable.initializer == null) {
5007 return null;
5008 } else {
5009 return _initializer ??= new FunctionElementForLink_Initializer(this);
5010 }
5011 }
5012
5013 @override
5014 bool get isConst => unlinkedVariable.isConst;
5015
5016 @override
5017 bool get isFinal => unlinkedVariable.isFinal;
5018
5019 @override
5020 bool get isStatic;
5021
5022 @override
5023 bool get isSynthetic => false;
5024
5025 @override
5026 String get name => unlinkedVariable.name;
5027
5028 @override
5029 DartType get propagatedType {
5030 return DynamicTypeImpl.instance;
5031 }
5032
5033 @override
5034 PropertyAccessorElementForLink_Variable get setter {
5035 if (!isConst && !isFinal) {
5036 return _setter ??=
5037 new PropertyAccessorElementForLink_Variable(this, true);
5038 } else {
5039 return null;
5040 }
5041 }
5042
5043 @override
5044 DartType get type => declaredType ?? inferredType;
5045
5046 @override
5047 void set type(DartType newType) {
5048 // TODO(paulberry): store inferred type.
5049 }
5050
5051 /**
5052 * The context in which type parameters should be interpreted, or `null` if
5053 * there are no type parameters in scope.
5054 */
5055 TypeParameterizedElementMixin get _typeParameterContext;
5056
5057 @override
5058 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
5059
5060 @override
5061 String toString() => '$enclosingElement.$name';
5062 }
OLDNEW
« no previous file with comments | « packages/analyzer/lib/src/summary/idl.dart ('k') | packages/analyzer/lib/src/summary/name_filter.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698