| OLD | NEW |
| (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 } |
| OLD | NEW |