| // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| import 'package:js_shared/variance.dart'; | |
| import '../common.dart'; | |
| import '../constants/constant_system.dart' as constant_system; | |
| import '../constants/values.dart'; | |
| import '../elements/entities.dart'; | |
| import '../elements/names.dart'; | |
| import '../elements/types.dart'; | |
| import '../inferrer/abstract_value_domain.dart'; | |
| import '../ir/element_map.dart'; | |
| import '../js_backend/native_data.dart' show NativeBasicData; | |
| import '../js_model/locals.dart'; | |
| import '../universe/selector.dart' show Selector; | |
| import '../universe/world_builder.dart'; | |
| import 'names.dart' show Identifiers, Uris; | |
| /// The common elements and types in Dart. | |
| abstract class CommonElements { | |
| final DartTypes dartTypes; | |
| final ElementEnvironment _env; | |
| ClassEntity? _symbolClass; | |
| ConstructorEntity? _symbolConstructorTarget; | |
| bool _computedSymbolConstructorDependencies = false; | |
| ConstructorEntity? _symbolConstructorImplementationTarget; | |
| ClassEntity? _mapLiteralClass; | |
| ClassEntity? _symbolImplementationClass; | |
| FieldEntity? _symbolImplementationField; | |
| CommonElements(this.dartTypes, this._env); | |
| /// The `Object` class defined in 'dart:core'. | |
| late final ClassEntity objectClass = _findClass(coreLibrary, 'Object'); | |
| /// The `bool` class defined in 'dart:core'. | |
| late final ClassEntity boolClass = _findClass(coreLibrary, 'bool'); | |
| /// The `num` class defined in 'dart:core'. | |
| late final ClassEntity numClass = _findClass(coreLibrary, 'num'); | |
| /// The `int` class defined in 'dart:core'. | |
| late final ClassEntity intClass = _findClass(coreLibrary, 'int'); | |
| /// The `double` class defined in 'dart:core'. | |
| late final ClassEntity doubleClass = _findClass(coreLibrary, 'double'); | |
| /// The `String` class defined in 'dart:core'. | |
| late final ClassEntity stringClass = _findClass(coreLibrary, 'String'); | |
| /// The `Function` class defined in 'dart:core'. | |
| late final ClassEntity functionClass = _findClass(coreLibrary, 'Function'); | |
| /// The `Record` class defined in 'dart:core'. | |
| late final ClassEntity recordClass = _findClass(coreLibrary, 'Record'); | |
| /// The `Resource` class defined in 'dart:core'. | |
| late final ClassEntity resourceClass = _findClass(coreLibrary, 'Resource'); | |
| /// The `Symbol` class defined in 'dart:core'. | |
| late final ClassEntity symbolClass = _findClass(coreLibrary, 'Symbol'); | |
| /// The `Null` class defined in 'dart:core'. | |
| late final ClassEntity nullClass = _findClass(coreLibrary, 'Null'); | |
| /// The `Type` class defined in 'dart:core'. | |
| late final ClassEntity typeClass = _findClass(coreLibrary, 'Type'); | |
| /// The `StackTrace` class defined in 'dart:core'; | |
| late final ClassEntity stackTraceClass = _findClass( | |
| coreLibrary, | |
| 'StackTrace', | |
| ); | |
| /// The `List` class defined in 'dart:core'; | |
| late final ClassEntity listClass = _findClass(coreLibrary, 'List'); | |
| /// The `Set` class defined in 'dart:core'; | |
| late final ClassEntity setClass = _findClass(coreLibrary, 'Set'); | |
| /// The `Map` class defined in 'dart:core'; | |
| late final ClassEntity mapClass = _findClass(coreLibrary, 'Map'); | |
| /// The `Set` class defined in 'dart:core'; | |
| late final ClassEntity unmodifiableSetClass = _findClass( | |
| collectionLibrary, | |
| '_UnmodifiableSet', | |
| ); | |
| /// The `Iterable` class defined in 'dart:core'; | |
| late final ClassEntity iterableClass = _findClass(coreLibrary, 'Iterable'); | |
| /// The `Future` class defined in 'async';. | |
| late final ClassEntity futureClass = _findClass(asyncLibrary, 'Future'); | |
| /// The `Stream` class defined in 'async'; | |
| late final ClassEntity streamClass = _findClass(asyncLibrary, 'Stream'); | |
| /// The dart:core library. | |
| late final LibraryEntity coreLibrary = _env.lookupLibrary( | |
| Uris.dartCore, | |
| required: true, | |
| )!; | |
| /// The dart:async library. | |
| late final LibraryEntity? asyncLibrary = _env.lookupLibrary(Uris.dartAsync); | |
| /// The dart:collection library. | |
| late final LibraryEntity? collectionLibrary = _env.lookupLibrary( | |
| Uris.dartCollection, | |
| ); | |
| /// The dart:mirrors library. | |
| /// Null if the program doesn't access dart:mirrors. | |
| late final LibraryEntity? mirrorsLibrary = _env.lookupLibrary( | |
| Uris.dartMirrors, | |
| ); | |
| /// The dart:typed_data library. | |
| late final LibraryEntity typedDataLibrary = _env.lookupLibrary( | |
| Uris.dartNativeTypedData, | |
| required: true, | |
| )!; | |
| /// The dart:_js_shared_embedded_names library. | |
| late final LibraryEntity sharedEmbeddedNamesLibrary = _env.lookupLibrary( | |
| Uris.dartJSSharedEmbeddedNames, | |
| required: true, | |
| )!; | |
| /// The dart:_js_helper library. | |
| late final LibraryEntity? jsHelperLibrary = _env.lookupLibrary( | |
| Uris.dartJSHelper, | |
| ); | |
| /// The dart:_late_helper library | |
| late final LibraryEntity? lateHelperLibrary = _env.lookupLibrary( | |
| Uris.dartLateHelper, | |
| ); | |
| /// The dart:_interceptors library. | |
| late final LibraryEntity? interceptorsLibrary = _env.lookupLibrary( | |
| Uris.dartInterceptors, | |
| ); | |
| /// The dart:_foreign_helper library. | |
| late final LibraryEntity? foreignLibrary = _env.lookupLibrary( | |
| Uris.dartForeignHelper, | |
| ); | |
| /// The dart:_rti library. | |
| late final LibraryEntity rtiLibrary = _env.lookupLibrary( | |
| Uris.dartRti, | |
| required: true, | |
| )!; | |
| /// The dart:_internal library. | |
| late final LibraryEntity internalLibrary = _env.lookupLibrary( | |
| Uris.dartInternal, | |
| required: true, | |
| )!; | |
| /// The dart:js_util library. | |
| late final LibraryEntity? dartJsUtilLibrary = _env.lookupLibrary( | |
| Uris.dartJSUtil, | |
| ); | |
| /// The package:js library. | |
| late final LibraryEntity? packageJsLibrary = _env.lookupLibrary( | |
| Uris.packageJS, | |
| ); | |
| /// The dart:_js_annotations library. | |
| late final LibraryEntity? dartJsAnnotationsLibrary = _env.lookupLibrary( | |
| Uris.dartJSAnnotations, | |
| ); | |
| /// The dart:js_interop library. | |
| late final LibraryEntity? dartJsInteropLibrary = _env.lookupLibrary( | |
| Uris.dartJSInterop, | |
| ); | |
| /// The `NativeTypedData` class from dart:typed_data. | |
| ClassEntity get typedDataClass => | |
| _findClass(typedDataLibrary, 'NativeTypedData'); | |
| /// Constructor of the `Symbol` class in dart:internal. | |
| /// | |
| /// This getter will ensure that `Symbol` is resolved and lookup the | |
| /// constructor on demand. | |
| ConstructorEntity get symbolConstructorTarget { | |
| // TODO(johnniwinther): Kernel does not include redirecting factories | |
| // so this cannot be found in kernel. Find a consistent way to handle | |
| // this and similar cases. | |
| return _symbolConstructorTarget ??= _env.lookupConstructor( | |
| symbolImplementationClass, | |
| '', | |
| )!; | |
| } | |
| void _ensureSymbolConstructorDependencies() { | |
| if (_computedSymbolConstructorDependencies) return; | |
| _computedSymbolConstructorDependencies = true; | |
| if (_symbolConstructorTarget == null) { | |
| _symbolImplementationClass ??= _findClassOrNull( | |
| internalLibrary, | |
| 'Symbol', | |
| ); | |
| if (_symbolImplementationClass != null) { | |
| _symbolConstructorTarget = _env.lookupConstructor( | |
| _symbolImplementationClass!, | |
| '', | |
| required: false, | |
| ); | |
| } | |
| } | |
| _symbolClass ??= _findClassOrNull(coreLibrary, 'Symbol'); | |
| if (_symbolClass == null) { | |
| return; | |
| } | |
| _symbolConstructorImplementationTarget = _env.lookupConstructor( | |
| symbolClass, | |
| '', | |
| required: false, | |
| ); | |
| } | |
| /// Whether [element] is the same as [symbolConstructor]. | |
| /// | |
| /// Used to check for the constructor without computing it until it is likely | |
| /// to be seen. | |
| bool isSymbolConstructor(ConstructorEntity element) { | |
| _ensureSymbolConstructorDependencies(); | |
| return element == _symbolConstructorImplementationTarget || | |
| element == _symbolConstructorTarget; | |
| } | |
| /// The function `identical` in dart:core. | |
| late final FunctionEntity identicalFunction = _findLibraryMember( | |
| coreLibrary, | |
| 'identical', | |
| )!; | |
| /// Whether [element] is the `Function.apply` method. | |
| /// | |
| /// This will not resolve the apply method if it hasn't been seen yet during | |
| /// compilation. | |
| bool isFunctionApplyMethod(MemberEntity element) => | |
| element.name == 'apply' && element.enclosingClass == functionClass; | |
| /// The `dynamic` type. | |
| DynamicType get dynamicType => _env.dynamicType as DynamicType; | |
| /// The `Object` type defined in 'dart:core'. | |
| InterfaceType get objectType => _getRawType(objectClass); | |
| /// The `bool` type defined in 'dart:core'. | |
| InterfaceType get boolType => _getRawType(boolClass); | |
| /// The `num` type defined in 'dart:core'. | |
| InterfaceType get numType => _getRawType(numClass); | |
| /// The `int` type defined in 'dart:core'. | |
| InterfaceType get intType => _getRawType(intClass); | |
| /// The `double` type defined in 'dart:core'. | |
| InterfaceType get doubleType => _getRawType(doubleClass); | |
| /// The `String` type defined in 'dart:core'. | |
| InterfaceType get stringType => _getRawType(stringClass); | |
| /// The `Symbol` type defined in 'dart:core'. | |
| InterfaceType get symbolType => _getRawType(symbolClass); | |
| /// The `Function` type defined in 'dart:core'. | |
| InterfaceType get functionType => _getRawType(functionClass); | |
| /// The `Null` type defined in 'dart:core'. | |
| InterfaceType get nullType => _getRawType(nullClass); | |
| /// The `Record` type defined in 'dart:core'. | |
| InterfaceType get recordType => _getRawType(recordClass); | |
| /// The `Type` type defined in 'dart:core'. | |
| InterfaceType get typeType => _getRawType(typeClass); | |
| InterfaceType get typeLiteralType => _getRawType(typeLiteralClass); | |
| /// The `StackTrace` type defined in 'dart:core'; | |
| InterfaceType get stackTraceType => _getRawType(stackTraceClass); | |
| /// Returns an instance of the `List` type defined in 'dart:core' with | |
| /// [elementType] as its type argument. | |
| /// | |
| /// If no type argument is provided, the canonical raw type is returned. | |
| InterfaceType listType([DartType? elementType]) { | |
| if (elementType == null) { | |
| return _getRawType(listClass); | |
| } | |
| return _createInterfaceType(listClass, [elementType]); | |
| } | |
| /// Returns an instance of the `Set` type defined in 'dart:core' with | |
| /// [elementType] as its type argument. | |
| /// | |
| /// If no type argument is provided, the canonical raw type is returned. | |
| InterfaceType setType([DartType? elementType]) { | |
| if (elementType == null) { | |
| return _getRawType(setClass); | |
| } | |
| return _createInterfaceType(setClass, [elementType]); | |
| } | |
| /// Returns an instance of the `Map` type defined in 'dart:core' with | |
| /// [keyType] and [valueType] as its type arguments. | |
| /// | |
| /// If no type arguments are provided, the canonical raw type is returned. | |
| InterfaceType mapType([DartType? keyType, DartType? valueType]) { | |
| if (keyType == null && valueType == null) { | |
| return _getRawType(mapClass); | |
| } else if (keyType == null) { | |
| keyType = dynamicType; | |
| } else { | |
| valueType ??= dynamicType; | |
| } | |
| return _createInterfaceType(mapClass, [keyType, valueType!]); | |
| } | |
| /// Returns an instance of the `Iterable` type defined in 'dart:core' with | |
| /// [elementType] as its type argument. | |
| /// | |
| /// If no type argument is provided, the canonical raw type is returned. | |
| InterfaceType iterableType([DartType? elementType]) { | |
| if (elementType == null) { | |
| return _getRawType(iterableClass); | |
| } | |
| return _createInterfaceType(iterableClass, [elementType]); | |
| } | |
| /// Returns an instance of the `Future` type defined in 'dart:async' with | |
| /// [elementType] as its type argument. | |
| /// | |
| /// If no type argument is provided, the canonical raw type is returned. | |
| // CommonElementsForDartTypes | |
| InterfaceType futureType([DartType? elementType]) { | |
| if (elementType == null) { | |
| return _getRawType(futureClass); | |
| } | |
| return _createInterfaceType(futureClass, [elementType]); | |
| } | |
| /// Returns an instance of the `Stream` type defined in 'dart:async' with | |
| /// [elementType] as its type argument. | |
| /// | |
| /// If no type argument is provided, the canonical raw type is returned. | |
| InterfaceType streamType([DartType? elementType]) { | |
| if (elementType == null) { | |
| return _getRawType(streamClass); | |
| } | |
| return _createInterfaceType(streamClass, [elementType]); | |
| } | |
| ClassEntity _findClass(LibraryEntity? library, String name) { | |
| return _env.lookupClass(library!, name, required: true)!; | |
| } | |
| ClassEntity? _findClassOrNull(LibraryEntity? library, String name) { | |
| if (library == null) return null; | |
| return _env.lookupClass(library, name, required: false); | |
| } | |
| T? _findLibraryMember<T extends MemberEntity>( | |
| LibraryEntity? library, | |
| String name, { | |
| bool setter = false, | |
| bool required = true, | |
| }) { | |
| if (library == null) return null; | |
| return _env.lookupLibraryMember( | |
| library, | |
| name, | |
| setter: setter, | |
| required: required, | |
| ) as T?; | |
| } | |
| T? _findClassMemberOrNull<T extends MemberEntity>( | |
| ClassEntity cls, | |
| String name, | |
| ) { | |
| return _env.lookupLocalClassMember( | |
| cls, | |
| Name(name, cls.library.canonicalUri, isSetter: false), | |
| required: false, | |
| ) as T?; | |
| } | |
| T _findClassMember<T extends MemberEntity>(ClassEntity cls, String name) { | |
| return _env.lookupLocalClassMember( | |
| cls, | |
| Name(name, cls.library.canonicalUri, isSetter: false), | |
| required: true, | |
| ) as T; | |
| } | |
| /// Return the raw type of [cls]. | |
| InterfaceType _getRawType(ClassEntity cls) { | |
| return _env.getRawType(cls); | |
| } | |
| /// Create the instantiation of [cls] with the given [typeArguments] and | |
| /// [nullability]. | |
| InterfaceType _createInterfaceType( | |
| ClassEntity cls, | |
| List<DartType> typeArguments, | |
| ) { | |
| return _env.createInterfaceType(cls, typeArguments); | |
| } | |
| InterfaceType getConstantListTypeFor(InterfaceType sourceType) { | |
| // TODO(51534): Use CONST_CANONICAL_TYPE(T_i) for arguments. | |
| return _env.createInterfaceType(jsArrayClass, sourceType.typeArguments); | |
| } | |
| InterfaceType getConstantMapTypeFor( | |
| InterfaceType sourceType, { | |
| bool onlyStringKeys = false, | |
| }) { | |
| // TODO(51534): Use CONST_CANONICAL_TYPE(T_i) for arguments. | |
| ClassEntity classElement = onlyStringKeys | |
| ? constantStringMapClass | |
| : generalConstantMapClass; | |
| return _env.createInterfaceType(classElement, sourceType.typeArguments); | |
| } | |
| InterfaceType getConstantSetTypeFor( | |
| InterfaceType sourceType, { | |
| bool onlyStringKeys = false, | |
| }) { | |
| // TODO(51534): Use CONST_CANONICAL_TYPE(T_i) for arguments. | |
| ClassEntity classElement = onlyStringKeys | |
| ? constantStringSetClass | |
| : generalConstantSetClass; | |
| return _env.createInterfaceType(classElement, sourceType.typeArguments); | |
| } | |
| /// Returns the field that holds the internal name in the implementation class | |
| /// for `Symbol`. | |
| FieldEntity get symbolField => | |
| _symbolImplementationField ??= _env.lookupLocalClassMember( | |
| symbolImplementationClass, | |
| PrivateName('_name', symbolImplementationClass.library.canonicalUri), | |
| required: true, | |
| ) as FieldEntity; | |
| InterfaceType get symbolImplementationType => | |
| _env.getRawType(symbolImplementationClass); | |
| // From dart:core | |
| ClassEntity get mapLiteralClass { | |
| if (_mapLiteralClass == null) { | |
| _mapLiteralClass = _env.lookupClass(coreLibrary, 'LinkedHashMap'); | |
| _mapLiteralClass ??= _findClass(collectionLibrary, 'LinkedHashMap'); | |
| } | |
| return _mapLiteralClass!; | |
| } | |
| late final ConstructorEntity mapLiteralConstructor = _env.lookupConstructor( | |
| mapLiteralClass, | |
| '_literal', | |
| )!; | |
| late final ConstructorEntity mapLiteralConstructorEmpty = _env | |
| .lookupConstructor(mapLiteralClass, '_empty')!; | |
| late final ClassEntity setLiteralClass = _findClass( | |
| collectionLibrary, | |
| 'LinkedHashSet', | |
| ); | |
| late final ConstructorEntity setLiteralConstructor = _env.lookupConstructor( | |
| setLiteralClass, | |
| '_literal', | |
| )!; | |
| late final ConstructorEntity setLiteralConstructorEmpty = _env | |
| .lookupConstructor(setLiteralClass, '_empty')!; | |
| late final FunctionEntity? objectNoSuchMethod = _env.lookupLocalClassMember( | |
| objectClass, | |
| const PublicName(Identifiers.noSuchMethod_), | |
| ) as FunctionEntity?; | |
| bool isDefaultNoSuchMethodImplementation(FunctionEntity element) { | |
| ClassEntity? classElement = element.enclosingClass; | |
| return classElement == objectClass || | |
| classElement == jsInterceptorClass || | |
| classElement == jsNullClass; | |
| } | |
| // From dart:async | |
| ClassEntity _findAsyncHelperClass(String name) => | |
| _findClass(asyncLibrary, name); | |
| FunctionEntity _findAsyncHelperFunction(String name) => | |
| _findLibraryMember(asyncLibrary, name)!; | |
| FunctionEntity get asyncHelperStartSync => | |
| _findAsyncHelperFunction("_asyncStartSync"); | |
| FunctionEntity get asyncHelperAwait => | |
| _findAsyncHelperFunction("_asyncAwait"); | |
| FunctionEntity get asyncHelperReturn => | |
| _findAsyncHelperFunction("_asyncReturn"); | |
| FunctionEntity get asyncHelperRethrow => | |
| _findAsyncHelperFunction("_asyncRethrow"); | |
| FunctionEntity get wrapBody => | |
| _findAsyncHelperFunction("_wrapJsFunctionForAsync"); | |
| FunctionEntity get yieldStar => _env.lookupLocalClassMember( | |
| _findAsyncHelperClass("_IterationMarker"), | |
| const PublicName("yieldStar"), | |
| ) as FunctionEntity; | |
| FunctionEntity get yieldSingle => _env.lookupLocalClassMember( | |
| _findAsyncHelperClass("_IterationMarker"), | |
| const PublicName("yieldSingle"), | |
| ) as FunctionEntity; | |
| FunctionEntity get syncStarUncaughtError => _env.lookupLocalClassMember( | |
| _findAsyncHelperClass("_IterationMarker"), | |
| const PublicName("uncaughtError"), | |
| ) as FunctionEntity; | |
| FunctionEntity get asyncStarHelper => | |
| _findAsyncHelperFunction("_asyncStarHelper"); | |
| FunctionEntity get streamOfController => | |
| _findAsyncHelperFunction("_streamOfController"); | |
| FunctionEntity get endOfIteration => _env.lookupLocalClassMember( | |
| _findAsyncHelperClass("_IterationMarker"), | |
| const PublicName("endOfIteration"), | |
| ) as FunctionEntity; | |
| ClassEntity get syncStarIterable => | |
| _findAsyncHelperClass("_SyncStarIterable"); | |
| late final ClassEntity _syncStarIteratorClass = _findAsyncHelperClass( | |
| '_SyncStarIterator', | |
| ); | |
| late final FieldEntity syncStarIteratorCurrentField = _findClassMember( | |
| _syncStarIteratorClass, | |
| '_current', | |
| ); | |
| late final FieldEntity syncStarIteratorDatumField = _findClassMember( | |
| _syncStarIteratorClass, | |
| '_datum', | |
| ); | |
| late final FunctionEntity syncStarIteratorYieldStarMethod = _findClassMember( | |
| _syncStarIteratorClass, | |
| '_yieldStar', | |
| ); | |
| ClassEntity get futureImplementation => _findAsyncHelperClass('_Future'); | |
| ClassEntity get controllerStream => | |
| _findAsyncHelperClass("_ControllerStream"); | |
| ClassEntity get streamIterator => _findAsyncHelperClass("StreamIterator"); | |
| ConstructorEntity get streamIteratorConstructor => | |
| _env.lookupConstructor(streamIterator, "")!; | |
| late final FunctionEntity syncStarIterableFactory = _findAsyncHelperFunction( | |
| '_makeSyncStarIterable', | |
| ); | |
| late final FunctionEntity asyncAwaitCompleterFactory = | |
| _findAsyncHelperFunction('_makeAsyncAwaitCompleter'); | |
| late final FunctionEntity asyncStarStreamControllerFactory = | |
| _findAsyncHelperFunction('_makeAsyncStarStreamController'); | |
| // From dart:_interceptors | |
| ClassEntity _findInterceptorsClass(String name) => | |
| _findClass(interceptorsLibrary, name); | |
| FunctionEntity _findInterceptorsFunction(String name) => | |
| _findLibraryMember(interceptorsLibrary, name)!; | |
| late final ClassEntity jsInterceptorClass = _findInterceptorsClass( | |
| 'Interceptor', | |
| ); | |
| late final ClassEntity jsStringClass = _findInterceptorsClass('JSString'); | |
| late final ClassEntity jsArrayClass = _findInterceptorsClass('JSArray'); | |
| late final ClassEntity jsNumberClass = _findInterceptorsClass('JSNumber'); | |
| late final ClassEntity jsIntClass = _findInterceptorsClass('JSInt'); | |
| late final ClassEntity jsNumNotIntClass = _findInterceptorsClass( | |
| 'JSNumNotInt', | |
| ); | |
| late final ClassEntity jsNullClass = _findInterceptorsClass('JSNull'); | |
| late final ClassEntity jsBoolClass = _findInterceptorsClass('JSBool'); | |
| late final ClassEntity jsPlainJavaScriptObjectClass = _findInterceptorsClass( | |
| 'PlainJavaScriptObject', | |
| ); | |
| late final ClassEntity jsUnknownJavaScriptObjectClass = | |
| _findInterceptorsClass('UnknownJavaScriptObject'); | |
| late final ClassEntity jsJavaScriptBigIntClass = _findInterceptorsClass( | |
| 'JavaScriptBigInt', | |
| ); | |
| late final ClassEntity jsJavaScriptFunctionClass = _findInterceptorsClass( | |
| 'JavaScriptFunction', | |
| ); | |
| late final ClassEntity jsJavaScriptSymbolClass = _findInterceptorsClass( | |
| 'JavaScriptSymbol', | |
| ); | |
| InterfaceType get jsJavaScriptFunctionType => | |
| _getRawType(jsJavaScriptFunctionClass); | |
| late final ClassEntity jsLegacyJavaScriptObjectClass = _findInterceptorsClass( | |
| 'LegacyJavaScriptObject', | |
| ); | |
| late final ClassEntity jsJavaScriptObjectClass = _findInterceptorsClass( | |
| 'JavaScriptObject', | |
| ); | |
| InterfaceType get jsJavaScriptObjectType => | |
| _getRawType(jsJavaScriptObjectClass); | |
| late final ClassEntity jsIndexableClass = _findInterceptorsClass( | |
| 'JSIndexable', | |
| ); | |
| late final ClassEntity jsMutableIndexableClass = _findInterceptorsClass( | |
| 'JSMutableIndexable', | |
| ); | |
| late final ClassEntity jsMutableArrayClass = _findInterceptorsClass( | |
| 'JSMutableArray', | |
| ); | |
| late final ClassEntity jsFixedArrayClass = _findInterceptorsClass( | |
| 'JSFixedArray', | |
| ); | |
| late final ClassEntity jsExtendableArrayClass = _findInterceptorsClass( | |
| 'JSExtendableArray', | |
| ); | |
| late final ClassEntity jsUnmodifiableArrayClass = _findInterceptorsClass( | |
| 'JSUnmodifiableArray', | |
| ); | |
| late final ClassEntity jsPositiveIntClass = _findInterceptorsClass( | |
| 'JSPositiveInt', | |
| ); | |
| late final ClassEntity jsUInt32Class = _findInterceptorsClass('JSUInt32'); | |
| late final ClassEntity jsUInt31Class = _findInterceptorsClass('JSUInt31'); | |
| // Static interop JavaScript object interface class. | |
| late final ClassEntity jsObjectClass = _findInterceptorsClass('JSObject'); | |
| /// Returns `true` member is the 'findIndexForNativeSubclassType' method | |
| /// declared in `dart:_interceptors`. | |
| bool isFindIndexForNativeSubclassType(MemberEntity member) { | |
| return member.name == 'findIndexForNativeSubclassType' && | |
| member.isTopLevel && | |
| member.library == interceptorsLibrary; | |
| } | |
| late final FunctionEntity getNativeInterceptorMethod = | |
| _findInterceptorsFunction('getNativeInterceptor'); | |
| late final ConstructorEntity jsArrayTypedConstructor = _env.lookupConstructor( | |
| jsArrayClass, | |
| 'typed', | |
| )!; | |
| // From dart:_js_helper | |
| // TODO(johnniwinther): Avoid the need for this (from [CheckedModeHelper]). | |
| FunctionEntity findHelperFunction(String name) => _findHelperFunction(name); | |
| FunctionEntity _findHelperFunction(String name) => | |
| _findLibraryMember(jsHelperLibrary, name)!; | |
| ClassEntity _findHelperClass(String name) => | |
| _findClass(jsHelperLibrary, name); | |
| FunctionEntity _findLateHelperFunction(String name) => | |
| _findLibraryMember(lateHelperLibrary, name)!; | |
| late final ClassEntity closureClass = _findHelperClass('Closure'); | |
| late final ClassEntity closureClass0Args = _findHelperClass('Closure0Args'); | |
| late final ClassEntity closureClass2Args = _findHelperClass('Closure2Args'); | |
| late final ClassEntity boundClosureClass = _findHelperClass('BoundClosure'); | |
| late final ClassEntity typeLiteralClass = _findRtiClass('_Type'); | |
| late final ClassEntity constMapLiteralClass = _findHelperClass('ConstantMap'); | |
| late final ClassEntity constSetLiteralClass = _findHelperClass('ConstantSet'); | |
| /// Base class for all records. | |
| late final ClassEntity recordBaseClass = _findHelperClass('_Record'); | |
| /// A function that is used to model the back-end impacts of record lowering | |
| /// in the front-end. | |
| late final FunctionEntity recordImpactModel = _findHelperFunction( | |
| '_recordImpactModel', | |
| ); | |
| /// Base class for records with N fields. Can be a fixed-arity class or a | |
| /// general class that works for any arity. | |
| ClassEntity recordArityClass(int n) { | |
| return _findClassOrNull(jsHelperLibrary, '_Record$n') ?? | |
| (n == 0 ? emptyRecordClass : recordGeneralBaseClass); | |
| } | |
| late final ClassEntity recordGeneralBaseClass = _findHelperClass('_RecordN'); | |
| late final ClassEntity emptyRecordClass = _findHelperClass('_EmptyRecord'); | |
| late final FunctionEntity recordTestByListHelper = _findHelperFunction( | |
| '_testRecordValues', | |
| ); | |
| late final ClassEntity jsInvocationMirrorClass = _findHelperClass( | |
| 'JSInvocationMirror', | |
| ); | |
| late final ClassEntity requiredSentinelClass = _findHelperClass('_Required'); | |
| InterfaceType get requiredSentinelType => _getRawType(requiredSentinelClass); | |
| late final MemberEntity invocationTypeArgumentGetter = _findClassMember( | |
| jsInvocationMirrorClass, | |
| 'typeArguments', | |
| ); | |
| /// Interface used to determine if an object has the JavaScript | |
| /// indexing behavior. The interface is only visible to specific libraries. | |
| late final ClassEntity jsIndexingBehaviorInterface = _findHelperClass( | |
| 'JavaScriptIndexingBehavior', | |
| ); | |
| late final ClassEntity stackTraceHelperClass = _findHelperClass( | |
| '_StackTrace', | |
| ); | |
| late final ClassEntity constantMapClass = _findHelperClass( | |
| constant_system.JavaScriptMapConstant.dartClass, | |
| ); | |
| late final ClassEntity constantStringMapClass = _findHelperClass( | |
| constant_system.JavaScriptMapConstant.dartStringClass, | |
| ); | |
| late final ClassEntity generalConstantMapClass = _findHelperClass( | |
| constant_system.JavaScriptMapConstant.dartGeneralClass, | |
| ); | |
| late final ClassEntity constantStringSetClass = _findHelperClass( | |
| constant_system.JavaScriptSetConstant.dartStringClass, | |
| ); | |
| late final ClassEntity generalConstantSetClass = _findHelperClass( | |
| constant_system.JavaScriptSetConstant.dartGeneralClass, | |
| ); | |
| late final ClassEntity annotationCreatesClass = _findHelperClass('Creates'); | |
| late final ClassEntity annotationReturnsClass = _findHelperClass('Returns'); | |
| late final ClassEntity annotationJSNameClass = _findHelperClass('JSName'); | |
| /// The class for native annotations defined in dart:_js_helper. | |
| late final ClassEntity nativeAnnotationClass = _findHelperClass('Native'); | |
| bool isAssertTest(MemberEntity member) => | |
| member.name == 'assertTest' && | |
| member.isFunction && | |
| member.isTopLevel && | |
| member.library == jsHelperLibrary; | |
| late final assertTest = _findHelperFunction('assertTest'); | |
| late final assertThrow = _findHelperFunction('assertThrow'); | |
| bool isAssertHelper(MemberEntity member) => | |
| member.name == 'assertHelper' && | |
| member.isFunction && | |
| member.isTopLevel && | |
| member.library == jsHelperLibrary; | |
| late final assertHelper = _findHelperFunction('assertHelper'); | |
| late final assertUnreachableMethod = _findHelperFunction('assertUnreachable'); | |
| /// Holds the method "getIsolateAffinityTag" when dart:_js_helper has been | |
| /// loaded. | |
| late final getIsolateAffinityTagMarker = _findHelperFunction( | |
| 'getIsolateAffinityTag', | |
| ); | |
| /// Holds the method "requiresPreamble" in _js_helper. | |
| late final requiresPreambleMarker = _findHelperFunction('requiresPreamble'); | |
| /// Holds the method "_rawStartupMetrics" in _js_helper. | |
| late final rawStartupMetrics = _findHelperFunction('rawStartupMetrics'); | |
| FunctionEntity get loadDeferredLibrary => | |
| _findHelperFunction("loadDeferredLibrary"); | |
| FunctionEntity get traceHelper => _findHelperFunction('traceHelper'); | |
| FunctionEntity get closureFromTearOff => | |
| _findHelperFunction('closureFromTearOff'); | |
| FunctionEntity get isJsIndexable => _findHelperFunction('isJsIndexable'); | |
| FunctionEntity get throwIllegalArgumentException => | |
| _findHelperFunction('iae'); | |
| FunctionEntity get throwIndexOutOfRangeException => | |
| _findHelperFunction('ioore'); | |
| FunctionEntity get exceptionUnwrapper => | |
| _findHelperFunction('unwrapException'); | |
| FunctionEntity get throwUnsupportedError => | |
| _findHelperFunction('throwUnsupportedError'); | |
| FunctionEntity get throwTypeError => _findRtiFunction('throwTypeError'); | |
| /// Recognizes the `checkConcurrentModificationError` helper without needing | |
| /// it to be resolved. | |
| bool isCheckConcurrentModificationError(MemberEntity member) { | |
| return member.name == 'checkConcurrentModificationError' && | |
| member.isFunction && | |
| member.isTopLevel && | |
| member.library == jsHelperLibrary; | |
| } | |
| late final FunctionEntity checkConcurrentModificationError = | |
| _findHelperFunction('checkConcurrentModificationError'); | |
| FunctionEntity get throwConcurrentModificationError => | |
| _findHelperFunction('throwConcurrentModificationError'); | |
| FunctionEntity get stringInterpolationHelper => _findHelperFunction('S'); | |
| FunctionEntity get initializeExceptionWrapper => | |
| _findHelperFunction('initializeExceptionWrapper'); | |
| FunctionEntity get wrapExceptionHelper => | |
| _findHelperFunction('wrapException'); | |
| FunctionEntity get throwExpressionHelper => | |
| _findHelperFunction('throwExpression'); | |
| FunctionEntity get closureConverter => | |
| _findHelperFunction('convertDartClosureToJS'); | |
| FunctionEntity get traceFromException => | |
| _findHelperFunction('getTraceFromException'); | |
| FunctionEntity get checkDeferredIsLoaded => | |
| _findHelperFunction('checkDeferredIsLoaded'); | |
| FunctionEntity get createRuntimeType => _findRtiFunction('createRuntimeType'); | |
| FunctionEntity get createInvocationMirror => | |
| _findHelperFunction('createInvocationMirror'); | |
| FunctionEntity get createUnmangledInvocationMirror => | |
| _findHelperFunction('createUnmangledInvocationMirror'); | |
| FunctionEntity get throwUnsupportedOperation => | |
| _findHelperFunction('throwUnsupportedOperation'); | |
| FunctionEntity get defineProperty => _findHelperFunction('defineProperty'); | |
| FunctionEntity get throwLateFieldNI => | |
| _findLateHelperFunction('throwLateFieldNI'); | |
| FunctionEntity get throwLateFieldAI => | |
| _findLateHelperFunction('throwLateFieldAI'); | |
| FunctionEntity get throwLateFieldADI => | |
| _findLateHelperFunction('throwLateFieldADI'); | |
| FunctionEntity get throwUnnamedLateFieldNI => | |
| _findLateHelperFunction('throwUnnamedLateFieldNI'); | |
| FunctionEntity get throwUnnamedLateFieldAI => | |
| _findLateHelperFunction('throwUnnamedLateFieldAI'); | |
| FunctionEntity get throwUnnamedLateFieldADI => | |
| _findLateHelperFunction('throwUnnamedLateFieldADI'); | |
| bool isExtractTypeArguments(FunctionEntity member) { | |
| return member.name == 'extractTypeArguments' && | |
| member.library == internalLibrary; | |
| } | |
| // TODO(johnniwinther,sra): Support arbitrary type argument count. | |
| void _checkTypeArgumentCount(int typeArgumentCount) { | |
| assert(typeArgumentCount > 0); | |
| if (typeArgumentCount > 20) { | |
| failedAt( | |
| noLocationSpannable, | |
| "Unsupported instantiation argument count: " | |
| "$typeArgumentCount", | |
| ); | |
| } | |
| } | |
| ClassEntity getInstantiationClass(int typeArgumentCount) { | |
| _checkTypeArgumentCount(typeArgumentCount); | |
| return _findHelperClass('Instantiation$typeArgumentCount'); | |
| } | |
| FunctionEntity getInstantiateFunction(int typeArgumentCount) { | |
| _checkTypeArgumentCount(typeArgumentCount); | |
| return _findHelperFunction('instantiate$typeArgumentCount'); | |
| } | |
| FunctionEntity get convertMainArgumentList => | |
| _findHelperFunction('convertMainArgumentList'); | |
| // From dart:_rti | |
| ClassEntity _findRtiClass(String name) => _findClass(rtiLibrary, name); | |
| FunctionEntity _findRtiFunction(String name) => | |
| _findLibraryMember(rtiLibrary, name)!; | |
| late final FunctionEntity interopNullAssertion = _findRtiFunction( | |
| '_interopNullAssertion', | |
| ); | |
| late final FunctionEntity setArrayType = _findRtiFunction('_setArrayType'); | |
| late final FunctionEntity findType = _findRtiFunction('findType'); | |
| late final FunctionEntity instanceType = _findRtiFunction('instanceType'); | |
| late final FunctionEntity arrayInstanceType = _findRtiFunction( | |
| '_arrayInstanceType', | |
| ); | |
| late final FunctionEntity simpleInstanceType = _findRtiFunction( | |
| '_instanceType', | |
| ); | |
| late final FunctionEntity typeLiteralMaker = _findRtiFunction('typeLiteral'); | |
| late final FunctionEntity checkTypeBound = _findRtiFunction('checkTypeBound'); | |
| late final FunctionEntity pairwiseIsTest = _findRtiFunction('pairwiseIsTest'); | |
| ClassEntity get _rtiImplClass => _findRtiClass('Rti'); | |
| ClassEntity get _rtiUniverseClass => _findRtiClass('_Universe'); | |
| FieldEntity _findRtiClassField(String name) => | |
| _findClassMember(_rtiImplClass, name); | |
| late final FieldEntity rtiAsField = _findRtiClassField('_as'); | |
| late final FieldEntity rtiIsField = _findRtiClassField('_is'); | |
| late final FieldEntity rtiRestField = _findRtiClassField('_rest'); | |
| late final FieldEntity rtiPrecomputed1Field = _findRtiClassField( | |
| '_precomputed1', | |
| ); | |
| late final FunctionEntity rtiEvalMethod = _findClassMember( | |
| _rtiImplClass, | |
| '_eval', | |
| ); | |
| late final FunctionEntity rtiBindMethod = _findClassMember( | |
| _rtiImplClass, | |
| '_bind', | |
| ); | |
| late final FunctionEntity rtiAddRulesMethod = _findClassMember( | |
| _rtiUniverseClass, | |
| 'addRules', | |
| ); | |
| late final FunctionEntity rtiAddErasedTypesMethod = _findClassMember( | |
| _rtiUniverseClass, | |
| 'addErasedTypes', | |
| ); | |
| late final FunctionEntity rtiAddTypeParameterVariancesMethod = | |
| _findClassMember(_rtiUniverseClass, 'addTypeParameterVariances'); | |
| FunctionEntity get installSpecializedIsTest => | |
| _findRtiFunction('_installSpecializedIsTest'); | |
| FunctionEntity get installSpecializedAsCheck => | |
| _findRtiFunction('_installSpecializedAsCheck'); | |
| late final FunctionEntity generalIsTestImplementation = _findRtiFunction( | |
| '_generalIsTestImplementation', | |
| ); | |
| late final FunctionEntity generalNullableIsTestImplementation = | |
| _findRtiFunction('_generalNullableIsTestImplementation'); | |
| late final FunctionEntity generalAsCheckImplementation = _findRtiFunction( | |
| '_generalAsCheckImplementation', | |
| ); | |
| late final FunctionEntity generalNullableAsCheckImplementation = | |
| _findRtiFunction('_generalNullableAsCheckImplementation'); | |
| late final FunctionEntity specializedIsObject = _findRtiFunction('_isObject'); | |
| late final FunctionEntity specializedAsObject = _findRtiFunction('_asObject'); | |
| FunctionEntity get specializedIsTop => _findRtiFunction('_isTop'); | |
| FunctionEntity get specializedAsTop => _findRtiFunction('_asTop'); | |
| FunctionEntity get specializedIsBool => _findRtiFunction('_isBool'); | |
| FunctionEntity get specializedAsBool => _findRtiFunction('_asBool'); | |
| FunctionEntity get specializedAsBoolNullable => _findRtiFunction('_asBoolQ'); | |
| FunctionEntity get specializedAsDouble => _findRtiFunction('_asDouble'); | |
| FunctionEntity get specializedAsDoubleNullable => | |
| _findRtiFunction('_asDoubleQ'); | |
| FunctionEntity get specializedIsInt => _findRtiFunction('_isInt'); | |
| FunctionEntity get specializedAsInt => _findRtiFunction('_asInt'); | |
| FunctionEntity get specializedAsIntNullable => _findRtiFunction('_asIntQ'); | |
| FunctionEntity get specializedIsNum => _findRtiFunction('_isNum'); | |
| FunctionEntity get specializedAsNum => _findRtiFunction('_asNum'); | |
| FunctionEntity get specializedAsNumNullable => _findRtiFunction('_asNumQ'); | |
| FunctionEntity get specializedIsString => _findRtiFunction('_isString'); | |
| FunctionEntity get specializedAsString => _findRtiFunction('_asString'); | |
| FunctionEntity get specializedAsStringNullable => | |
| _findRtiFunction('_asStringQ'); | |
| FunctionEntity get specializedAsJSObject => _findRtiFunction('_asJSObject'); | |
| FunctionEntity get specializedAsJSObjectNullable => | |
| _findRtiFunction('_asJSObjectQ'); | |
| FunctionEntity get instantiatedGenericFunctionType => | |
| _findRtiFunction('instantiatedGenericFunctionType'); | |
| FunctionEntity get closureFunctionType => | |
| _findRtiFunction('closureFunctionType'); | |
| // From dart:_internal | |
| late final ClassEntity symbolImplementationClass = _findClass( | |
| internalLibrary, | |
| 'Symbol', | |
| ); | |
| /// Used to annotate items that have the keyword "native". | |
| late final ClassEntity externalNameClass = _findClass( | |
| internalLibrary, | |
| 'ExternalName', | |
| ); | |
| InterfaceType get externalNameType => _getRawType(externalNameClass); | |
| // From dart:_js_embedded_names | |
| late final ClassEntity jsGetNameEnum = _findClass( | |
| sharedEmbeddedNamesLibrary, | |
| 'JsGetName', | |
| ); | |
| /// Returns `true` if [member] is a "foreign helper", that is, a member whose | |
| /// semantics is defined synthetically and not through Dart code. | |
| /// | |
| /// Most foreign helpers are located in the `dart:_foreign_helper` library. | |
| bool isForeignHelper(MemberEntity member) { | |
| return member.library == foreignLibrary || | |
| isLateReadCheck(member) || | |
| isLateWriteOnceCheck(member) || | |
| isLateInitializeOnceCheck(member) || | |
| isCreateInvocationMirrorHelper(member); | |
| } | |
| bool _isTopLevelFunctionNamed(String name, MemberEntity member) => | |
| member.name == name && member.isFunction && member.isTopLevel; | |
| /// Returns `true` if [member] is the `createJsSentinel` function defined in | |
| /// dart:_foreign_helper. | |
| bool isCreateJsSentinel(MemberEntity member) => | |
| member.library == foreignLibrary && | |
| _isTopLevelFunctionNamed('createJsSentinel', member); | |
| /// Returns `true` if [member] is the `isJsSentinel` function defined in | |
| /// dart:_foreign_helper. | |
| bool isIsJsSentinel(MemberEntity member) => | |
| member.library == foreignLibrary && | |
| _isTopLevelFunctionNamed('isJsSentinel', member); | |
| /// Returns `true` if [member] is the `_lateReadCheck` function defined in | |
| /// dart:_late_helper. | |
| bool isLateReadCheck(MemberEntity member) => | |
| member.library == lateHelperLibrary && | |
| _isTopLevelFunctionNamed('_lateReadCheck', member); | |
| /// Returns `true` if [member] is the `_lateWriteOnceCheck` function defined | |
| /// in dart:_late_helper. | |
| bool isLateWriteOnceCheck(MemberEntity member) => | |
| member.library == lateHelperLibrary && | |
| _isTopLevelFunctionNamed('_lateWriteOnceCheck', member); | |
| /// Returns `true` if [member] is the `_lateInitializeOnceCheck` function | |
| /// defined in dart:_late_helper. | |
| bool isLateInitializeOnceCheck(MemberEntity member) => | |
| member.library == lateHelperLibrary && | |
| _isTopLevelFunctionNamed('_lateInitializeOnceCheck', member); | |
| /// Returns `true` if [member] is the `createSentinel` function defined in | |
| /// dart:_internal. | |
| bool isCreateSentinel(MemberEntity member) => | |
| member.library == internalLibrary && | |
| _isTopLevelFunctionNamed('createSentinel', member); | |
| /// Returns `true` if [member] is the `isSentinel` function defined in | |
| /// dart:_internal. | |
| bool isIsSentinel(MemberEntity member) => | |
| member.library == internalLibrary && | |
| _isTopLevelFunctionNamed('isSentinel', member); | |
| /// Returns `true` if [member] is the `allowInterop` function defined in | |
| /// dart:js_util. | |
| bool isAllowInterop(MemberEntity member) => | |
| member.library == dartJsUtilLibrary && | |
| _isTopLevelFunctionNamed('allowInterop', member); | |
| ClassEntity getDefaultSuperclass( | |
| ClassEntity cls, | |
| NativeBasicData nativeBasicData, | |
| ) { | |
| final defaultedClass = defaultReceiverClass(this, nativeBasicData, cls); | |
| if (defaultedClass != cls) return defaultedClass; | |
| // Native classes inherit from Interceptor. | |
| return nativeBasicData.isNativeClass(cls) | |
| ? jsInterceptorClass | |
| : objectClass; | |
| } | |
| // From dart:js_util | |
| late final FunctionEntity? jsAllowInterop = _findLibraryMember( | |
| dartJsUtilLibrary, | |
| 'allowInterop', | |
| required: false, | |
| ); | |
| bool isCreateInvocationMirrorHelper(MemberEntity member) { | |
| return member.isTopLevel && | |
| member.name == '_createInvocationMirror' && | |
| member.library == coreLibrary; | |
| } | |
| } | |
| class KCommonElements extends CommonElements { | |
| KCommonElements(super.dartTypes, super.env); | |
| // From dart:js_interop | |
| late final ClassEntity? jsAnnotationClass1 = _findClassOrNull( | |
| dartJsInteropLibrary, | |
| 'JS', | |
| ); | |
| late final ClassEntity? jsAnonymousClass1 = _findClassOrNull( | |
| dartJsInteropLibrary, | |
| '_Anonymous', | |
| ); | |
| // From package:js | |
| late final ClassEntity? jsAnnotationClass2 = _findClassOrNull( | |
| packageJsLibrary, | |
| 'JS', | |
| ); | |
| late final ClassEntity? jsAnonymousClass2 = _findClassOrNull( | |
| packageJsLibrary, | |
| '_Anonymous', | |
| ); | |
| // From dart:_js_annotations | |
| late final ClassEntity? jsAnnotationClass3 = _findClassOrNull( | |
| dartJsAnnotationsLibrary, | |
| 'JS', | |
| ); | |
| /// Returns `true` if [cls] is a @JS() annotation. | |
| /// | |
| /// The class can come from either `package:js`, `dart:_js_annotations`, or | |
| /// `dart:js_interop`. | |
| bool isJsAnnotationClass(ClassEntity cls) { | |
| return cls == jsAnnotationClass1 || | |
| cls == jsAnnotationClass2 || | |
| cls == jsAnnotationClass3; | |
| } | |
| /// Returns `true` if [cls] is an @anonymous annotation. | |
| /// | |
| /// The class can come from either `package:js` or `dart:_js_annotations`. | |
| bool isJsAnonymousClass(ClassEntity cls) { | |
| return cls == jsAnonymousClass1 || cls == jsAnonymousClass2; | |
| } | |
| late final ClassEntity pragmaClass = _findClass(coreLibrary, 'pragma'); | |
| late final FieldEntity pragmaClassNameField = _findClassMember( | |
| pragmaClass, | |
| 'name', | |
| ); | |
| late final FieldEntity pragmaClassOptionsField = _findClassMember( | |
| pragmaClass, | |
| 'options', | |
| ); | |
| } | |
| class JCommonElements extends CommonElements { | |
| JCommonElements(super.dartTypes, super.env); | |
| /// Returns `true` if [element] is the named constructor of `List`, | |
| /// e.g. `List.of`. | |
| /// | |
| /// This will not resolve the constructor if it hasn't been seen yet during | |
| /// compilation. | |
| bool isNamedListConstructor(String name, ConstructorEntity element) => | |
| element.name == name && element.enclosingClass == listClass; | |
| /// Returns `true` if [element] is the named constructor of `JSArray`, | |
| /// e.g. `JSArray.fixed`. | |
| /// | |
| /// This will not resolve the constructor if it hasn't been seen yet during | |
| /// compilation. | |
| bool isNamedJSArrayConstructor(String name, ConstructorEntity element) => | |
| element.name == name && element.enclosingClass == jsArrayClass; | |
| bool isDefaultEqualityImplementation(MemberEntity element) { | |
| assert(element.name == '=='); | |
| ClassEntity? classElement = element.enclosingClass; | |
| return classElement == objectClass || | |
| classElement == jsInterceptorClass || | |
| classElement == jsNullClass; | |
| } | |
| /// Returns `true` if [selector] applies to `JSIndexable.length`. | |
| bool appliesToJsIndexableLength(Selector selector) { | |
| return selector.name == 'length' && (selector.isGetter || selector.isCall); | |
| } | |
| late final FunctionEntity jsArrayRemoveLast = _findClassMember( | |
| jsArrayClass, | |
| 'removeLast', | |
| ); | |
| late final FunctionEntity jsArrayAdd = _findClassMember(jsArrayClass, 'add'); | |
| bool _isJsStringClass(ClassEntity cls) { | |
| return cls.name == 'JSString' && cls.library == interceptorsLibrary; | |
| } | |
| bool isJsStringSplit(MemberEntity member) { | |
| return member.name == 'split' && | |
| member.isInstanceMember && | |
| _isJsStringClass(member.enclosingClass!); | |
| } | |
| /// Returns `true` if [selector] applies to `JSString.split` on [receiver] | |
| /// in the given [world]. | |
| /// | |
| /// Returns `false` if `JSString.split` is not available (e.g. the | |
| /// method was tree-shaken in an earlier compilation phase). | |
| bool appliesToJsStringSplit( | |
| Selector selector, | |
| AbstractValue? receiver, | |
| AbstractValueDomain abstractValueDomain, | |
| ) { | |
| final splitMember = jsStringSplit; | |
| if (splitMember == null) return false; | |
| return selector.applies(splitMember) && | |
| (receiver == null || | |
| abstractValueDomain | |
| .isTargetingMember(receiver, splitMember, selector.memberName) | |
| .isPotentiallyTrue); | |
| } | |
| late final FunctionEntity? jsStringSplit = _findClassMemberOrNull( | |
| jsStringClass, | |
| 'split', | |
| ); | |
| late final FunctionEntity jsStringToString = _findClassMember( | |
| jsStringClass, | |
| 'toString', | |
| ); | |
| late final FunctionEntity jsStringOperatorAdd = _findClassMember( | |
| jsStringClass, | |
| '+', | |
| ); | |
| late final ClassEntity jsConstClass = _findClass(foreignLibrary, 'JS_CONST'); | |
| /// Return `true` if [member] is the 'checkInt' function defined in | |
| /// dart:_js_helpers. | |
| bool isCheckInt(MemberEntity member) { | |
| return member.isFunction && | |
| member.isTopLevel && | |
| member.library == jsHelperLibrary && | |
| member.name == 'checkInt'; | |
| } | |
| /// Return `true` if [member] is the 'checkNum' function defined in | |
| /// dart:_js_helpers. | |
| bool isCheckNum(MemberEntity member) { | |
| return member.isFunction && | |
| member.isTopLevel && | |
| member.library == jsHelperLibrary && | |
| member.name == 'checkNum'; | |
| } | |
| /// Return `true` if [member] is the 'checkString' function defined in | |
| /// dart:_js_helpers. | |
| bool isCheckString(MemberEntity member) { | |
| return member.isFunction && | |
| member.isTopLevel && | |
| member.library == jsHelperLibrary && | |
| member.name == 'checkString'; | |
| } | |
| bool isInstantiationClass(ClassEntity cls) { | |
| return cls.library == jsHelperLibrary && | |
| cls.name != 'Instantiation' && | |
| cls.name.startsWith('Instantiation'); | |
| } | |
| // From dart:_native_typed_data | |
| late final ClassEntity? typedArrayOfIntClass = _findClass( | |
| typedDataLibrary, | |
| 'NativeTypedArrayOfInt', | |
| ); | |
| late final ClassEntity typedArrayOfDoubleClass = _findClass( | |
| typedDataLibrary, | |
| 'NativeTypedArrayOfDouble', | |
| ); | |
| late final ClassEntity jsBuiltinEnum = _findClass( | |
| sharedEmbeddedNamesLibrary, | |
| 'JsBuiltin', | |
| ); | |
| bool isForeign(MemberEntity element) => element.library == foreignLibrary; | |
| /// Returns `true` if the implementation of the 'operator ==' [function] is | |
| /// known to handle `null` as argument. | |
| bool operatorEqHandlesNullArgument(FunctionEntity function) { | |
| assert( | |
| function.name == '==', | |
| failedAt(function, "Unexpected function $function."), | |
| ); | |
| ClassEntity? cls = function.enclosingClass; | |
| return cls == objectClass || | |
| cls == jsInterceptorClass || | |
| cls == jsNullClass; | |
| } | |
| } | |
| /// Interface for accessing libraries, classes and members. | |
| /// | |
| /// The element environment makes private and injected members directly | |
| /// available and should therefore not be used to determine scopes. | |
| /// | |
| /// The properties exposed are Dart-centric and should therefore, long-term, not | |
| /// be used during codegen, expect for mirrors. | |
| // TODO(johnniwinther): Split this into an element environment and a type query | |
| // interface, the first should only be used during resolution and the latter in | |
| // both resolution and codegen. | |
| abstract class ElementEnvironment { | |
| IrToElementMap get elementMap; | |
| /// Returns the main library for the compilation. | |
| LibraryEntity? get mainLibrary; | |
| /// Returns the main method for the compilation. | |
| FunctionEntity? get mainFunction; | |
| /// Returns all known libraries. | |
| Iterable<LibraryEntity> get libraries; | |
| /// Returns the library name of [library] or '' if the library is unnamed. | |
| String getLibraryName(LibraryEntity library); | |
| /// Lookup the library with the canonical [uri], fail if the library is | |
| /// missing and [required]; | |
| LibraryEntity? lookupLibrary(Uri uri, {bool required = false}); | |
| /// Calls [f] for every class declared in [library]. | |
| void forEachClass(LibraryEntity library, void Function(ClassEntity cls) f); | |
| /// Lookup the class [name] in [library], fail if the class is missing and | |
| /// [required]. | |
| ClassEntity? lookupClass( | |
| LibraryEntity library, | |
| String name, { | |
| bool required = false, | |
| }); | |
| /// Calls [f] for every top level member in [library]. | |
| void forEachLibraryMember( | |
| LibraryEntity library, | |
| void Function(MemberEntity member) f, | |
| ); | |
| /// Lookup the member [name] in [library], fail if the class is missing and | |
| /// [required]. | |
| MemberEntity? lookupLibraryMember( | |
| LibraryEntity library, | |
| String name, { | |
| bool setter = false, | |
| bool required = false, | |
| }); | |
| /// Lookup the member [name] in [cls], fail if the class is missing and | |
| /// [required]. | |
| MemberEntity? lookupLocalClassMember( | |
| ClassEntity cls, | |
| Name name, { | |
| bool required = false, | |
| }); | |
| /// Lookup the member [name] in [cls] and its superclasses. | |
| /// | |
| /// Return `null` if the member is not found in the class or any superclass. | |
| MemberEntity? lookupClassMember(ClassEntity cls, Name name) { | |
| ClassEntity? clsLocal = cls; | |
| while (clsLocal != null) { | |
| final entity = lookupLocalClassMember(clsLocal, name); | |
| if (entity != null) return entity; | |
| clsLocal = getSuperClass(clsLocal); | |
| } | |
| return null; | |
| } | |
| /// Lookup the constructor [name] in [cls], fail if the class is missing and | |
| /// [required]. | |
| ConstructorEntity? lookupConstructor( | |
| ClassEntity cls, | |
| String name, { | |
| bool required = false, | |
| }); | |
| /// Calls [f] for each class member declared in [cls]. | |
| void forEachLocalClassMember( | |
| ClassEntity cls, | |
| void Function(MemberEntity member) f, | |
| ); | |
| /// Calls [f] for each class member declared or inherited in [cls] together | |
| /// with the class that declared the member. | |
| /// | |
| /// TODO(johnniwinther): This should not include static members of | |
| /// superclasses. | |
| void forEachClassMember( | |
| ClassEntity cls, | |
| void Function(ClassEntity declarer, MemberEntity member) f, | |
| ); | |
| /// Calls [f] for every constructor declared in [cls]. | |
| /// | |
| /// Will ensure that the class and all constructors are resolved if | |
| /// [ensureResolved] is `true`. | |
| void forEachConstructor( | |
| ClassEntity cls, | |
| void Function(ConstructorEntity constructor) f, | |
| ); | |
| /// Returns the superclass of [cls]. | |
| /// | |
| /// If [skipUnnamedMixinApplications] is `true`, unnamed mixin applications | |
| /// are excluded, for instance for these classes | |
| /// | |
| /// class S {} | |
| /// class M {} | |
| /// class C extends S with M {} | |
| /// | |
| /// the result of `getSuperClass(C)` is the unnamed mixin application | |
| /// typically named `S+M` and `getSuperClass(S+M)` is `S`, whereas | |
| /// the result of `getSuperClass(C, skipUnnamedMixinApplications: false)` is | |
| /// `S`. | |
| ClassEntity? getSuperClass( | |
| ClassEntity cls, { | |
| bool skipUnnamedMixinApplications = false, | |
| }); | |
| /// Calls [f] for each supertype of [cls]. | |
| void forEachSupertype( | |
| ClassEntity cls, | |
| void Function(InterfaceType supertype) f, | |
| ); | |
| /// Calls [f] for each SuperClass of [cls]. | |
| void forEachSuperClass( | |
| ClassEntity cls, | |
| void Function(ClassEntity superClass) f, | |
| ) { | |
| for ( | |
| var superClass = getSuperClass(cls); | |
| superClass != null; | |
| superClass = getSuperClass(superClass) | |
| ) { | |
| f(superClass); | |
| } | |
| } | |
| /// Create the instantiation of [cls] with the given [typeArguments] and | |
| /// [nullability]. | |
| InterfaceType createInterfaceType( | |
| ClassEntity cls, | |
| List<DartType> typeArguments, | |
| ); | |
| /// Returns the `dynamic` type. | |
| DartType get dynamicType; | |
| /// Returns the 'raw type' of [cls]. That is, the instantiation of [cls] | |
| /// where all types arguments are `dynamic`. | |
| InterfaceType getRawType(ClassEntity cls); | |
| /// Returns the 'JS-interop type' of [cls]; that is, the instantiation of | |
| /// [cls] where all type arguments are 'any'. | |
| InterfaceType getJsInteropType(ClassEntity cls); | |
| /// Returns the 'this type' of [cls]. That is, the instantiation of [cls] | |
| /// where the type arguments are the type variables of [cls]. | |
| InterfaceType getThisType(ClassEntity cls); | |
| /// Returns the instantiation of [cls] to bounds. | |
| InterfaceType getClassInstantiationToBounds(ClassEntity cls); | |
| /// Returns `true` if [cls] is generic. | |
| bool isGenericClass(ClassEntity cls); | |
| /// Returns `true` if [cls] is a mixin application (named or unnamed). | |
| bool isMixinApplication(ClassEntity cls); | |
| /// Returns `true` if [cls] is an unnamed mixin application. | |
| bool isUnnamedMixinApplication(ClassEntity cls); | |
| /// The upper bound on the [typeVariable]. If not explicitly declared, this is | |
| /// `Object`. | |
| DartType getTypeVariableBound(TypeVariableEntity typeVariable); | |
| /// Returns the variances for each type parameter in [cls]. | |
| List<Variance> getTypeVariableVariances(ClassEntity cls); | |
| /// Returns the type of [function]. | |
| FunctionType getFunctionType(FunctionEntity function); | |
| /// Returns the function type variables defined on [function]. | |
| List<TypeVariableType> getFunctionTypeVariables(FunctionEntity function); | |
| /// Returns the type of the [local] function. | |
| FunctionType getLocalFunctionType(Local local); | |
| /// Returns the type of [field]. | |
| DartType getFieldType(FieldEntity field); | |
| /// Returns `true` if [cls] is a Dart enum class. | |
| bool isEnumClass(ClassEntity cls); | |
| /// Returns the 'effective' mixin class if [cls] is a mixin application, and | |
| /// `null` otherwise. | |
| /// | |
| /// The 'effective' mixin class is the class from which members are mixed in. | |
| /// Normally this is the mixin class itself, but not if the mixin class itself | |
| /// is a mixin application. | |
| /// | |
| /// Consider this hierarchy: | |
| /// | |
| /// class A {} | |
| /// class B = Object with A {} | |
| /// class C = Object with B {} | |
| /// | |
| /// The mixin classes of `B` and `C` are `A` and `B`, respectively, but the | |
| /// _effective_ mixin class of both is `A`. | |
| ClassEntity? getEffectiveMixinClass(ClassEntity cls); | |
| } | |
| abstract class KElementEnvironment extends ElementEnvironment { | |
| /// Calls [f] for each class that is mixed into [cls] or one of its | |
| /// superclasses. | |
| void forEachMixin(ClassEntity cls, void Function(ClassEntity mixin) f); | |
| /// Returns the imports seen in [library] | |
| Iterable<ImportEntity> getImports(LibraryEntity library); | |
| /// Returns the metadata constants declared on [member]. | |
| Iterable<ConstantValue> getMemberMetadata( | |
| MemberEntity member, { | |
| bool includeParameterMetadata = false, | |
| }); | |
| /// `true` if field is the backing field for a `late` or `late final` instance | |
| /// field. | |
| bool isLateBackingField(FieldEntity field); | |
| /// `true` if field is the backing field for a `late final` instance field. If | |
| /// this is true, so is [isLateBackingField]. | |
| bool isLateFinalBackingField(FieldEntity field); | |
| } | |
| abstract class JElementEnvironment extends ElementEnvironment { | |
| /// Calls [f] for each class member added to [cls] during compilation. | |
| void forEachInjectedClassMember( | |
| ClassEntity cls, | |
| void Function(MemberEntity member) f, | |
| ); | |
| /// Calls [f] for every constructor body in [cls]. | |
| void forEachConstructorBody( | |
| ClassEntity cls, | |
| void Function(ConstructorBodyEntity constructorBody) f, | |
| ); | |
| /// Calls [f] for each nested closure in [member]. | |
| void forEachNestedClosure( | |
| MemberEntity member, | |
| void Function(FunctionEntity closure) f, | |
| ); | |
| /// Returns `true` if [cls] is a mixin application with its own members. | |
| /// | |
| /// This occurs when a mixin contains methods with super calls or when | |
| /// the mixin application contains concrete forwarding stubs. | |
| bool isMixinApplicationWithMembers(ClassEntity cls); | |
| /// The default type of the [typeVariable]. | |
| /// | |
| /// This is the type used as the default type argument when no explicit type | |
| /// argument is passed. | |
| DartType getTypeVariableDefaultType(TypeVariableEntity typeVariable); | |
| /// Returns the 'element' type of a [function] with the async, async* or sync* | |
| /// marker. [returnType] is the return type of the marked function. | |
| DartType getAsyncOrSyncStarElementType( | |
| FunctionEntity function, | |
| DartType returnType, | |
| ); | |
| /// Returns the 'element' type of a function with an async, async* or sync* | |
| /// marker. The return type of the method is inspected to determine the type | |
| /// parameter of the Future, Stream or Iterable. | |
| DartType getFunctionAsyncOrSyncStarElementType(FunctionEntity function); | |
| /// Returns `true` if [field] has an explicit `covariant` declaration. | |
| bool isFieldCovariantByDeclaration(FieldEntity field); | |
| /// Calls [f] with every instance field, together with its declarer, in an | |
| /// instance of [cls]. All fields inherited from superclasses and mixins are | |
| /// included. | |
| /// | |
| /// If [isElided] is `true`, the field is not read and should therefore not | |
| /// be emitted. | |
| void forEachInstanceField( | |
| ClassEntity cls, | |
| void Function(ClassEntity declarer, FieldEntity field) f, | |
| ); | |
| /// Calls [f] with every instance field declared directly in class [cls] | |
| /// (i.e. no inherited fields). Fields are presented in initialization | |
| /// (i.e. textual) order. | |
| /// | |
| /// If [isElided] is `true`, the field is not read and should therefore not | |
| /// be emitted. | |
| void forEachDirectInstanceField( | |
| ClassEntity cls, | |
| void Function(FieldEntity field) f, | |
| ); | |
| /// Calls [f] for each parameter of [function] providing the type and name of | |
| /// the parameter and the [defaultValue] if the parameter is optional. | |
| void forEachParameter( | |
| covariant FunctionEntity function, | |
| void Function(DartType type, String? name, ConstantValue? defaultValue) f, | |
| ); | |
| /// Calls [f] for each parameter - given as a [Local] - of [function]. | |
| void forEachParameterAsLocal( | |
| GlobalLocalsMap globalLocalsMap, | |
| FunctionEntity function, | |
| void Function(Local parameter) f, | |
| ); | |
| } |