| // Copyright (c) 2018, 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 '../common.dart'; | |
| import '../common/elements.dart'; | |
| import '../common/names.dart'; | |
| import '../elements/entities.dart'; | |
| import '../elements/types.dart'; | |
| import '../js_backend/annotations.dart'; | |
| import '../js_backend/backend_usage.dart'; | |
| import '../js_backend/field_analysis.dart' show KFieldAnalysis; | |
| import '../js_backend/interceptor_data.dart'; | |
| import '../js_backend/native_data.dart'; | |
| import '../js_backend/no_such_method_registry.dart'; | |
| import '../js_backend/runtime_types_resolution.dart'; | |
| import '../js_model/elements.dart'; | |
| import '../options.dart'; | |
| import '../universe/class_hierarchy.dart'; | |
| import '../universe/member_usage.dart'; | |
| import '../universe/selector.dart'; | |
| import '../world.dart'; | |
| import 'element_map.dart'; | |
| /// The immutable result of the [ResolutionWorldBuilder]. | |
| class KClosedWorld implements BuiltWorld { | |
| final KernelToElementMap elementMap; | |
| final KElementEnvironment elementEnvironment; | |
| final DartTypes dartTypes; | |
| final KCommonElements commonElements; | |
| final NativeData nativeData; | |
| final InterceptorData interceptorData; | |
| final BackendUsage backendUsage; | |
| final NoSuchMethodData noSuchMethodData; | |
| final Map<ClassEntity, Set<ClassEntity>> mixinUses; | |
| final Map<ClassEntity, Set<ClassEntity>> typesImplementedBySubclasses; | |
| // TODO(johnniwinther): Can this be derived from [ClassSet]s? | |
| final Set<ClassEntity> _implementedClasses; | |
| final Iterable<MemberEntity> liveInstanceMembers; | |
| final Iterable<MemberEntity> liveAbstractInstanceMembers; | |
| /// Members that are written either directly or through a setter selector. | |
| final Iterable<MemberEntity> assignedInstanceMembers; | |
| final KFieldAnalysis fieldAnalysis; | |
| final Iterable<ClassEntity> liveNativeClasses; | |
| final Map<MemberEntity, MemberUsage> liveMemberUsage; | |
| @override | |
| final ClassHierarchy classHierarchy; | |
| @override | |
| final AnnotationsData annotationsData; | |
| late RuntimeTypesNeed _rtiNeed; | |
| @override | |
| final Set<DartType> isChecks; | |
| @override | |
| final Set<TypeVariableType> namedTypeVariables; | |
| final Map<Entity, Set<DartType>> staticTypeArgumentDependencies; | |
| final Map<Selector, Set<DartType>> dynamicTypeArgumentDependencies; | |
| @override | |
| final Set<TypeVariableType> typeVariableTypeLiterals; | |
| @override | |
| final Set<Local> genericLocalFunctions; | |
| /// Set of live closurized members whose signatures reference type variables. | |
| /// | |
| /// A closurized method is considered live if the enclosing class has been | |
| /// instantiated. | |
| final Set<FunctionEntity> closurizedMembersWithFreeTypeVariables; | |
| /// Set of (live) local functions (closures). | |
| /// | |
| /// A live function is one whose enclosing member function has been enqueued. | |
| final Iterable<Local> localFunctions; | |
| @override | |
| final Iterable<InterfaceType> instantiatedTypes; | |
| final Iterable<RecordType> instantiatedRecordTypes; | |
| RuntimeTypesNeed get rtiNeed => _rtiNeed; | |
| KClosedWorld( | |
| this.elementMap, { | |
| required CompilerOptions options, | |
| required this.elementEnvironment, | |
| required this.dartTypes, | |
| required this.commonElements, | |
| required this.nativeData, | |
| required this.interceptorData, | |
| required this.backendUsage, | |
| required this.noSuchMethodData, | |
| required RuntimeTypesNeedBuilder rtiNeedBuilder, | |
| required this.fieldAnalysis, | |
| required this._implementedClasses, | |
| required this.liveNativeClasses, | |
| required this.liveInstanceMembers, | |
| required this.liveAbstractInstanceMembers, | |
| required this.assignedInstanceMembers, | |
| required this.liveMemberUsage, | |
| required this.mixinUses, | |
| required this.typesImplementedBySubclasses, | |
| required this.classHierarchy, | |
| required this.annotationsData, | |
| required this.isChecks, | |
| required this.namedTypeVariables, | |
| required this.staticTypeArgumentDependencies, | |
| required this.dynamicTypeArgumentDependencies, | |
| required this.typeVariableTypeLiterals, | |
| required this.genericLocalFunctions, | |
| required this.closurizedMembersWithFreeTypeVariables, | |
| required this.localFunctions, | |
| required this.instantiatedTypes, | |
| required this.instantiatedRecordTypes, | |
| }) { | |
| _rtiNeed = rtiNeedBuilder.computeRuntimeTypesNeed(this, options); | |
| assert(_checkIntegrity()); | |
| } | |
| bool _checkIntegrity() { | |
| for (MemberEntity member in liveMemberUsage.keys) { | |
| if (member.enclosingClass != null) { | |
| if (!elementMap.classes | |
| .getEnv(member.enclosingClass as JClass) | |
| .checkHasMember(elementMap.getMemberNode(member))) { | |
| throw SpannableAssertionFailure( | |
| member, | |
| "Member $member is not in the environment of its enclosing class" | |
| " ${member.enclosingClass}.", | |
| ); | |
| } | |
| } | |
| } | |
| return true; | |
| } | |
| /// Returns `true` if [cls] is implemented by an instantiated class. | |
| bool isImplemented(ClassEntity cls) { | |
| return _implementedClasses.contains(cls); | |
| } | |
| /// Needed for testing. | |
| Iterable<MemberEntity> get processedMembers => liveMemberUsage.keys; | |
| @override | |
| void forEachStaticTypeArgument( | |
| void Function(Entity function, Set<DartType> typeArguments) f, | |
| ) { | |
| staticTypeArgumentDependencies.forEach(f); | |
| } | |
| @override | |
| void forEachDynamicTypeArgument( | |
| void Function(Selector selector, Set<DartType> typeArguments) f, | |
| ) { | |
| dynamicTypeArgumentDependencies.forEach(f); | |
| } | |
| /// Returns `true` if [member] has been marked as used (called, read, etc.) in | |
| /// this world builder. | |
| bool isMemberUsed(MemberEntity member) => liveMemberUsage.containsKey(member); | |
| @override | |
| void forEachGenericMethod(void Function(FunctionEntity e) f) { | |
| liveMemberUsage.forEach((MemberEntity member, MemberUsage usage) { | |
| if (member is FunctionEntity && | |
| elementEnvironment.getFunctionTypeVariables(member).isNotEmpty) { | |
| f(member); | |
| } | |
| }); | |
| } | |
| @override | |
| void forEachGenericInstanceMethod(void Function(FunctionEntity e) f) { | |
| liveMemberUsage.forEach((MemberEntity member, MemberUsage usage) { | |
| if (member is FunctionEntity && | |
| member.isInstanceMember && | |
| elementEnvironment.getFunctionTypeVariables(member).isNotEmpty) { | |
| f(member); | |
| } | |
| }); | |
| } | |
| @override | |
| late final Iterable<FunctionEntity> userNoSuchMethods = (() { | |
| final result = <FunctionEntity>[]; | |
| liveMemberUsage.forEach((MemberEntity member, MemberUsage memberUsage) { | |
| if (member is FunctionEntity && memberUsage.hasUse) { | |
| if (member.isInstanceMember && | |
| member.name == Identifiers.noSuchMethod_ && | |
| !commonElements.isDefaultNoSuchMethodImplementation(member)) { | |
| result.add(member); | |
| } | |
| } | |
| }); | |
| return result; | |
| })(); | |
| @override | |
| late final Iterable<FunctionEntity> closurizedMembers = (() { | |
| final result = <FunctionEntity>{}; | |
| liveMemberUsage.forEach((MemberEntity member, MemberUsage usage) { | |
| if (member.isFunction && member.isInstanceMember && usage.hasRead) { | |
| result.add(member as FunctionEntity); | |
| } | |
| }); | |
| return result; | |
| }()); | |
| @override | |
| late final Iterable<FunctionEntity> closurizedStatics = (() { | |
| final result = <FunctionEntity>{}; | |
| liveMemberUsage.forEach((MemberEntity member, MemberUsage usage) { | |
| if (member.isFunction && | |
| (member.isStatic || member.isTopLevel) && | |
| usage.hasRead) { | |
| result.add(member as FunctionEntity); | |
| } | |
| }); | |
| return result; | |
| })(); | |
| @override | |
| late final Map<MemberEntity, DartType> genericCallableProperties = (() { | |
| final result = <MemberEntity, DartType>{}; | |
| liveMemberUsage.forEach((MemberEntity member, MemberUsage usage) { | |
| if (usage.hasRead) { | |
| DartType? type; | |
| if (member is FieldEntity) { | |
| type = elementEnvironment.getFieldType(member); | |
| } else if (member.isGetter) { | |
| type = elementEnvironment | |
| .getFunctionType(member as FunctionEntity) | |
| .returnType; | |
| } | |
| if (type == null) return; | |
| if (dartTypes.canAssignGenericFunctionTo(type)) { | |
| result[member] = type; | |
| } else { | |
| type = type.withoutNullability; | |
| if (type is InterfaceType) { | |
| FunctionType? callType = dartTypes.getCallType(type); | |
| if (callType != null && | |
| dartTypes.canAssignGenericFunctionTo(callType)) { | |
| result[member] = callType; | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| return result; | |
| })(); | |
| } |