diff --git a/runtime/docs/types.md b/runtime/docs/types.md index 7d41d989f2d..55b5d024772 100644 --- a/runtime/docs/types.md +++ b/runtime/docs/types.md @@ -27,7 +27,8 @@ A parameter type in the signature can be either a `Type`, a `FunctionType`, or a ## AbstractType -The VM declares the class `AbstractType` as a placeholder to store a concrete type. The following classes extend `AbstractType`: `Type`, `FunctionType`, `TypeParameter`, and `TypeRef`. The latter one, `TypeRef` is used to break cycles in recursive type graphs. More on it later. `AbstractType` declares several virtual methods that may be overridden by concrete types. See its declaration in [object.h](https://github.com/dart-lang/sdk/blob/main/runtime/vm/object.h). +The VM declares the class `AbstractType` as a placeholder to store a concrete type. The following classes extend `AbstractType`: `Type`, `FunctionType`, `TypeParameter`, and `RecordType`. +`AbstractType` declares several virtual methods that may be overridden by concrete types. See its declaration in [object.h](https://github.com/dart-lang/sdk/blob/main/runtime/vm/object.h). ## TypeArguments @@ -123,14 +124,14 @@ The *function type arguments* are the concatenation of the type argument vectors A `TypeParameter` object specifies whether it is declared by a class (it is then a *class type parameter*) or by a function (it is then a *function type parameter*), thereby selecting the vector to use for its instantiation. The index value then identifies the type argument from that specific vector to be used to substitute the type parameter. To complete the instantiation, a normalization step is applied after the substitution. The virtual method to instantiate an `AbstractType` is declared as follows: -```dart +```c++ virtual AbstractTypePtr InstantiateFrom( const TypeArguments& instantiator_type_arguments, const TypeArguments& function_type_arguments, intptr_t num_free_fun_type_params, Heap::Space space, - TrailPtr trail = nullptr) const; - + FunctionTypeMapping* function_type_mapping = nullptr, + intptr_t num_parent_type_args_adjustment = 0) const; ``` Note how both instantiators explained above are passed in, `instantiator_type_arguments` and `function_type_arguments`. Note also that an integer `num_free_fun_type_params` is provided. Its value indicates how many type arguments in the `function_type_arguments` vector are considered to be free variables and are therefore available to substitute type parameters with an index below this value. Type parameters with an index equal or above that value remain uninstantiated. Here is an example: @@ -143,27 +144,20 @@ class C { ``` Although method `foo` is not generic, it takes a generic function `bar()` as argument and its function type refers to class type parameter `T` and function type parameter `B`. When instantiating the function type of `foo` for a particular value of `T`, the function type parameter `B` must remain uninstantiated, because only `T` is a free variable in this function type. An instantiation in the context of `C` would yield `int foo(bar(int t, B b))`. In this case, the `InstantiateFrom` method would be called with `num_free_fun_type_params = 0`, as no function type parameters are free in this example. -## Trail - -Another argument passed to the `InstantiateFrom` method above is `trail`. The trail prevents infinite recursion when traversing cyclic type graphs. When building type graphs, the VM makes sure that back references to the graph creating a cycle are represented by a `TypeRef` object. During graph traversal, when a `TypeRef` node is encountered, the implementation checks that the `TypeRef` is not already in the trail, in which case a repeated traversal of the same cycle is avoided. If not yet present, the `TypeRef` node is inserted in the trail, and the trail is passed down to recursive traversal calls. - -There are different type graph traversal methods in the VM performing various operations. Each one of these traversals requires a trail to avoid divergence. Some take a single type graph as input, such as type instantiation and type instantiation check (whether a type is instantiated), but others take two type graphs as input, such as subtype test (whether a type is a subtype of another type) and type equivalence (whether two types are equivalent). - -The traversals that take two type graphs as input use the trail differently. When a `TypeRef` is encountered on the left hand side, it is inserted in the trail in association with the right hand side type node being currently traversed. The implementation calls the right hand side type node the `buddy` of the `TypeRef` node. The trail consists of pairs of nodes. The implementation checks that a particular pair is already present before inserting it. - ## Type Equivalence The same virtual method `IsEquivalent` of `AbstractType` is used to traverse a pair of type graphs and decide whether they are canonically equal, syntactically equal, or equal in the context of subtype tests: -```dart +```c++ enum class TypeEquality { kCanonical = 0, kSyntactical = 1, kInSubtypeTest = 2, }; - virtual bool IsEquivalent(const Instance& other, - TypeEquality kind, - TrailPtr trail = nullptr) const; + virtual bool IsEquivalent( + const Instance& other, + TypeEquality kind, + FunctionTypeMapping* function_type_equivalence = nullptr) const; ``` Instead of implementing three different traversals, the kind of type equality is passed as an argument to a single traversal method. @@ -178,8 +172,7 @@ As a last step of finalization, types and type argument vectors get canonicalize ## Canonicalization and Hash The VM keeps global tables of canonical types and type arguments. Canonicalizing a type or a type argument vector consists in a table look up using a hash code to find a candidate, and then comparing the type with the candidate using the `IsEquivalent` method mentioned above (passing `kind = kCanonical`). - -It is therefore imperative that two canonically equal types share the same hash code. `TypeRef` objects pose a problem in this regard. Namely, the hash of a `TypeRef` node cannot depend on the hash of the referenced type graph, otherwise, the hash code would depend on the location in the cycle where hash computation started and ended. Instead, the hash of a `TypeRef` node can only depend on information obtainable by “peeking” at the referenced type node, but not at the whole referenced type graph. See the comments in the [implementation](https://github.com/dart-lang/sdk/blob/main/runtime/vm/object.cc) of `TypeRef::Hash()` for details. +It is therefore imperative that two canonically equal types share the same hash code. ## Cached Instantiations of TypeArguments diff --git a/runtime/lib/async.cc b/runtime/lib/async.cc index e443c2d346a..c92d6acba9b 100644 --- a/runtime/lib/async.cc +++ b/runtime/lib/async.cc @@ -48,7 +48,7 @@ DEFINE_NATIVE_ENTRY(SuspendState_instantiateClosureWithFutureTypeArgument, } auto& type_args = TypeArguments::Handle(zone, type.arguments()); ASSERT(type_args.IsNull() || type_args.Length() == 1); - type_args = type_args.Canonicalize(thread, nullptr); + type_args = type_args.Canonicalize(thread); ASSERT(closure.delayed_type_arguments() == Object::empty_type_arguments().ptr()); diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc index 9363969e308..e330dae4fc1 100644 --- a/runtime/lib/mirrors.cc +++ b/runtime/lib/mirrors.cc @@ -302,12 +302,6 @@ static InstancePtr CreateClassMirror(const Class& cls, const AbstractType& type, const Bool& is_declaration, const Instance& owner_mirror) { - if (type.IsTypeRef()) { - AbstractType& ref_type = AbstractType::Handle(TypeRef::Cast(type).type()); - ASSERT(!ref_type.IsTypeRef()); - ASSERT(ref_type.IsCanonical()); - return CreateClassMirror(cls, ref_type, is_declaration, owner_mirror); - } ASSERT(!cls.IsDynamicClass()); ASSERT(!cls.IsVoidClass()); ASSERT(!cls.IsNeverClass()); @@ -518,12 +512,6 @@ DEFINE_NATIVE_ENTRY(LibraryMirror_libraryDependencies, 0, 2) { } static InstancePtr CreateTypeMirror(const AbstractType& type) { - if (type.IsTypeRef()) { - AbstractType& ref_type = AbstractType::Handle(TypeRef::Cast(type).type()); - ASSERT(!ref_type.IsTypeRef()); - ASSERT(ref_type.IsCanonical()); - return CreateTypeMirror(ref_type); - } ASSERT(type.IsFinalized()); ASSERT(type.IsCanonical()); @@ -557,7 +545,7 @@ static InstancePtr CreateTypeMirror(const AbstractType& type) { if (!type.IsNullType()) { Type& legacy_type = Type::Handle( Type::Cast(type).ToNullability(Nullability::kLegacy, Heap::kOld)); - legacy_type ^= legacy_type.Canonicalize(Thread::Current(), nullptr); + legacy_type ^= legacy_type.Canonicalize(Thread::Current()); return CreateClassMirror(cls, legacy_type, Bool::False(), Object::null_instance()); } @@ -567,7 +555,7 @@ static InstancePtr CreateTypeMirror(const AbstractType& type) { TypeParameter& legacy_type = TypeParameter::Handle(TypeParameter::Cast(type).ToNullability( Nullability::kLegacy, Heap::kOld)); - legacy_type ^= legacy_type.Canonicalize(Thread::Current(), nullptr); + legacy_type ^= legacy_type.Canonicalize(Thread::Current()); return CreateTypeVariableMirror(legacy_type, Object::null_instance()); } UNREACHABLE(); @@ -628,7 +616,7 @@ static AbstractTypePtr InstantiateType(const AbstractType& type, Thread* thread = Thread::Current(); if (type.IsInstantiated()) { - return type.Canonicalize(thread, nullptr); + return type.Canonicalize(thread); } TypeArguments& instantiator_type_args = TypeArguments::Handle(); if (!instantiator.IsNull() && instantiator.IsType()) { @@ -646,7 +634,7 @@ static AbstractTypePtr InstantiateType(const AbstractType& type, instantiator_type_args, Object::null_type_arguments(), kAllFree, Heap::kOld)); ASSERT(result.IsFinalized()); - return result.Canonicalize(thread, nullptr); + return result.Canonicalize(thread); } DEFINE_NATIVE_ENTRY(MirrorSystem_libraries, 0, 0) { @@ -915,7 +903,7 @@ DEFINE_NATIVE_ENTRY(FunctionTypeMirror_return_type, 0, 1) { ASSERT(!sig.IsNull()); AbstractType& type = AbstractType::Handle(sig.result_type()); // Signatures of function types are instantiated, but not canonical. - return type.Canonicalize(thread, nullptr); + return type.Canonicalize(thread); } DEFINE_NATIVE_ENTRY(ClassMirror_libraryUri, 0, 1) { @@ -1265,7 +1253,7 @@ DEFINE_NATIVE_ENTRY(InstanceMirror_computeType, 0, 1) { const AbstractType& type = AbstractType::Handle(instance.GetType(Heap::kNew)); // The static type of null is specified to be the bottom type, however, the // runtime type of null is the Null type, which we correctly return here. - return type.Canonicalize(thread, nullptr); + return type.Canonicalize(thread); } DEFINE_NATIVE_ENTRY(ClosureMirror_function, 0, 1) { @@ -1551,8 +1539,8 @@ DEFINE_NATIVE_ENTRY(MethodMirror_return_type, 0, 2) { // We handle constructors in Dart code. ASSERT(!func.IsGenerativeConstructor()); AbstractType& type = AbstractType::Handle(func.result_type()); - type = type.Canonicalize( - thread, nullptr); // Instantiated signatures are not canonical. + type = + type.Canonicalize(thread); // Instantiated signatures are not canonical. return InstantiateType(type, instantiator); } @@ -1642,8 +1630,8 @@ DEFINE_NATIVE_ENTRY(ParameterMirror_type, 0, 3) { FunctionType::Handle(ref.GetFunctionTypeReferent()); AbstractType& type = AbstractType::Handle(signature.ParameterTypeAt( signature.num_implicit_parameters() + pos.Value())); - type = type.Canonicalize( - thread, nullptr); // Instantiated signatures are not canonical. + type = + type.Canonicalize(thread); // Instantiated signatures are not canonical. return InstantiateType(type, instantiator); } diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc index 9cf08c65a57..28eead06e31 100644 --- a/runtime/lib/object.cc +++ b/runtime/lib/object.cc @@ -92,7 +92,7 @@ DEFINE_NATIVE_ENTRY(Object_runtimeType, 0, 1) { zone, Type::New(cls, type_arguments, Nullability::kNonNullable, Heap::kNew)); type.SetIsFinalized(); - return type.Canonicalize(thread, nullptr); + return type.Canonicalize(thread); } return instance.GetType(Heap::kNew); @@ -462,7 +462,7 @@ DEFINE_NATIVE_ENTRY(Internal_extractTypeArguments, 0, 2) { extracted_type_args.SetTypeAt(i, type_arg); } extracted_type_args = - extracted_type_args.Canonicalize(thread, nullptr); // Can be null. + extracted_type_args.Canonicalize(thread); // Can be null. } } // Call the closure 'extract'. diff --git a/runtime/observatory/lib/src/elements/instance_ref.dart b/runtime/observatory/lib/src/elements/instance_ref.dart index dc163aa96d5..4c5d32cf3c7 100644 --- a/runtime/observatory/lib/src/elements/instance_ref.dart +++ b/runtime/observatory/lib/src/elements/instance_ref.dart @@ -123,7 +123,6 @@ class InstanceRefElement extends CustomElement implements Renderable { ]; case M.InstanceKind.type: case M.InstanceKind.functionType: - case M.InstanceKind.typeRef: case M.InstanceKind.typeParameter: case M.InstanceKind.recordType: return [ diff --git a/runtime/observatory/lib/src/elements/instance_view.dart b/runtime/observatory/lib/src/elements/instance_view.dart index 022d3b96d6c..0c6cb821e41 100644 --- a/runtime/observatory/lib/src/elements/instance_view.dart +++ b/runtime/observatory/lib/src/elements/instance_view.dart @@ -236,9 +236,6 @@ class InstanceViewElement extends CustomElement implements Renderable { if (_instance.parameterIndex != null) { members.add(member('parameter index', '${_instance.parameterIndex}')); } - if (_instance.targetType != null) { - members.add(member('target type', _instance.targetType)); - } if (_instance.bound != null) { members.add(member('bound', _instance.bound)); } diff --git a/runtime/observatory/lib/src/models/objects/field.dart b/runtime/observatory/lib/src/models/objects/field.dart index 91c4a055fd8..1c5a7a02a12 100644 --- a/runtime/observatory/lib/src/models/objects/field.dart +++ b/runtime/observatory/lib/src/models/objects/field.dart @@ -15,7 +15,7 @@ abstract class FieldRef extends ObjectRef { /// The declared type of this field. /// /// The value will always be of one of the kinds: - /// Type, FunctionType, TypeRef, TypeParameter. + /// Type, FunctionType, RecordType, TypeParameter. InstanceRef? get declaredType; /// Is this field const? diff --git a/runtime/observatory/lib/src/models/objects/instance.dart b/runtime/observatory/lib/src/models/objects/instance.dart index 4f880900045..79410fa47d1 100644 --- a/runtime/observatory/lib/src/models/objects/instance.dart +++ b/runtime/observatory/lib/src/models/objects/instance.dart @@ -125,9 +125,6 @@ enum InstanceKind { /// An instance of the Dart class TypeParameter. typeParameter, - /// An instance of the Dart class TypeRef. - typeRef, - /// An instance of the Dart class RawReceivePort receivePort, @@ -190,7 +187,7 @@ bool isAbstractType(InstanceKind? kind) { switch (kind) { case InstanceKind.type: case InstanceKind.functionType: - case InstanceKind.typeRef: + case InstanceKind.recordType: case InstanceKind.typeParameter: return true; default: @@ -410,19 +407,10 @@ abstract class Instance extends Object implements InstanceRef { /// TypeParameter int? get parameterIndex; - /// [optional] The referent of a TypeRef instance. - /// - /// The value will always be of one of the kinds: - /// Type, FunctionType, TypeRef, TypeParameter. - /// - /// Provided for instance kinds: - /// TypeRef - InstanceRef? get targetType; - /// [optional] The bound of a TypeParameter. /// /// The value will always be of one of the kinds: - /// Type, FunctionType, TypeRef, TypeParameter. + /// Type, FunctionType, RecordType, TypeParameter. /// /// Provided for instance kinds: /// TypeParameter diff --git a/runtime/observatory/lib/src/models/objects/type_arguments.dart b/runtime/observatory/lib/src/models/objects/type_arguments.dart index a8dc1343545..f3161b37666 100644 --- a/runtime/observatory/lib/src/models/objects/type_arguments.dart +++ b/runtime/observatory/lib/src/models/objects/type_arguments.dart @@ -13,6 +13,6 @@ abstract class TypeArguments extends Object implements TypeArgumentsRef { /// A list of types. /// /// The value will always be one of the kinds: - /// Type, FunctionType, TypeRef, TypeParameter. + /// Type, FunctionType, RecordType, TypeParameter. Iterable? get types; } diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart index 3086a67eef7..5bc7e5e463b 100644 --- a/runtime/observatory/lib/src/service/object.dart +++ b/runtime/observatory/lib/src/service/object.dart @@ -2778,8 +2778,6 @@ M.InstanceKind stringToInstanceKind(String s) { return M.InstanceKind.functionType; case 'TypeParameter': return M.InstanceKind.typeParameter; - case 'TypeRef': - return M.InstanceKind.typeRef; case 'ReceivePort': return M.InstanceKind.receivePort; case 'RecordType': @@ -2852,7 +2850,6 @@ class Instance extends HeapObject implements M.Instance { Class? parameterizedClass; TypeArguments? typeArguments; int? parameterIndex; - Instance? targetType; Instance? bound; Iterable? fields; @@ -3046,7 +3043,6 @@ class Instance extends HeapObject implements M.Instance { parameterizedClass = map['parameterizedClass']; typeArguments = map['typeArguments']; parameterIndex = map['parameterIndex']; - targetType = map['targetType']; bound = map['bound']; referent = map['mirrorReferent']; diff --git a/runtime/observatory_2/lib/src/elements/instance_ref.dart b/runtime/observatory_2/lib/src/elements/instance_ref.dart index bb207cef06c..cae8d992e57 100644 --- a/runtime/observatory_2/lib/src/elements/instance_ref.dart +++ b/runtime/observatory_2/lib/src/elements/instance_ref.dart @@ -125,7 +125,6 @@ class InstanceRefElement extends CustomElement implements Renderable { ]; case M.InstanceKind.type: case M.InstanceKind.functionType: - case M.InstanceKind.typeRef: case M.InstanceKind.typeParameter: case M.InstanceKind.recordType: return [ diff --git a/runtime/observatory_2/lib/src/elements/instance_view.dart b/runtime/observatory_2/lib/src/elements/instance_view.dart index 5982340b4c2..e971655252a 100644 --- a/runtime/observatory_2/lib/src/elements/instance_view.dart +++ b/runtime/observatory_2/lib/src/elements/instance_view.dart @@ -251,9 +251,6 @@ class InstanceViewElement extends CustomElement implements Renderable { if (_instance.parameterIndex != null) { members.add(member('parameter index', '${_instance.parameterIndex}')); } - if (_instance.targetType != null) { - members.add(member('target type', _instance.targetType)); - } if (_instance.bound != null) { members.add(member('bound', _instance.bound)); } diff --git a/runtime/observatory_2/lib/src/models/objects/field.dart b/runtime/observatory_2/lib/src/models/objects/field.dart index 53bc59dee6a..b4b228160bf 100644 --- a/runtime/observatory_2/lib/src/models/objects/field.dart +++ b/runtime/observatory_2/lib/src/models/objects/field.dart @@ -15,7 +15,7 @@ abstract class FieldRef extends ObjectRef { /// The declared type of this field. /// /// The value will always be of one of the kinds: - /// Type, FunctionType, TypeRef, TypeParameter. + /// Type, FunctionType, RecordType, TypeParameter. InstanceRef get declaredType; /// Is this field const? diff --git a/runtime/observatory_2/lib/src/models/objects/instance.dart b/runtime/observatory_2/lib/src/models/objects/instance.dart index ba3a8e11a58..80ad75e0049 100644 --- a/runtime/observatory_2/lib/src/models/objects/instance.dart +++ b/runtime/observatory_2/lib/src/models/objects/instance.dart @@ -125,9 +125,6 @@ enum InstanceKind { /// An instance of the Dart class TypeParameter. typeParameter, - /// An instance of the Dart class TypeRef. - typeRef, - /// An instance of the Dart class RawReceivePort receivePort, @@ -181,7 +178,7 @@ bool isAbstractType(InstanceKind kind) { switch (kind) { case InstanceKind.type: case InstanceKind.functionType: - case InstanceKind.typeRef: + case InstanceKind.recordType: case InstanceKind.typeParameter: return true; default: @@ -401,19 +398,10 @@ abstract class Instance extends Object implements InstanceRef { /// TypeParameter int get parameterIndex; - /// [optional] The referent of a TypeRef instance. - /// - /// The value will always be of one of the kinds: - /// Type, FunctionType, TypeRef, TypeParameter. - /// - /// Provided for instance kinds: - /// TypeRef - InstanceRef get targetType; - /// [optional] The bound of a TypeParameter. /// /// The value will always be of one of the kinds: - /// Type, FunctionType, TypeRef, TypeParameter. + /// Type, FunctionType, RecordType, TypeParameter. /// /// Provided for instance kinds: /// TypeParameter diff --git a/runtime/observatory_2/lib/src/models/objects/type_arguments.dart b/runtime/observatory_2/lib/src/models/objects/type_arguments.dart index a6469df7181..5632b52f85a 100644 --- a/runtime/observatory_2/lib/src/models/objects/type_arguments.dart +++ b/runtime/observatory_2/lib/src/models/objects/type_arguments.dart @@ -13,6 +13,6 @@ abstract class TypeArguments extends Object implements TypeArgumentsRef { /// A list of types. /// /// The value will always be one of the kinds: - /// Type, FunctionType, TypeRef, TypeParameter. + /// Type, FunctionType, RecordType, TypeParameter. Iterable get types; } diff --git a/runtime/observatory_2/lib/src/service/object.dart b/runtime/observatory_2/lib/src/service/object.dart index 761da1ebe04..1faee04a4fc 100644 --- a/runtime/observatory_2/lib/src/service/object.dart +++ b/runtime/observatory_2/lib/src/service/object.dart @@ -2793,8 +2793,6 @@ M.InstanceKind stringToInstanceKind(String s) { return M.InstanceKind.functionType; case 'TypeParameter': return M.InstanceKind.typeParameter; - case 'TypeRef': - return M.InstanceKind.typeRef; case 'ReceivePort': return M.InstanceKind.receivePort; case 'Record': @@ -2867,7 +2865,6 @@ class Instance extends HeapObject implements M.Instance { Class parameterizedClass; TypeArguments typeArguments; int parameterIndex; - Instance targetType; Instance bound; Iterable fields; @@ -3065,7 +3062,6 @@ class Instance extends HeapObject implements M.Instance { parameterizedClass = map['parameterizedClass']; typeArguments = map['typeArguments']; parameterIndex = map['parameterIndex']; - targetType = map['targetType']; bound = map['bound']; referent = map['mirrorReferent']; diff --git a/runtime/vm/app_snapshot.cc b/runtime/vm/app_snapshot.cc index b33ac56b6f9..10626647c2c 100644 --- a/runtime/vm/app_snapshot.cc +++ b/runtime/vm/app_snapshot.cc @@ -562,14 +562,8 @@ class CanonicalSetSerializationCluster : public SerializationCluster { element ^= ptr; intptr_t entry = -1; const bool present = table.FindKeyOrDeletedOrUnused(element, &entry); - if (!present) { - table.InsertKey(entry, element); - } else { - // Two recursive types with different topology (and hashes) - // may be equal. - ASSERT(element.IsRecursive()); - objects_[num_occupied++] = ptr; - } + ASSERT(!present); + table.InsertKey(entry, element); } else { objects_[num_occupied++] = ptr; } @@ -901,7 +895,7 @@ class TypeArgumentsDeserializationCluster TypeArguments& type_arg = TypeArguments::Handle(d->zone()); for (intptr_t i = start_index_, n = stop_index_; i < n; i++) { type_arg ^= refs.At(i); - type_arg = type_arg.Canonicalize(d->thread(), nullptr); + type_arg = type_arg.Canonicalize(d->thread()); refs.SetAt(i, type_arg); } } @@ -4186,7 +4180,7 @@ class TypeDeserializationCluster AbstractType& type = AbstractType::Handle(d->zone()); for (intptr_t i = start_index_, n = stop_index_; i < n; i++) { type ^= refs.At(i); - type = type.Canonicalize(d->thread(), nullptr); + type = type.Canonicalize(d->thread()); refs.SetAt(i, type); } } @@ -4302,7 +4296,7 @@ class FunctionTypeDeserializationCluster AbstractType& type = AbstractType::Handle(d->zone()); for (intptr_t i = start_index_, n = stop_index_; i < n; i++) { type ^= refs.At(i); - type = type.Canonicalize(d->thread(), nullptr); + type = type.Canonicalize(d->thread()); refs.SetAt(i, type); } } @@ -4413,7 +4407,7 @@ class RecordTypeDeserializationCluster AbstractType& type = AbstractType::Handle(d->zone()); for (intptr_t i = start_index_, n = stop_index_; i < n; i++) { type ^= refs.At(i); - type = type.Canonicalize(d->thread(), nullptr); + type = type.Canonicalize(d->thread()); refs.SetAt(i, type); } } @@ -4436,97 +4430,6 @@ class RecordTypeDeserializationCluster } }; -#if !defined(DART_PRECOMPILED_RUNTIME) -class TypeRefSerializationCluster : public SerializationCluster { - public: - TypeRefSerializationCluster() - : SerializationCluster("TypeRef", - kTypeRefCid, - compiler::target::TypeRef::InstanceSize()) {} - ~TypeRefSerializationCluster() {} - - void Trace(Serializer* s, ObjectPtr object) { - TypeRefPtr type = TypeRef::RawCast(object); - objects_.Add(type); - PushFromTo(type); - } - - void WriteAlloc(Serializer* s) { - const intptr_t count = objects_.length(); - s->WriteUnsigned(count); - for (intptr_t i = 0; i < count; i++) { - TypeRefPtr type = objects_[i]; - s->AssignRef(type); - } - } - - void WriteFill(Serializer* s) { - const intptr_t count = objects_.length(); - for (intptr_t i = 0; i < count; i++) { - TypeRefPtr type = objects_[i]; - AutoTraceObject(type); - WriteFromTo(type); - } - } - - private: - GrowableArray objects_; -}; -#endif // !DART_PRECOMPILED_RUNTIME - -class TypeRefDeserializationCluster : public DeserializationCluster { - public: - TypeRefDeserializationCluster() : DeserializationCluster("TypeRef") {} - ~TypeRefDeserializationCluster() {} - - void ReadAlloc(Deserializer* d) { - ReadAllocFixedSize(d, TypeRef::InstanceSize()); - } - - void ReadFill(Deserializer* d_, bool primary) { - Deserializer::Local d(d_); - - const bool mark_canonical = primary && is_canonical(); - for (intptr_t id = start_index_, n = stop_index_; id < n; id++) { - TypeRefPtr type = static_cast(d.Ref(id)); - Deserializer::InitializeHeader(type, kTypeRefCid, TypeRef::InstanceSize(), - mark_canonical); - d.ReadFromTo(type); - } - } - - void PostLoad(Deserializer* d, const Array& refs, bool primary) { - if (!primary && is_canonical()) { - AbstractType& type = AbstractType::Handle(d->zone()); - for (intptr_t i = start_index_, n = stop_index_; i < n; i++) { - type ^= refs.At(i); - type = type.Canonicalize(d->thread(), nullptr); - refs.SetAt(i, type); - } - } - - TypeRef& type_ref = TypeRef::Handle(d->zone()); - AbstractType& type = AbstractType::Handle(d->zone()); - Code& stub = Code::Handle(d->zone()); - const bool includes_code = Snapshot::IncludesCode(d->kind()); - - for (intptr_t id = start_index_, n = stop_index_; id < n; id++) { - type_ref ^= refs.At(id); - - // Refresh finalization state and nullability. - type = type_ref.type(); - type_ref.set_type(type); - - if (includes_code) { - type_ref.UpdateTypeTestingStubEntryPoint(); - } else { - stub = TypeTestingStubGenerator::DefaultCodeForType(type_ref); - type_ref.InitializeTypeTestingStubNonAtomic(stub); - } - } - } -}; - #if !defined(DART_PRECOMPILED_RUNTIME) class TypeParameterSerializationCluster : public CanonicalSetSerializationClusterzone()); for (intptr_t i = start_index_, n = stop_index_; i < n; i++) { type_param ^= refs.At(i); - type_param ^= type_param.Canonicalize(d->thread(), nullptr); + type_param ^= type_param.Canonicalize(d->thread()); refs.SetAt(i, type_param); } } @@ -7263,8 +7166,6 @@ SerializationCluster* Serializer::NewClusterForClass(intptr_t cid, case kRecordTypeCid: return new (Z) RecordTypeSerializationCluster( is_canonical, cluster_represents_canonical_set); - case kTypeRefCid: - return new (Z) TypeRefSerializationCluster(); case kTypeParameterCid: return new (Z) TypeParameterSerializationCluster( is_canonical, cluster_represents_canonical_set); @@ -8442,9 +8343,6 @@ DeserializationCluster* Deserializer::ReadCluster() { case kRecordTypeCid: return new (Z) RecordTypeDeserializationCluster(is_canonical, !is_non_root_unit_); - case kTypeRefCid: - ASSERT(!is_canonical); - return new (Z) TypeRefDeserializationCluster(); case kTypeParameterCid: return new (Z) TypeParameterDeserializationCluster(is_canonical, !is_non_root_unit_); diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc index 6972582b100..eafd8a6caac 100644 --- a/runtime/vm/class_finalizer.cc +++ b/runtime/vm/class_finalizer.cc @@ -364,7 +364,7 @@ TypeArgumentsPtr ClassFinalizer::FinalizeTypeArguments( } } if (finalization >= kCanonicalize) { - return type_args.Canonicalize(Thread::Current(), nullptr); + return type_args.Canonicalize(Thread::Current()); } return type_args.ptr(); } @@ -375,7 +375,7 @@ AbstractTypePtr ClassFinalizer::FinalizeType(const AbstractType& type, // Ensure type is canonical if canonicalization is requested. if ((finalization >= kCanonicalize) && !type.IsCanonical() && !type.IsBeingFinalized()) { - return type.Canonicalize(Thread::Current(), nullptr); + return type.Canonicalize(Thread::Current()); } return type.ptr(); } @@ -383,22 +383,6 @@ AbstractTypePtr ClassFinalizer::FinalizeType(const AbstractType& type, Thread* thread = Thread::Current(); Zone* zone = thread->zone(); - if (type.IsTypeRef()) { - if (type.IsBeingFinalized()) { - // The referenced type will be finalized later by the code that set the - // is_being_finalized mark bit. - return type.ptr(); - } - type.SetIsBeingFinalized(); - AbstractType& ref_type = - AbstractType::Handle(zone, TypeRef::Cast(type).type()); - ref_type = FinalizeType(ref_type, finalization); - ASSERT(ref_type.IsFinalized()); - TypeRef::Cast(type).set_type(ref_type); - ASSERT(type.IsFinalized()); - return type.ptr(); - } - ASSERT(!type.IsBeingFinalized()); // Mark the type as being finalized in order to detect self reference. @@ -411,11 +395,12 @@ AbstractTypePtr ClassFinalizer::FinalizeType(const AbstractType& type, if (type.IsTypeParameter()) { const TypeParameter& type_parameter = TypeParameter::Cast(type); - const Class& parameterized_class = - Class::Handle(zone, type_parameter.parameterized_class()); // The base and index of a function type parameter are eagerly calculated // upon loading and do not require adjustment here. - if (!parameterized_class.IsNull()) { + if (type_parameter.IsClassTypeParameter()) { + const Class& parameterized_class = + Class::Cast(Object::Handle(zone, type_parameter.owner())); + ASSERT(!parameterized_class.IsNull()); // The index must reflect the position of this type parameter in the type // arguments vector of its parameterized class. The offset to add is the // number of type arguments in the super type, which is equal to the @@ -431,17 +416,17 @@ AbstractTypePtr ClassFinalizer::FinalizeType(const AbstractType& type, type_parameter.set_base(offset); // Informative, but not needed. type_parameter.set_index(index); - // Remove the reference to the parameterized class. - type_parameter.set_parameterized_class_id(kClassCid); + if (AbstractType::Handle(zone, type_parameter.bound()) + .IsNullableObjectType()) { + // Remove the reference to the parameterized class to + // canonicalize common class type parameters + // with 'Object?' bound and same indices to the same + // instances. + type_parameter.set_owner(Object::null_object()); + } } type_parameter.SetIsFinalized(); - AbstractType& upper_bound = AbstractType::Handle(zone); - upper_bound = type_parameter.bound(); - if (!upper_bound.IsBeingFinalized()) { - upper_bound = FinalizeType(upper_bound, kFinalize); - type_parameter.set_bound(upper_bound); - } if (FLAG_trace_type_finalization) { THR_Print("Done finalizing type parameter at index %" Pd "\n", @@ -449,7 +434,7 @@ AbstractTypePtr ClassFinalizer::FinalizeType(const AbstractType& type, } if (finalization >= kCanonicalize) { - return type_parameter.Canonicalize(thread, nullptr); + return type_parameter.Canonicalize(thread); } return type_parameter.ptr(); } @@ -497,12 +482,12 @@ AbstractTypePtr ClassFinalizer::FinalizeType(const AbstractType& type, THR_Print("Canonicalizing type '%s'\n", String::Handle(zone, type.Name()).ToCString()); AbstractType& canonical_type = - AbstractType::Handle(zone, type.Canonicalize(thread, nullptr)); + AbstractType::Handle(zone, type.Canonicalize(thread)); THR_Print("Done canonicalizing type '%s'\n", String::Handle(zone, canonical_type.Name()).ToCString()); return canonical_type.ptr(); } - return type.Canonicalize(thread, nullptr); + return type.Canonicalize(thread); } else { return type.ptr(); } @@ -540,7 +525,7 @@ AbstractTypePtr ClassFinalizer::FinalizeSignature( signature.SetIsFinalized(); if (finalization >= kCanonicalize) { - return signature.Canonicalize(Thread::Current(), nullptr); + return signature.Canonicalize(Thread::Current()); } return signature.ptr(); } @@ -568,7 +553,7 @@ AbstractTypePtr ClassFinalizer::FinalizeRecordType( record.SetIsFinalized(); if (finalization >= kCanonicalize) { - return record.Canonicalize(Thread::Current(), nullptr); + return record.Canonicalize(Thread::Current()); } return record.ptr(); } @@ -1198,9 +1183,9 @@ void ClassFinalizer::RemapClassIds(intptr_t* old_to_new_cid) { // The following instances use cids for the computation of canonical hash codes // indirectly: // -// * TypeRefPtr (due to UntaggedTypeRef::type_->type_class_id) // * TypePtr (due to type arguments) // * FunctionTypePtr (due to the result and parameter types) +// * RecordTypePtr (due to field types) // * TypeArgumentsPtr (due to type references) // * InstancePtr (due to instance fields) // * ArrayPtr (due to type arguments & array entries) @@ -1215,11 +1200,6 @@ void ClassFinalizer::RemapClassIds(intptr_t* old_to_new_cid) { // * InstancePtr (weak table) // * ArrayPtr (weak table) // -// No caching of canonical hash codes (i.e. it gets re-computed every time) -// happens for: -// -// * TypeRefPtr (computed via UntaggedTypeRef::type_->type_class_id) -// // Usages of canonical hash codes are: // // * ObjectStore::canonical_types() @@ -1293,8 +1273,7 @@ void ClassFinalizer::RehashTypes() { for (intptr_t i = 0; i < types.Length(); i++) { type ^= types.At(i); bool present = types_table.Insert(type); - // Two recursive types with different topology (and hashes) may be equal. - ASSERT(!present || type.IsRecursive()); + ASSERT(!present); } object_store->set_canonical_types(types_table.Release()); @@ -1314,8 +1293,7 @@ void ClassFinalizer::RehashTypes() { for (intptr_t i = 0; i < function_types.Length(); i++) { function_type ^= function_types.At(i); bool present = function_types_table.Insert(function_type); - // Two recursive types with different topology (and hashes) may be equal. - ASSERT(!present || function_type.IsRecursive()); + ASSERT(!present); } object_store->set_canonical_function_types(function_types_table.Release()); @@ -1335,8 +1313,7 @@ void ClassFinalizer::RehashTypes() { for (intptr_t i = 0; i < record_types.Length(); i++) { record_type ^= record_types.At(i); bool present = record_types_table.Insert(record_type); - // Two recursive types with different topology (and hashes) may be equal. - ASSERT(!present || record_type.IsRecursive()); + ASSERT(!present); } object_store->set_canonical_record_types(record_types_table.Release()); @@ -1356,8 +1333,7 @@ void ClassFinalizer::RehashTypes() { for (intptr_t i = 0; i < typeparams.Length(); i++) { typeparam ^= typeparams.At(i); bool present = typeparams_table.Insert(typeparam); - // Two recursive types with different topology (and hashes) may be equal. - ASSERT(!present || typeparam.IsRecursive()); + ASSERT(!present); } object_store->set_canonical_type_parameters(typeparams_table.Release()); @@ -1381,8 +1357,7 @@ void ClassFinalizer::RehashTypes() { for (intptr_t i = 0; i < typeargs.Length(); i++) { typearg ^= typeargs.At(i); bool present = typeargs_table.Insert(typearg); - // Two recursive types with different topology (and hashes) may be equal. - ASSERT(!present || typearg.IsRecursive()); + ASSERT(!present); } object_store->set_canonical_type_arguments(typeargs_table.Release()); } diff --git a/runtime/vm/class_id.h b/runtime/vm/class_id.h index fa442729c2e..d1e92265701 100644 --- a/runtime/vm/class_id.h +++ b/runtime/vm/class_id.h @@ -75,7 +75,6 @@ static constexpr intptr_t kClassIdTagMax = (1 << 20) - 1; V(Type) \ V(FunctionType) \ V(RecordType) \ - V(TypeRef) \ V(TypeParameter) \ V(FinalizerBase) \ V(Finalizer) \ diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc index fa059723fd8..642c32847c4 100644 --- a/runtime/vm/compiler/aot/precompiler.cc +++ b/runtime/vm/compiler/aot/precompiler.cc @@ -1161,8 +1161,14 @@ void Precompiler::AddType(const AbstractType& abstype) { if (typeparams_to_retain_.HasKey(¶m)) return; typeparams_to_retain_.Insert(&TypeParameter::ZoneHandle(Z, param.ptr())); - auto& bound = AbstractType::Handle(Z, param.bound()); - AddType(bound); + Object& owner = Object::Handle(Z, param.owner()); + if (owner.IsClass()) { + AddTypesOf(Class::Cast(owner)); + } else if (owner.IsFunctionType()) { + AddType(FunctionType::Cast(owner)); + } else { + RELEASE_ASSERT(owner.IsNull()); + } return; } @@ -1193,10 +1199,6 @@ void Precompiler::AddType(const AbstractType& abstype) { AddTypesOf(cls); const TypeArguments& vector = TypeArguments::Handle(Z, type.arguments()); AddTypeArguments(vector); - } else if (abstype.IsTypeRef()) { - AbstractType& type = AbstractType::Handle(Z); - type = TypeRef::Cast(abstype).type(); - AddType(type); } else if (abstype.IsRecordType()) { const auto& rec = RecordType::Cast(abstype); AbstractType& type = AbstractType::Handle(Z); @@ -2404,8 +2406,7 @@ void Precompiler::AttachOptimizedTypeTestingStub() { void VisitObject(ObjectPtr obj) override { if (obj->GetClassId() == kTypeCid || obj->GetClassId() == kFunctionTypeCid || - obj->GetClassId() == kRecordTypeCid || - obj->GetClassId() == kTypeRefCid) { + obj->GetClassId() == kRecordTypeCid) { type_ ^= obj; types_->Add(type_); } diff --git a/runtime/vm/compiler/backend/constant_propagator.cc b/runtime/vm/compiler/backend/constant_propagator.cc index 564a23a174b..8e9372f1ada 100644 --- a/runtime/vm/compiler/backend/constant_propagator.cc +++ b/runtime/vm/compiler/backend/constant_propagator.cc @@ -1055,11 +1055,8 @@ void ConstantPropagator::VisitInstantiateType(InstantiateTypeInstr* instr) { AbstractType& result = AbstractType::Handle( Z, instr->type().InstantiateFrom( instantiator_type_args, function_type_args, kAllFree, Heap::kOld)); - if (result.IsTypeRef()) { - result = TypeRef::Cast(result).type(); - } ASSERT(result.IsInstantiated()); - result = result.Canonicalize(T, nullptr); + result = result.Canonicalize(T); SetValue(instr, result); } @@ -1126,7 +1123,7 @@ void ConstantPropagator::VisitInstantiateTypeArguments( Z, type_arguments.InstantiateFrom( instantiator_type_args, function_type_args, kAllFree, Heap::kOld)); ASSERT(result.IsInstantiated()); - result = result.Canonicalize(T, nullptr); + result = result.Canonicalize(T); SetValue(instr, result); } diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc index 3c7f4901a76..526eb1943d7 100644 --- a/runtime/vm/compiler/backend/il.cc +++ b/runtime/vm/compiler/backend/il.cc @@ -1027,9 +1027,6 @@ Instruction* AssertSubtypeInstr::Canonicalize(FlowGraph* flow_graph) { auto& constant_super_type = AbstractType::Handle( Z, AbstractType::Cast(super_type()->BoundConstant()).ptr()); - ASSERT(!constant_super_type.IsTypeRef()); - ASSERT(!constant_sub_type.IsTypeRef()); - if (AbstractType::InstantiateAndTestSubtype( &constant_sub_type, &constant_super_type, constant_instantiator_type_args, constant_function_type_args)) { @@ -3025,10 +3022,7 @@ Definition* AssertAssignableInstr::Canonicalize(FlowGraph* flow_graph) { // Failed instantiation in dead code. return this; } - if (new_dst_type.IsTypeRef()) { - new_dst_type = TypeRef::Cast(new_dst_type).type(); - } - new_dst_type = new_dst_type.Canonicalize(Thread::Current(), nullptr); + new_dst_type = new_dst_type.Canonicalize(Thread::Current()); // Successfully instantiated destination type: update the type attached // to this instruction and set type arguments to null because we no diff --git a/runtime/vm/compiler/backend/il_serializer.cc b/runtime/vm/compiler/backend/il_serializer.cc index 53b15ff01e7..4fec37c30a9 100644 --- a/runtime/vm/compiler/backend/il_serializer.cc +++ b/runtime/vm/compiler/backend/il_serializer.cc @@ -1425,7 +1425,7 @@ void FlowGraphSerializer::WriteTrait::Write( ASSERT(cid != kIllegalCid); // Do not write objects repeatedly. const intptr_t object_id = s->heap()->GetObjectId(x.ptr()); - if (object_id != 0) { + if (object_id > 0) { const intptr_t object_index = object_id - 1; s->Write(kIllegalCid); s->Write(object_index); @@ -1458,6 +1458,109 @@ void FlowGraphDeserializer::SetObjectAt(intptr_t object_index, objects_[object_index] = &object; } +bool FlowGraphSerializer::IsWritten(const Object& obj) { + const intptr_t object_id = heap()->GetObjectId(obj.ptr()); + return (object_id != 0); +} + +bool FlowGraphSerializer::HasEnclosingTypes(const Object& obj) { + if (num_free_fun_type_params_ == 0) return false; + if (obj.IsAbstractType()) { + return !AbstractType::Cast(obj).IsInstantiated(kFunctions, + num_free_fun_type_params_); + } else if (obj.IsTypeArguments()) { + return !TypeArguments::Cast(obj).IsInstantiated(kFunctions, + num_free_fun_type_params_); + } else { + UNREACHABLE(); + } +} + +bool FlowGraphSerializer::WriteObjectWithEnclosingTypes(const Object& obj) { + if (HasEnclosingTypes(obj)) { + Write(true); + // Reset assigned object id so it could be written + // while writing enclosing types. + heap()->SetObjectId(obj.ptr(), -1); + WriteEnclosingTypes(obj, num_free_fun_type_params_); + Write(false); + // Can write any type parameters after all enclosing types are written. + const intptr_t saved_num_free_fun_type_params = num_free_fun_type_params_; + num_free_fun_type_params_ = 0; + Write(obj); + num_free_fun_type_params_ = saved_num_free_fun_type_params; + return true; + } else { + Write(false); + return false; + } +} + +void FlowGraphSerializer::WriteEnclosingTypes( + const Object& obj, + intptr_t num_free_fun_type_params) { + if (obj.IsType()) { + const auto& type = Type::Cast(obj); + if (type.arguments() != TypeArguments::null()) { + const auto& type_args = TypeArguments::Handle(Z, type.arguments()); + WriteEnclosingTypes(type_args, num_free_fun_type_params); + } + } else if (obj.IsRecordType()) { + const auto& rec = RecordType::Cast(obj); + auto& elem = AbstractType::Handle(Z); + for (intptr_t i = 0, n = rec.NumFields(); i < n; ++i) { + elem = rec.FieldTypeAt(i); + WriteEnclosingTypes(elem, num_free_fun_type_params); + } + } else if (obj.IsFunctionType()) { + const auto& sig = FunctionType::Cast(obj); + const intptr_t num_parent_type_args = sig.NumParentTypeArguments(); + if (num_free_fun_type_params > num_parent_type_args) { + num_free_fun_type_params = num_parent_type_args; + } + AbstractType& elem = AbstractType::Handle(Z, sig.result_type()); + WriteEnclosingTypes(elem, num_free_fun_type_params); + for (intptr_t i = 0, n = sig.NumParameters(); i < n; ++i) { + elem = sig.ParameterTypeAt(i); + WriteEnclosingTypes(elem, num_free_fun_type_params); + } + if (sig.IsGeneric()) { + const TypeParameters& type_params = + TypeParameters::Handle(Z, sig.type_parameters()); + WriteEnclosingTypes(TypeArguments::Handle(Z, type_params.bounds()), + num_free_fun_type_params); + } + } else if (obj.IsTypeParameter()) { + const auto& tp = TypeParameter::Cast(obj); + if (tp.IsFunctionTypeParameter() && + (tp.index() < num_free_fun_type_params)) { + const auto& owner = FunctionType::Cast(Object::Handle(Z, tp.owner())); + if (!IsWritten(owner)) { + Write(true); + Write(owner); + } + } + } else if (obj.IsTypeArguments()) { + const auto& type_args = TypeArguments::Cast(obj); + auto& elem = AbstractType::Handle(Z); + for (intptr_t i = 0, n = type_args.Length(); i < n; ++i) { + elem = type_args.TypeAt(i); + WriteEnclosingTypes(elem, num_free_fun_type_params); + } + } +} + +const Object& FlowGraphDeserializer::ReadObjectWithEnclosingTypes() { + if (Read()) { + while (Read()) { + Read(); + } + return Read(); + } else { + return Object::null_object(); + } +} + void FlowGraphSerializer::WriteObjectImpl(const Object& x, intptr_t cid, intptr_t object_index) { @@ -1519,24 +1622,23 @@ void FlowGraphSerializer::WriteObjectImpl(const Object& x, case kFunctionTypeCid: { const auto& type = FunctionType::Cast(x); ASSERT(type.IsFinalized()); - TypeScope type_scope(this, type.IsRecursive()); + if (WriteObjectWithEnclosingTypes(type)) { + break; + } + const intptr_t saved_num_free_fun_type_params = num_free_fun_type_params_; + const intptr_t num_parent_type_args = type.NumParentTypeArguments(); + if (num_free_fun_type_params_ > num_parent_type_args) { + num_free_fun_type_params_ = num_parent_type_args; + } Write(static_cast(type.nullability())); Write(type.packed_parameter_counts()); Write(type.packed_type_parameter_counts()); Write( TypeParameters::Handle(Z, type.type_parameters())); - AbstractType& t = AbstractType::Handle(Z, type.result_type()); - Write(t); - // Do not write parameter types as Array to avoid eager canonicalization - // when reading. - const Array& param_types = Array::Handle(Z, type.parameter_types()); - ASSERT(param_types.Length() == type.NumParameters()); - for (intptr_t i = 0, n = type.NumParameters(); i < n; ++i) { - t ^= param_types.At(i); - Write(t); - } + Write(AbstractType::Handle(Z, type.result_type())); + Write(Array::Handle(Z, type.parameter_types())); Write(Array::Handle(Z, type.named_parameter_names())); - Write(type_scope.CanBeCanonicalized()); + num_free_fun_type_params_ = saved_num_free_fun_type_params; break; } case kICDataCid: { @@ -1618,11 +1720,12 @@ void FlowGraphSerializer::WriteObjectImpl(const Object& x, case kRecordTypeCid: { const auto& rec = RecordType::Cast(x); ASSERT(rec.IsFinalized()); - TypeScope type_scope(this, rec.IsRecursive()); + if (WriteObjectWithEnclosingTypes(rec)) { + break; + } Write(static_cast(rec.nullability())); Write(rec.shape()); Write(Array::Handle(Z, rec.field_types())); - Write(type_scope.CanBeCanonicalized()); break; } case kSentinelCid: @@ -1653,21 +1756,24 @@ void FlowGraphSerializer::WriteObjectImpl(const Object& x, case kTypeCid: { const auto& type = Type::Cast(x); ASSERT(type.IsFinalized()); + if (WriteObjectWithEnclosingTypes(type)) { + break; + } const auto& cls = Class::Handle(Z, type.type_class()); - TypeScope type_scope(this, type.IsRecursive() && cls.IsGeneric()); Write(static_cast(type.nullability())); Write(type.type_class_id()); if (cls.IsGeneric()) { const auto& type_args = TypeArguments::Handle(Z, type.arguments()); Write(type_args); } - Write(type_scope.CanBeCanonicalized()); break; } case kTypeArgumentsCid: { const auto& type_args = TypeArguments::Cast(x); ASSERT(type_args.IsFinalized()); - TypeScope type_scope(this, type_args.IsRecursive()); + if (WriteObjectWithEnclosingTypes(type_args)) { + break; + } const intptr_t len = type_args.Length(); Write(len); auto& type = AbstractType::Handle(Z); @@ -1675,19 +1781,21 @@ void FlowGraphSerializer::WriteObjectImpl(const Object& x, type = type_args.TypeAt(i); Write(type); } - Write(type_scope.CanBeCanonicalized()); break; } case kTypeParameterCid: { const auto& tp = TypeParameter::Cast(x); ASSERT(tp.IsFinalized()); - TypeScope type_scope(this, tp.IsRecursive()); - Write(tp.parameterized_class_id()); + if (WriteObjectWithEnclosingTypes(tp)) { + break; + } Write(tp.base()); Write(tp.index()); Write(static_cast(tp.nullability())); - Write(AbstractType::Handle(Z, tp.bound())); - Write(type_scope.CanBeCanonicalized()); + Write(tp.parameterized_class_id()); + if (tp.IsFunctionTypeParameter()) { + Write(Object::Handle(Z, tp.owner())); + } break; } case kTypeParametersCid: { @@ -1698,14 +1806,6 @@ void FlowGraphSerializer::WriteObjectImpl(const Object& x, Write(TypeArguments::Handle(Z, tps.defaults())); break; } - case kTypeRefCid: { - const auto& tr = TypeRef::Cast(x); - ASSERT(tr.IsFinalized()); - TypeScope type_scope(this, tr.IsRecursive()); - Write(AbstractType::Handle(Z, tr.type())); - Write(type_scope.CanBeCanonicalized()); - break; - } default: { const classid_t cid = x.GetClassId(); if ((cid >= kNumPredefinedCids) || (cid == kInstanceCid)) { @@ -1793,6 +1893,10 @@ const Object& FlowGraphDeserializer::ReadObjectImpl(intptr_t cid, case kFunctionCid: return Read(); case kFunctionTypeCid: { + const auto& enc_type = ReadObjectWithEnclosingTypes(); + if (!enc_type.IsNull()) { + return enc_type; + } const Nullability nullability = static_cast(Read()); auto& result = FunctionType::ZoneHandle(Z, FunctionType::New(0, nullability)); @@ -1801,15 +1905,10 @@ const Object& FlowGraphDeserializer::ReadObjectImpl(intptr_t cid, result.set_packed_type_parameter_counts(Read()); result.SetTypeParameters(Read()); result.set_result_type(Read()); - const Array& param_types = - Array::Handle(Z, Array::New(result.NumParameters(), Heap::kOld)); - for (intptr_t i = 0, n = result.NumParameters(); i < n; ++i) { - param_types.SetAt(i, Read()); - } - result.set_parameter_types(param_types); + result.set_parameter_types(Read()); result.set_named_parameter_names(Read()); result.SetIsFinalized(); - result ^= MaybeCanonicalize(result, object_index, Read()); + result ^= result.Canonicalize(thread()); return result; } case kICDataCid: { @@ -1897,13 +1996,17 @@ const Object& FlowGraphDeserializer::ReadObjectImpl(intptr_t cid, return record; } case kRecordTypeCid: { + const auto& enc_type = ReadObjectWithEnclosingTypes(); + if (!enc_type.IsNull()) { + return enc_type; + } const Nullability nullability = static_cast(Read()); const RecordShape shape = Read(); const Array& field_types = Read(); RecordType& rec = RecordType::ZoneHandle( Z, RecordType::New(shape, field_types, nullability)); rec.SetIsFinalized(); - rec ^= MaybeCanonicalize(rec, object_index, Read()); + rec ^= rec.Canonicalize(thread()); return rec; } case kSentinelCid: @@ -1927,6 +2030,10 @@ const Object& FlowGraphDeserializer::ReadObjectImpl(intptr_t cid, return String::ZoneHandle(Z, Symbols::FromUTF16(thread(), utf16, length)); } case kTypeCid: { + const auto& enc_type = ReadObjectWithEnclosingTypes(); + if (!enc_type.IsNull()) { + return enc_type; + } const Nullability nullability = static_cast(Read()); const classid_t type_class_id = Read(); const auto& cls = Class::Handle(Z, GetClassById(type_class_id)); @@ -1941,37 +2048,43 @@ const Object& FlowGraphDeserializer::ReadObjectImpl(intptr_t cid, result = cls.DeclarationType(); result = result.ToNullability(nullability, Heap::kOld); } - result ^= MaybeCanonicalize(result, object_index, Read()); + result ^= result.Canonicalize(thread()); return result; } case kTypeArgumentsCid: { + const auto& enc_type_args = ReadObjectWithEnclosingTypes(); + if (!enc_type_args.IsNull()) { + return enc_type_args; + } const intptr_t len = Read(); auto& type_args = TypeArguments::ZoneHandle(Z, TypeArguments::New(len)); SetObjectAt(object_index, type_args); for (intptr_t i = 0; i < len; ++i) { type_args.SetTypeAt(i, Read()); } - type_args ^= MaybeCanonicalize(type_args, object_index, Read()); + type_args ^= type_args.Canonicalize(thread()); return type_args; } case kTypeParameterCid: { - const classid_t parameterized_class_id = Read(); + const auto& enc_type = ReadObjectWithEnclosingTypes(); + if (!enc_type.IsNull()) { + return enc_type; + } const intptr_t base = Read(); const intptr_t index = Read(); const Nullability nullability = static_cast(Read()); - const auto& parameterized_class = - Class::Handle(Z, (parameterized_class_id == kFunctionCid) - ? Class::null() - : GetClassById(parameterized_class_id)); + const classid_t parameterized_class_id = Read(); + const Object& owner = + (parameterized_class_id == kObjectCid) + ? Object::null_object() + : ((parameterized_class_id == kFunctionCid) + ? Read() + : Class::Handle(Z, GetClassById(parameterized_class_id))); auto& tp = TypeParameter::ZoneHandle( - Z, TypeParameter::New(parameterized_class, base, index, - /*bound=*/Object::null_abstract_type(), - nullability)); + Z, TypeParameter::New(owner, base, index, nullability)); SetObjectAt(object_index, tp); - const auto& bound = Read(); - tp.set_bound(bound); tp.SetIsFinalized(); - tp ^= MaybeCanonicalize(tp, object_index, Read()); + tp ^= tp.Canonicalize(thread()); return tp; } case kTypeParametersCid: { @@ -1982,16 +2095,6 @@ const Object& FlowGraphDeserializer::ReadObjectImpl(intptr_t cid, tps.set_defaults(Read()); return tps; } - case kTypeRefCid: { - auto& tr = - TypeRef::ZoneHandle(Z, TypeRef::New(Object::null_abstract_type())); - SetObjectAt(object_index, tr); - const auto& type = Read(); - ASSERT(!type.IsNull()); - tr.set_type(type); - tr ^= MaybeCanonicalize(tr, object_index, Read()); - return tr; - } default: if ((cid >= kNumPredefinedCids) || (cid == kInstanceCid)) { const auto& cls = Class::Handle(Z, GetClassById(cid)); @@ -2024,29 +2127,6 @@ const Object& FlowGraphDeserializer::ReadObjectImpl(intptr_t cid, return Object::null_object(); } -InstancePtr FlowGraphDeserializer::MaybeCanonicalize( - const Instance& obj, - intptr_t object_index, - bool can_be_canonicalized) { - if (can_be_canonicalized) { - intptr_t remaining = 0; - for (intptr_t idx : pending_canonicalization_) { - if (idx < object_index) { - pending_canonicalization_[remaining++] = idx; - } else { - objects_[idx] = &Instance::ZoneHandle( - Z, Instance::Cast(*objects_[idx]).Canonicalize(thread())); - } - } - pending_canonicalization_.TruncateTo(remaining); - return obj.Canonicalize(thread()); - } else { - ASSERT(objects_[object_index]->ptr() == obj.ptr()); - pending_canonicalization_.Add(object_index); - return obj.ptr(); - } -} - #define HANDLES_SERIALIZABLE_AS_OBJECT(V) \ V(AbstractType, Object::null_abstract_type()) \ V(Array, Object::null_array()) \ diff --git a/runtime/vm/compiler/backend/il_serializer.h b/runtime/vm/compiler/backend/il_serializer.h index dc5fff5c350..25d9c867606 100644 --- a/runtime/vm/compiler/backend/il_serializer.h +++ b/runtime/vm/compiler/backend/il_serializer.h @@ -306,31 +306,11 @@ class FlowGraphSerializer : public ValueObject { private: void WriteObjectImpl(const Object& x, intptr_t cid, intptr_t object_index); - - // Used to track scopes of recursive types during serialization. - struct TypeScope { - TypeScope(FlowGraphSerializer* serializer, bool is_recursive) - : serializer_(serializer), - is_recursive_(is_recursive), - was_writing_recursive_type_(serializer->writing_recursive_type_) { - serializer->writing_recursive_type_ = is_recursive; - } - - ~TypeScope() { - serializer_->writing_recursive_type_ = was_writing_recursive_type_; - } - - // Returns true if type of the current scope can be canonicalized - // during deserialization. Recursive types which were not - // fully deserialized should not be canonicalized. - bool CanBeCanonicalized() const { - return !is_recursive_ || !was_writing_recursive_type_; - } - - FlowGraphSerializer* const serializer_; - const bool is_recursive_; - const bool was_writing_recursive_type_; - }; + bool IsWritten(const Object& obj); + bool HasEnclosingTypes(const Object& obj); + bool WriteObjectWithEnclosingTypes(const Object& type); + void WriteEnclosingTypes(const Object& type, + intptr_t num_free_fun_type_params); NonStreamingWriteStream* stream_; Zone* zone_; @@ -339,7 +319,7 @@ class FlowGraphSerializer : public ValueObject { Heap* heap_; intptr_t object_counter_ = 0; bool can_write_refs_ = false; - bool writing_recursive_type_ = false; + intptr_t num_free_fun_type_params_ = kMaxInt; }; // Deserializes flow graph. @@ -521,10 +501,7 @@ class FlowGraphDeserializer : public ValueObject { ClassPtr GetClassById(classid_t id) const; const Object& ReadObjectImpl(intptr_t cid, intptr_t object_index); void SetObjectAt(intptr_t object_index, const Object& object); - - InstancePtr MaybeCanonicalize(const Instance& obj, - intptr_t object_index, - bool can_be_canonicalized); + const Object& ReadObjectWithEnclosingTypes(); const ParsedFunction& parsed_function_; ReadStream* stream_; @@ -539,7 +516,6 @@ class FlowGraphDeserializer : public ValueObject { GrowableArray definitions_; GrowableArray objects_; intptr_t object_counter_ = 0; - GrowableArray pending_canonicalization_; }; } // namespace dart diff --git a/runtime/vm/compiler/backend/range_analysis.cc b/runtime/vm/compiler/backend/range_analysis.cc index bd93b086e34..bf52812ace3 100644 --- a/runtime/vm/compiler/backend/range_analysis.cc +++ b/runtime/vm/compiler/backend/range_analysis.cc @@ -2834,7 +2834,6 @@ void LoadFieldInstr::InferRange(RangeAnalysis* analysis, Range* range) { case Slot::Kind::kTypeParameters_flags: case Slot::Kind::kTypeParameters_bounds: case Slot::Kind::kTypeParameters_defaults: - case Slot::Kind::kTypeParameter_bound: case Slot::Kind::kUnhandledException_exception: case Slot::Kind::kUnhandledException_stacktrace: case Slot::Kind::kWeakProperty_key: diff --git a/runtime/vm/compiler/backend/slot.cc b/runtime/vm/compiler/backend/slot.cc index 08fed799a87..9e1181d75a7 100644 --- a/runtime/vm/compiler/backend/slot.cc +++ b/runtime/vm/compiler/backend/slot.cc @@ -201,7 +201,6 @@ bool Slot::IsImmutableLengthSlot() const { case Slot::Kind::kTypeParameters_flags: case Slot::Kind::kTypeParameters_bounds: case Slot::Kind::kTypeParameters_defaults: - case Slot::Kind::kTypeParameter_bound: case Slot::Kind::kUnhandledException_exception: case Slot::Kind::kUnhandledException_stacktrace: case Slot::Kind::kWeakProperty_key: diff --git a/runtime/vm/compiler/backend/slot.h b/runtime/vm/compiler/backend/slot.h index d860ed96b75..e4e6efdfd9b 100644 --- a/runtime/vm/compiler/backend/slot.h +++ b/runtime/vm/compiler/backend/slot.h @@ -130,7 +130,6 @@ class ParsedFunction; V(TypeArguments, UntaggedTypeArguments, hash, Smi, VAR) \ V(TypeArguments, UntaggedTypeArguments, length, Smi, FINAL) \ V(TypeParameters, UntaggedTypeParameters, names, Array, FINAL) \ - V(TypeParameter, UntaggedTypeParameter, bound, Dynamic, FINAL) \ V(UnhandledException, UntaggedUnhandledException, exception, Dynamic, FINAL) \ V(UnhandledException, UntaggedUnhandledException, stacktrace, Dynamic, FINAL) diff --git a/runtime/vm/compiler/backend/type_propagator.cc b/runtime/vm/compiler/backend/type_propagator.cc index c895976d6cf..c145c3d7092 100644 --- a/runtime/vm/compiler/backend/type_propagator.cc +++ b/runtime/vm/compiler/backend/type_propagator.cc @@ -931,7 +931,6 @@ static bool CanPotentiallyBeSmi(const AbstractType& type, bool recurse) { // Comparable). if (type.IsFutureOrType() || type.type_class() == CompilerState::Current().ComparableClass().ptr()) { - // Type may be a TypeRef. const auto& args = TypeArguments::Handle(type.arguments()); const auto& arg0 = AbstractType::Handle(args.TypeAt(0)); return !recurse || CanPotentiallyBeSmi(arg0, /*recurse=*/true); diff --git a/runtime/vm/compiler/frontend/constant_reader.cc b/runtime/vm/compiler/frontend/constant_reader.cc index 2327667b1bb..8cd0f662b35 100644 --- a/runtime/vm/compiler/frontend/constant_reader.cc +++ b/runtime/vm/compiler/frontend/constant_reader.cc @@ -541,7 +541,7 @@ InstancePtr ConstantReader::ReadConstantInternal(intptr_t constant_index) { for (intptr_t j = 0; j < number_of_type_arguments; ++j) { type_arguments.SetTypeAt(j, type_translator.BuildType()); } - type_arguments = type_arguments.Canonicalize(Thread::Current(), nullptr); + type_arguments = type_arguments.Canonicalize(Thread::Current()); // Make a copy of the old closure, and set delayed type arguments. Closure& closure = Closure::Handle(Z, Closure::RawCast(constant.ptr())); Function& function = Function::Handle(Z, closure.function()); diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc index 708487ae863..d94f95eb06f 100644 --- a/runtime/vm/compiler/frontend/kernel_to_il.cc +++ b/runtime/vm/compiler/frontend/kernel_to_il.cc @@ -1993,9 +1993,6 @@ void FlowGraphBuilder::BuildTypeArgumentTypeChecks(TypeChecksToBuild mode, type_param = dart_function.TypeParameterAt(i); } ASSERT(type_param.IsFinalized()); - if (bound.IsTypeRef()) { - bound = TypeRef::Cast(bound).type(); - } check_bounds += AssertSubtype(TokenPosition::kNoSource, type_param, bound, name); } @@ -4313,7 +4310,7 @@ Fragment FlowGraphBuilder::FfiPointerFromAddress() { // do not appear in the type arguments to a any Pointer classes in an FFI // signature. ASSERT(args.IsNull() || args.IsInstantiated()); - args = args.Canonicalize(thread_, nullptr); + args = args.Canonicalize(thread_); Fragment code; code += Constant(args); diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc index 8b28888b3c8..c98328f0403 100644 --- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc +++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc @@ -789,7 +789,6 @@ Type& TranslationHelper::GetDeclarationType(const Class& klass) { TypeParameter& type_param = TypeParameter::Handle(); for (intptr_t i = 0; i < num_type_params; i++) { type_param = klass.TypeParameterAt(i); - ASSERT(type_param.bound() != AbstractType::null()); type_args.SetTypeAt(i, type_param); } } @@ -3103,7 +3102,6 @@ ActiveTypeParametersScope::ActiveTypeParametersScope( for (intptr_t j = f.NumTypeParameters() - 1; j >= 0; --j) { const auto& type_param = TypeParameter::Handle(Z, f.TypeParameterAt(j)); params.SetTypeAt(--index, type_param); - active_class_->RecordDerivedTypeParameter(Z, type_param); } } @@ -3139,27 +3137,13 @@ ActiveTypeParametersScope::ActiveTypeParametersScope( ? active_class->klass->TypeParameterAt(i) : innermost_signature->TypeParameterAt(i)); extended_params.SetTypeAt(index++, type_param); - active_class->RecordDerivedTypeParameter(Z, type_param); } active_class_->local_type_parameters = &extended_params; } ActiveTypeParametersScope::~ActiveTypeParametersScope() { - GrowableObjectArray* dropped = active_class_->derived_type_parameters; - const bool preserve_unpatched = - dropped != nullptr && saved_.derived_type_parameters == nullptr; *active_class_ = saved_; - if (preserve_unpatched) { - // Preserve still unpatched derived type parameters that would be dropped. - auto& derived = TypeParameter::Handle(Z); - for (intptr_t i = 0, n = dropped->Length(); i < n; ++i) { - derived ^= dropped->At(i); - if (derived.bound() == AbstractType::null()) { - active_class_->RecordDerivedTypeParameter(Z, derived); - } - } - } } TypeTranslator::TypeTranslator(KernelReaderHelper* helper, @@ -3178,7 +3162,6 @@ TypeTranslator::TypeTranslator(KernelReaderHelper* helper, zone_(translation_helper_.zone()), result_(AbstractType::Handle(translation_helper_.zone())), finalize_(finalize), - refers_to_derived_type_param_(false), apply_canonical_type_erasure_(apply_canonical_type_erasure), in_constant_context_(in_constant_context) {} @@ -3238,10 +3221,6 @@ void TypeTranslator::BuildTypeInternal() { break; case kTypeParameterType: BuildTypeParameterType(); - if (result_.IsTypeParameter() && - TypeParameter::Cast(result_).bound() == AbstractType::null()) { - refers_to_derived_type_param_ = true; - } break; case kIntersectionType: BuildIntersectionType(); @@ -3467,8 +3446,6 @@ void TypeTranslator::BuildTypeParameterType() { if (class_type_parameter_count > parameter_index) { result_ = active_class_->klass->TypeParameterAt(parameter_index, nullability); - active_class_->RecordDerivedTypeParameter(Z, - TypeParameter::Cast(result_)); return; } parameter_index -= class_type_parameter_count; @@ -3495,8 +3472,6 @@ void TypeTranslator::BuildTypeParameterType() { if (class_type_parameter_count > parameter_index) { result_ = active_class_->klass->TypeParameterAt(parameter_index, nullability); - active_class_->RecordDerivedTypeParameter( - Z, TypeParameter::Cast(result_)); return; } parameter_index -= class_type_parameter_count; @@ -3512,12 +3487,7 @@ void TypeTranslator::BuildTypeParameterType() { result_ = active_class_->member->TypeParameterAt(parameter_index, nullability); if (finalize_) { - ASSERT(TypeParameter::Cast(result_).bound() != - AbstractType::null()); result_ = ClassFinalizer::FinalizeType(result_); - } else { - active_class_->RecordDerivedTypeParameter( - Z, TypeParameter::Cast(result_)); } return; } @@ -3531,11 +3501,7 @@ void TypeTranslator::BuildTypeParameterType() { Z, active_class_->local_type_parameters->TypeAt(parameter_index)); result_ = type_param.ToNullability(nullability, Heap::kOld); if (finalize_) { - ASSERT(TypeParameter::Cast(result_).bound() != AbstractType::null()); result_ = ClassFinalizer::FinalizeType(result_); - } else { - active_class_->RecordDerivedTypeParameter(Z, - TypeParameter::Cast(result_)); } return; } @@ -3587,7 +3553,7 @@ const TypeArguments& TypeTranslator::BuildTypeArguments(intptr_t length) { } if (finalize_) { - type_arguments = type_arguments.Canonicalize(Thread::Current(), nullptr); + type_arguments = type_arguments.Canonicalize(Thread::Current()); } } return type_arguments; @@ -3688,14 +3654,8 @@ void TypeTranslator::LoadAndSetupBounds( TypeParameterHelper helper(helper_); helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kBound); - bool saved_refers_to_derived_type_param = refers_to_derived_type_param_; - refers_to_derived_type_param_ = false; AbstractType& bound = BuildTypeWithoutFinalization(); // read ith bound. ASSERT(!bound.IsNull()); - if (refers_to_derived_type_param_) { - bound = TypeRef::New(bound); - } - refers_to_derived_type_param_ = saved_refers_to_derived_type_param; type_parameters.SetBoundAt(i, bound); helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kDefaultType); AbstractType& default_arg = BuildTypeWithoutFinalization(); @@ -3703,30 +3663,6 @@ void TypeTranslator::LoadAndSetupBounds( type_parameters.SetDefaultAt(i, default_arg); helper.Finish(); } - - // Fix bounds in all derived type parameters. - const intptr_t offset = !parameterized_signature.IsNull() - ? parameterized_signature.NumParentTypeArguments() - : 0; - if (active_class->derived_type_parameters != nullptr) { - auto& derived = TypeParameter::Handle(Z); - auto& bound = AbstractType::Handle(Z); - for (intptr_t i = 0, n = active_class->derived_type_parameters->Length(); - i < n; ++i) { - derived ^= active_class->derived_type_parameters->At(i); - if (derived.bound() == AbstractType::null() && - ((!parameterized_class.IsNull() && - derived.parameterized_class_id() == parameterized_class.id()) || - (!parameterized_signature.IsNull() && - derived.parameterized_class_id() == kFunctionCid && - derived.index() >= offset && - derived.index() < offset + type_parameter_count))) { - bound = type_parameters.BoundAt(derived.index() - offset); - ASSERT(!bound.IsNull()); - derived.set_bound(bound); - } - } - } } const Type& TypeTranslator::ReceiverType(const Class& klass) { @@ -3752,7 +3688,6 @@ const Type& TypeTranslator::ReceiverType(const Class& klass) { TypeParameter& type_param = TypeParameter::Handle(); for (intptr_t i = 0; i < num_type_params; i++) { type_param = klass.TypeParameterAt(i); - ASSERT(type_param.bound() != AbstractType::null()); type_args.SetTypeAt(i, type_param); } } diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.h b/runtime/vm/compiler/frontend/kernel_translation_helper.h index f2a975004f6..1ae31495251 100644 --- a/runtime/vm/compiler/frontend/kernel_translation_helper.h +++ b/runtime/vm/compiler/frontend/kernel_translation_helper.h @@ -1429,16 +1429,6 @@ class ActiveClass { return klass->NumTypeArguments(); } - void RecordDerivedTypeParameter(Zone* zone, const TypeParameter& derived) { - if (derived.bound() == AbstractType::null()) { - if (derived_type_parameters == nullptr) { - derived_type_parameters = &GrowableObjectArray::Handle( - zone, GrowableObjectArray::New(Heap::kOld)); - } - derived_type_parameters->Add(derived); - } - } - const char* ToCString() { return member != nullptr ? member->ToCString() : klass->ToCString(); } @@ -1453,8 +1443,6 @@ class ActiveClass { const FunctionType* enclosing; const TypeArguments* local_type_parameters; - - GrowableObjectArray* derived_type_parameters = nullptr; }; class ActiveClassScope { @@ -1625,7 +1613,6 @@ class TypeTranslator { Zone* zone_; AbstractType& result_; bool finalize_; - bool refers_to_derived_type_param_; const bool apply_canonical_type_erasure_; const bool in_constant_context_; diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h index e5e2f1f235e..3bb4c9fd2c7 100644 --- a/runtime/vm/compiler/runtime_api.h +++ b/runtime/vm/compiler/runtime_api.h @@ -743,13 +743,6 @@ class RecordType : public AllStatic { FINAL_CLASS(); }; -class TypeRef : public AllStatic { - public: - static word type_offset(); - static word InstanceSize(); - FINAL_CLASS(); -}; - class Nullability : public AllStatic { public: static const uint8_t kNullable; @@ -977,7 +970,6 @@ class Bool : public AllStatic { class TypeParameter : public AllStatic { public: - static word bound_offset(); static word InstanceSize(); FINAL_CLASS(); static word parameterized_class_id_offset(); diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h index 0e5fb7a98e8..5bd544181f8 100644 --- a/runtime/vm/compiler/runtime_offsets_extracted.h +++ b/runtime/vm/compiler/runtime_offsets_extracted.h @@ -570,8 +570,6 @@ static constexpr dart::compiler::target::word TypeParameters_flags_offset = 8; static constexpr dart::compiler::target::word TypeParameters_bounds_offset = 12; static constexpr dart::compiler::target::word TypeParameters_defaults_offset = 16; -static constexpr dart::compiler::target::word TypeParameter_bound_offset = 20; -static constexpr dart::compiler::target::word TypeRef_type_offset = 16; static constexpr dart::compiler::target::word TypedDataBase_length_offset = 8; static constexpr dart::compiler::target::word TypedDataView_typed_data_offset = 12; @@ -680,7 +678,6 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Type_InstanceSize = 24; static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 32; static constexpr dart::compiler::target::word TypeParameters_InstanceSize = 20; -static constexpr dart::compiler::target::word TypeRef_InstanceSize = 20; static constexpr dart::compiler::target::word TypedData_HeaderSize = 12; static constexpr dart::compiler::target::word TypedDataBase_InstanceSize = 12; static constexpr dart::compiler::target::word TypedDataView_InstanceSize = 20; @@ -1257,8 +1254,6 @@ static constexpr dart::compiler::target::word TypeParameters_flags_offset = 16; static constexpr dart::compiler::target::word TypeParameters_bounds_offset = 24; static constexpr dart::compiler::target::word TypeParameters_defaults_offset = 32; -static constexpr dart::compiler::target::word TypeParameter_bound_offset = 40; -static constexpr dart::compiler::target::word TypeRef_type_offset = 32; static constexpr dart::compiler::target::word TypedDataBase_length_offset = 16; static constexpr dart::compiler::target::word TypedDataView_typed_data_offset = 24; @@ -1369,7 +1364,6 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Type_InstanceSize = 48; static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 56; static constexpr dart::compiler::target::word TypeParameters_InstanceSize = 40; -static constexpr dart::compiler::target::word TypeRef_InstanceSize = 40; static constexpr dart::compiler::target::word TypedData_HeaderSize = 24; static constexpr dart::compiler::target::word TypedDataBase_InstanceSize = 24; static constexpr dart::compiler::target::word TypedDataView_InstanceSize = 40; @@ -1937,8 +1931,6 @@ static constexpr dart::compiler::target::word TypeParameters_flags_offset = 8; static constexpr dart::compiler::target::word TypeParameters_bounds_offset = 12; static constexpr dart::compiler::target::word TypeParameters_defaults_offset = 16; -static constexpr dart::compiler::target::word TypeParameter_bound_offset = 20; -static constexpr dart::compiler::target::word TypeRef_type_offset = 16; static constexpr dart::compiler::target::word TypedDataBase_length_offset = 8; static constexpr dart::compiler::target::word TypedDataView_typed_data_offset = 12; @@ -2047,7 +2039,6 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Type_InstanceSize = 24; static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 32; static constexpr dart::compiler::target::word TypeParameters_InstanceSize = 20; -static constexpr dart::compiler::target::word TypeRef_InstanceSize = 20; static constexpr dart::compiler::target::word TypedData_HeaderSize = 12; static constexpr dart::compiler::target::word TypedDataBase_InstanceSize = 12; static constexpr dart::compiler::target::word TypedDataView_InstanceSize = 20; @@ -2624,8 +2615,6 @@ static constexpr dart::compiler::target::word TypeParameters_flags_offset = 16; static constexpr dart::compiler::target::word TypeParameters_bounds_offset = 24; static constexpr dart::compiler::target::word TypeParameters_defaults_offset = 32; -static constexpr dart::compiler::target::word TypeParameter_bound_offset = 40; -static constexpr dart::compiler::target::word TypeRef_type_offset = 32; static constexpr dart::compiler::target::word TypedDataBase_length_offset = 16; static constexpr dart::compiler::target::word TypedDataView_typed_data_offset = 24; @@ -2737,7 +2726,6 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Type_InstanceSize = 48; static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 56; static constexpr dart::compiler::target::word TypeParameters_InstanceSize = 40; -static constexpr dart::compiler::target::word TypeRef_InstanceSize = 40; static constexpr dart::compiler::target::word TypedData_HeaderSize = 24; static constexpr dart::compiler::target::word TypedDataBase_InstanceSize = 24; static constexpr dart::compiler::target::word TypedDataView_InstanceSize = 40; @@ -3312,8 +3300,6 @@ static constexpr dart::compiler::target::word TypeParameters_flags_offset = 12; static constexpr dart::compiler::target::word TypeParameters_bounds_offset = 16; static constexpr dart::compiler::target::word TypeParameters_defaults_offset = 20; -static constexpr dart::compiler::target::word TypeParameter_bound_offset = 28; -static constexpr dart::compiler::target::word TypeRef_type_offset = 24; static constexpr dart::compiler::target::word TypedDataBase_length_offset = 20; static constexpr dart::compiler::target::word TypedDataView_typed_data_offset = 24; @@ -3424,7 +3410,6 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Type_InstanceSize = 32; static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 40; static constexpr dart::compiler::target::word TypeParameters_InstanceSize = 24; -static constexpr dart::compiler::target::word TypeRef_InstanceSize = 32; static constexpr dart::compiler::target::word TypedData_HeaderSize = 24; static constexpr dart::compiler::target::word TypedDataBase_InstanceSize = 24; static constexpr dart::compiler::target::word TypedDataView_InstanceSize = 32; @@ -3999,8 +3984,6 @@ static constexpr dart::compiler::target::word TypeParameters_flags_offset = 12; static constexpr dart::compiler::target::word TypeParameters_bounds_offset = 16; static constexpr dart::compiler::target::word TypeParameters_defaults_offset = 20; -static constexpr dart::compiler::target::word TypeParameter_bound_offset = 28; -static constexpr dart::compiler::target::word TypeRef_type_offset = 24; static constexpr dart::compiler::target::word TypedDataBase_length_offset = 20; static constexpr dart::compiler::target::word TypedDataView_typed_data_offset = 24; @@ -4112,7 +4095,6 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Type_InstanceSize = 32; static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 40; static constexpr dart::compiler::target::word TypeParameters_InstanceSize = 24; -static constexpr dart::compiler::target::word TypeRef_InstanceSize = 32; static constexpr dart::compiler::target::word TypedData_HeaderSize = 24; static constexpr dart::compiler::target::word TypedDataBase_InstanceSize = 24; static constexpr dart::compiler::target::word TypedDataView_InstanceSize = 32; @@ -4680,8 +4662,6 @@ static constexpr dart::compiler::target::word TypeParameters_flags_offset = 8; static constexpr dart::compiler::target::word TypeParameters_bounds_offset = 12; static constexpr dart::compiler::target::word TypeParameters_defaults_offset = 16; -static constexpr dart::compiler::target::word TypeParameter_bound_offset = 20; -static constexpr dart::compiler::target::word TypeRef_type_offset = 16; static constexpr dart::compiler::target::word TypedDataBase_length_offset = 8; static constexpr dart::compiler::target::word TypedDataView_typed_data_offset = 12; @@ -4792,7 +4772,6 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Type_InstanceSize = 24; static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 32; static constexpr dart::compiler::target::word TypeParameters_InstanceSize = 20; -static constexpr dart::compiler::target::word TypeRef_InstanceSize = 20; static constexpr dart::compiler::target::word TypedData_HeaderSize = 12; static constexpr dart::compiler::target::word TypedDataBase_InstanceSize = 12; static constexpr dart::compiler::target::word TypedDataView_InstanceSize = 20; @@ -5369,8 +5348,6 @@ static constexpr dart::compiler::target::word TypeParameters_flags_offset = 16; static constexpr dart::compiler::target::word TypeParameters_bounds_offset = 24; static constexpr dart::compiler::target::word TypeParameters_defaults_offset = 32; -static constexpr dart::compiler::target::word TypeParameter_bound_offset = 40; -static constexpr dart::compiler::target::word TypeRef_type_offset = 32; static constexpr dart::compiler::target::word TypedDataBase_length_offset = 16; static constexpr dart::compiler::target::word TypedDataView_typed_data_offset = 24; @@ -5482,7 +5459,6 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Type_InstanceSize = 48; static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 56; static constexpr dart::compiler::target::word TypeParameters_InstanceSize = 40; -static constexpr dart::compiler::target::word TypeRef_InstanceSize = 40; static constexpr dart::compiler::target::word TypedData_HeaderSize = 24; static constexpr dart::compiler::target::word TypedDataBase_InstanceSize = 24; static constexpr dart::compiler::target::word TypedDataView_InstanceSize = 40; @@ -6044,8 +6020,6 @@ static constexpr dart::compiler::target::word TypeParameters_flags_offset = 8; static constexpr dart::compiler::target::word TypeParameters_bounds_offset = 12; static constexpr dart::compiler::target::word TypeParameters_defaults_offset = 16; -static constexpr dart::compiler::target::word TypeParameter_bound_offset = 20; -static constexpr dart::compiler::target::word TypeRef_type_offset = 16; static constexpr dart::compiler::target::word TypedDataBase_length_offset = 8; static constexpr dart::compiler::target::word TypedDataView_typed_data_offset = 12; @@ -6154,7 +6128,6 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Type_InstanceSize = 24; static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 32; static constexpr dart::compiler::target::word TypeParameters_InstanceSize = 20; -static constexpr dart::compiler::target::word TypeRef_InstanceSize = 20; static constexpr dart::compiler::target::word TypedData_HeaderSize = 12; static constexpr dart::compiler::target::word TypedDataBase_InstanceSize = 12; static constexpr dart::compiler::target::word TypedDataView_InstanceSize = 20; @@ -6723,8 +6696,6 @@ static constexpr dart::compiler::target::word TypeParameters_flags_offset = 16; static constexpr dart::compiler::target::word TypeParameters_bounds_offset = 24; static constexpr dart::compiler::target::word TypeParameters_defaults_offset = 32; -static constexpr dart::compiler::target::word TypeParameter_bound_offset = 40; -static constexpr dart::compiler::target::word TypeRef_type_offset = 32; static constexpr dart::compiler::target::word TypedDataBase_length_offset = 16; static constexpr dart::compiler::target::word TypedDataView_typed_data_offset = 24; @@ -6835,7 +6806,6 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Type_InstanceSize = 48; static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 56; static constexpr dart::compiler::target::word TypeParameters_InstanceSize = 40; -static constexpr dart::compiler::target::word TypeRef_InstanceSize = 40; static constexpr dart::compiler::target::word TypedData_HeaderSize = 24; static constexpr dart::compiler::target::word TypedDataBase_InstanceSize = 24; static constexpr dart::compiler::target::word TypedDataView_InstanceSize = 40; @@ -7395,8 +7365,6 @@ static constexpr dart::compiler::target::word TypeParameters_flags_offset = 8; static constexpr dart::compiler::target::word TypeParameters_bounds_offset = 12; static constexpr dart::compiler::target::word TypeParameters_defaults_offset = 16; -static constexpr dart::compiler::target::word TypeParameter_bound_offset = 20; -static constexpr dart::compiler::target::word TypeRef_type_offset = 16; static constexpr dart::compiler::target::word TypedDataBase_length_offset = 8; static constexpr dart::compiler::target::word TypedDataView_typed_data_offset = 12; @@ -7505,7 +7473,6 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Type_InstanceSize = 24; static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 32; static constexpr dart::compiler::target::word TypeParameters_InstanceSize = 20; -static constexpr dart::compiler::target::word TypeRef_InstanceSize = 20; static constexpr dart::compiler::target::word TypedData_HeaderSize = 12; static constexpr dart::compiler::target::word TypedDataBase_InstanceSize = 12; static constexpr dart::compiler::target::word TypedDataView_InstanceSize = 20; @@ -8074,8 +8041,6 @@ static constexpr dart::compiler::target::word TypeParameters_flags_offset = 16; static constexpr dart::compiler::target::word TypeParameters_bounds_offset = 24; static constexpr dart::compiler::target::word TypeParameters_defaults_offset = 32; -static constexpr dart::compiler::target::word TypeParameter_bound_offset = 40; -static constexpr dart::compiler::target::word TypeRef_type_offset = 32; static constexpr dart::compiler::target::word TypedDataBase_length_offset = 16; static constexpr dart::compiler::target::word TypedDataView_typed_data_offset = 24; @@ -8187,7 +8152,6 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Type_InstanceSize = 48; static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 56; static constexpr dart::compiler::target::word TypeParameters_InstanceSize = 40; -static constexpr dart::compiler::target::word TypeRef_InstanceSize = 40; static constexpr dart::compiler::target::word TypedData_HeaderSize = 24; static constexpr dart::compiler::target::word TypedDataBase_InstanceSize = 24; static constexpr dart::compiler::target::word TypedDataView_InstanceSize = 40; @@ -8754,8 +8718,6 @@ static constexpr dart::compiler::target::word TypeParameters_flags_offset = 12; static constexpr dart::compiler::target::word TypeParameters_bounds_offset = 16; static constexpr dart::compiler::target::word TypeParameters_defaults_offset = 20; -static constexpr dart::compiler::target::word TypeParameter_bound_offset = 28; -static constexpr dart::compiler::target::word TypeRef_type_offset = 24; static constexpr dart::compiler::target::word TypedDataBase_length_offset = 20; static constexpr dart::compiler::target::word TypedDataView_typed_data_offset = 24; @@ -8866,7 +8828,6 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Type_InstanceSize = 32; static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 40; static constexpr dart::compiler::target::word TypeParameters_InstanceSize = 24; -static constexpr dart::compiler::target::word TypeRef_InstanceSize = 32; static constexpr dart::compiler::target::word TypedData_HeaderSize = 24; static constexpr dart::compiler::target::word TypedDataBase_InstanceSize = 24; static constexpr dart::compiler::target::word TypedDataView_InstanceSize = 32; @@ -9433,8 +9394,6 @@ static constexpr dart::compiler::target::word TypeParameters_flags_offset = 12; static constexpr dart::compiler::target::word TypeParameters_bounds_offset = 16; static constexpr dart::compiler::target::word TypeParameters_defaults_offset = 20; -static constexpr dart::compiler::target::word TypeParameter_bound_offset = 28; -static constexpr dart::compiler::target::word TypeRef_type_offset = 24; static constexpr dart::compiler::target::word TypedDataBase_length_offset = 20; static constexpr dart::compiler::target::word TypedDataView_typed_data_offset = 24; @@ -9546,7 +9505,6 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Type_InstanceSize = 32; static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 40; static constexpr dart::compiler::target::word TypeParameters_InstanceSize = 24; -static constexpr dart::compiler::target::word TypeRef_InstanceSize = 32; static constexpr dart::compiler::target::word TypedData_HeaderSize = 24; static constexpr dart::compiler::target::word TypedDataBase_InstanceSize = 24; static constexpr dart::compiler::target::word TypedDataView_InstanceSize = 32; @@ -10106,8 +10064,6 @@ static constexpr dart::compiler::target::word TypeParameters_flags_offset = 8; static constexpr dart::compiler::target::word TypeParameters_bounds_offset = 12; static constexpr dart::compiler::target::word TypeParameters_defaults_offset = 16; -static constexpr dart::compiler::target::word TypeParameter_bound_offset = 20; -static constexpr dart::compiler::target::word TypeRef_type_offset = 16; static constexpr dart::compiler::target::word TypedDataBase_length_offset = 8; static constexpr dart::compiler::target::word TypedDataView_typed_data_offset = 12; @@ -10218,7 +10174,6 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Type_InstanceSize = 24; static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 32; static constexpr dart::compiler::target::word TypeParameters_InstanceSize = 20; -static constexpr dart::compiler::target::word TypeRef_InstanceSize = 20; static constexpr dart::compiler::target::word TypedData_HeaderSize = 12; static constexpr dart::compiler::target::word TypedDataBase_InstanceSize = 12; static constexpr dart::compiler::target::word TypedDataView_InstanceSize = 20; @@ -10787,8 +10742,6 @@ static constexpr dart::compiler::target::word TypeParameters_flags_offset = 16; static constexpr dart::compiler::target::word TypeParameters_bounds_offset = 24; static constexpr dart::compiler::target::word TypeParameters_defaults_offset = 32; -static constexpr dart::compiler::target::word TypeParameter_bound_offset = 40; -static constexpr dart::compiler::target::word TypeRef_type_offset = 32; static constexpr dart::compiler::target::word TypedDataBase_length_offset = 16; static constexpr dart::compiler::target::word TypedDataView_typed_data_offset = 24; @@ -10900,7 +10853,6 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Type_InstanceSize = 48; static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 56; static constexpr dart::compiler::target::word TypeParameters_InstanceSize = 40; -static constexpr dart::compiler::target::word TypeRef_InstanceSize = 40; static constexpr dart::compiler::target::word TypedData_HeaderSize = 24; static constexpr dart::compiler::target::word TypedDataBase_InstanceSize = 24; static constexpr dart::compiler::target::word TypedDataView_InstanceSize = 40; @@ -11529,9 +11481,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameters_bounds_offset = 12; static constexpr dart::compiler::target::word AOT_TypeParameters_defaults_offset = 16; -static constexpr dart::compiler::target::word AOT_TypeParameter_bound_offset = - 20; -static constexpr dart::compiler::target::word AOT_TypeRef_type_offset = 16; static constexpr dart::compiler::target::word AOT_TypedDataBase_length_offset = 8; static constexpr dart::compiler::target::word @@ -11655,7 +11604,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameter_InstanceSize = 32; static constexpr dart::compiler::target::word AOT_TypeParameters_InstanceSize = 20; -static constexpr dart::compiler::target::word AOT_TypeRef_InstanceSize = 20; static constexpr dart::compiler::target::word AOT_TypedData_HeaderSize = 12; static constexpr dart::compiler::target::word AOT_TypedDataBase_InstanceSize = 12; @@ -12288,9 +12236,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameters_bounds_offset = 24; static constexpr dart::compiler::target::word AOT_TypeParameters_defaults_offset = 32; -static constexpr dart::compiler::target::word AOT_TypeParameter_bound_offset = - 40; -static constexpr dart::compiler::target::word AOT_TypeRef_type_offset = 32; static constexpr dart::compiler::target::word AOT_TypedDataBase_length_offset = 16; static constexpr dart::compiler::target::word @@ -12416,7 +12361,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameter_InstanceSize = 56; static constexpr dart::compiler::target::word AOT_TypeParameters_InstanceSize = 40; -static constexpr dart::compiler::target::word AOT_TypeRef_InstanceSize = 40; static constexpr dart::compiler::target::word AOT_TypedData_HeaderSize = 24; static constexpr dart::compiler::target::word AOT_TypedDataBase_InstanceSize = 24; @@ -13052,9 +12996,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameters_bounds_offset = 24; static constexpr dart::compiler::target::word AOT_TypeParameters_defaults_offset = 32; -static constexpr dart::compiler::target::word AOT_TypeParameter_bound_offset = - 40; -static constexpr dart::compiler::target::word AOT_TypeRef_type_offset = 32; static constexpr dart::compiler::target::word AOT_TypedDataBase_length_offset = 16; static constexpr dart::compiler::target::word @@ -13181,7 +13122,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameter_InstanceSize = 56; static constexpr dart::compiler::target::word AOT_TypeParameters_InstanceSize = 40; -static constexpr dart::compiler::target::word AOT_TypeRef_InstanceSize = 40; static constexpr dart::compiler::target::word AOT_TypedData_HeaderSize = 24; static constexpr dart::compiler::target::word AOT_TypedDataBase_InstanceSize = 24; @@ -13815,9 +13755,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameters_bounds_offset = 16; static constexpr dart::compiler::target::word AOT_TypeParameters_defaults_offset = 20; -static constexpr dart::compiler::target::word AOT_TypeParameter_bound_offset = - 28; -static constexpr dart::compiler::target::word AOT_TypeRef_type_offset = 24; static constexpr dart::compiler::target::word AOT_TypedDataBase_length_offset = 20; static constexpr dart::compiler::target::word @@ -13943,7 +13880,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameter_InstanceSize = 40; static constexpr dart::compiler::target::word AOT_TypeParameters_InstanceSize = 24; -static constexpr dart::compiler::target::word AOT_TypeRef_InstanceSize = 32; static constexpr dart::compiler::target::word AOT_TypedData_HeaderSize = 24; static constexpr dart::compiler::target::word AOT_TypedDataBase_InstanceSize = 24; @@ -14577,9 +14513,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameters_bounds_offset = 16; static constexpr dart::compiler::target::word AOT_TypeParameters_defaults_offset = 20; -static constexpr dart::compiler::target::word AOT_TypeParameter_bound_offset = - 28; -static constexpr dart::compiler::target::word AOT_TypeRef_type_offset = 24; static constexpr dart::compiler::target::word AOT_TypedDataBase_length_offset = 20; static constexpr dart::compiler::target::word @@ -14706,7 +14639,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameter_InstanceSize = 40; static constexpr dart::compiler::target::word AOT_TypeParameters_InstanceSize = 24; -static constexpr dart::compiler::target::word AOT_TypeRef_InstanceSize = 32; static constexpr dart::compiler::target::word AOT_TypedData_HeaderSize = 24; static constexpr dart::compiler::target::word AOT_TypedDataBase_InstanceSize = 24; @@ -15336,9 +15268,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameters_bounds_offset = 12; static constexpr dart::compiler::target::word AOT_TypeParameters_defaults_offset = 16; -static constexpr dart::compiler::target::word AOT_TypeParameter_bound_offset = - 20; -static constexpr dart::compiler::target::word AOT_TypeRef_type_offset = 16; static constexpr dart::compiler::target::word AOT_TypedDataBase_length_offset = 8; static constexpr dart::compiler::target::word @@ -15464,7 +15393,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameter_InstanceSize = 32; static constexpr dart::compiler::target::word AOT_TypeParameters_InstanceSize = 20; -static constexpr dart::compiler::target::word AOT_TypeRef_InstanceSize = 20; static constexpr dart::compiler::target::word AOT_TypedData_HeaderSize = 12; static constexpr dart::compiler::target::word AOT_TypedDataBase_InstanceSize = 12; @@ -16097,9 +16025,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameters_bounds_offset = 24; static constexpr dart::compiler::target::word AOT_TypeParameters_defaults_offset = 32; -static constexpr dart::compiler::target::word AOT_TypeParameter_bound_offset = - 40; -static constexpr dart::compiler::target::word AOT_TypeRef_type_offset = 32; static constexpr dart::compiler::target::word AOT_TypedDataBase_length_offset = 16; static constexpr dart::compiler::target::word @@ -16226,7 +16151,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameter_InstanceSize = 56; static constexpr dart::compiler::target::word AOT_TypeParameters_InstanceSize = 40; -static constexpr dart::compiler::target::word AOT_TypeRef_InstanceSize = 40; static constexpr dart::compiler::target::word AOT_TypedData_HeaderSize = 24; static constexpr dart::compiler::target::word AOT_TypedDataBase_InstanceSize = 24; @@ -16849,9 +16773,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameters_bounds_offset = 12; static constexpr dart::compiler::target::word AOT_TypeParameters_defaults_offset = 16; -static constexpr dart::compiler::target::word AOT_TypeParameter_bound_offset = - 20; -static constexpr dart::compiler::target::word AOT_TypeRef_type_offset = 16; static constexpr dart::compiler::target::word AOT_TypedDataBase_length_offset = 8; static constexpr dart::compiler::target::word @@ -16975,7 +16896,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameter_InstanceSize = 32; static constexpr dart::compiler::target::word AOT_TypeParameters_InstanceSize = 20; -static constexpr dart::compiler::target::word AOT_TypeRef_InstanceSize = 20; static constexpr dart::compiler::target::word AOT_TypedData_HeaderSize = 12; static constexpr dart::compiler::target::word AOT_TypedDataBase_InstanceSize = 12; @@ -17599,9 +17519,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameters_bounds_offset = 24; static constexpr dart::compiler::target::word AOT_TypeParameters_defaults_offset = 32; -static constexpr dart::compiler::target::word AOT_TypeParameter_bound_offset = - 40; -static constexpr dart::compiler::target::word AOT_TypeRef_type_offset = 32; static constexpr dart::compiler::target::word AOT_TypedDataBase_length_offset = 16; static constexpr dart::compiler::target::word @@ -17727,7 +17644,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameter_InstanceSize = 56; static constexpr dart::compiler::target::word AOT_TypeParameters_InstanceSize = 40; -static constexpr dart::compiler::target::word AOT_TypeRef_InstanceSize = 40; static constexpr dart::compiler::target::word AOT_TypedData_HeaderSize = 24; static constexpr dart::compiler::target::word AOT_TypedDataBase_InstanceSize = 24; @@ -18354,9 +18270,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameters_bounds_offset = 24; static constexpr dart::compiler::target::word AOT_TypeParameters_defaults_offset = 32; -static constexpr dart::compiler::target::word AOT_TypeParameter_bound_offset = - 40; -static constexpr dart::compiler::target::word AOT_TypeRef_type_offset = 32; static constexpr dart::compiler::target::word AOT_TypedDataBase_length_offset = 16; static constexpr dart::compiler::target::word @@ -18483,7 +18396,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameter_InstanceSize = 56; static constexpr dart::compiler::target::word AOT_TypeParameters_InstanceSize = 40; -static constexpr dart::compiler::target::word AOT_TypeRef_InstanceSize = 40; static constexpr dart::compiler::target::word AOT_TypedData_HeaderSize = 24; static constexpr dart::compiler::target::word AOT_TypedDataBase_InstanceSize = 24; @@ -19108,9 +19020,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameters_bounds_offset = 16; static constexpr dart::compiler::target::word AOT_TypeParameters_defaults_offset = 20; -static constexpr dart::compiler::target::word AOT_TypeParameter_bound_offset = - 28; -static constexpr dart::compiler::target::word AOT_TypeRef_type_offset = 24; static constexpr dart::compiler::target::word AOT_TypedDataBase_length_offset = 20; static constexpr dart::compiler::target::word @@ -19236,7 +19145,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameter_InstanceSize = 40; static constexpr dart::compiler::target::word AOT_TypeParameters_InstanceSize = 24; -static constexpr dart::compiler::target::word AOT_TypeRef_InstanceSize = 32; static constexpr dart::compiler::target::word AOT_TypedData_HeaderSize = 24; static constexpr dart::compiler::target::word AOT_TypedDataBase_InstanceSize = 24; @@ -19861,9 +19769,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameters_bounds_offset = 16; static constexpr dart::compiler::target::word AOT_TypeParameters_defaults_offset = 20; -static constexpr dart::compiler::target::word AOT_TypeParameter_bound_offset = - 28; -static constexpr dart::compiler::target::word AOT_TypeRef_type_offset = 24; static constexpr dart::compiler::target::word AOT_TypedDataBase_length_offset = 20; static constexpr dart::compiler::target::word @@ -19990,7 +19895,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameter_InstanceSize = 40; static constexpr dart::compiler::target::word AOT_TypeParameters_InstanceSize = 24; -static constexpr dart::compiler::target::word AOT_TypeRef_InstanceSize = 32; static constexpr dart::compiler::target::word AOT_TypedData_HeaderSize = 24; static constexpr dart::compiler::target::word AOT_TypedDataBase_InstanceSize = 24; @@ -20611,9 +20515,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameters_bounds_offset = 12; static constexpr dart::compiler::target::word AOT_TypeParameters_defaults_offset = 16; -static constexpr dart::compiler::target::word AOT_TypeParameter_bound_offset = - 20; -static constexpr dart::compiler::target::word AOT_TypeRef_type_offset = 16; static constexpr dart::compiler::target::word AOT_TypedDataBase_length_offset = 8; static constexpr dart::compiler::target::word @@ -20739,7 +20640,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameter_InstanceSize = 32; static constexpr dart::compiler::target::word AOT_TypeParameters_InstanceSize = 20; -static constexpr dart::compiler::target::word AOT_TypeRef_InstanceSize = 20; static constexpr dart::compiler::target::word AOT_TypedData_HeaderSize = 12; static constexpr dart::compiler::target::word AOT_TypedDataBase_InstanceSize = 12; @@ -21363,9 +21263,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameters_bounds_offset = 24; static constexpr dart::compiler::target::word AOT_TypeParameters_defaults_offset = 32; -static constexpr dart::compiler::target::word AOT_TypeParameter_bound_offset = - 40; -static constexpr dart::compiler::target::word AOT_TypeRef_type_offset = 32; static constexpr dart::compiler::target::word AOT_TypedDataBase_length_offset = 16; static constexpr dart::compiler::target::word @@ -21492,7 +21389,6 @@ static constexpr dart::compiler::target::word AOT_TypeParameter_InstanceSize = 56; static constexpr dart::compiler::target::word AOT_TypeParameters_InstanceSize = 40; -static constexpr dart::compiler::target::word AOT_TypeRef_InstanceSize = 40; static constexpr dart::compiler::target::word AOT_TypedData_HeaderSize = 24; static constexpr dart::compiler::target::word AOT_TypedDataBase_InstanceSize = 24; diff --git a/runtime/vm/compiler/runtime_offsets_list.h b/runtime/vm/compiler/runtime_offsets_list.h index 29863171f81..8333dc7d217 100644 --- a/runtime/vm/compiler/runtime_offsets_list.h +++ b/runtime/vm/compiler/runtime_offsets_list.h @@ -385,8 +385,6 @@ FIELD(TypeParameters, flags_offset) \ FIELD(TypeParameters, bounds_offset) \ FIELD(TypeParameters, defaults_offset) \ - FIELD(TypeParameter, bound_offset) \ - FIELD(TypeRef, type_offset) \ FIELD(TypedDataBase, length_offset) \ FIELD(TypedDataView, typed_data_offset) \ FIELD(TypedDataView, offset_in_bytes_offset) \ @@ -478,7 +476,6 @@ SIZEOF(Type, InstanceSize, UntaggedType) \ SIZEOF(TypeParameter, InstanceSize, UntaggedTypeParameter) \ SIZEOF(TypeParameters, InstanceSize, UntaggedTypeParameters) \ - SIZEOF(TypeRef, InstanceSize, UntaggedTypeRef) \ SIZEOF(TypedData, HeaderSize, UntaggedTypedData) \ SIZEOF(TypedDataBase, InstanceSize, UntaggedTypedDataBase) \ SIZEOF(TypedDataView, InstanceSize, UntaggedTypedDataView) \ diff --git a/runtime/vm/compiler/stub_code_compiler.cc b/runtime/vm/compiler/stub_code_compiler.cc index 2bd4b6bc7a6..b38153353a7 100644 --- a/runtime/vm/compiler/stub_code_compiler.cc +++ b/runtime/vm/compiler/stub_code_compiler.cc @@ -586,10 +586,6 @@ static void BuildInstantiateTypeParameterStub(Assembler* assembler, __ LoadClassId(InstantiateTypeABI::kScratchReg, InstantiateTypeABI::kResultTypeReg); - // Handle/unwrap TypeRefs in runtime. - __ CompareImmediate(InstantiateTypeABI::kScratchReg, kTypeRefCid); - __ BranchIf(EQUAL, &runtime_call); - switch (nullability) { case Nullability::kNonNullable: __ Ret(); @@ -689,15 +685,6 @@ static void EnsureIsTypeOrFunctionTypeOrTypeParameter(Assembler* assembler, __ CompareImmediate(scratch_reg, kFunctionTypeCid); __ BranchIf(EQUAL, &is_type_param_or_type_or_function_type, compiler::Assembler::kNearJump); - // Type references show up in F-bounded polymorphism, which is limited - // to classes. Thus, TypeRefs only appear in places like class type - // arguments or the bounds of uninstantiated class type parameters. - // - // Since this stub is currently used only by the dynamic versions of - // AssertSubtype and AssertAssignable, where kDstType is either the bound of - // a function type parameter or the type of a function parameter - // (respectively), we should never see a TypeRef here. This check is here - // in case this changes and we need to update this stub. __ Stop("not a type or function type or type parameter"); __ Bind(&is_type_param_or_type_or_function_type); #endif diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc index cd675abebb4..55b98e935ca 100644 --- a/runtime/vm/dart_api_impl.cc +++ b/runtime/vm/dart_api_impl.cc @@ -2571,7 +2571,7 @@ DART_EXPORT Dart_Handle Dart_InstanceGetType(Dart_Handle instance) { } const AbstractType& type = AbstractType::Handle(Instance::Cast(obj).GetType(Heap::kNew)); - return Api::NewHandle(T, type.Canonicalize(T, nullptr)); + return Api::NewHandle(T, type.Canonicalize(T)); } DART_EXPORT Dart_Handle Dart_FunctionName(Dart_Handle function) { diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h index f8891a64e91..d1197a06f6c 100644 --- a/runtime/vm/flag_list.h +++ b/runtime/vm/flag_list.h @@ -220,6 +220,8 @@ constexpr bool FLAG_support_il_printer = false; P(trace_strong_mode_types, bool, false, \ "Trace optimizations based on strong mode types.") \ D(trace_type_checks, bool, false, "Trace runtime type checks.") \ + D(trace_type_checks_verbose, bool, false, \ + "Enable verbose trace of runtime type checks.") \ D(trace_patching, bool, false, "Trace patching of code.") \ D(trace_optimized_ic_calls, bool, false, \ "Trace IC calls in optimized code.") \ diff --git a/runtime/vm/message_snapshot.cc b/runtime/vm/message_snapshot.cc index 597c7796576..37cdabb949e 100644 --- a/runtime/vm/message_snapshot.cc +++ b/runtime/vm/message_snapshot.cc @@ -796,95 +796,6 @@ class TypeMessageDeserializationCluster : public MessageDeserializationCluster { } }; -class TypeRefMessageSerializationCluster : public MessageSerializationCluster { - public: - explicit TypeRefMessageSerializationCluster(bool is_canonical) - : MessageSerializationCluster("TypeRef", - MessagePhase::kTypes, - kTypeRefCid, - is_canonical) {} - ~TypeRefMessageSerializationCluster() {} - - void Trace(MessageSerializer* s, Object* object) { - TypeRef* type = static_cast(object); - objects_.Add(type); - - s->Push(type->type()); - } - - void WriteNodes(MessageSerializer* s) { - const intptr_t count = objects_.length(); - s->WriteUnsigned(count); - for (intptr_t i = 0; i < count; i++) { - TypeRef* type = objects_[i]; - s->AssignRef(type); - } - } - - void WriteEdges(MessageSerializer* s) { - const intptr_t count = objects_.length(); - for (intptr_t i = 0; i < count; i++) { - TypeRef* type = objects_[i]; - s->WriteRef(type->type()); - } - } - - private: - GrowableArray objects_; -}; - -class TypeRefMessageDeserializationCluster - : public MessageDeserializationCluster { - public: - explicit TypeRefMessageDeserializationCluster(bool is_canonical) - : MessageDeserializationCluster("TypeRef", is_canonical) {} - ~TypeRefMessageDeserializationCluster() {} - - void ReadNodes(MessageDeserializer* d) { - const intptr_t count = d->ReadUnsigned(); - for (intptr_t i = 0; i < count; i++) { - d->AssignRef(TypeRef::New()); - } - } - - void ReadEdges(MessageDeserializer* d) { - for (intptr_t id = start_index_; id < stop_index_; id++) { - TypeRefPtr type = static_cast(d->Ref(id)); - type->untag()->set_type(static_cast(d->ReadRef())); - } - } - - ObjectPtr PostLoad(MessageDeserializer* d) { - ClassFinalizer::FinalizationKind finalization = - is_canonical() ? ClassFinalizer::kCanonicalize - : ClassFinalizer::kFinalize; - Code& code = Code::Handle(d->zone()); - TypeRef& type = TypeRef::Handle(d->zone()); - for (intptr_t id = start_index_; id < stop_index_; id++) { - type ^= d->Ref(id); - type ^= ClassFinalizer::FinalizeType(type, finalization); - d->UpdateRef(id, type); - - code = TypeTestingStubGenerator::DefaultCodeForType(type); - type.InitializeTypeTestingStubNonAtomic(code); - } - return nullptr; - } - - void ReadNodesApi(ApiMessageDeserializer* d) { - intptr_t count = d->ReadUnsigned(); - for (intptr_t i = 0; i < count; i++) { - d->AssignRef(nullptr); - } - } - - void ReadEdgesApi(ApiMessageDeserializer* d) { - for (intptr_t id = start_index_; id < stop_index_; id++) { - d->ReadRef(); // Type. - } - } -}; - class SmiMessageSerializationCluster : public MessageSerializationCluster { public: explicit SmiMessageSerializationCluster(Zone* zone) @@ -3159,8 +3070,6 @@ MessageSerializationCluster* BaseSerializer::NewClusterForClass( return new (Z) TypeArgumentsMessageSerializationCluster(is_canonical); case kTypeCid: return new (Z) TypeMessageSerializationCluster(is_canonical); - case kTypeRefCid: - return new (Z) TypeRefMessageSerializationCluster(is_canonical); case kSmiCid: return new (Z) SmiMessageSerializationCluster(Z); case kMintCid: @@ -3238,8 +3147,6 @@ MessageDeserializationCluster* BaseDeserializer::ReadCluster() { return new (Z) TypeArgumentsMessageDeserializationCluster(is_canonical); case kTypeCid: return new (Z) TypeMessageDeserializationCluster(is_canonical); - case kTypeRefCid: - return new (Z) TypeRefMessageDeserializationCluster(is_canonical); case kSmiCid: ASSERT(is_canonical); return new (Z) SmiMessageDeserializationCluster(); diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index eee7226fd4f..a694e7ccc03 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -216,6 +216,18 @@ PRECOMPILER_WSR_FIELD_DEFINITION(Function, FunctionType, signature) #undef PRECOMPILER_WSR_FIELD_DEFINITION +#if defined(_MSC_VER) +#define TRACE_TYPE_CHECKS_VERBOSE(format, ...) \ + if (FLAG_trace_type_checks_verbose) { \ + OS::PrintErr(format, __VA_ARGS__); \ + } +#else +#define TRACE_TYPE_CHECKS_VERBOSE(format, ...) \ + if (FLAG_trace_type_checks_verbose) { \ + OS::PrintErr(format, ##__VA_ARGS__); \ + } +#endif + // Remove private keys, but retain getter/setter/constructor/mixin manglings. StringPtr String::RemovePrivateKey(const String& name) { ASSERT(name.IsOneByteString()); @@ -1803,8 +1815,6 @@ ErrorPtr Object::Init(IsolateGroup* isolate_group, zone, Class::New(isolate_group)); const Class& record_type_cls = Class::Handle( zone, Class::New(isolate_group)); - const Class& type_ref_cls = - Class::Handle(zone, Class::New(isolate_group)); const Class& type_parameter_cls = Class::Handle( zone, Class::New(isolate_group)); const Class& library_prefix_cls = Class::Handle( @@ -1852,7 +1862,7 @@ ErrorPtr Object::Init(IsolateGroup* isolate_group, type = Type::New(Class::Handle(zone, cls.ptr()), Object::null_type_arguments(), Nullability::kNonNullable); type.SetIsFinalized(); - type ^= type.Canonicalize(thread, nullptr); + type ^= type.Canonicalize(thread); object_store->set_array_type(type); cls = object_store->growable_object_array_class(); // Was allocated above. @@ -1989,9 +1999,6 @@ ErrorPtr Object::Init(IsolateGroup* isolate_group, RegisterPrivateClass(record_type_cls, Symbols::_RecordType(), core_lib); pending_classes.Add(record_type_cls); - RegisterPrivateClass(type_ref_cls, Symbols::_TypeRef(), core_lib); - pending_classes.Add(type_ref_cls); - RegisterPrivateClass(type_parameter_cls, Symbols::_TypeParameter(), core_lib); pending_classes.Add(type_parameter_cls); @@ -2343,7 +2350,7 @@ ErrorPtr Object::Init(IsolateGroup* isolate_group, type = Type::New(cls, Object::null_type_arguments(), Nullability::kNullable); type.SetIsFinalized(); - type ^= type.Canonicalize(thread, nullptr); + type ^= type.Canonicalize(thread); object_store->set_null_type(type); cls.set_declaration_type(type); ASSERT(type.IsNullable()); @@ -2356,11 +2363,11 @@ ErrorPtr Object::Init(IsolateGroup* isolate_group, type = Type::New(cls, Object::null_type_arguments(), Nullability::kNonNullable); type.SetIsFinalized(); - type ^= type.Canonicalize(thread, nullptr); + type ^= type.Canonicalize(thread); object_store->set_never_type(type); type_args = TypeArguments::New(1); type_args.SetTypeAt(0, type); - type_args = type_args.Canonicalize(thread, nullptr); + type_args = type_args.Canonicalize(thread); object_store->set_type_argument_never(type_args); // Create and cache commonly used type arguments , , @@ -2368,43 +2375,43 @@ ErrorPtr Object::Init(IsolateGroup* isolate_group, type_args = TypeArguments::New(1); type = object_store->int_type(); type_args.SetTypeAt(0, type); - type_args = type_args.Canonicalize(thread, nullptr); + type_args = type_args.Canonicalize(thread); object_store->set_type_argument_int(type_args); type_args = TypeArguments::New(1); type = object_store->legacy_int_type(); type_args.SetTypeAt(0, type); - type_args = type_args.Canonicalize(thread, nullptr); + type_args = type_args.Canonicalize(thread); object_store->set_type_argument_legacy_int(type_args); type_args = TypeArguments::New(1); type = object_store->double_type(); type_args.SetTypeAt(0, type); - type_args = type_args.Canonicalize(thread, nullptr); + type_args = type_args.Canonicalize(thread); object_store->set_type_argument_double(type_args); type_args = TypeArguments::New(1); type = object_store->string_type(); type_args.SetTypeAt(0, type); - type_args = type_args.Canonicalize(thread, nullptr); + type_args = type_args.Canonicalize(thread); object_store->set_type_argument_string(type_args); type_args = TypeArguments::New(1); type = object_store->legacy_string_type(); type_args.SetTypeAt(0, type); - type_args = type_args.Canonicalize(thread, nullptr); + type_args = type_args.Canonicalize(thread); object_store->set_type_argument_legacy_string(type_args); type_args = TypeArguments::New(2); type = object_store->string_type(); type_args.SetTypeAt(0, type); type_args.SetTypeAt(1, Object::dynamic_type()); - type_args = type_args.Canonicalize(thread, nullptr); + type_args = type_args.Canonicalize(thread); object_store->set_type_argument_string_dynamic(type_args); type_args = TypeArguments::New(2); type = object_store->string_type(); type_args.SetTypeAt(0, type); type_args.SetTypeAt(1, type); - type_args = type_args.Canonicalize(thread, nullptr); + type_args = type_args.Canonicalize(thread); object_store->set_type_argument_string_string(type_args); lib = Library::LookupLibrary(thread, Symbols::DartFfi()); @@ -2532,7 +2539,6 @@ ErrorPtr Object::Init(IsolateGroup* isolate_group, cls = Class::New(isolate_group); cls = Class::New(isolate_group); cls = Class::New(isolate_group); - cls = Class::New(isolate_group); cls = Class::New(isolate_group); cls = Class::New(isolate_group); @@ -2923,6 +2929,8 @@ bool Object::IsNotTemporaryScopedHandle() const { ObjectPtr Object::Clone(const Object& orig, Heap::Space space, bool load_with_relaxed_atomics) { + // Generic function types should be cloned with FunctionType::Clone. + ASSERT(!orig.IsFunctionType() || !FunctionType::Cast(orig).IsGeneric()); const Class& cls = Class::Handle(orig.clazz()); intptr_t size = orig.ptr()->untag()->HeapSize(); ObjectPtr raw_clone = @@ -3510,7 +3518,7 @@ TypeArgumentsPtr Class::GetDeclarationInstanceTypeArguments() const { } } } - args = args.Canonicalize(thread, nullptr); + args = args.Canonicalize(thread); set_declaration_instance_type_arguments(args); return args.ptr(); } @@ -3541,7 +3549,7 @@ TypeArgumentsPtr Class::GetInstanceTypeArguments( Object::null_type_arguments(), kAllFree, Heap::kOld); } if (canonicalize) { - args = args.Canonicalize(thread, nullptr); + args = args.Canonicalize(thread); } return args.ptr(); } @@ -3685,12 +3693,8 @@ void Class::set_super_type(const Type& value) const { TypeParameterPtr Class::TypeParameterAt(intptr_t index, Nullability nullability) const { ASSERT(index >= 0 && index < NumTypeParameters()); - const TypeParameters& type_params = TypeParameters::Handle(type_parameters()); - const TypeArguments& bounds = TypeArguments::Handle(type_params.bounds()); - const AbstractType& bound = AbstractType::Handle( - bounds.IsNull() ? Type::DynamicType() : bounds.TypeAt(index)); - TypeParameter& type_param = TypeParameter::Handle( - TypeParameter::New(*this, 0, index, bound, nullability)); + TypeParameter& type_param = + TypeParameter::Handle(TypeParameter::New(*this, 0, index, nullability)); if (is_type_finalized()) { type_param ^= ClassFinalizer::FinalizeType(type_param); } @@ -5780,7 +5784,7 @@ bool Class::IsSubtypeOf(const Class& cls, Nullability nullability, const AbstractType& other, Heap::Space space, - TrailPtr trail) { + FunctionTypeMapping* function_type_equivalence) { // This function does not support Null, Never, dynamic, or void as type T0. classid_t this_cid = cls.id(); ASSERT(this_cid != kNullCid && this_cid != kNeverCid && @@ -5826,11 +5830,12 @@ bool Class::IsSubtypeOf(const Class& cls, this_class.NumTypeParameters() == 1); ASSERT(type_arguments.IsNull() || type_arguments.Length() >= 1); if (Class::IsSubtypeOf(future_class, type_arguments, - Nullability::kNonNullable, other, space, trail)) { + Nullability::kNonNullable, other, space, + function_type_equivalence)) { // Check S0 <: T1. const AbstractType& type_arg = AbstractType::Handle(zone, type_arguments.TypeAtNullSafe(0)); - if (type_arg.IsSubtypeOf(other, space, trail)) { + if (type_arg.IsSubtypeOf(other, space, function_type_equivalence)) { return verified_nullability; } } @@ -5854,7 +5859,8 @@ bool Class::IsSubtypeOf(const Class& cls, const AbstractType& type_arg = AbstractType::Handle(zone, type_arguments.TypeAtNullSafe(0)); // If T0 is Future, then T0 <: Future, iff S0 <: S1. - if (type_arg.IsSubtypeOf(other_type_arg, space, trail)) { + if (type_arg.IsSubtypeOf(other_type_arg, space, + function_type_equivalence)) { // verified_nullability doesn't take into account the nullability of // S1, just of the FutureOr type. if (verified_nullability || !other_type_arg.IsNonNullable()) { @@ -5866,7 +5872,8 @@ bool Class::IsSubtypeOf(const Class& cls, // Check T0 <: S1. if (other_type_arg.HasTypeClass() && Class::IsSubtypeOf(this_class, type_arguments, nullability, - other_type_arg, space, trail)) { + other_type_arg, space, + function_type_equivalence)) { return true; } } @@ -5897,7 +5904,7 @@ bool Class::IsSubtypeOf(const Class& cls, type = type_arguments.TypeAtNullSafe(from_index + i); other_type = other_type_arguments.TypeAt(i); ASSERT(!type.IsNull() && !other_type.IsNull()); - if (!type.IsSubtypeOf(other_type, space, trail)) { + if (!type.IsSubtypeOf(other_type, space, function_type_equivalence)) { return false; } } @@ -5939,9 +5946,9 @@ bool Class::IsSubtypeOf(const Class& cls, if (interface_class.IsDartFunctionClass()) { continue; } - // No need to pass the trail as cycles are not possible via interfaces. if (Class::IsSubtypeOf(interface_class, interface_args, - Nullability::kNonNullable, other, space)) { + Nullability::kNonNullable, other, space, + function_type_equivalence)) { return true; } } @@ -6394,6 +6401,66 @@ bool Class::RequireCanonicalTypeErasureOfConstants(Zone* zone) const { return result; } +// Scoped mapping FunctionType -> FunctionType. +// Used for tracking and updating nested generic function types +// and their type parameters. +class FunctionTypeMapping : public ValueObject { + public: + FunctionTypeMapping(Zone* zone, + FunctionTypeMapping** mapping, + const FunctionType& from, + const FunctionType& to) + : zone_(zone), parent_(*mapping), from_(from), to_(to) { + // Add self to the linked list. + *mapping = this; + } + + const FunctionType* Find(const Object& from) const { + if (!from.IsFunctionType()) { + return nullptr; + } + for (const FunctionTypeMapping* scope = this; scope != nullptr; + scope = scope->parent_) { + if (scope->from_.ptr() == from.ptr()) { + return &(scope->to_); + } + } + return nullptr; + } + + TypeParameterPtr MapTypeParameter(const TypeParameter& type_param) const { + ASSERT(type_param.IsFunctionTypeParameter()); + const FunctionType* new_owner = + Find(Object::Handle(zone_, type_param.owner())); + if (new_owner != nullptr) { + return new_owner->TypeParameterAt(type_param.index() - type_param.base(), + type_param.nullability()); + } + return type_param.ptr(); + } + + bool ContainsOwnersOfTypeParameters(const TypeParameter& p1, + const TypeParameter& p2) const { + auto& from = Object::Handle(zone_, p1.owner()); + const FunctionType* to = Find(from); + if (to != nullptr) { + return to->ptr() == p2.owner(); + } + from = p2.owner(); + to = Find(from); + if (to != nullptr) { + return to->ptr() == p1.owner(); + } + return false; + } + + private: + Zone* zone_; + const FunctionTypeMapping* const parent_; + const FunctionType& from_; + const FunctionType& to_; +}; + intptr_t TypeParameters::Length() const { if (IsNull() || untag()->names() == Array::null()) return 0; return Smi::Value(untag()->names()->untag()->length()); @@ -6589,7 +6656,7 @@ intptr_t TypeArguments::ComputeNullability() const { for (intptr_t i = 0; i < num_types; i++) { type = TypeAt(i); intptr_t type_bits = 0; - if (!type.IsNull() && !type.IsNullTypeRef()) { + if (!type.IsNull()) { switch (type.nullability()) { case Nullability::kNullable: type_bits = kNullableBits; @@ -6622,26 +6689,7 @@ uword TypeArguments::HashForRange(intptr_t from_index, intptr_t len) const { AbstractType& type = AbstractType::Handle(); for (intptr_t i = 0; i < len; i++) { type = TypeAt(from_index + i); - // The hash may be calculated during type finalization (for debugging - // purposes only) while a type argument is still temporarily null. - if (type.IsNull() || type.IsNullTypeRef()) { - return 0; // Do not cache hash, since it will still change. - } - if (type.IsTypeRef()) { - // Unwrapping the TypeRef here cannot lead to infinite recursion, because - // traversal during hash computation stops at the TypeRef. Indeed, - // unwrapping the TypeRef does not always remove it completely, but may - // only rotate the cycle. The same TypeRef can be encountered when calling - // type.Hash() below after traversing the whole cycle. The class id of the - // referenced type is used and the traversal stops. - // By dereferencing the TypeRef, we maximize the information reflected by - // the hash value. Two equal vectors may have some of their type arguments - // 'oriented' differently, i.e. pointing to identical (TypeRef containing) - // cyclic type graphs, but to two different nodes in the cycle, thereby - // breaking the hash computation earlier for one vector and yielding two - // different hash values for identical type graphs. - type = TypeRef::Cast(type).type(); - } + ASSERT(!type.IsNull()); result = CombineHashes(result, type.Hash()); } result = FinalizeHash(result, kHashBits); @@ -6681,7 +6729,7 @@ TypeArgumentsPtr TypeArguments::Prepend(Zone* zone, type = IsNull() ? Type::DynamicType() : TypeAt(i - other_length); result.SetTypeAt(i, type); } - return result.Canonicalize(Thread::Current(), nullptr); + return result.Canonicalize(Thread::Current()); } TypeArgumentsPtr TypeArguments::ConcatenateTypeParameters( @@ -6755,11 +6803,12 @@ void TypeArguments::PrintTo(BaseTextBuffer* buffer) const { } } -bool TypeArguments::IsSubvectorEquivalent(const TypeArguments& other, - intptr_t from_index, - intptr_t len, - TypeEquality kind, - TrailPtr trail) const { +bool TypeArguments::IsSubvectorEquivalent( + const TypeArguments& other, + intptr_t from_index, + intptr_t len, + TypeEquality kind, + FunctionTypeMapping* function_type_equivalence) const { if (this->ptr() == other.ptr()) { return true; } @@ -6775,44 +6824,26 @@ bool TypeArguments::IsSubvectorEquivalent(const TypeArguments& other, AbstractType& other_type = AbstractType::Handle(); for (intptr_t i = from_index; i < from_index + len; i++) { type = IsNull() ? Type::DynamicType() : TypeAt(i); + ASSERT(!type.IsNull()); other_type = other.IsNull() ? Type::DynamicType() : other.TypeAt(i); - // Still unfinalized vectors should not be considered equivalent. - if (type.IsNull() || !type.IsEquivalent(other_type, kind, trail)) { + ASSERT(!other_type.IsNull()); + if (!type.IsEquivalent(other_type, kind, function_type_equivalence)) { return false; } } return true; } -bool TypeArguments::IsRecursive(TrailPtr trail) const { - if (IsNull()) return false; - const intptr_t num_types = Length(); - AbstractType& type = AbstractType::Handle(); - for (intptr_t i = 0; i < num_types; i++) { - type = TypeAt(i); - // If this type argument is null, the type parameterized with this type - // argument is still being finalized and is definitely recursive. The null - // type argument will be replaced by a non-null type before the type is - // marked as finalized. - if (type.IsNull() || type.IsRecursive(trail)) { - return true; - } - } - return false; -} - bool TypeArguments::RequireConstCanonicalTypeErasure(Zone* zone, intptr_t from_index, - intptr_t len, - TrailPtr trail) const { + intptr_t len) const { if (IsNull()) return false; ASSERT(Length() >= (from_index + len)); AbstractType& type = AbstractType::Handle(zone); for (intptr_t i = 0; i < len; i++) { type = TypeAt(from_index + i); if (type.IsNonNullable() || - (type.IsNullable() && - type.RequireConstCanonicalTypeErasure(zone, trail))) { + (type.IsNullable() && type.RequireConstCanonicalTypeErasure(zone))) { // It is not possible for a legacy type to have non-nullable type // arguments or for a legacy function type to have non-nullable type in // its signature. @@ -7200,11 +7231,11 @@ void TypeArguments::SetTypeAt(intptr_t index, const AbstractType& value) const { return untag()->set_element(index, value.ptr()); } -bool TypeArguments::IsSubvectorInstantiated(intptr_t from_index, - intptr_t len, - Genericity genericity, - intptr_t num_free_fun_type_params, - TrailPtr trail) const { +bool TypeArguments::IsSubvectorInstantiated( + intptr_t from_index, + intptr_t len, + Genericity genericity, + intptr_t num_free_fun_type_params) const { ASSERT(!IsNull()); AbstractType& type = AbstractType::Handle(); for (intptr_t i = 0; i < len; i++) { @@ -7216,7 +7247,7 @@ bool TypeArguments::IsSubvectorInstantiated(intptr_t from_index, // solely on the type parameters of A and will be replaced by a non-null // type before A is marked as finalized. if (!type.IsNull() && - !type.IsInstantiated(genericity, num_free_fun_type_params, trail)) { + !type.IsInstantiated(genericity, num_free_fun_type_params)) { return false; } } @@ -7416,7 +7447,7 @@ TypeArgumentsPtr TypeArguments::InstantiateFrom( const TypeArguments& function_type_arguments, intptr_t num_free_fun_type_params, Heap::Space space, - TrailPtr trail, + FunctionTypeMapping* function_type_mapping, intptr_t num_parent_type_args_adjustment) const { ASSERT(!IsInstantiated()); if ((instantiator_type_arguments.IsNull() || @@ -7437,10 +7468,10 @@ TypeArgumentsPtr TypeArguments::InstantiateFrom( // solely on the type parameters of A and will be replaced by a non-null // type before A is marked as finalized. if (!type.IsNull() && !type.IsInstantiated()) { - type = type.InstantiateFrom(instantiator_type_arguments, - function_type_arguments, - num_free_fun_type_params, space, trail, - num_parent_type_args_adjustment); + type = type.InstantiateFrom( + instantiator_type_arguments, function_type_arguments, + num_free_fun_type_params, space, function_type_mapping, + num_parent_type_args_adjustment); // A returned null type indicates a failed instantiation in dead code that // must be propagated up to the caller, the optimizing compiler. if (type.IsNull()) { @@ -7452,20 +7483,20 @@ TypeArgumentsPtr TypeArguments::InstantiateFrom( return instantiated_array.ptr(); } -TypeArgumentsPtr TypeArguments::UpdateParentFunctionType( +TypeArgumentsPtr TypeArguments::UpdateFunctionTypes( intptr_t num_parent_type_args_adjustment, intptr_t num_free_fun_type_params, Heap::Space space, - TrailPtr trail) const { + FunctionTypeMapping* function_type_mapping) const { Zone* zone = Thread::Current()->zone(); TypeArguments* updated_args = nullptr; AbstractType& type = AbstractType::Handle(zone); AbstractType& updated = AbstractType::Handle(zone); for (intptr_t i = 0, n = Length(); i < n; ++i) { type = TypeAt(i); - updated = - type.UpdateParentFunctionType(num_parent_type_args_adjustment, - num_free_fun_type_params, space, trail); + updated = type.UpdateFunctionTypes(num_parent_type_args_adjustment, + num_free_fun_type_params, space, + function_type_mapping); if (type.ptr() != updated.ptr()) { if (updated_args == nullptr) { updated_args = @@ -7537,7 +7568,7 @@ TypeArgumentsPtr TypeArguments::InstantiateAndCanonicalizeFrom( result = InstantiateFrom(instantiator_type_arguments, function_type_arguments, kAllFree, Heap::kOld); // Canonicalize type arguments. - result = result.Canonicalize(thread, nullptr); + result = result.Canonicalize(thread); // InstantiateAndCanonicalizeFrom is not reentrant. It cannot have been called // indirectly, so the prior_instantiations array cannot have grown. ASSERT(cache.data_.ptr() == instantiations()); @@ -7576,8 +7607,7 @@ void TypeArguments::SetLength(intptr_t value) const { untag()->set_length(Smi::New(value)); } -TypeArgumentsPtr TypeArguments::Canonicalize(Thread* thread, - TrailPtr trail) const { +TypeArgumentsPtr TypeArguments::Canonicalize(Thread* thread) const { if (IsNull() || IsCanonical()) { ASSERT(IsOld()); return this->ptr(); @@ -7606,19 +7636,9 @@ TypeArgumentsPtr TypeArguments::Canonicalize(Thread* thread, num_types); for (intptr_t i = 0; i < num_types; i++) { type_arg = TypeAt(i); - type_arg = type_arg.Canonicalize(thread, trail); - if (IsCanonical()) { - // Canonicalizing this type_arg canonicalized this type. - ASSERT(IsRecursive()); - return this->ptr(); - } + type_arg = type_arg.Canonicalize(thread); canonicalized_types.Add(type_arg); } - // Canonicalization of a type argument of a recursive type argument vector - // may change the hash of the vector, so invalidate. - if (IsRecursive()) { - SetHash(0); - } SafepointMutexLocker ml(isolate_group->type_canonicalization_mutex()); CanonicalTypeArgumentsSet table(zone, object_store->canonical_type_arguments()); @@ -8410,13 +8430,14 @@ void Function::SetSignature(const FunctionType& value) const { TypeParameterPtr FunctionType::TypeParameterAt(intptr_t index, Nullability nullability) const { ASSERT(index >= 0 && index < NumTypeParameters()); - const TypeParameters& type_params = TypeParameters::Handle(type_parameters()); - const AbstractType& bound = AbstractType::Handle(type_params.BoundAt(index)); + Thread* thread = Thread::Current(); + Zone* zone = thread->zone(); TypeParameter& type_param = TypeParameter::Handle( - TypeParameter::New(Object::null_class(), NumParentTypeArguments(), - NumParentTypeArguments() + index, bound, nullability)); + zone, TypeParameter::New(*this, NumParentTypeArguments(), + NumParentTypeArguments() + index, nullability)); + type_param.SetIsFinalized(); if (IsFinalized()) { - type_param ^= ClassFinalizer::FinalizeType(type_param); + type_param ^= type_param.Canonicalize(thread); } return type_param.ptr(); } @@ -9457,7 +9478,7 @@ AbstractTypePtr FunctionType::InstantiateFrom( const TypeArguments& function_type_arguments, intptr_t num_free_fun_type_params, Heap::Space space, - TrailPtr trail, + FunctionTypeMapping* function_type_mapping, intptr_t num_parent_type_args_adjustment) const { ASSERT(IsFinalized() || IsBeingFinalized()); Zone* zone = Thread::Current()->zone(); @@ -9492,6 +9513,8 @@ AbstractTypePtr FunctionType::InstantiateFrom( FunctionType::New(remaining_parent_type_params, nullability(), space)); AbstractType& type = AbstractType::Handle(zone); + FunctionTypeMapping scope(zone, &function_type_mapping, *this, sig); + // Copy the type parameters and instantiate their bounds and defaults. if (!delete_type_parameters) { const TypeParameters& type_params = @@ -9503,12 +9526,13 @@ AbstractTypePtr FunctionType::InstantiateFrom( // length of the names array defines the number of type parameters. sig_type_params.set_names(Array::Handle(zone, type_params.names())); sig_type_params.set_flags(Array::Handle(zone, type_params.flags())); + sig.SetTypeParameters(sig_type_params); TypeArguments& type_args = TypeArguments::Handle(zone); type_args = type_params.bounds(); if (!type_args.IsNull() && !type_args.IsInstantiated()) { type_args = type_args.InstantiateFrom( instantiator_type_arguments, function_type_arguments, - num_free_fun_type_params, space, trail, + num_free_fun_type_params, space, function_type_mapping, num_parent_type_args_adjustment); } sig_type_params.set_bounds(type_args); @@ -9516,20 +9540,19 @@ AbstractTypePtr FunctionType::InstantiateFrom( if (!type_args.IsNull() && !type_args.IsInstantiated()) { type_args = type_args.InstantiateFrom( instantiator_type_arguments, function_type_arguments, - num_free_fun_type_params, space, trail, + num_free_fun_type_params, space, function_type_mapping, num_parent_type_args_adjustment); } sig_type_params.set_defaults(type_args); - sig.SetTypeParameters(sig_type_params); } } type = result_type(); if (!type.IsInstantiated()) { - type = - type.InstantiateFrom(instantiator_type_arguments, - function_type_arguments, num_free_fun_type_params, - space, trail, num_parent_type_args_adjustment); + type = type.InstantiateFrom( + instantiator_type_arguments, function_type_arguments, + num_free_fun_type_params, space, function_type_mapping, + num_parent_type_args_adjustment); // A returned null type indicates a failed instantiation in dead code that // must be propagated up to the caller, the optimizing compiler. if (type.IsNull()) { @@ -9546,10 +9569,10 @@ AbstractTypePtr FunctionType::InstantiateFrom( for (intptr_t i = 0; i < num_params; i++) { type = ParameterTypeAt(i); if (!type.IsInstantiated()) { - type = type.InstantiateFrom(instantiator_type_arguments, - function_type_arguments, - num_free_fun_type_params, space, trail, - num_parent_type_args_adjustment); + type = type.InstantiateFrom( + instantiator_type_arguments, function_type_arguments, + num_free_fun_type_params, space, function_type_mapping, + num_parent_type_args_adjustment); // A returned null type indicates a failed instantiation in dead code that // must be propagated up to the caller, the optimizing compiler. if (type.IsNull()) { @@ -9576,12 +9599,12 @@ AbstractTypePtr FunctionType::InstantiateFrom( return sig.ptr(); } -AbstractTypePtr FunctionType::UpdateParentFunctionType( +AbstractTypePtr FunctionType::UpdateFunctionTypes( intptr_t num_parent_type_args_adjustment, intptr_t num_free_fun_type_params, Heap::Space space, - TrailPtr trail) const { - ASSERT(num_parent_type_args_adjustment > 0); + FunctionTypeMapping* function_type_mapping) const { + ASSERT(num_parent_type_args_adjustment >= 0); ASSERT(IsFinalized()); Zone* zone = Thread::Current()->zone(); @@ -9598,6 +9621,8 @@ AbstractTypePtr FunctionType::UpdateParentFunctionType( nullability(), space)); AbstractType& type = AbstractType::Handle(zone); + FunctionTypeMapping scope(zone, &function_type_mapping, *this, new_type); + const TypeParameters& type_params = TypeParameters::Handle(zone, type_parameters()); if (!type_params.IsNull()) { @@ -9610,24 +9635,25 @@ AbstractTypePtr FunctionType::UpdateParentFunctionType( TypeArguments& type_args = TypeArguments::Handle(zone); type_args = type_params.bounds(); if (!type_args.IsNull()) { - type_args = type_args.UpdateParentFunctionType( - num_parent_type_args_adjustment, num_free_fun_type_params, space, - trail); + type_args = type_args.UpdateFunctionTypes(num_parent_type_args_adjustment, + num_free_fun_type_params, space, + function_type_mapping); } new_type_params.set_bounds(type_args); type_args = type_params.defaults(); if (!type_args.IsNull()) { - type_args = type_args.UpdateParentFunctionType( - num_parent_type_args_adjustment, num_free_fun_type_params, space, - trail); + type_args = type_args.UpdateFunctionTypes(num_parent_type_args_adjustment, + num_free_fun_type_params, space, + function_type_mapping); } new_type_params.set_defaults(type_args); new_type.SetTypeParameters(new_type_params); } type = result_type(); - type = type.UpdateParentFunctionType(num_parent_type_args_adjustment, - num_free_fun_type_params, space, trail); + type = type.UpdateFunctionTypes(num_parent_type_args_adjustment, + num_free_fun_type_params, space, + function_type_mapping); new_type.set_result_type(type); const intptr_t num_params = NumParameters(); @@ -9638,9 +9664,9 @@ AbstractTypePtr FunctionType::UpdateParentFunctionType( new_type.set_parameter_types(Array::Handle(Array::New(num_params, space))); for (intptr_t i = 0; i < num_params; i++) { type = ParameterTypeAt(i); - type = - type.UpdateParentFunctionType(num_parent_type_args_adjustment, - num_free_fun_type_params, space, trail); + type = type.UpdateFunctionTypes(num_parent_type_args_adjustment, + num_free_fun_type_params, space, + function_type_mapping); new_type.SetParameterTypeAt(i, type); } new_type.set_named_parameter_names( @@ -9654,10 +9680,12 @@ AbstractTypePtr FunctionType::UpdateParentFunctionType( // supertype of the type of the specified parameter of the other signature // (i.e. check parameter contravariance). // Note that types marked as covariant are already dealt with in the front-end. -bool FunctionType::IsContravariantParameter(intptr_t parameter_position, - const FunctionType& other, - intptr_t other_parameter_position, - Heap::Space space) const { +bool FunctionType::IsContravariantParameter( + intptr_t parameter_position, + const FunctionType& other, + intptr_t other_parameter_position, + Heap::Space space, + FunctionTypeMapping* function_type_equivalence) const { const AbstractType& param_type = AbstractType::Handle(ParameterTypeAt(parameter_position)); if (param_type.IsTopTypeForSubtyping()) { @@ -9665,16 +9693,23 @@ bool FunctionType::IsContravariantParameter(intptr_t parameter_position, } const AbstractType& other_param_type = AbstractType::Handle(other.ParameterTypeAt(other_parameter_position)); - return other_param_type.IsSubtypeOf(param_type, space); + return other_param_type.IsSubtypeOf(param_type, space, + function_type_equivalence); } -bool FunctionType::HasSameTypeParametersAndBounds(const FunctionType& other, - TypeEquality kind, - TrailPtr trail) const { +bool FunctionType::HasSameTypeParametersAndBounds( + const FunctionType& other, + TypeEquality kind, + FunctionTypeMapping* function_type_equivalence) const { Zone* const zone = Thread::Current()->zone(); + TRACE_TYPE_CHECKS_VERBOSE( + " FunctionType::HasSameTypeParametersAndBounds(%s, %s)\n", ToCString(), + other.ToCString()); const intptr_t num_type_params = NumTypeParameters(); if (num_type_params != other.NumTypeParameters()) { + TRACE_TYPE_CHECKS_VERBOSE( + " - result: false (number of type parameters)\n"); return false; } if (num_type_params > 0) { @@ -9693,21 +9728,29 @@ bool FunctionType::HasSameTypeParametersAndBounds(const FunctionType& other, bound = type_params.BoundAt(i); other_bound = other_type_params.BoundAt(i); // Bounds that are mutual subtypes are considered equal. - if (!bound.IsSubtypeOf(other_bound, Heap::kOld) || - !other_bound.IsSubtypeOf(bound, Heap::kOld)) { + if (!bound.IsSubtypeOf(other_bound, Heap::kOld, + function_type_equivalence) || + !other_bound.IsSubtypeOf(bound, Heap::kOld, + function_type_equivalence)) { + TRACE_TYPE_CHECKS_VERBOSE( + " - result: false (bounds are not mutual subtypes)\n"); return false; } } } } else { if (NumParentTypeArguments() != other.NumParentTypeArguments()) { + TRACE_TYPE_CHECKS_VERBOSE( + " - result: false (mismatch in number of type arguments)\n"); return false; } const TypeArguments& bounds = TypeArguments::Handle(zone, type_params.bounds()); const TypeArguments& other_bounds = TypeArguments::Handle(zone, other_type_params.bounds()); - if (!bounds.IsEquivalent(other_bounds, kind, trail)) { + if (!bounds.IsEquivalent(other_bounds, kind, function_type_equivalence)) { + TRACE_TYPE_CHECKS_VERBOSE( + " - result: false (bounds are not equivalent)\n"); return false; } if (kind == TypeEquality::kCanonical) { @@ -9718,9 +9761,14 @@ bool FunctionType::HasSameTypeParametersAndBounds(const FunctionType& other, TypeArguments::Handle(zone, other_type_params.defaults()); if (defaults.IsNull()) { if (!other_defaults.IsNull()) { + TRACE_TYPE_CHECKS_VERBOSE( + " - result: false (mismatch in defaults)\n"); return false; } - } else if (!defaults.IsEquivalent(other_defaults, kind, trail)) { + } else if (!defaults.IsEquivalent(other_defaults, kind, + function_type_equivalence)) { + TRACE_TYPE_CHECKS_VERBOSE( + " - result: false (default types are not equivalent)\n"); return false; } } @@ -9728,15 +9776,21 @@ bool FunctionType::HasSameTypeParametersAndBounds(const FunctionType& other, if (kind != TypeEquality::kInSubtypeTest) { // Compare flags (IsGenericCovariantImpl). if (!Array::Equals(type_params.flags(), other_type_params.flags())) { + TRACE_TYPE_CHECKS_VERBOSE(" - result: false (flags are not equal)\n"); return false; } } } + TRACE_TYPE_CHECKS_VERBOSE(" - result: true\n"); return true; } -bool FunctionType::IsSubtypeOf(const FunctionType& other, - Heap::Space space) const { +bool FunctionType::IsSubtypeOf( + const FunctionType& other, + Heap::Space space, + FunctionTypeMapping* function_type_equivalence) const { + TRACE_TYPE_CHECKS_VERBOSE(" FunctionType::IsSubtypeOf(%s, %s)\n", + ToCString(), other.ToCString()); const intptr_t num_fixed_params = num_fixed_parameters(); const intptr_t num_opt_pos_params = NumOptionalPositionalParameters(); const intptr_t num_opt_named_params = NumOptionalNamedParameters(); @@ -9755,22 +9809,31 @@ bool FunctionType::IsSubtypeOf(const FunctionType& other, (other_num_fixed_params - other_num_ignored_params + other_num_opt_pos_params)) || (num_opt_named_params < other_num_opt_named_params)) { - return false; - } - // Check the type parameters and bounds of generic functions. - if (!HasSameTypeParametersAndBounds(other, TypeEquality::kInSubtypeTest)) { + TRACE_TYPE_CHECKS_VERBOSE( + " - result: false (mismatch in number of parameters)\n"); return false; } Thread* thread = Thread::Current(); Zone* zone = thread->zone(); auto isolate_group = thread->isolate_group(); + FunctionTypeMapping scope(zone, &function_type_equivalence, *this, other); + + // Check the type parameters and bounds of generic functions. + if (!HasSameTypeParametersAndBounds(other, TypeEquality::kInSubtypeTest, + function_type_equivalence)) { + TRACE_TYPE_CHECKS_VERBOSE( + " - result: false (mismatch in type parameters)\n"); + return false; + } // Check the result type. const AbstractType& other_res_type = AbstractType::Handle(zone, other.result_type()); // 'void Function()' is a subtype of 'Object Function()'. if (!other_res_type.IsTopTypeForSubtyping()) { const AbstractType& res_type = AbstractType::Handle(zone, result_type()); - if (!res_type.IsSubtypeOf(other_res_type, space)) { + if (!res_type.IsSubtypeOf(other_res_type, space, + function_type_equivalence)) { + TRACE_TYPE_CHECKS_VERBOSE(" - result: false (result type)\n"); return false; } } @@ -9779,7 +9842,9 @@ bool FunctionType::IsSubtypeOf(const FunctionType& other, other_num_opt_pos_params); i++) { if (!IsContravariantParameter(i + num_ignored_params, other, - i + other_num_ignored_params, space)) { + i + other_num_ignored_params, space, + function_type_equivalence)) { + TRACE_TYPE_CHECKS_VERBOSE(" - result: false (parameter type)\n"); return false; } } @@ -9801,13 +9866,18 @@ bool FunctionType::IsSubtypeOf(const FunctionType& other, ASSERT(String::Handle(zone, ParameterNameAt(j)).IsSymbol()); if (ParameterNameAt(j) == other_param_name.ptr()) { found_param_name = true; - if (!IsContravariantParameter(j, other, i, space)) { + if (!IsContravariantParameter(j, other, i, space, + function_type_equivalence)) { + TRACE_TYPE_CHECKS_VERBOSE( + " - result: false (optional parameter type)\n"); return false; } break; } } if (!found_param_name) { + TRACE_TYPE_CHECKS_VERBOSE( + " - result: false (named parameter not found)\n"); return false; } } @@ -9825,16 +9895,22 @@ bool FunctionType::IsSubtypeOf(const FunctionType& other, if (other.ParameterNameAt(i) == param_name.ptr()) { found = true; if (!other.IsRequiredAt(i)) { + TRACE_TYPE_CHECKS_VERBOSE( + " - result: false (mismatch in required named " + "parameters)\n"); return false; } } } if (!found) { + TRACE_TYPE_CHECKS_VERBOSE( + " - result: false (required named parameter not found)\n"); return false; } } } } + TRACE_TYPE_CHECKS_VERBOSE(" - result: true\n"); return true; } @@ -10039,46 +10115,106 @@ FunctionPtr Function::ImplicitClosureFunction() const { FunctionType& closure_signature = FunctionType::Handle(zone, closure_function.signature()); - // Set closure function's type parameters and result type. - if (IsConstructor()) { - // Inherit type parameters from owner class. - const auto& cls = Class::Handle(zone, Owner()); - closure_signature.SetTypeParameters( - TypeParameters::Handle(zone, cls.type_parameters())); - ASSERT(closure_signature.NumTypeParameters() == cls.NumTypeParameters()); + const auto& cls = Class::Handle(zone, Owner()); + const intptr_t num_type_params = + IsConstructor() ? cls.NumTypeParameters() : NumTypeParameters(); - Type& result_type = Type::Handle(zone); + TypeArguments& instantiator_type_arguments = TypeArguments::Handle(zone); + TypeArguments& function_type_arguments = TypeArguments::Handle(zone); + + FunctionTypeMapping* function_type_mapping = nullptr; + FunctionTypeMapping scope(zone, &function_type_mapping, + FunctionType::Handle(zone, signature()), + closure_signature); + + auto transform_type = [&](AbstractType& type) { + if (num_type_params > 0) { + if (IsConstructor()) { + type = type.UpdateFunctionTypes(num_type_params, kAllFree, Heap::kOld, + nullptr); + if (!type.IsInstantiated(kCurrentClass)) { + type = type.InstantiateFrom( + instantiator_type_arguments, function_type_arguments, + kNoneFree /* avoid truncating parent type args */, Heap::kOld); + } + } else { + type = type.UpdateFunctionTypes(0, kNoneFree, Heap::kOld, + function_type_mapping); + } + } + }; + + auto transform_type_args = [&](TypeArguments& type_args) { + ASSERT(num_type_params > 0); + if (!type_args.IsNull()) { + if (IsConstructor()) { + type_args = type_args.UpdateFunctionTypes(num_type_params, kAllFree, + Heap::kOld, nullptr); + if (!type_args.IsInstantiated(kCurrentClass)) { + type_args = type_args.InstantiateFrom( + instantiator_type_arguments, function_type_arguments, + kNoneFree /* avoid truncating parent type args */, Heap::kOld); + } + } else { + type_args = type_args.UpdateFunctionTypes(0, kNoneFree, Heap::kOld, + function_type_mapping); + } + } + }; + + // Set closure function's type parameters. + if (num_type_params > 0) { + const TypeParameters& old_type_params = TypeParameters::Handle( + zone, IsConstructor() ? cls.type_parameters() : type_parameters()); + const TypeParameters& new_type_params = + TypeParameters::Handle(zone, TypeParameters::New()); + // No need to set names that are ignored in a signature, however, the + // length of the names array defines the number of type parameters. + new_type_params.set_names(Array::Handle(zone, old_type_params.names())); + new_type_params.set_flags(Array::Handle(zone, old_type_params.flags())); + + closure_signature.SetTypeParameters(new_type_params); + ASSERT(closure_signature.NumTypeParameters() == num_type_params); + + TypeArguments& type_args = TypeArguments::Handle(zone); + type_args = TypeArguments::New(num_type_params); + TypeParameter& type_param = TypeParameter::Handle(zone); + for (intptr_t i = 0; i < num_type_params; i++) { + type_param = closure_signature.TypeParameterAt(i); + type_args.SetTypeAt(i, type_param); + } + + if (IsConstructor()) { + instantiator_type_arguments = + type_args.ToInstantiatorTypeArguments(thread, cls); + } else { + ASSERT(NumTypeArguments() == type_args.Length()); + function_type_arguments = type_args.ptr(); + } + + type_args = old_type_params.bounds(); + transform_type_args(type_args); + new_type_params.set_bounds(type_args); + + type_args = old_type_params.defaults(); + transform_type_args(type_args); + new_type_params.set_defaults(type_args); + } + + // Set closure function's result type. + AbstractType& result_type = AbstractType::Handle(zone); + if (IsConstructor()) { const Nullability result_nullability = (nnbd_mode() == NNBDMode::kOptedInLib) ? Nullability::kNonNullable : Nullability::kLegacy; - if (cls.IsGeneric()) { - TypeArguments& type_args = TypeArguments::Handle(zone); - const intptr_t num_type_params = cls.NumTypeParameters(); - ASSERT(num_type_params > 0); - type_args = TypeArguments::New(num_type_params); - TypeParameter& type_param = TypeParameter::Handle(zone); - for (intptr_t i = 0; i < num_type_params; i++) { - type_param = closure_signature.TypeParameterAt(i); - type_args.SetTypeAt(i, type_param); - } - result_type = Type::New(cls, type_args, result_nullability); - result_type ^= ClassFinalizer::FinalizeType(result_type); - } else { - result_type = cls.DeclarationType(); - result_type = result_type.ToNullability(result_nullability, Heap::kOld); - } - closure_signature.set_result_type(result_type); + result_type = cls.DeclarationType(); + result_type = + Type::Cast(result_type).ToNullability(result_nullability, Heap::kOld); } else { - // This function cannot be local, therefore it has no generic parent. - // Its implicit closure function therefore has no generic parent function - // either. That is why it is safe to simply copy the type parameters. - closure_signature.SetTypeParameters( - TypeParameters::Handle(zone, type_parameters())); - - // Set closure function's result type to this result type. - closure_signature.set_result_type( - AbstractType::Handle(zone, result_type())); + result_type = this->result_type(); } + transform_type(result_type); + closure_signature.set_result_type(result_type); // Set closure function's end token to this end token. closure_function.set_end_token_pos(end_token_pos()); @@ -10114,6 +10250,7 @@ FunctionPtr Function::ImplicitClosureFunction() const { closure_function.SetParameterNameAt(0, Symbols::ClosureParameter()); for (int i = kClosure; i < num_pos_params; i++) { param_type = ParameterTypeAt(num_implicit_params - kClosure + i); + transform_type(param_type); closure_signature.SetParameterTypeAt(i, param_type); param_name = ParameterNameAt(num_implicit_params - kClosure + i); // Set the name in the function for positional parameters. @@ -10121,6 +10258,7 @@ FunctionPtr Function::ImplicitClosureFunction() const { } for (int i = num_pos_params; i < num_params; i++) { param_type = ParameterTypeAt(num_implicit_params - kClosure + i); + transform_type(param_type); closure_signature.SetParameterTypeAt(i, param_type); param_name = ParameterNameAt(num_implicit_params - kClosure + i); // Set the name in the signature for named parameters. @@ -10153,28 +10291,6 @@ FunctionPtr Function::ImplicitClosureFunction() const { closure_signature.SetParameterTypeAt(i, object_type); } } - } else if (IsConstructor() && closure_signature.IsGeneric()) { - // Instantiate types of parameters as they may reference - // class type parameters. - const auto& result_type = - Type::Cast(AbstractType::Handle(zone, closure_signature.result_type())); - auto& instantiator_type_args = - TypeArguments::Handle(zone, result_type.arguments()); - instantiator_type_args = instantiator_type_args.ToInstantiatorTypeArguments( - thread, Class::Handle(zone, result_type.type_class())); - const intptr_t num_type_args = closure_signature.NumTypeArguments(); - auto& param_type = AbstractType::Handle(zone); - for (intptr_t i = kClosure; i < num_params; ++i) { - param_type = closure_signature.ParameterTypeAt(i); - param_type = param_type.UpdateParentFunctionType(num_type_args, kAllFree, - Heap::kOld); - if (!param_type.IsInstantiated(kCurrentClass)) { - param_type = param_type.InstantiateFrom( - instantiator_type_args, Object::null_type_arguments(), - kNoneFree /* avoid truncating parent type args */, Heap::kOld); - closure_signature.SetParameterTypeAt(i, param_type); - } - } } ASSERT(!closure_signature.IsFinalized()); closure_signature ^= ClassFinalizer::FinalizeType(closure_signature); @@ -10367,16 +10483,15 @@ void FunctionType::Print(NameVisibility name_visibility, } } -bool Function::HasInstantiatedSignature(Genericity genericity, - intptr_t num_free_fun_type_params, - TrailPtr trail) const { +bool Function::HasInstantiatedSignature( + Genericity genericity, + intptr_t num_free_fun_type_params) const { return FunctionType::Handle(signature()) - .IsInstantiated(genericity, num_free_fun_type_params, trail); + .IsInstantiated(genericity, num_free_fun_type_params); } bool FunctionType::IsInstantiated(Genericity genericity, - intptr_t num_free_fun_type_params, - TrailPtr trail) const { + intptr_t num_free_fun_type_params) const { if (num_free_fun_type_params == kCurrentAndEnclosingFree) { num_free_fun_type_params = kAllFree; } else if (genericity != kCurrentClass) { @@ -10395,13 +10510,13 @@ bool FunctionType::IsInstantiated(Genericity genericity, } } AbstractType& type = AbstractType::Handle(result_type()); - if (!type.IsInstantiated(genericity, num_free_fun_type_params, trail)) { + if (!type.IsInstantiated(genericity, num_free_fun_type_params)) { return false; } const intptr_t num_parameters = NumParameters(); for (intptr_t i = 0; i < num_parameters; i++) { type = ParameterTypeAt(i); - if (!type.IsInstantiated(genericity, num_free_fun_type_params, trail)) { + if (!type.IsInstantiated(genericity, num_free_fun_type_params)) { return false; } } @@ -10411,7 +10526,7 @@ bool FunctionType::IsInstantiated(Genericity genericity, if (!type_params.AllDynamicBounds()) { for (intptr_t i = 0; i < type_params.Length(); ++i) { type = type_params.BoundAt(i); - if (!type.IsInstantiated(genericity, num_free_fun_type_params, trail)) { + if (!type.IsInstantiated(genericity, num_free_fun_type_params)) { return false; } } @@ -11211,6 +11326,17 @@ FunctionTypePtr FunctionType::New(intptr_t num_parent_type_arguments, return result.ptr(); } +FunctionTypePtr FunctionType::Clone(const FunctionType& orig, + Heap::Space space) { + if (orig.IsGeneric()) { + // Need a deep clone in order to update owners of type parameters. + return FunctionType::RawCast( + orig.UpdateFunctionTypes(0, kAllFree, space, nullptr)); + } else { + return FunctionType::RawCast(Object::Clone(orig, space)); + } +} + const char* FunctionType::ToUserVisibleCString() const { Zone* zone = Thread::Current()->zone(); ZoneTextBuffer printer(zone); @@ -18405,7 +18531,7 @@ bool Code::IsTypeTestStubCode() const { auto const cid = OwnerClassId(); return cid == kAbstractTypeCid || cid == kTypeCid || cid == kFunctionTypeCid || cid == kRecordTypeCid || - cid == kTypeRefCid || cid == kTypeParameterCid; + cid == kTypeParameterCid; } bool Code::IsFunctionCode() const { @@ -20259,7 +20385,7 @@ AbstractTypePtr Instance::GetType(Heap::Space space) const { if (!signature.IsFinalized()) { signature.SetIsFinalized(); } - signature ^= signature.Canonicalize(thread, nullptr); + signature ^= signature.Canonicalize(thread); return signature.ptr(); } if (IsRecord()) { @@ -20285,7 +20411,7 @@ AbstractTypePtr Instance::GetType(Heap::Space space) const { } type = Type::New(cls, type_arguments, Nullability::kNonNullable, space); type.SetIsFinalized(); - type ^= type.Canonicalize(thread, nullptr); + type ^= type.Canonicalize(thread); } return type.ptr(); } @@ -20373,7 +20499,6 @@ bool Instance::NullIsInstanceOf( const TypeArguments& other_instantiator_type_arguments, const TypeArguments& other_function_type_arguments) { ASSERT(other.IsFinalized()); - ASSERT(!other.IsTypeRef()); // Must be dereferenced at compile time. if (other.IsNullable()) { // This case includes top types (void, dynamic, Object?). // The uninstantiated nullable type will remain nullable after @@ -20391,9 +20516,6 @@ bool Instance::NullIsInstanceOf( auto& type = AbstractType::Handle(other.InstantiateFrom( other_instantiator_type_arguments, other_function_type_arguments, kAllFree, Heap::kOld)); - if (type.IsTypeRef()) { - type = TypeRef::Cast(type).type(); - } return Instance::NullIsInstanceOf(type, Object::null_type_arguments(), Object::null_type_arguments()); } @@ -20437,8 +20559,6 @@ bool Instance::NullIsAssignableTo( const auto& type = AbstractType::Handle(other.InstantiateFrom( other_instantiator_type_arguments, other_function_type_arguments, kAllFree, Heap::kNew)); - // At runtime, uses of TypeRef should not occur. - ASSERT(!type.IsTypeRef()); return NullIsAssignableTo(type); } @@ -20447,7 +20567,6 @@ bool Instance::RuntimeTypeIsSubtypeOf( const TypeArguments& other_instantiator_type_arguments, const TypeArguments& other_function_type_arguments) const { ASSERT(other.IsFinalized()); - ASSERT(!other.IsTypeRef()); // Must be dereferenced at compile time. ASSERT(ptr() != Object::sentinel().ptr()); // Instance may not have runtimeType dynamic, void, or Never. if (other.IsTopTypeForSubtyping()) { @@ -20471,9 +20590,6 @@ bool Instance::RuntimeTypeIsSubtypeOf( instantiated_other = other.InstantiateFrom( other_instantiator_type_arguments, other_function_type_arguments, kAllFree, Heap::kOld); - if (instantiated_other.IsTypeRef()) { - instantiated_other = TypeRef::Cast(instantiated_other).type(); - } if (instantiated_other.IsTopTypeForSubtyping() || instantiated_other.IsObjectType() || instantiated_other.IsDartFunctionType()) { @@ -20499,9 +20615,6 @@ bool Instance::RuntimeTypeIsSubtypeOf( instantiated_other = other.InstantiateFrom( other_instantiator_type_arguments, other_function_type_arguments, kAllFree, Heap::kOld); - if (instantiated_other.IsTypeRef()) { - instantiated_other = TypeRef::Cast(instantiated_other).type(); - } if (instantiated_other.IsTopTypeForSubtyping() || instantiated_other.IsObjectType() || instantiated_other.IsDartRecordType()) { @@ -20554,9 +20667,6 @@ bool Instance::RuntimeTypeIsSubtypeOf( instantiated_other = other.InstantiateFrom( other_instantiator_type_arguments, other_function_type_arguments, kAllFree, Heap::kOld); - if (instantiated_other.IsTypeRef()) { - instantiated_other = TypeRef::Cast(instantiated_other).type(); - } if (instantiated_other.IsTopTypeForSubtyping()) { return true; } @@ -20826,10 +20936,6 @@ bool AbstractType::IsStrictlyNonNullable() const { return false; } - if (IsTypeRef()) { - return AbstractType::Handle(zone, TypeRef::Cast(*this).type()) - .IsStrictlyNonNullable(); - } if (IsTypeParameter()) { const auto& bound = AbstractType::Handle(zone, TypeParameter::Cast(*this).bound()); @@ -20878,11 +20984,7 @@ AbstractTypePtr AbstractType::SetInstantiatedNullability( if (IsTypeParameter()) { return TypeParameter::Cast(*this).ToNullability(result_nullability, space); } - // TODO(regis): TypeRefs are problematic, since changing the nullability of - // a type by cloning it may break the graph of a recursive type. - ASSERT(IsTypeRef()); - return AbstractType::Handle(TypeRef::Cast(*this).type()) - .SetInstantiatedNullability(type_param, space); + UNREACHABLE(); } AbstractTypePtr AbstractType::NormalizeFutureOrType(Heap::Space space) const { @@ -20925,8 +21027,7 @@ AbstractTypePtr AbstractType::NormalizeFutureOrType(Heap::Space space) const { } bool AbstractType::IsInstantiated(Genericity genericity, - intptr_t num_free_fun_type_params, - TrailPtr trail) const { + intptr_t num_free_fun_type_params) const { // All subclasses should implement this appropriately, so the only value that // should reach this implementation should be the null value. ASSERT(IsNull()); @@ -20963,9 +21064,10 @@ void AbstractType::set_nullability(Nullability value) const { static_cast(value), untag()->flags())); } -bool AbstractType::IsEquivalent(const Instance& other, - TypeEquality kind, - TrailPtr trail) const { +bool AbstractType::IsEquivalent( + const Instance& other, + TypeEquality kind, + FunctionTypeMapping* function_type_equivalence) const { // All subclasses should implement this appropriately, so the only value that // should reach this implementation should be the null value. ASSERT(IsNull()); @@ -21003,17 +21105,7 @@ bool AbstractType::IsNullabilityEquivalent(Thread* thread, return true; } -bool AbstractType::IsRecursive(TrailPtr trail) const { - // All subclasses should implement this appropriately, so the only value that - // should reach this implementation should be the null value. - ASSERT(IsNull()); - // AbstractType is an abstract class. - UNREACHABLE(); - return false; -} - -bool AbstractType::RequireConstCanonicalTypeErasure(Zone* zone, - TrailPtr trail) const { +bool AbstractType::RequireConstCanonicalTypeErasure(Zone* zone) const { // All subclasses should implement this appropriately, so the only value that // should reach this implementation should be the null value. ASSERT(IsNull()); @@ -21027,7 +21119,7 @@ AbstractTypePtr AbstractType::InstantiateFrom( const TypeArguments& function_type_arguments, intptr_t num_free_fun_type_params, Heap::Space space, - TrailPtr trail, + FunctionTypeMapping* function_type_mapping, intptr_t num_parent_type_args_adjustment) const { // All subclasses should implement this appropriately, so the only value that // should reach this implementation should be the null value. @@ -21037,17 +21129,16 @@ AbstractTypePtr AbstractType::InstantiateFrom( return nullptr; } -AbstractTypePtr AbstractType::UpdateParentFunctionType( +AbstractTypePtr AbstractType::UpdateFunctionTypes( intptr_t num_parent_type_args_adjustment, intptr_t num_free_fun_type_params, Heap::Space space, - TrailPtr trail) const { + FunctionTypeMapping* function_type_mapping) const { UNREACHABLE(); return nullptr; } -AbstractTypePtr AbstractType::Canonicalize(Thread* thread, - TrailPtr trail) const { +AbstractTypePtr AbstractType::Canonicalize(Thread* thread) const { // All subclasses should implement this appropriately, so the only value that // should reach this implementation should be the null value. ASSERT(IsNull()); @@ -21064,68 +21155,6 @@ void AbstractType::EnumerateURIs(URIs* uris) const { UNREACHABLE(); } -AbstractTypePtr AbstractType::OnlyBuddyInTrail(TrailPtr trail) const { - if (trail == nullptr) { - return AbstractType::null(); - } - const intptr_t len = trail->length(); - ASSERT((len % 2) == 0); - for (intptr_t i = 0; i < len; i += 2) { - DEBUG_ASSERT(trail->At(i).IsNotTemporaryScopedHandle()); - DEBUG_ASSERT(trail->At(i + 1).IsNotTemporaryScopedHandle()); - if (trail->At(i).ptr() == this->ptr()) { - ASSERT(!trail->At(i + 1).IsNull()); - return trail->At(i + 1).ptr(); - } - } - return AbstractType::null(); -} - -void AbstractType::AddOnlyBuddyToTrail(TrailPtr* trail, - const AbstractType& buddy) const { - if (*trail == nullptr) { - *trail = new Trail(Thread::Current()->zone(), 4); - } else { - ASSERT(OnlyBuddyInTrail(*trail) == AbstractType::null()); - } - (*trail)->Add(*this); - (*trail)->Add(buddy); -} - -bool AbstractType::TestAndAddToTrail(TrailPtr* trail) const { - if (*trail == nullptr) { - *trail = new Trail(Thread::Current()->zone(), 4); - } else { - const intptr_t len = (*trail)->length(); - for (intptr_t i = 0; i < len; i++) { - if ((*trail)->At(i).ptr() == this->ptr()) { - return true; - } - } - } - (*trail)->Add(*this); - return false; -} - -bool AbstractType::TestAndAddBuddyToTrail(TrailPtr* trail, - const AbstractType& buddy) const { - if (*trail == nullptr) { - *trail = new Trail(Thread::Current()->zone(), 4); - } else { - const intptr_t len = (*trail)->length(); - ASSERT((len % 2) == 0); - for (intptr_t i = 0; i < len; i += 2) { - if ((*trail)->At(i).ptr() == this->ptr() && - (*trail)->At(i + 1).ptr() == buddy.ptr()) { - return true; - } - } - } - (*trail)->Add(*this); - (*trail)->Add(buddy); - return false; -} - void AbstractType::AddURI(URIs* uris, const String& name, const String& uri) { ASSERT(uris != nullptr); const intptr_t len = uris->length(); @@ -21228,10 +21257,6 @@ StringPtr AbstractType::ClassName() const { return Class::Handle(type_class()).Name(); } -bool AbstractType::IsNullTypeRef() const { - return IsTypeRef() && (TypeRef::Cast(*this).type() == AbstractType::null()); -} - bool AbstractType::IsNullType() const { return type_class_id() == kNullCid; } @@ -21384,7 +21409,6 @@ bool AbstractType::IsTypeClassAllowedBySpawnUri() const { } AbstractTypePtr AbstractType::UnwrapFutureOr() const { - // Works properly for a TypeRef without dereferencing it. if (!IsFutureOrType()) { return ptr(); } @@ -21412,10 +21436,6 @@ bool AbstractType::NeedsNullAssertion() const { if (!IsNonNullable()) { return false; } - if (IsTypeRef()) { - return AbstractType::Handle(TypeRef::Cast(*this).type()) - .NeedsNullAssertion(); - } if (IsTypeParameter()) { return AbstractType::Handle(TypeParameter::Cast(*this).bound()) .NeedsNullAssertion(); @@ -21426,9 +21446,10 @@ bool AbstractType::NeedsNullAssertion() const { return true; } -bool AbstractType::IsSubtypeOf(const AbstractType& other, - Heap::Space space, - TrailPtr trail) const { +bool AbstractType::IsSubtypeOf( + const AbstractType& other, + Heap::Space space, + FunctionTypeMapping* function_type_equivalence) const { ASSERT(IsFinalized()); ASSERT(other.IsFinalized()); // Reflexivity. @@ -21452,23 +21473,6 @@ bool AbstractType::IsSubtypeOf(const AbstractType& other, if (IsDynamicType() || IsVoidType()) { return false; } - // Left TypeRef. - if (IsTypeRef()) { - if (TestAndAddBuddyToTrail(&trail, other)) { - return true; - } - const AbstractType& ref_type = - AbstractType::Handle(TypeRef::Cast(*this).type()); - return ref_type.IsSubtypeOf(other, space, trail); - } - // Right TypeRef. - if (other.IsTypeRef()) { - // Unfold right hand type. Divergence is controlled by left hand type. - const AbstractType& other_ref_type = - AbstractType::Handle(TypeRef::Cast(other).type()); - ASSERT(!other_ref_type.IsTypeRef()); - return IsSubtypeOf(other_ref_type, space, trail); - } // Left Null type. if (IsNullType()) { return Instance::NullIsAssignableTo(other); @@ -21492,21 +21496,19 @@ bool AbstractType::IsSubtypeOf(const AbstractType& other, const TypeParameter& type_param = TypeParameter::Cast(*this); if (other.IsTypeParameter()) { const TypeParameter& other_type_param = TypeParameter::Cast(other); - // It is ok to pass the IsSubtypeOf trail to TypeParameter::IsEquivalent, - // because it will only be used in a IsSubtypeOf test of the type - // parameter bounds. if (type_param.IsEquivalent(other_type_param, - TypeEquality::kInSubtypeTest, trail)) { + TypeEquality::kInSubtypeTest, + function_type_equivalence)) { return true; } } const AbstractType& bound = AbstractType::Handle(zone, type_param.bound()); ASSERT(bound.IsFinalized()); - if (bound.IsSubtypeOf(other, space, trail)) { + if (bound.IsSubtypeOf(other, space, function_type_equivalence)) { return true; } // Apply additional subtyping rules if 'other' is 'FutureOr'. - if (IsSubtypeOfFutureOr(zone, other, space, trail)) { + if (IsSubtypeOfFutureOr(zone, other, space, function_type_equivalence)) { return true; } return false; @@ -21528,11 +21530,11 @@ bool AbstractType::IsSubtypeOf(const AbstractType& other, other.IsNonNullable()) { return false; } - return FunctionType::Cast(*this).IsSubtypeOf(FunctionType::Cast(other), - space); + return FunctionType::Cast(*this).IsSubtypeOf( + FunctionType::Cast(other), space, function_type_equivalence); } // Apply additional subtyping rules if 'other' is 'FutureOr'. - if (IsSubtypeOfFutureOr(zone, other, space, trail)) { + if (IsSubtypeOfFutureOr(zone, other, space, function_type_equivalence)) { return true; } // All possible supertypes for FunctionType have been checked. @@ -21554,11 +21556,11 @@ bool AbstractType::IsSubtypeOf(const AbstractType& other, other.IsNonNullable()) { return false; } - return RecordType::Cast(*this).IsSubtypeOf(RecordType::Cast(other), - space); + return RecordType::Cast(*this).IsSubtypeOf(RecordType::Cast(other), space, + function_type_equivalence); } // Apply additional subtyping rules if 'other' is 'FutureOr'. - if (IsSubtypeOfFutureOr(zone, other, space, trail)) { + if (IsSubtypeOfFutureOr(zone, other, space, function_type_equivalence)) { return true; } // All possible supertypes for record type have been checked. @@ -21574,13 +21576,14 @@ bool AbstractType::IsSubtypeOf(const AbstractType& other, type_cls, TypeArguments::Handle(zone, Type::Cast(*this).GetInstanceTypeArguments( thread, /*canonicalize=*/false)), - nullability(), other, space, trail); + nullability(), other, space, function_type_equivalence); } -bool AbstractType::IsSubtypeOfFutureOr(Zone* zone, - const AbstractType& other, - Heap::Space space, - TrailPtr trail) const { +bool AbstractType::IsSubtypeOfFutureOr( + Zone* zone, + const AbstractType& other, + Heap::Space space, + FunctionTypeMapping* function_type_equivalence) const { if (other.IsFutureOrType()) { // This function is only called with a receiver that is either a function // type, record type, or an uninstantiated type parameter. @@ -21594,7 +21597,7 @@ bool AbstractType::IsSubtypeOfFutureOr(Zone* zone, return true; } // Retry the IsSubtypeOf check after unwrapping type arg of FutureOr. - if (IsSubtypeOf(other_type_arg, space, trail)) { + if (IsSubtypeOf(other_type_arg, space, function_type_equivalence)) { return true; } } @@ -21755,7 +21758,7 @@ TypePtr Type::NewNonParameterizedType(const Class& type_class) { type = Type::New(Class::Handle(type_class.ptr()), Object::null_type_arguments(), Nullability::kNonNullable); type.SetIsFinalized(); - type ^= type.Canonicalize(Thread::Current(), nullptr); + type ^= type.Canonicalize(Thread::Current()); type_class.set_declaration_type(type); } ASSERT(type.IsFinalized()); @@ -21791,7 +21794,7 @@ TypePtr Type::ToNullability(Nullability value, Heap::Space space) const { if (IsCanonical()) { // Object::Clone does not clone canonical bit. ASSERT(!type.IsCanonical()); - type ^= type.Canonicalize(Thread::Current(), nullptr); + type ^= type.Canonicalize(Thread::Current()); } return type.ptr(); } @@ -21802,10 +21805,7 @@ FunctionTypePtr FunctionType::ToNullability(Nullability value, return ptr(); } // Clone function type and set new nullability. - FunctionType& type = FunctionType::Handle(); - // Always cloning in old space and removing space parameter would not satisfy - // currently existing requests for type instantiation in new space. - type ^= Object::Clone(*this, space); + FunctionType& type = FunctionType::Handle(FunctionType::Clone(*this, space)); type.set_nullability(value); type.SetHash(0); type.InitializeTypeTestingStubNonAtomic( @@ -21813,7 +21813,7 @@ FunctionTypePtr FunctionType::ToNullability(Nullability value, if (IsCanonical()) { // Object::Clone does not clone canonical bit. ASSERT(!type.IsCanonical()); - type ^= type.Canonicalize(Thread::Current(), nullptr); + type ^= type.Canonicalize(Thread::Current()); } return type.ptr(); } @@ -21827,8 +21827,7 @@ ClassPtr Type::type_class() const { } bool Type::IsInstantiated(Genericity genericity, - intptr_t num_free_fun_type_params, - TrailPtr trail) const { + intptr_t num_free_fun_type_params) const { if (type_state() == UntaggedType::kFinalizedInstantiated) { return true; } @@ -21841,7 +21840,7 @@ bool Type::IsInstantiated(Genericity genericity, } const TypeArguments& args = TypeArguments::Handle(arguments()); return args.IsSubvectorInstantiated(0, args.Length(), genericity, - num_free_fun_type_params, trail); + num_free_fun_type_params); } AbstractTypePtr Type::InstantiateFrom( @@ -21849,7 +21848,7 @@ AbstractTypePtr Type::InstantiateFrom( const TypeArguments& function_type_arguments, intptr_t num_free_fun_type_params, Heap::Space space, - TrailPtr trail, + FunctionTypeMapping* function_type_mapping, intptr_t num_parent_type_args_adjustment) const { Zone* zone = Thread::Current()->zone(); ASSERT(IsFinalized() || IsBeingFinalized()); @@ -21862,7 +21861,8 @@ AbstractTypePtr Type::InstantiateFrom( ASSERT(type_arguments.Length() == cls.NumTypeParameters()); type_arguments = type_arguments.InstantiateFrom( instantiator_type_arguments, function_type_arguments, - num_free_fun_type_params, space, trail, num_parent_type_args_adjustment); + num_free_fun_type_params, space, function_type_mapping, + num_parent_type_args_adjustment); // A returned empty_type_arguments indicates a failed instantiation in dead // code that must be propagated up to the caller, the optimizing compiler. if (type_arguments.ptr() == Object::empty_type_arguments().ptr()) { @@ -21883,22 +21883,22 @@ AbstractTypePtr Type::InstantiateFrom( return instantiated_type.NormalizeFutureOrType(space); } -AbstractTypePtr Type::UpdateParentFunctionType( +AbstractTypePtr Type::UpdateFunctionTypes( intptr_t num_parent_type_args_adjustment, intptr_t num_free_fun_type_params, Heap::Space space, - TrailPtr trail) const { + FunctionTypeMapping* function_type_mapping) const { ASSERT(IsFinalized()); - ASSERT(num_parent_type_args_adjustment > 0); + ASSERT(num_parent_type_args_adjustment >= 0); if (arguments() == Object::null()) { return ptr(); } Zone* zone = Thread::Current()->zone(); const auto& type_args = TypeArguments::Handle(zone, arguments()); - const auto& updated_type_args = - TypeArguments::Handle(zone, type_args.UpdateParentFunctionType( - num_parent_type_args_adjustment, - num_free_fun_type_params, space, trail)); + const auto& updated_type_args = TypeArguments::Handle( + zone, type_args.UpdateFunctionTypes(num_parent_type_args_adjustment, + num_free_fun_type_params, space, + function_type_mapping)); if (type_args.ptr() == updated_type_args.ptr()) { return ptr(); } @@ -21928,18 +21928,11 @@ static classid_t NormalizeClassIdForSyntacticalTypeEquality(classid_t cid) { bool Type::IsEquivalent(const Instance& other, TypeEquality kind, - TrailPtr trail) const { + FunctionTypeMapping* function_type_equivalence) const { ASSERT(!IsNull()); if (ptr() == other.ptr()) { return true; } - if (other.IsTypeRef()) { - // Unfold right hand type. Divergence is controlled by left hand type. - const AbstractType& other_ref_type = - AbstractType::Handle(TypeRef::Cast(other).type()); - ASSERT(!other_ref_type.IsTypeRef()); - return IsEquivalent(other_ref_type, kind, trail); - } if (!other.IsType()) { return false; } @@ -21973,23 +21966,18 @@ bool Type::IsEquivalent(const Instance& other, TypeArguments::Handle(zone, this->arguments()); const TypeArguments& other_type_args = TypeArguments::Handle(zone, other_type.arguments()); - return type_args.IsEquivalent(other_type_args, kind, trail); + return type_args.IsEquivalent(other_type_args, kind, + function_type_equivalence); } -bool FunctionType::IsEquivalent(const Instance& other, - TypeEquality kind, - TrailPtr trail) const { +bool FunctionType::IsEquivalent( + const Instance& other, + TypeEquality kind, + FunctionTypeMapping* function_type_equivalence) const { ASSERT(!IsNull()); if (ptr() == other.ptr()) { return true; } - if (other.IsTypeRef()) { - // Unfold right hand type. Divergence is controlled by left hand type. - const AbstractType& other_ref_type = - AbstractType::Handle(TypeRef::Cast(other).type()); - ASSERT(!other_ref_type.IsTypeRef()); - return IsEquivalent(other_ref_type, kind, trail); - } if (!other.IsFunctionType()) { return false; } @@ -22009,12 +21997,15 @@ bool FunctionType::IsEquivalent(const Instance& other, ASSERT(kind != TypeEquality::kCanonical); return false; // Too early to decide if equal. } + FunctionTypeMapping scope(zone, &function_type_equivalence, *this, + other_type); + // Equal function types must have equal signature types and equal optional // named arguments. - // Compare function type parameters and their bounds. // Check the type parameters and bounds of generic functions. - if (!HasSameTypeParametersAndBounds(other_type, kind, trail)) { + if (!HasSameTypeParametersAndBounds(other_type, kind, + function_type_equivalence)) { return false; } AbstractType& param_type = Type::Handle(zone); @@ -22022,7 +22013,8 @@ bool FunctionType::IsEquivalent(const Instance& other, // Check the result type. param_type = result_type(); other_param_type = other_type.result_type(); - if (!param_type.IsEquivalent(other_param_type, kind, trail)) { + if (!param_type.IsEquivalent(other_param_type, kind, + function_type_equivalence)) { return false; } // Check the types of all parameters. @@ -22032,7 +22024,8 @@ bool FunctionType::IsEquivalent(const Instance& other, param_type = ParameterTypeAt(i); other_param_type = other_type.ParameterTypeAt(i); // Use contravariant order in case we test for subtyping. - if (!other_param_type.IsEquivalent(param_type, kind, trail)) { + if (!other_param_type.IsEquivalent(param_type, kind, + function_type_equivalence)) { return false; } } @@ -22050,11 +22043,7 @@ bool FunctionType::IsEquivalent(const Instance& other, return true; } -bool Type::IsRecursive(TrailPtr trail) const { - return TypeArguments::Handle(arguments()).IsRecursive(trail); -} - -bool Type::RequireConstCanonicalTypeErasure(Zone* zone, TrailPtr trail) const { +bool Type::RequireConstCanonicalTypeErasure(Zone* zone) const { if (IsNonNullable()) { return true; } @@ -22064,8 +22053,8 @@ bool Type::RequireConstCanonicalTypeErasure(Zone* zone, TrailPtr trail) const { return false; } const auto& type_args = TypeArguments::Handle(zone, this->arguments()); - return type_args.RequireConstCanonicalTypeErasure(zone, 0, type_args.Length(), - trail); + return type_args.RequireConstCanonicalTypeErasure(zone, 0, + type_args.Length()); } bool Type::IsDeclarationTypeOf(const Class& cls) const { @@ -22080,7 +22069,7 @@ bool Type::IsDeclarationTypeOf(const Class& cls) const { } // Keep in sync with TypeSerializationCluster::IsInCanonicalSet. -AbstractTypePtr Type::Canonicalize(Thread* thread, TrailPtr trail) const { +AbstractTypePtr Type::Canonicalize(Thread* thread) const { Zone* zone = thread->zone(); ASSERT(IsFinalized()); if (IsCanonical()) { @@ -22114,12 +22103,7 @@ AbstractTypePtr Type::Canonicalize(Thread* thread, TrailPtr trail) const { (isolate_group == Dart::vm_isolate_group())); // Canonicalize the type arguments of the supertype, if any. TypeArguments& type_args = TypeArguments::Handle(zone, arguments()); - type_args = type_args.Canonicalize(thread, trail); - if (IsCanonical()) { - // Canonicalizing type_args canonicalized this type. - ASSERT(IsRecursive()); - return this->ptr(); - } + type_args = type_args.Canonicalize(thread); set_arguments(type_args); type = cls.declaration_type(); // May be set while canonicalizing type args. @@ -22163,13 +22147,7 @@ AbstractTypePtr Type::Canonicalize(Thread* thread, TrailPtr trail) const { TypeArguments& type_args = TypeArguments::Handle(zone, arguments()); ASSERT(type_args.IsNull() || (type_args.Length() == cls.NumTypeParameters())); - type_args = type_args.Canonicalize(thread, trail); - if (IsCanonical()) { - // Canonicalizing type_args canonicalized this type as a side effect. - ASSERT(IsRecursive()); - // A type can be recursive due to a cycle in its type arguments. - return this->ptr(); - } + type_args = type_args.Canonicalize(thread); set_arguments(type_args); ASSERT(type_args.IsNull() || type_args.IsOld()); @@ -22197,9 +22175,6 @@ AbstractTypePtr Type::Canonicalize(Thread* thread, TrailPtr trail) const { #if defined(DEBUG) bool Type::CheckIsCanonical(Thread* thread) const { - if (IsRecursive()) { - return true; - } const classid_t cid = type_class_id(); if (cid == kDynamicCid) { return (ptr() == Object::dynamic_type().ptr()); @@ -22284,7 +22259,7 @@ uword Type::ComputeHash() const { uint32_t type_args_hash = TypeArguments::kAllDynamicHash; if (arguments() != TypeArguments::null()) { const TypeArguments& args = TypeArguments::Handle(arguments()); - type_args_hash = args.HashForRange(0, args.Length()); + type_args_hash = args.Hash(); } result = CombineHashes(result, type_args_hash); result = FinalizeHash(result, kHashBits); @@ -22308,13 +22283,8 @@ uword FunctionType::ComputeHash() const { if (num_type_params > 0) { const TypeParameters& type_params = TypeParameters::Handle(type_parameters()); - // Do not calculate the hash of the bounds using TypeArguments::Hash(), - // because HashForRange() dereferences TypeRefs which should not be here. - AbstractType& bound = AbstractType::Handle(); - for (intptr_t i = 0; i < num_type_params; i++) { - bound = type_params.BoundAt(i); - result = CombineHashes(result, bound.Hash()); - } + const TypeArguments& bounds = TypeArguments::Handle(type_params.bounds()); + result = CombineHashes(result, bounds.Hash()); // Since the default arguments are ignored when comparing two generic // function types for type equality, the hash does not depend on them. } @@ -22414,46 +22384,10 @@ const char* Type::ToCString() const { const String& name = String::Handle(zone, cls.Name()); class_name = name.IsNull() ? "" : name.ToCString(); const char* suffix = NullabilitySuffix(kInternalName); - if (IsFinalized() && IsRecursive()) { - const intptr_t hash = Hash(); - return OS::SCreate(zone, "Type: (H%" Px ") %s%s%s", hash, class_name, - args_cstr, suffix); - } else { - return OS::SCreate(zone, "Type: %s%s%s", class_name, args_cstr, suffix); - } + return OS::SCreate(zone, "Type: %s%s%s", class_name, args_cstr, suffix); } -bool FunctionType::IsRecursive(TrailPtr trail) const { - if (IsGeneric()) { - const TypeParameters& type_params = - TypeParameters::Handle(type_parameters()); - TypeArguments& type_args = TypeArguments::Handle(); - type_args = type_params.bounds(); - if (type_args.IsRecursive(trail)) { - return true; - } - type_args = type_params.defaults(); - if (type_args.IsRecursive(trail)) { - return true; - } - } - AbstractType& type = AbstractType::Handle(); - type = result_type(); - if (type.IsRecursive(trail)) { - return true; - } - const intptr_t num_params = NumParameters(); - for (intptr_t i = 0; i < num_params; i++) { - type = ParameterTypeAt(i); - if (type.IsRecursive(trail)) { - return true; - } - } - return false; -} - -bool FunctionType::RequireConstCanonicalTypeErasure(Zone* zone, - TrailPtr trail) const { +bool FunctionType::RequireConstCanonicalTypeErasure(Zone* zone) const { if (IsNonNullable()) { return true; } @@ -22468,33 +22402,30 @@ bool FunctionType::RequireConstCanonicalTypeErasure(Zone* zone, TypeParameters::Handle(type_parameters()); TypeArguments& type_args = TypeArguments::Handle(); type_args = type_params.bounds(); - if (type_args.RequireConstCanonicalTypeErasure(zone, 0, num_type_params, - trail)) { + if (type_args.RequireConstCanonicalTypeErasure(zone, 0, num_type_params)) { return true; } type_args = type_params.defaults(); - if (type_args.RequireConstCanonicalTypeErasure(zone, 0, num_type_params, - trail)) { + if (type_args.RequireConstCanonicalTypeErasure(zone, 0, num_type_params)) { return true; } } AbstractType& type = AbstractType::Handle(zone); type = result_type(); - if (type.RequireConstCanonicalTypeErasure(zone, trail)) { + if (type.RequireConstCanonicalTypeErasure(zone)) { return true; } const intptr_t num_params = NumParameters(); for (intptr_t i = 0; i < num_params; i++) { type = ParameterTypeAt(i); - if (type.RequireConstCanonicalTypeErasure(zone, trail)) { + if (type.RequireConstCanonicalTypeErasure(zone)) { return true; } } return false; } -AbstractTypePtr FunctionType::Canonicalize(Thread* thread, - TrailPtr trail) const { +AbstractTypePtr FunctionType::Canonicalize(Thread* thread) const { ASSERT(IsFinalized()); Zone* zone = thread->zone(); if (IsCanonical()) { @@ -22540,61 +22471,62 @@ AbstractTypePtr FunctionType::Canonicalize(Thread* thread, if (sig.IsNull()) { // The function type was not found in the table. It is not canonical yet. // Canonicalize its type parameters and types. - if (IsGeneric()) { + + // Clone this function type to the old heap and update + // owners of type parameters. + FunctionType& new_sig = FunctionType::Handle(zone); + if (this->IsNew()) { + new_sig ^= FunctionType::Clone(*this, Heap::kOld); + } else { + new_sig ^= this->ptr(); + } + ASSERT(new_sig.IsOld()); + + if (new_sig.IsGeneric()) { const TypeParameters& type_params = - TypeParameters::Handle(zone, type_parameters()); + TypeParameters::Handle(zone, new_sig.type_parameters()); ASSERT(type_params.IsOld()); TypeArguments& type_args = TypeArguments::Handle(zone); type_args = type_params.bounds(); if (!type_args.IsCanonical()) { - type_args = type_args.Canonicalize(thread, trail); + type_args = type_args.Canonicalize(thread); type_params.set_bounds(type_args); - SetHash(0); + new_sig.SetHash(0); } type_args = type_params.defaults(); if (!type_args.IsCanonical()) { - type_args = type_args.Canonicalize(thread, trail); + type_args = type_args.Canonicalize(thread); type_params.set_defaults(type_args); - SetHash(0); + new_sig.SetHash(0); } } AbstractType& type = AbstractType::Handle(zone); - type = result_type(); + type = new_sig.result_type(); if (!type.IsCanonical()) { - type = type.Canonicalize(thread, trail); - set_result_type(type); - SetHash(0); + type = type.Canonicalize(thread); + new_sig.set_result_type(type); + new_sig.SetHash(0); } - ASSERT(Array::Handle(zone, parameter_types()).IsOld()); - ASSERT(Array::Handle(zone, named_parameter_names()).IsOld()); - const intptr_t num_params = NumParameters(); + ASSERT(Array::Handle(zone, new_sig.parameter_types()).IsOld()); + ASSERT(Array::Handle(zone, new_sig.named_parameter_names()).IsOld()); + const intptr_t num_params = new_sig.NumParameters(); for (intptr_t i = 0; i < num_params; i++) { - type = ParameterTypeAt(i); + type = new_sig.ParameterTypeAt(i); if (!type.IsCanonical()) { - type = type.Canonicalize(thread, trail); - SetParameterTypeAt(i, type); - SetHash(0); + type = type.Canonicalize(thread); + new_sig.SetParameterTypeAt(i, type); + new_sig.SetHash(0); } } - if (IsCanonical()) { - // Canonicalizing signature types canonicalized this signature as a - // side effect. - ASSERT(IsRecursive()); - return this->ptr(); - } - // Check to see if the function type got added to canonical table as part - // of the canonicalization of its signature types. + // Check to see if the function type got added to canonical table + // during canonicalization of its signature types. SafepointMutexLocker ml(isolate_group->type_canonicalization_mutex()); CanonicalFunctionTypeSet table(zone, object_store->canonical_function_types()); - sig ^= table.GetOrNull(CanonicalFunctionTypeKey(*this)); + sig ^= table.GetOrNull(CanonicalFunctionTypeKey(new_sig)); if (sig.IsNull()) { // Add this function type into the canonical table of function types. - if (this->IsNew()) { - sig ^= Object::Clone(*this, Heap::kOld); - } else { - sig = this->ptr(); - } + sig = new_sig.ptr(); ASSERT(sig.IsOld()); sig.SetCanonical(); // Mark object as being canonical. bool present = table.Insert(sig); @@ -22651,227 +22583,6 @@ void FunctionType::PrintName(NameVisibility name_visibility, } } -bool TypeRef::RequireConstCanonicalTypeErasure(Zone* zone, - TrailPtr trail) const { - if (TestAndAddToTrail(&trail)) { - return false; - } - const AbstractType& ref_type = AbstractType::Handle(zone, type()); - return !ref_type.IsNull() && - ref_type.RequireConstCanonicalTypeErasure(zone, trail); -} - -bool TypeRef::IsInstantiated(Genericity genericity, - intptr_t num_free_fun_type_params, - TrailPtr trail) const { - if (TestAndAddToTrail(&trail)) { - return true; - } - const AbstractType& ref_type = AbstractType::Handle(type()); - return !ref_type.IsNull() && - ref_type.IsInstantiated(genericity, num_free_fun_type_params, trail); -} - -bool TypeRef::IsEquivalent(const Instance& other, - TypeEquality kind, - TrailPtr trail) const { - if (ptr() == other.ptr()) { - return true; - } - if (!other.IsAbstractType()) { - return false; - } - if (TestAndAddBuddyToTrail(&trail, AbstractType::Cast(other))) { - return true; - } - const AbstractType& ref_type = AbstractType::Handle(type()); - return !ref_type.IsNull() && ref_type.IsEquivalent(other, kind, trail); -} - -AbstractTypePtr TypeRef::InstantiateFrom( - const TypeArguments& instantiator_type_arguments, - const TypeArguments& function_type_arguments, - intptr_t num_free_fun_type_params, - Heap::Space space, - TrailPtr trail, - intptr_t num_parent_type_args_adjustment) const { - TypeRef& instantiated_type_ref = TypeRef::Handle(); - instantiated_type_ref ^= OnlyBuddyInTrail(trail); - if (!instantiated_type_ref.IsNull()) { - return instantiated_type_ref.ptr(); - } - instantiated_type_ref = TypeRef::New(); - AddOnlyBuddyToTrail(&trail, instantiated_type_ref); - - AbstractType& ref_type = AbstractType::Handle(type()); - ASSERT(!ref_type.IsNull() && !ref_type.IsTypeRef()); - AbstractType& instantiated_ref_type = AbstractType::Handle(); - instantiated_ref_type = ref_type.InstantiateFrom( - instantiator_type_arguments, function_type_arguments, - num_free_fun_type_params, space, trail, num_parent_type_args_adjustment); - // A returned null type indicates a failed instantiation in dead code that - // must be propagated up to the caller, the optimizing compiler. - if (instantiated_ref_type.IsNull()) { - return TypeRef::null(); - } - ASSERT(!instantiated_ref_type.IsTypeRef()); - instantiated_type_ref.set_type(instantiated_ref_type); - - instantiated_type_ref.InitializeTypeTestingStubNonAtomic(Code::Handle( - TypeTestingStubGenerator::DefaultCodeForType(instantiated_type_ref))); - return instantiated_type_ref.ptr(); -} - -AbstractTypePtr TypeRef::UpdateParentFunctionType( - intptr_t num_parent_type_args_adjustment, - intptr_t num_free_fun_type_params, - Heap::Space space, - TrailPtr trail) const { - ASSERT(IsFinalized()); - ASSERT(num_parent_type_args_adjustment > 0); - Zone* zone = Thread::Current()->zone(); - TypeRef& new_type_ref = TypeRef::Handle(zone); - new_type_ref ^= OnlyBuddyInTrail(trail); - if (!new_type_ref.IsNull()) { - return new_type_ref.ptr(); - } - new_type_ref = TypeRef::New(); - AddOnlyBuddyToTrail(&trail, new_type_ref); - - AbstractType& ref_type = AbstractType::Handle(type()); - ASSERT(!ref_type.IsNull() && !ref_type.IsTypeRef()); - - const auto& updated_ref_type = - AbstractType::Handle(zone, ref_type.UpdateParentFunctionType( - num_parent_type_args_adjustment, - num_free_fun_type_params, space, trail)); - ASSERT(!updated_ref_type.IsTypeRef()); - new_type_ref.set_type(updated_ref_type); - - return new_type_ref.ptr(); -} - -void TypeRef::set_type(const AbstractType& value) const { - ASSERT(!value.IsTypeRef()); - if (value.IsNull()) { - ASSERT(!IsFinalized()); - } else { - set_type_state(value.type_state()); - set_nullability(value.nullability()); - } - untag()->set_type(value.ptr()); -} - -// A TypeRef cannot be canonical by definition. Only its referenced type can be. -// Consider the type Derived, where class Derived extends Base. -// The first type argument of its flattened type argument vector is Derived, -// represented by a TypeRef pointing to itself. -AbstractTypePtr TypeRef::Canonicalize(Thread* thread, TrailPtr trail) const { - if (TestAndAddToTrail(&trail)) { - return ptr(); - } - // TODO(regis): Try to reduce the number of nodes required to represent the - // referenced recursive type. - AbstractType& ref_type = AbstractType::Handle(type()); - ASSERT(!ref_type.IsNull()); - ref_type = ref_type.Canonicalize(thread, trail); - { - SafepointMutexLocker ml( - thread->isolate_group()->type_canonicalization_mutex()); - set_type(ref_type); - } - return ptr(); -} - -#if defined(DEBUG) -bool TypeRef::CheckIsCanonical(Thread* thread) const { - AbstractType& ref_type = AbstractType::Handle(type()); - ASSERT(!ref_type.IsNull()); - return ref_type.CheckIsCanonical(thread); -} -#endif // DEBUG - -void TypeRef::EnumerateURIs(URIs* uris) const { - Thread* thread = Thread::Current(); - Zone* zone = thread->zone(); - const AbstractType& ref_type = AbstractType::Handle(zone, type()); - ASSERT(!ref_type.IsDynamicType() && !ref_type.IsVoidType() && - !ref_type.IsNeverType()); - const Class& cls = Class::Handle(zone, ref_type.type_class()); - const String& name = String::Handle(zone, cls.UserVisibleName()); - const Library& library = Library::Handle(zone, cls.library()); - const String& uri = String::Handle(zone, library.url()); - AddURI(uris, name, uri); - // Break cycle by not printing type arguments. -} - -void TypeRef::PrintName(NameVisibility name_visibility, - BaseTextBuffer* printer) const { - // Cycles via base class type arguments are not a problem (not printed). - const AbstractType& ref_type = - AbstractType::Handle(TypeRef::Cast(*this).type()); - ref_type.PrintName(name_visibility, printer); -} - -uword TypeRef::Hash() const { - // Do not use hash of the referenced type because - // - we could be in process of calculating it (as TypeRef is used to - // represent recursive references to types). - // - referenced type might be incomplete (e.g. not all its - // type arguments are set). - const AbstractType& ref_type = AbstractType::Handle(type()); - ASSERT(!ref_type.IsNull()); - uint32_t result; - if (ref_type.IsTypeParameter()) { - result = TypeParameter::Cast(ref_type).parameterized_class_id(); - result = CombineHashes(result, TypeParameter::Cast(ref_type).index()); - } else { - ASSERT(ref_type.IsType() || ref_type.IsFunctionType()); - result = ref_type.type_class_id(); - } - // A legacy type should have the same hash as its non-nullable version to be - // consistent with the definition of type equality in Dart code. - Nullability ref_type_nullability = ref_type.nullability(); - if (ref_type_nullability == Nullability::kLegacy) { - ref_type_nullability = Nullability::kNonNullable; - } - result = CombineHashes(result, static_cast(ref_type_nullability)); - return FinalizeHash(result, kHashBits); -} - -TypeRefPtr TypeRef::New() { - ObjectPtr raw = - Object::Allocate(TypeRef::kClassId, TypeRef::InstanceSize(), Heap::kOld, - TypeRef::ContainsCompressedPointers()); - return static_cast(raw); -} - -TypeRefPtr TypeRef::New(const AbstractType& type) { - Zone* Z = Thread::Current()->zone(); - const TypeRef& result = TypeRef::Handle(Z, TypeRef::New()); - result.set_type(type); - - result.InitializeTypeTestingStubNonAtomic( - Code::Handle(Z, TypeTestingStubGenerator::DefaultCodeForType(result))); - return result.ptr(); -} - -const char* TypeRef::ToCString() const { - Zone* zone = Thread::Current()->zone(); - AbstractType& ref_type = AbstractType::Handle(zone, type()); - if (ref_type.IsNull()) { - return "TypeRef: null"; - } - ZoneTextBuffer printer(zone); - printer.AddString("TypeRef: "); - ref_type.PrintName(kInternalName, &printer); - if (ref_type.IsFinalized()) { - const intptr_t hash = ref_type.Hash(); - printer.Printf(" (H%" Px ")", hash); - } - return printer.buffer(); -} - TypeParameterPtr TypeParameter::ToNullability(Nullability value, Heap::Space space) const { if (nullability() == value) { @@ -22889,121 +22600,85 @@ TypeParameterPtr TypeParameter::ToNullability(Nullability value, ASSERT(!type_parameter.IsCanonical()); ASSERT(IsFinalized()); ASSERT(type_parameter.IsFinalized()); - type_parameter ^= type_parameter.Canonicalize(Thread::Current(), nullptr); + type_parameter ^= type_parameter.Canonicalize(Thread::Current()); } return type_parameter.ptr(); } bool TypeParameter::IsInstantiated(Genericity genericity, - intptr_t num_free_fun_type_params, - TrailPtr trail) const { + intptr_t num_free_fun_type_params) const { // Bounds of class type parameters are ignored in the VM. if (IsClassTypeParameter()) { return genericity == kFunctions; } ASSERT(IsFunctionTypeParameter()); - if ((genericity != kCurrentClass) && (index() < num_free_fun_type_params)) { - return false; - } - // Although the type parameter is instantiated, its bound may not be. - const AbstractType& upper_bound = AbstractType::Handle(bound()); - if (!upper_bound.IsInstantiated(genericity, num_free_fun_type_params, - trail)) { - return false; - } - return true; + return (genericity == kCurrentClass) || (index() >= num_free_fun_type_params); } -bool TypeParameter::IsEquivalent(const Instance& other, - TypeEquality kind, - TrailPtr trail) const { +bool TypeParameter::IsEquivalent( + const Instance& other, + TypeEquality kind, + FunctionTypeMapping* function_type_equivalence) const { + TRACE_TYPE_CHECKS_VERBOSE(" TypeParameter::IsEquivalent(%s, %s, kind %d)\n", + ToCString(), other.ToCString(), kind); if (ptr() == other.ptr()) { + TRACE_TYPE_CHECKS_VERBOSE(" - result: true (same types)\n"); return true; } - if (other.IsTypeRef()) { - // Unfold right hand type. Divergence is controlled by left hand type. - const AbstractType& other_ref_type = - AbstractType::Handle(TypeRef::Cast(other).type()); - ASSERT(!other_ref_type.IsTypeRef()); - return IsEquivalent(other_ref_type, kind, trail); - } if (!other.IsTypeParameter()) { + TRACE_TYPE_CHECKS_VERBOSE( + " - result: false (other is not a type parameter)\n"); return false; } const TypeParameter& other_type_param = TypeParameter::Cast(other); ASSERT(IsFinalized() && other_type_param.IsFinalized()); - // Compare index, name, bound, default argument, and flags. + // Compare index, base and owner. if (IsFunctionTypeParameter()) { if (!other_type_param.IsFunctionTypeParameter()) { + TRACE_TYPE_CHECKS_VERBOSE( + " - result: false (other is not a function type parameter)\n"); return false; } - if (base() != other_type_param.base() || - index() != other_type_param.index()) { + if ((owner() != other_type_param.owner()) && + ((function_type_equivalence == nullptr) || + !function_type_equivalence->ContainsOwnersOfTypeParameters( + *this, other_type_param))) { + TRACE_TYPE_CHECKS_VERBOSE( + " - result: false (owners are not equivalent)\n"); return false; } - if (kind == TypeEquality::kInSubtypeTest) { - AbstractType& upper_bound = AbstractType::Handle(bound()); - AbstractType& other_type_param_upper_bound = - AbstractType::Handle(other_type_param.bound()); - // Bounds that are mutual subtypes are considered equal. - // It is ok to pass the IsEquivalent trail as the IsSubtypeOf trail, - // because it is more restrictive (equivalence implies subtype). - if (!upper_bound.IsSubtypeOf(other_type_param_upper_bound, Heap::kOld, - trail) || - !other_type_param_upper_bound.IsSubtypeOf(upper_bound, Heap::kOld, - trail)) { - return false; - } - } else { - AbstractType& type = AbstractType::Handle(bound()); - AbstractType& other_type = AbstractType::Handle(other_type_param.bound()); - if (!type.IsEquivalent(other_type, kind, trail)) { - return false; - } - } } else { if (!other_type_param.IsClassTypeParameter()) { + TRACE_TYPE_CHECKS_VERBOSE( + " - result: false (other is not a class type parameter)\n"); return false; } - if (kind == TypeEquality::kCanonical) { - if (parameterized_class_id() != - other_type_param.parameterized_class_id()) { - // This also rejects finalized vs unfinalized comparison. - return false; - } - if (base() != other_type_param.base() || - index() != other_type_param.index()) { - return false; - } - } else { - if (index() != other_type_param.index()) { - return false; - } - } - AbstractType& upper_bound = AbstractType::Handle(bound()); - AbstractType& other_type_param_upper_bound = - AbstractType::Handle(other_type_param.bound()); - if (!upper_bound.IsEquivalent(other_type_param_upper_bound, kind, trail)) { + if (parameterized_class_id() != other_type_param.parameterized_class_id()) { + TRACE_TYPE_CHECKS_VERBOSE( + " - result: false (parameterized class id)\n"); return false; } } - return IsNullabilityEquivalent(Thread::Current(), other_type_param, kind); + if (base() != other_type_param.base() || + index() != other_type_param.index()) { + TRACE_TYPE_CHECKS_VERBOSE(" - result: false (mismatch base/index)\n"); + return false; + } + if (!IsNullabilityEquivalent(Thread::Current(), other_type_param, kind)) { + TRACE_TYPE_CHECKS_VERBOSE(" - result: false (mismatch nullability)\n"); + return false; + } + TRACE_TYPE_CHECKS_VERBOSE(" - result: true\n"); + return true; } -bool TypeParameter::IsRecursive(TrailPtr trail) const { - if (AbstractType::Handle(bound()).IsRecursive(trail)) { - return true; - } - return false; -} - -void TypeParameter::set_parameterized_class(const Class& value) const { - // Set value may be null. - classid_t cid = kFunctionCid; // Denotes a function type parameter. - if (!value.IsNull()) { - cid = value.id(); - } - set_parameterized_class_id(cid); +void TypeParameter::set_owner(const Object& value) const { + ASSERT(value.IsNull() || value.IsClass() || value.IsFunctionType()); + untag()->set_owner(value.ptr()); + set_parameterized_class_id( + value.IsNull() + ? kObjectCid + : (value.IsClass() ? Class::Cast(value).id() : kFunctionCid)); } void TypeParameter::set_parameterized_class_id(classid_t value) const { @@ -23014,15 +22689,6 @@ classid_t TypeParameter::parameterized_class_id() const { return untag()->parameterized_class_id_; } -ClassPtr TypeParameter::parameterized_class() const { - classid_t cid = parameterized_class_id(); - // A canonicalized class type parameter does not refer to its class anymore. - if (cid == kClassCid || cid == kFunctionCid) { - return Class::null(); - } - return IsolateGroup::Current()->class_table()->At(cid); -} - void TypeParameter::set_base(intptr_t value) const { ASSERT(value >= 0); ASSERT(Utils::IsUint(16, value)); @@ -23035,9 +22701,15 @@ void TypeParameter::set_index(intptr_t value) const { StoreNonPointer(&untag()->index_, value); } -void TypeParameter::set_bound(const AbstractType& value) const { - ASSERT(!IsCanonical()); - untag()->set_bound(value.ptr()); +AbstractTypePtr TypeParameter::bound() const { + const auto& owner = Object::Handle(this->owner()); + if (owner.IsNull()) { + return IsolateGroup::Current()->object_store()->nullable_object_type(); + } + const auto& type_parameters = TypeParameters::Handle( + owner.IsClass() ? Class::Cast(owner).type_parameters() + : FunctionType::Cast(owner).type_parameters()); + return type_parameters.BoundAt(index() - base()); } AbstractTypePtr TypeParameter::GetFromTypeArguments( @@ -23055,42 +22727,39 @@ AbstractTypePtr TypeParameter::InstantiateFrom( const TypeArguments& function_type_arguments, intptr_t num_free_fun_type_params, Heap::Space space, - TrailPtr trail, + FunctionTypeMapping* function_type_mapping, intptr_t num_parent_type_args_adjustment) const { - AbstractType& result = AbstractType::Handle(); + Zone* zone = Thread::Current()->zone(); + AbstractType& result = AbstractType::Handle(zone); bool substituted = false; if (IsFunctionTypeParameter()) { ASSERT(IsFinalized()); if (index() >= num_free_fun_type_params) { - // Do not instantiate the function type parameter, but possibly its bound. - // Also adjust index/base of the type parameter. - result = ptr(); - AbstractType& upper_bound = AbstractType::Handle(bound()); + // Do not instantiate the function type parameter. + // Get a replacement from the updated function type. + ASSERT(function_type_mapping != nullptr); + result = function_type_mapping->MapTypeParameter(*this); + ASSERT(TypeParameter::Cast(result).index() == + index() - num_free_fun_type_params); + ASSERT(TypeParameter::Cast(result).base() == + base() - num_free_fun_type_params); + ASSERT(TypeParameter::Cast(result).nullability() == nullability()); + AbstractType& upper_bound = AbstractType::Handle(zone, bound()); if (!upper_bound.IsInstantiated()) { upper_bound = upper_bound.InstantiateFrom( instantiator_type_arguments, function_type_arguments, - num_free_fun_type_params, space, trail, + num_free_fun_type_params, space, function_type_mapping, num_parent_type_args_adjustment); } - if ((upper_bound.IsTypeRef() && - TypeRef::Cast(upper_bound).type() == Type::NeverType()) || - (upper_bound.ptr() == Type::NeverType())) { + if (upper_bound.ptr() == Type::NeverType()) { // Normalize 'X extends Never' to 'Never'. result = Type::NeverType(); - } else if ((upper_bound.ptr() != bound()) || - (num_free_fun_type_params != 0)) { - result ^= Object::Clone(result, space); - const auto& tp = TypeParameter::Cast(result); - tp.set_bound(upper_bound); - tp.set_base(tp.base() - num_free_fun_type_params); - tp.set_index(tp.index() - num_free_fun_type_params); } } else if (function_type_arguments.IsNull()) { return Type::DynamicType(); } else { result = function_type_arguments.TypeAt(index()); substituted = true; - ASSERT(!result.IsTypeParameter()); } } else { ASSERT(IsClassTypeParameter()); @@ -23119,31 +22788,28 @@ AbstractTypePtr TypeParameter::InstantiateFrom( // A type being substituted can have nested function types, // whose number of parent function type arguments should be adjusted // after the substitution. - result = result.UpdateParentFunctionType(num_parent_type_args_adjustment, - kAllFree, space); + result = result.UpdateFunctionTypes(num_parent_type_args_adjustment, + kAllFree, space, function_type_mapping); } // Canonicalization is not part of instantiation. return result.NormalizeFutureOrType(space); } -AbstractTypePtr TypeParameter::UpdateParentFunctionType( +AbstractTypePtr TypeParameter::UpdateFunctionTypes( intptr_t num_parent_type_args_adjustment, intptr_t num_free_fun_type_params, Heap::Space space, - TrailPtr trail) const { + FunctionTypeMapping* function_type_mapping) const { ASSERT(IsFinalized()); - ASSERT(num_parent_type_args_adjustment > 0); + ASSERT(num_parent_type_args_adjustment >= 0); if (IsFunctionTypeParameter() && (index() >= num_free_fun_type_params)) { Zone* zone = Thread::Current()->zone(); - auto& new_tp = TypeParameter::Handle(zone); - new_tp ^= Object::Clone(*this, space); - new_tp.set_base(base() + num_parent_type_args_adjustment); - new_tp.set_index(index() + num_parent_type_args_adjustment); - auto& type = AbstractType::Handle(zone, bound()); - type = - type.UpdateParentFunctionType(num_parent_type_args_adjustment, - num_free_fun_type_params, space, trail); - new_tp.set_bound(type); + ASSERT(function_type_mapping != nullptr); + const auto& new_tp = TypeParameter::Handle( + zone, function_type_mapping->MapTypeParameter(*this)); + ASSERT(new_tp.base() == base() + num_parent_type_args_adjustment); + ASSERT(new_tp.index() == index() + num_parent_type_args_adjustment); + ASSERT(new_tp.nullability() == nullability()); ASSERT(new_tp.IsFinalized()); return new_tp.ptr(); } else { @@ -23151,16 +22817,12 @@ AbstractTypePtr TypeParameter::UpdateParentFunctionType( } } -AbstractTypePtr TypeParameter::Canonicalize(Thread* thread, - TrailPtr trail) const { +AbstractTypePtr TypeParameter::Canonicalize(Thread* thread) const { ASSERT(IsFinalized()); Zone* zone = thread->zone(); if (IsCanonical()) { #ifdef DEBUG - // Verify that all fields are allocated in old space and are canonical. - const AbstractType& upper_bound = AbstractType::Handle(zone, bound()); - ASSERT(upper_bound.IsOld()); - ASSERT(upper_bound.IsCanonical() || upper_bound.IsTypeRef()); + ASSERT(Object::Handle(zone, owner()).IsOld()); #endif return this->ptr(); } @@ -23168,24 +22830,6 @@ AbstractTypePtr TypeParameter::Canonicalize(Thread* thread, ObjectStore* object_store = isolate_group->object_store(); TypeParameter& type_parameter = TypeParameter::Handle(zone); { - SafepointMutexLocker ml(isolate_group->type_canonicalization_mutex()); - CanonicalTypeParameterSet table(zone, - object_store->canonical_type_parameters()); - type_parameter ^= table.GetOrNull(CanonicalTypeParameterKey(*this)); - ASSERT(object_store->canonical_type_parameters() == table.Release().ptr()); - } - if (type_parameter.IsNull()) { - AbstractType& upper_bound = AbstractType::Handle(zone, bound()); - upper_bound = upper_bound.Canonicalize(thread, trail); - if (IsCanonical()) { - // Canonicalizing the bound canonicalized this type parameter - // as a side effect. - ASSERT(IsRecursive()); // Self-referring bound or default argument. - return ptr(); - } - set_bound(upper_bound); - // Check to see if the type parameter got added to canonical table as part - // of the canonicalization of its bound and default argument. SafepointMutexLocker ml(isolate_group->type_canonicalization_mutex()); CanonicalTypeParameterSet table(zone, object_store->canonical_type_parameters()); @@ -23209,9 +22853,6 @@ AbstractTypePtr TypeParameter::Canonicalize(Thread* thread, #if defined(DEBUG) bool TypeParameter::CheckIsCanonical(Thread* thread) const { - if (IsRecursive()) { - return true; - } Zone* zone = thread->zone(); auto isolate_group = thread->isolate_group(); @@ -23239,10 +22880,8 @@ void TypeParameter::PrintName(NameVisibility name_visibility, } uword TypeParameter::ComputeHash() const { - ASSERT(IsFinalized() || IsBeingFinalized()); // Bound may not be finalized. + ASSERT(IsFinalized()); uint32_t result = parameterized_class_id(); - const AbstractType& upper_bound = AbstractType::Handle(bound()); - result = CombineHashes(result, upper_bound.Hash()); // May be a TypeRef. result = CombineHashes(result, base()); result = CombineHashes(result, index()); // A legacy type should have the same hash as its non-nullable version to be @@ -23264,17 +22903,16 @@ TypeParameterPtr TypeParameter::New() { return static_cast(raw); } -TypeParameterPtr TypeParameter::New(const Class& parameterized_class, +TypeParameterPtr TypeParameter::New(const Object& owner, intptr_t base, intptr_t index, - const AbstractType& bound, Nullability nullability) { + ASSERT(owner.IsNull() || owner.IsClass() || owner.IsFunctionType()); Zone* Z = Thread::Current()->zone(); const TypeParameter& result = TypeParameter::Handle(Z, TypeParameter::New()); - result.set_parameterized_class(parameterized_class); + result.set_owner(owner); result.set_base(base); result.set_index(index); - result.set_bound(bound); result.SetHash(0); result.set_flags(0); result.set_nullability(nullability); @@ -23308,13 +22946,6 @@ const char* TypeParameter::ToCString() const { printer.Printf("TypeParameter: "); printer.AddString(CanonicalNameCString()); printer.AddString(NullabilitySuffix(kInternalName)); - printer.Printf("; bound: "); - const AbstractType& upper_bound = AbstractType::Handle(bound()); - if (upper_bound.IsNull()) { - printer.AddString(""); - } else { - upper_bound.PrintName(kInternalName, &printer); - } return printer.buffer(); } @@ -25354,7 +24985,7 @@ ArrayPtr Array::New(intptr_t len, if (!element_type.IsDynamicType()) { TypeArguments& type_args = TypeArguments::Handle(TypeArguments::New(1)); type_args.SetTypeAt(0, element_type); - type_args = type_args.Canonicalize(Thread::Current(), nullptr); + type_args = type_args.Canonicalize(Thread::Current()); result.SetTypeArguments(type_args); } return result.ptr(); @@ -25823,7 +25454,7 @@ void LinkedHashBase::CanonicalizeFieldsLocked(Thread* thread) const { TypeArguments& type_args = TypeArguments::Handle(zone, GetTypeArguments()); if (!type_args.IsNull()) { - type_args = type_args.Canonicalize(thread, nullptr); + type_args = type_args.Canonicalize(thread); SetTypeArguments(type_args); } @@ -26512,17 +26143,17 @@ void Closure::CanonicalizeFieldsLocked(Thread* thread) const { TypeArguments& type_args = TypeArguments::Handle(); type_args = instantiator_type_arguments(); if (!type_args.IsNull()) { - type_args = type_args.Canonicalize(thread, nullptr); + type_args = type_args.Canonicalize(thread); set_instantiator_type_arguments(type_args); } type_args = function_type_arguments(); if (!type_args.IsNull()) { - type_args = type_args.Canonicalize(thread, nullptr); + type_args = type_args.Canonicalize(thread); set_function_type_arguments(type_args); } type_args = delayed_type_arguments(); if (!type_args.IsNull()) { - type_args = type_args.Canonicalize(thread, nullptr); + type_args = type_args.Canonicalize(thread); set_delayed_type_arguments(type_args); } // Ignore function, context, hash. @@ -28005,13 +27636,12 @@ const char* RecordType::ToCString() const { } bool RecordType::IsInstantiated(Genericity genericity, - intptr_t num_free_fun_type_params, - TrailPtr trail) const { + intptr_t num_free_fun_type_params) const { AbstractType& type = AbstractType::Handle(); const intptr_t num_fields = NumFields(); for (intptr_t i = 0; i < num_fields; ++i) { type = FieldTypeAt(i); - if (!type.IsInstantiated(genericity, num_free_fun_type_params, trail)) { + if (!type.IsInstantiated(genericity, num_free_fun_type_params)) { return false; } } @@ -28059,25 +27689,19 @@ RecordTypePtr RecordType::ToNullability(Nullability value, if (IsCanonical()) { // Object::Clone does not clone canonical bit. ASSERT(!type.IsCanonical()); - type ^= type.Canonicalize(Thread::Current(), nullptr); + type ^= type.Canonicalize(Thread::Current()); } return type.ptr(); } -bool RecordType::IsEquivalent(const Instance& other, - TypeEquality kind, - TrailPtr trail) const { +bool RecordType::IsEquivalent( + const Instance& other, + TypeEquality kind, + FunctionTypeMapping* function_type_equivalence) const { ASSERT(!IsNull()); if (ptr() == other.ptr()) { return true; } - if (other.IsTypeRef()) { - // Unfold right hand type. Divergence is controlled by left hand type. - const AbstractType& other_ref_type = - AbstractType::Handle(TypeRef::Cast(other).type()); - ASSERT(!other_ref_type.IsTypeRef()); - return IsEquivalent(other_ref_type, kind, trail); - } if (!other.IsRecordType()) { return false; } @@ -28099,7 +27723,8 @@ bool RecordType::IsEquivalent(const Instance& other, for (intptr_t i = 0; i < num_fields; ++i) { field_type = FieldTypeAt(i); other_field_type = other_type.FieldTypeAt(i); - if (!field_type.IsEquivalent(other_field_type, kind, trail)) { + if (!field_type.IsEquivalent(other_field_type, kind, + function_type_equivalence)) { return false; } } @@ -28128,20 +27753,7 @@ uword RecordType::ComputeHash() const { return result; } -bool RecordType::IsRecursive(TrailPtr trail) const { - AbstractType& type = AbstractType::Handle(); - const intptr_t num_fields = NumFields(); - for (intptr_t i = 0; i < num_fields; ++i) { - type = FieldTypeAt(i); - if (type.IsRecursive(trail)) { - return true; - } - } - return false; -} - -bool RecordType::RequireConstCanonicalTypeErasure(Zone* zone, - TrailPtr trail) const { +bool RecordType::RequireConstCanonicalTypeErasure(Zone* zone) const { if (IsNonNullable()) { return true; } @@ -28152,14 +27764,14 @@ bool RecordType::RequireConstCanonicalTypeErasure(Zone* zone, const intptr_t num_fields = NumFields(); for (intptr_t i = 0; i < num_fields; ++i) { type = FieldTypeAt(i); - if (type.RequireConstCanonicalTypeErasure(zone, trail)) { + if (type.RequireConstCanonicalTypeErasure(zone)) { return true; } } return false; } -AbstractTypePtr RecordType::Canonicalize(Thread* thread, TrailPtr trail) const { +AbstractTypePtr RecordType::Canonicalize(Thread* thread) const { ASSERT(IsFinalized()); Zone* zone = thread->zone(); AbstractType& type = AbstractType::Handle(zone); @@ -28191,17 +27803,11 @@ AbstractTypePtr RecordType::Canonicalize(Thread* thread, TrailPtr trail) const { for (intptr_t i = 0; i < num_fields; ++i) { type = FieldTypeAt(i); if (!type.IsCanonical()) { - type = type.Canonicalize(thread, trail); + type = type.Canonicalize(thread); SetFieldTypeAt(i, type); SetHash(0); } } - if (IsCanonical()) { - // Canonicalizing fields types canonicalized this record as a - // side effect. - ASSERT(IsRecursive()); - return this->ptr(); - } // Check to see if the record type got added to canonical table as part // of the canonicalization of its signature types. SafepointMutexLocker ml(isolate_group->type_canonicalization_mutex()); @@ -28261,7 +27867,7 @@ AbstractTypePtr RecordType::InstantiateFrom( const TypeArguments& function_type_arguments, intptr_t num_free_fun_type_params, Heap::Space space, - TrailPtr trail, + FunctionTypeMapping* function_type_mapping, intptr_t num_parent_type_args_adjustment) const { ASSERT(IsFinalized() || IsBeingFinalized()); Zone* zone = Thread::Current()->zone(); @@ -28274,10 +27880,10 @@ AbstractTypePtr RecordType::InstantiateFrom( for (intptr_t i = 0; i < num_fields; ++i) { type ^= old_field_types.At(i); if (!type.IsInstantiated()) { - type = type.InstantiateFrom(instantiator_type_arguments, - function_type_arguments, - num_free_fun_type_params, space, trail, - num_parent_type_args_adjustment); + type = type.InstantiateFrom( + instantiator_type_arguments, function_type_arguments, + num_free_fun_type_params, space, function_type_mapping, + num_parent_type_args_adjustment); // A returned null type indicates a failed instantiation in dead code that // must be propagated up to the caller, the optimizing compiler. if (type.IsNull()) { @@ -28302,13 +27908,13 @@ AbstractTypePtr RecordType::InstantiateFrom( return rec.ptr(); } -AbstractTypePtr RecordType::UpdateParentFunctionType( +AbstractTypePtr RecordType::UpdateFunctionTypes( intptr_t num_parent_type_args_adjustment, intptr_t num_free_fun_type_params, Heap::Space space, - TrailPtr trail) const { + FunctionTypeMapping* function_type_mapping) const { ASSERT(IsFinalized()); - ASSERT(num_parent_type_args_adjustment > 0); + ASSERT(num_parent_type_args_adjustment >= 0); Zone* zone = Thread::Current()->zone(); const auto& types = Array::Handle(zone, field_types()); Array* updated_types = nullptr; @@ -28316,9 +27922,9 @@ AbstractTypePtr RecordType::UpdateParentFunctionType( auto& updated = AbstractType::Handle(zone); for (intptr_t i = 0, n = NumFields(); i < n; ++i) { type ^= types.At(i); - updated = - type.UpdateParentFunctionType(num_parent_type_args_adjustment, - num_free_fun_type_params, space, trail); + updated = type.UpdateFunctionTypes(num_parent_type_args_adjustment, + num_free_fun_type_params, space, + function_type_mapping); if (type.ptr() != updated.ptr()) { if (updated_types == nullptr) { updated_types = &Array::Handle(zone, Array::New(n, space)); @@ -28341,7 +27947,10 @@ AbstractTypePtr RecordType::UpdateParentFunctionType( return new_rt.ptr(); } -bool RecordType::IsSubtypeOf(const RecordType& other, Heap::Space space) const { +bool RecordType::IsSubtypeOf( + const RecordType& other, + Heap::Space space, + FunctionTypeMapping* function_type_equivalence) const { if (ptr() == other.ptr()) { return true; } @@ -28363,7 +27972,8 @@ bool RecordType::IsSubtypeOf(const RecordType& other, Heap::Space space) const { for (intptr_t i = 0; i < num_fields; ++i) { field_type = FieldTypeAt(i); other_field_type = other.FieldTypeAt(i); - if (!field_type.IsSubtypeOf(other_field_type, space)) { + if (!field_type.IsSubtypeOf(other_field_type, space, + function_type_equivalence)) { return false; } } diff --git a/runtime/vm/object.h b/runtime/vm/object.h index 4d3b723c044..ce0b5d3286f 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -67,6 +67,7 @@ class CallSiteResetter; class CodeStatistics; class IsolateGroupReloadContext; class ObjectGraphCopier; +class FunctionTypeMapping; class NativeArguments; #define REUSABLE_FORWARD_DECLARATION(name) class Reusable##name##HandleScope; @@ -984,9 +985,6 @@ class PassiveObject : public Object { DISALLOW_COPY_AND_ASSIGN(PassiveObject); }; -typedef ZoneGrowableHandlePtrArray Trail; -typedef ZoneGrowableHandlePtrArray* TrailPtr; - // A URIs array contains triplets of strings. // The first string in the triplet is a type name (usually a class). // The second string in the triplet is the URI of the type. @@ -1485,12 +1483,13 @@ class Class : public Object { // Returns true if the type specified by cls, type_arguments, and nullability // is a subtype of the other type. - static bool IsSubtypeOf(const Class& cls, - const TypeArguments& type_arguments, - Nullability nullability, - const AbstractType& other, - Heap::Space space, - TrailPtr trail = nullptr); + static bool IsSubtypeOf( + const Class& cls, + const TypeArguments& type_arguments, + Nullability nullability, + const AbstractType& other, + Heap::Space space, + FunctionTypeMapping* function_type_equivalence = nullptr); // Check if this is the top level class. bool IsTopLevel() const; @@ -2887,9 +2886,9 @@ class Function : public Object { // Note that function type parameters declared by this function do not make // its signature uninstantiated, only type parameters declared by parent // generic functions or class type parameters. - bool HasInstantiatedSignature(Genericity genericity = kAny, - intptr_t num_free_fun_type_params = kAllFree, - TrailPtr trail = nullptr) const; + bool HasInstantiatedSignature( + Genericity genericity = kAny, + intptr_t num_free_fun_type_params = kAllFree) const; bool IsPrivate() const; @@ -8148,14 +8147,10 @@ class TypeArguments : public Instance { return IsDynamicTypes(true, 0, len); } - // Return true if this vector contains a TypeRef. - bool IsRecursive(TrailPtr trail = nullptr) const; - // Return true if this vector contains a non-nullable type. bool RequireConstCanonicalTypeErasure(Zone* zone, intptr_t from_index, - intptr_t len, - TrailPtr trail = nullptr) const; + intptr_t len) const; TypeArgumentsPtr Prepend(Zone* zone, const TypeArguments& other, @@ -8172,31 +8167,32 @@ class TypeArguments : public Instance { TypeEquality::kCanonical); } - bool IsEquivalent(const TypeArguments& other, - TypeEquality kind, - TrailPtr trail = nullptr) const { + bool IsEquivalent( + const TypeArguments& other, + TypeEquality kind, + FunctionTypeMapping* function_type_equivalence = nullptr) const { // Make a null vector a vector of dynamic as long as the other vector. return IsSubvectorEquivalent(other, 0, IsNull() ? other.Length() : Length(), - kind, trail); + kind, function_type_equivalence); } - bool IsSubvectorEquivalent(const TypeArguments& other, - intptr_t from_index, - intptr_t len, - TypeEquality kind, - TrailPtr trail = nullptr) const; + bool IsSubvectorEquivalent( + const TypeArguments& other, + intptr_t from_index, + intptr_t len, + TypeEquality kind, + FunctionTypeMapping* function_type_equivalence = nullptr) const; // Check if the vector is instantiated (it must not be null). bool IsInstantiated(Genericity genericity = kAny, - intptr_t num_free_fun_type_params = kAllFree, - TrailPtr trail = nullptr) const { + intptr_t num_free_fun_type_params = kAllFree) const { return IsSubvectorInstantiated(0, Length(), genericity, - num_free_fun_type_params, trail); + num_free_fun_type_params); } - bool IsSubvectorInstantiated(intptr_t from_index, - intptr_t len, - Genericity genericity = kAny, - intptr_t num_free_fun_type_params = kAllFree, - TrailPtr trail = nullptr) const; + bool IsSubvectorInstantiated( + intptr_t from_index, + intptr_t len, + Genericity genericity = kAny, + intptr_t num_free_fun_type_params = kAllFree) const; bool IsUninstantiatedIdentity() const; // Determine whether this uninstantiated type argument vector can share its @@ -8218,11 +8214,11 @@ class TypeArguments : public Instance { // Caller must hold IsolateGroup::constant_canonicalization_mutex_. virtual InstancePtr CanonicalizeLocked(Thread* thread) const { - return Canonicalize(thread, nullptr); + return Canonicalize(thread); } // Canonicalize only if instantiated, otherwise returns 'this'. - TypeArgumentsPtr Canonicalize(Thread* thread, TrailPtr trail = nullptr) const; + TypeArgumentsPtr Canonicalize(Thread* thread) const; // Shrinks flattened instance type arguments to ordinary type arguments. TypeArgumentsPtr FromInstanceTypeArguments(Thread* thread, @@ -8252,16 +8248,16 @@ class TypeArguments : public Instance { const TypeArguments& function_type_arguments, intptr_t num_free_fun_type_params, Heap::Space space, - TrailPtr trail = nullptr, + FunctionTypeMapping* function_type_mapping = nullptr, intptr_t num_parent_type_args_adjustment = 0) const; // Update number of parent function type arguments for // all elements of this vector. - TypeArgumentsPtr UpdateParentFunctionType( + TypeArgumentsPtr UpdateFunctionTypes( intptr_t num_parent_type_args_adjustment, intptr_t num_free_fun_type_params, Heap::Space space, - TrailPtr trail = nullptr) const; + FunctionTypeMapping* function_type_mapping) const; // Runtime instantiation with canonicalization. Not to be used during type // finalization at compile time. @@ -8574,9 +8570,9 @@ class AbstractType : public Instance { virtual classid_t type_class_id() const; virtual ClassPtr type_class() const; virtual TypeArgumentsPtr arguments() const; - virtual bool IsInstantiated(Genericity genericity = kAny, - intptr_t num_free_fun_type_params = kAllFree, - TrailPtr trail = nullptr) const; + virtual bool IsInstantiated( + Genericity genericity = kAny, + intptr_t num_free_fun_type_params = kAllFree) const; virtual bool CanonicalizeEquals(const Instance& other) const { return Equals(other); } @@ -8584,12 +8580,11 @@ class AbstractType : public Instance { virtual bool Equals(const Instance& other) const { return IsEquivalent(other, TypeEquality::kCanonical); } - virtual bool IsEquivalent(const Instance& other, - TypeEquality kind, - TrailPtr trail = nullptr) const; - virtual bool IsRecursive(TrailPtr trail = nullptr) const; - virtual bool RequireConstCanonicalTypeErasure(Zone* zone, - TrailPtr trail = nullptr) const; + virtual bool IsEquivalent( + const Instance& other, + TypeEquality kind, + FunctionTypeMapping* function_type_equivalence = nullptr) const; + virtual bool RequireConstCanonicalTypeErasure(Zone* zone) const; // Instantiate this type using the given type argument vectors. // @@ -8607,30 +8602,32 @@ class AbstractType : public Instance { const TypeArguments& function_type_arguments, intptr_t num_free_fun_type_params, Heap::Space space, - TrailPtr trail = nullptr, + FunctionTypeMapping* function_type_mapping = nullptr, intptr_t num_parent_type_args_adjustment = 0) const; // Update number of parent function type arguments for the // nested function types and their type parameters. // // This adjustment is needed when nesting one generic function type - // inside another. + // inside another. It is also needed when function type is copied + // and owners of type parameters need to be adjusted. + // // Number of parent function type arguments is adjusted by // [num_parent_type_args_adjustment]. // Type parameters up to [num_free_fun_type_params] are not adjusted. - virtual AbstractTypePtr UpdateParentFunctionType( + virtual AbstractTypePtr UpdateFunctionTypes( intptr_t num_parent_type_args_adjustment, intptr_t num_free_fun_type_params, Heap::Space space, - TrailPtr trail = nullptr) const; + FunctionTypeMapping* function_type_mapping) const; // Caller must hold IsolateGroup::constant_canonicalization_mutex_. virtual InstancePtr CanonicalizeLocked(Thread* thread) const { - return Canonicalize(thread, nullptr); + return Canonicalize(thread); } // Return the canonical version of this type. - virtual AbstractTypePtr Canonicalize(Thread* thread, TrailPtr trail) const; + virtual AbstractTypePtr Canonicalize(Thread* thread) const; #if defined(DEBUG) // Check if abstract type is canonical. @@ -8640,25 +8637,6 @@ class AbstractType : public Instance { } #endif // DEBUG - // Return the object associated with the receiver in the trail or - // AbstractType::null() if the receiver is not contained in the trail. - AbstractTypePtr OnlyBuddyInTrail(TrailPtr trail) const; - - // If the trail is null, allocate a trail, add the pair to - // the trail. The receiver may only be added once with its only buddy. - void AddOnlyBuddyToTrail(TrailPtr* trail, const AbstractType& buddy) const; - - // Return true if the receiver is contained in the trail. - // Otherwise, if the trail is null, allocate a trail, then add the receiver to - // the trail and return false. - bool TestAndAddToTrail(TrailPtr* trail) const; - - // Return true if the pair is contained in the trail. - // Otherwise, if the trail is null, allocate a trail, add the pair to the trail and return false. - // The receiver may be added several times, each time with a different buddy. - bool TestAndAddBuddyToTrail(TrailPtr* trail, const AbstractType& buddy) const; - // Add the pair to the list, if not already present. static void AddURI(URIs* uris, const String& name, const String& uri); @@ -8695,9 +8673,6 @@ class AbstractType : public Instance { // type. StringPtr ClassName() const; - // Check if this type is a still uninitialized TypeRef. - bool IsNullTypeRef() const; - // Check if this type represents the 'dynamic' type. bool IsDynamicType() const { return type_class_id() == kDynamicCid; } @@ -8716,6 +8691,11 @@ class AbstractType : public Instance { // Check if this type represents the 'Object' type. bool IsObjectType() const { return type_class_id() == kInstanceCid; } + // Check if this type represents the 'Object?' type. + bool IsNullableObjectType() const { + return IsObjectType() && (nullability() == Nullability::kNullable); + } + // Check if this type represents a top type for subtyping, // assignability and 'as' type tests. // @@ -8796,9 +8776,10 @@ class AbstractType : public Instance { bool IsTypeClassAllowedBySpawnUri() const; // Check the subtype relationship. - bool IsSubtypeOf(const AbstractType& other, - Heap::Space space, - TrailPtr trail = nullptr) const; + bool IsSubtypeOf( + const AbstractType& other, + Heap::Space space, + FunctionTypeMapping* function_type_equivalence = nullptr) const; // Returns true iff subtype is a subtype of supertype, false otherwise or if // an error occurred. @@ -8849,10 +8830,11 @@ class AbstractType : public Instance { private: // Returns true if this type is a subtype of FutureOr specified by 'other'. // Returns false if other type is not a FutureOr. - bool IsSubtypeOfFutureOr(Zone* zone, - const AbstractType& other, - Heap::Space space, - TrailPtr trail = nullptr) const; + bool IsSubtypeOfFutureOr( + Zone* zone, + const AbstractType& other, + Heap::Space space, + FunctionTypeMapping* function_type_equivalence = nullptr) const; protected: bool IsNullabilityEquivalent(Thread* thread, @@ -8871,7 +8853,6 @@ class AbstractType : public Instance { friend class Class; friend class Function; friend class TypeArguments; - friend class TypeRef; }; // A Type consists of a class, possibly parameterized with type @@ -8898,15 +8879,14 @@ class Type : public AbstractType { TypeArgumentsPtr GetInstanceTypeArguments(Thread* thread, bool canonicalize = true) const; - virtual bool IsInstantiated(Genericity genericity = kAny, - intptr_t num_free_fun_type_params = kAllFree, - TrailPtr trail = nullptr) const; - virtual bool IsEquivalent(const Instance& other, - TypeEquality kind, - TrailPtr trail = nullptr) const; - virtual bool IsRecursive(TrailPtr trail = nullptr) const; - virtual bool RequireConstCanonicalTypeErasure(Zone* zone, - TrailPtr trail = nullptr) const; + virtual bool IsInstantiated( + Genericity genericity = kAny, + intptr_t num_free_fun_type_params = kAllFree) const; + virtual bool IsEquivalent( + const Instance& other, + TypeEquality kind, + FunctionTypeMapping* function_type_equivalence = nullptr) const; + virtual bool RequireConstCanonicalTypeErasure(Zone* zone) const; // Return true if this type can be used as the declaration type of cls after // canonicalization (passed-in cls must match type_class()). @@ -8917,16 +8897,16 @@ class Type : public AbstractType { const TypeArguments& function_type_arguments, intptr_t num_free_fun_type_params, Heap::Space space, - TrailPtr trail = nullptr, + FunctionTypeMapping* function_type_mapping = nullptr, intptr_t num_parent_type_args_adjustment = 0) const; - virtual AbstractTypePtr UpdateParentFunctionType( + virtual AbstractTypePtr UpdateFunctionTypes( intptr_t num_parent_type_args_adjustment, intptr_t num_free_fun_type_params, Heap::Space space, - TrailPtr trail = nullptr) const; + FunctionTypeMapping* function_type_mapping) const; - virtual AbstractTypePtr Canonicalize(Thread* thread, TrailPtr trail) const; + virtual AbstractTypePtr Canonicalize(Thread* thread) const; #if defined(DEBUG) // Check if type is canonical. virtual bool CheckIsCanonical(Thread* thread) const; @@ -9050,31 +9030,30 @@ class FunctionType : public AbstractType { virtual bool HasTypeClass() const { return false; } FunctionTypePtr ToNullability(Nullability value, Heap::Space space) const; virtual classid_t type_class_id() const { return kIllegalCid; } - virtual bool IsInstantiated(Genericity genericity = kAny, - intptr_t num_free_fun_type_params = kAllFree, - TrailPtr trail = nullptr) const; - virtual bool IsEquivalent(const Instance& other, - TypeEquality kind, - TrailPtr trail = nullptr) const; - virtual bool IsRecursive(TrailPtr trail = nullptr) const; - virtual bool RequireConstCanonicalTypeErasure(Zone* zone, - TrailPtr trail = nullptr) const; + virtual bool IsInstantiated( + Genericity genericity = kAny, + intptr_t num_free_fun_type_params = kAllFree) const; + virtual bool IsEquivalent( + const Instance& other, + TypeEquality kind, + FunctionTypeMapping* function_type_equivalence = nullptr) const; + virtual bool RequireConstCanonicalTypeErasure(Zone* zone) const; virtual AbstractTypePtr InstantiateFrom( const TypeArguments& instantiator_type_arguments, const TypeArguments& function_type_arguments, intptr_t num_free_fun_type_params, Heap::Space space, - TrailPtr trail = nullptr, + FunctionTypeMapping* function_type_mapping = nullptr, intptr_t num_parent_type_args_adjustment = 0) const; - virtual AbstractTypePtr UpdateParentFunctionType( + virtual AbstractTypePtr UpdateFunctionTypes( intptr_t num_parent_type_args_adjustment, intptr_t num_free_fun_type_params, Heap::Space space, - TrailPtr trail = nullptr) const; + FunctionTypeMapping* function_type_mapping) const; - virtual AbstractTypePtr Canonicalize(Thread* thread, TrailPtr trail) const; + virtual AbstractTypePtr Canonicalize(Thread* thread) const; #if defined(DEBUG) // Check if type is canonical. virtual bool CheckIsCanonical(Thread* thread) const; @@ -9086,7 +9065,10 @@ class FunctionType : public AbstractType { virtual uword Hash() const; uword ComputeHash() const; - bool IsSubtypeOf(const FunctionType& other, Heap::Space space) const; + bool IsSubtypeOf( + const FunctionType& other, + Heap::Space space, + FunctionTypeMapping* function_type_equivalence = nullptr) const; static intptr_t NumParentTypeArgumentsOf(FunctionTypePtr ptr) { return ptr->untag() @@ -9261,9 +9243,10 @@ class FunctionType : public AbstractType { // Returns true if this function type has the same number of type parameters // with equal bounds as the other function type. Type parameter names and // parameter names (unless optional named) are ignored. - bool HasSameTypeParametersAndBounds(const FunctionType& other, - TypeEquality kind, - TrailPtr trail = nullptr) const; + bool HasSameTypeParametersAndBounds( + const FunctionType& other, + TypeEquality kind, + FunctionTypeMapping* function_type_equivalence = nullptr) const; // Return true if this function type declares type parameters. static bool IsGeneric(FunctionTypePtr ptr) { @@ -9277,10 +9260,12 @@ class FunctionType : public AbstractType { // Returns true if the type of the formal parameter at the given position in // this function type is contravariant with the type of the other formal // parameter at the given position in the other function type. - bool IsContravariantParameter(intptr_t parameter_position, - const FunctionType& other, - intptr_t other_parameter_position, - Heap::Space space) const; + bool IsContravariantParameter( + intptr_t parameter_position, + const FunctionType& other, + intptr_t other_parameter_position, + Heap::Space space, + FunctionTypeMapping* function_type_equivalence) const; // Returns the index in the parameter names array of the corresponding flag // for the given parameter index. Also returns (via flag_mask) the @@ -9304,6 +9289,8 @@ class FunctionType : public AbstractType { Nullability nullability = Nullability::kLegacy, Heap::Space space = Heap::kOld); + static FunctionTypePtr Clone(const FunctionType& orig, Heap::Space space); + private: void SetHash(intptr_t value) const; @@ -9315,76 +9302,6 @@ class FunctionType : public AbstractType { friend class Function; }; -// A TypeRef is used to break cycles in the representation of recursive types. -// Its only field is the recursive AbstractType it refers to, which can -// temporarily be null during finalization. -// Note that the cycle always involves type arguments. -class TypeRef : public AbstractType { - public: - static intptr_t type_offset() { return OFFSET_OF(UntaggedTypeRef, type_); } - - virtual bool HasTypeClass() const { - return (type() != AbstractType::null()) && - AbstractType::Handle(type()).HasTypeClass(); - } - AbstractTypePtr type() const { return untag()->type(); } - void set_type(const AbstractType& value) const; - virtual classid_t type_class_id() const { - return AbstractType::Handle(type()).type_class_id(); - } - virtual ClassPtr type_class() const { - return AbstractType::Handle(type()).type_class(); - } - virtual TypeArgumentsPtr arguments() const { - return AbstractType::Handle(type()).arguments(); - } - virtual bool IsInstantiated(Genericity genericity = kAny, - intptr_t num_free_fun_type_params = kAllFree, - TrailPtr trail = nullptr) const; - virtual bool IsEquivalent(const Instance& other, - TypeEquality kind, - TrailPtr trail = nullptr) const; - virtual bool IsRecursive(TrailPtr trail = nullptr) const { return true; } - virtual bool RequireConstCanonicalTypeErasure(Zone* zone, - TrailPtr trail = nullptr) const; - virtual AbstractTypePtr InstantiateFrom( - const TypeArguments& instantiator_type_arguments, - const TypeArguments& function_type_arguments, - intptr_t num_free_fun_type_params, - Heap::Space space, - TrailPtr trail = nullptr, - intptr_t num_parent_type_args_adjustment = 0) const; - - virtual AbstractTypePtr UpdateParentFunctionType( - intptr_t num_parent_type_args_adjustment, - intptr_t num_free_fun_type_params, - Heap::Space space, - TrailPtr trail = nullptr) const; - - virtual AbstractTypePtr Canonicalize(Thread* thread, TrailPtr trail) const; -#if defined(DEBUG) - // Check if typeref is canonical. - virtual bool CheckIsCanonical(Thread* thread) const; -#endif // DEBUG - virtual void EnumerateURIs(URIs* uris) const; - virtual void PrintName(NameVisibility visibility, - BaseTextBuffer* printer) const; - - virtual uword Hash() const; - - static intptr_t InstanceSize() { - return RoundedAllocationSize(sizeof(UntaggedTypeRef)); - } - - static TypeRefPtr New(const AbstractType& type); - - private: - static TypeRefPtr New(); - - FINAL_HEAP_OBJECT_IMPLEMENTATION(TypeRef, AbstractType); - friend class Class; -}; - // A TypeParameter represents a type parameter of a parameterized class. // It specifies its index (and its name for debugging purposes), as well as its // upper bound. @@ -9402,7 +9319,6 @@ class TypeParameter : public AbstractType { virtual classid_t type_class_id() const { return kIllegalCid; } classid_t parameterized_class_id() const; void set_parameterized_class_id(classid_t value) const; - ClassPtr parameterized_class() const; bool IsClassTypeParameter() const { return parameterized_class_id() != kFunctionCid; } @@ -9422,22 +9338,19 @@ class TypeParameter : public AbstractType { return OFFSET_OF(UntaggedTypeParameter, index_); } - AbstractTypePtr bound() const { return untag()->bound(); } - void set_bound(const AbstractType& value) const; - static intptr_t bound_offset() { - return OFFSET_OF(UntaggedTypeParameter, bound_); - } + ObjectPtr owner() const { return untag()->owner(); } + void set_owner(const Object& value) const; - virtual bool IsInstantiated(Genericity genericity = kAny, - intptr_t num_free_fun_type_params = kAllFree, - TrailPtr trail = nullptr) const; - virtual bool IsEquivalent(const Instance& other, - TypeEquality kind, - TrailPtr trail = nullptr) const; - virtual bool IsRecursive(TrailPtr trail = nullptr) const; - virtual bool RequireConstCanonicalTypeErasure( - Zone* zone, - TrailPtr trail = nullptr) const { + AbstractTypePtr bound() const; + + virtual bool IsInstantiated( + Genericity genericity = kAny, + intptr_t num_free_fun_type_params = kAllFree) const; + virtual bool IsEquivalent( + const Instance& other, + TypeEquality kind, + FunctionTypeMapping* function_type_equivalence = nullptr) const; + virtual bool RequireConstCanonicalTypeErasure(Zone* zone) const { return IsNonNullable(); } virtual AbstractTypePtr InstantiateFrom( @@ -9445,16 +9358,16 @@ class TypeParameter : public AbstractType { const TypeArguments& function_type_arguments, intptr_t num_free_fun_type_params, Heap::Space space, - TrailPtr trail = nullptr, + FunctionTypeMapping* function_type_mapping = nullptr, intptr_t num_parent_type_args_adjustment = 0) const; - virtual AbstractTypePtr UpdateParentFunctionType( + virtual AbstractTypePtr UpdateFunctionTypes( intptr_t num_parent_type_args_adjustment, intptr_t num_free_fun_type_params, Heap::Space space, - TrailPtr trail = nullptr) const; + FunctionTypeMapping* function_type_mapping) const; - virtual AbstractTypePtr Canonicalize(Thread* thread, TrailPtr trail) const; + virtual AbstractTypePtr Canonicalize(Thread* thread) const; #if defined(DEBUG) // Check if type parameter is canonical. virtual bool CheckIsCanonical(Thread* thread) const; @@ -9486,20 +9399,16 @@ class TypeParameter : public AbstractType { return RoundedAllocationSize(sizeof(UntaggedTypeParameter)); } - // 'parameterized_class' is null for a function type parameter. - static TypeParameterPtr New(const Class& parameterized_class, + // 'owner' is a Class or FunctionType. + static TypeParameterPtr New(const Object& owner, intptr_t base, intptr_t index, - const AbstractType& bound, Nullability nullability); private: uword ComputeHash() const; void SetHash(intptr_t value) const; - void set_parameterized_class(const Class& value) const; - void set_name(const String& value) const; - static TypeParameterPtr New(); FINAL_HEAP_OBJECT_IMPLEMENTATION(TypeParameter, AbstractType); @@ -9843,8 +9752,6 @@ class String : public Instance { return GetCachedHash(ptr()) != 0; } - bool IsRecursive() const { return false; } // Required by HashSet templates. - static intptr_t hash_offset() { #if defined(HASH_IN_OBJECT_HEADER) COMPILE_ASSERT(UntaggedObject::kHashTagPos % kBitsPerByte == 0); @@ -11149,31 +11056,30 @@ class RecordType : public AbstractType { virtual bool HasTypeClass() const { return false; } RecordTypePtr ToNullability(Nullability value, Heap::Space space) const; virtual classid_t type_class_id() const { return kIllegalCid; } - virtual bool IsInstantiated(Genericity genericity = kAny, - intptr_t num_free_fun_type_params = kAllFree, - TrailPtr trail = nullptr) const; - virtual bool IsEquivalent(const Instance& other, - TypeEquality kind, - TrailPtr trail = nullptr) const; - virtual bool IsRecursive(TrailPtr trail = nullptr) const; - virtual bool RequireConstCanonicalTypeErasure(Zone* zone, - TrailPtr trail = nullptr) const; + virtual bool IsInstantiated( + Genericity genericity = kAny, + intptr_t num_free_fun_type_params = kAllFree) const; + virtual bool IsEquivalent( + const Instance& other, + TypeEquality kind, + FunctionTypeMapping* function_type_equivalence = nullptr) const; + virtual bool RequireConstCanonicalTypeErasure(Zone* zone) const; virtual AbstractTypePtr InstantiateFrom( const TypeArguments& instantiator_type_arguments, const TypeArguments& function_type_arguments, intptr_t num_free_fun_type_params, Heap::Space space, - TrailPtr trail = nullptr, + FunctionTypeMapping* function_type_mapping = nullptr, intptr_t num_parent_type_args_adjustment = 0) const; - virtual AbstractTypePtr UpdateParentFunctionType( + virtual AbstractTypePtr UpdateFunctionTypes( intptr_t num_parent_type_args_adjustment, intptr_t num_free_fun_type_params, Heap::Space space, - TrailPtr trail = nullptr) const; + FunctionTypeMapping* function_type_mapping) const; - virtual AbstractTypePtr Canonicalize(Thread* thread, TrailPtr trail) const; + virtual AbstractTypePtr Canonicalize(Thread* thread) const; #if defined(DEBUG) // Check if type is canonical. virtual bool CheckIsCanonical(Thread* thread) const; @@ -11185,7 +11091,10 @@ class RecordType : public AbstractType { virtual uword Hash() const; uword ComputeHash() const; - bool IsSubtypeOf(const RecordType& other, Heap::Space space) const; + bool IsSubtypeOf( + const RecordType& other, + Heap::Space space, + FunctionTypeMapping* function_type_equivalence = nullptr) const; RecordShape shape() const { return RecordShape(untag()->shape()); } @@ -13200,7 +13109,7 @@ inline intptr_t RecordType::NumFields() const { } inline uword TypeParameter::Hash() const { - ASSERT(IsFinalized() || IsBeingFinalized()); // Bound may not be finalized. + ASSERT(IsFinalized()); intptr_t result = Smi::Value(untag()->hash()); if (result != 0) { return result; diff --git a/runtime/vm/object_graph_copy.cc b/runtime/vm/object_graph_copy.cc index 6fbd142fe0d..69f4f676098 100644 --- a/runtime/vm/object_graph_copy.cc +++ b/runtime/vm/object_graph_copy.cc @@ -83,7 +83,6 @@ V(TypeArguments) \ V(TypeParameter) \ V(TypeParameters) \ - V(TypeRef) \ V(TypedDataBase) \ V(UnhandledException) \ V(UnlinkedCall) \ diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc index 323352f3d24..538bfeb27d0 100644 --- a/runtime/vm/object_service.cc +++ b/runtime/vm/object_service.cc @@ -1464,22 +1464,6 @@ void RecordType::PrintJSONImpl(JSONStream* stream, bool ref) const { void RecordType::PrintImplementationFieldsImpl( const JSONArray& jsarr_fields) const {} -void TypeRef::PrintJSONImpl(JSONStream* stream, bool ref) const { - JSONObject jsobj(stream); - PrintSharedInstanceJSON(&jsobj, ref); - jsobj.AddProperty("kind", "TypeRef"); - const String& user_name = String::Handle(UserVisibleName()); - const String& vm_name = String::Handle(Name()); - AddNameProperties(&jsobj, user_name.ToCString(), vm_name.ToCString()); - if (ref) { - return; - } - jsobj.AddProperty("targetType", AbstractType::Handle(type())); -} - -void TypeRef::PrintImplementationFieldsImpl( - const JSONArray& jsarr_fields) const {} - void TypeParameter::PrintJSONImpl(JSONStream* stream, bool ref) const { JSONObject jsobj(stream); PrintSharedInstanceJSON(&jsobj, ref); @@ -1488,8 +1472,7 @@ void TypeParameter::PrintJSONImpl(JSONStream* stream, bool ref) const { const String& vm_name = String::Handle(Name()); AddNameProperties(&jsobj, user_name.ToCString(), vm_name.ToCString()); // TODO(regis): parameterizedClass is meaningless and always null. - const Class& param_cls = Class::Handle(parameterized_class()); - jsobj.AddProperty("parameterizedClass", param_cls); + jsobj.AddProperty("parameterizedClass", Object::null_class()); if (ref) { return; } diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc index aebbc328cb4..75d95384a27 100644 --- a/runtime/vm/object_store.cc +++ b/runtime/vm/object_store.cc @@ -510,7 +510,7 @@ void ObjectStore::LazyInitAsyncMembers() { type_args.SetTypeAt(0, type); type = Type::New(cls, type_args, Nullability::kNonNullable); type.SetIsFinalized(); - type ^= type.Canonicalize(thread, nullptr); + type ^= type.Canonicalize(thread); non_nullable_future_never_type_.store(type.ptr()); type = null_type(); @@ -519,7 +519,7 @@ void ObjectStore::LazyInitAsyncMembers() { type_args.SetTypeAt(0, type); type = Type::New(cls, type_args, Nullability::kNullable); type.SetIsFinalized(); - type ^= type.Canonicalize(thread, nullptr); + type ^= type.Canonicalize(thread); nullable_future_null_type_.store(type.ptr()); type = cls.RareType(); diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc index 2ced70b8524..a5614f9f92b 100644 --- a/runtime/vm/object_test.cc +++ b/runtime/vm/object_test.cc @@ -275,8 +275,8 @@ ISOLATE_UNIT_TEST_CASE(TypeArguments) { OS::PrintErr("2: %s\n", type_arguments2.ToCString()); EXPECT(type_arguments1.Equals(type_arguments2)); TypeArguments& type_arguments3 = TypeArguments::Handle(); - type_arguments1.Canonicalize(thread, nullptr); - type_arguments3 ^= type_arguments2.Canonicalize(thread, nullptr); + type_arguments1.Canonicalize(thread); + type_arguments3 ^= type_arguments2.Canonicalize(thread); EXPECT_EQ(type_arguments1.ptr(), type_arguments3.ptr()); } @@ -7660,14 +7660,13 @@ ISOLATE_UNIT_TEST_CASE(ClosureType_SubtypeOfFunctionType) { Class::Handle(async_lib.LookupClass(Symbols::FutureOr())); auto& tav_function_nullable = TypeArguments::Handle(TypeArguments::New(1)); tav_function_nullable.SetTypeAt(0, function_type_nullable); - tav_function_nullable = tav_function_nullable.Canonicalize(thread, nullptr); + tav_function_nullable = tav_function_nullable.Canonicalize(thread); auto& tav_function_legacy = TypeArguments::Handle(TypeArguments::New(1)); tav_function_legacy.SetTypeAt(0, function_type_legacy); - tav_function_legacy = tav_function_legacy.Canonicalize(thread, nullptr); + tav_function_legacy = tav_function_legacy.Canonicalize(thread); auto& tav_function_nonnullable = TypeArguments::Handle(TypeArguments::New(1)); tav_function_nonnullable.SetTypeAt(0, function_type_nonnullable); - tav_function_nonnullable = - tav_function_nonnullable.Canonicalize(thread, nullptr); + tav_function_nonnullable = tav_function_nonnullable.Canonicalize(thread); auto& future_or_function_type_nullable = Type::Handle(Type::New(future_or_class, tav_function_nullable)); @@ -7772,18 +7771,18 @@ TEST_CASE(Class_GetInstantiationOf) { TypeParameter::CheckedHandle(zone, decl_type_args_a1.TypeAt(1)); auto& tav_a1_y = TypeArguments::Handle(TypeArguments::New(1)); tav_a1_y.SetTypeAt(0, type_arg_a1_y); - tav_a1_y = tav_a1_y.Canonicalize(thread, nullptr); + tav_a1_y = tav_a1_y.Canonicalize(thread); auto& type_list_a1_y = Type::CheckedHandle( zone, decl_type_list.InstantiateFrom(tav_a1_y, null_tav, kAllFree, Heap::kNew)); - type_list_a1_y ^= type_list_a1_y.Canonicalize(thread, nullptr); + type_list_a1_y ^= type_list_a1_y.Canonicalize(thread); auto& tav_list_a1_y = TypeArguments::Handle(TypeArguments::New(1)); tav_list_a1_y.SetTypeAt(0, type_list_a1_y); - tav_list_a1_y = tav_list_a1_y.Canonicalize(thread, nullptr); + tav_list_a1_y = tav_list_a1_y.Canonicalize(thread); auto& type_b_list_a1_y = Type::CheckedHandle( zone, decl_type_b.InstantiateFrom(tav_list_a1_y, null_tav, kAllFree, Heap::kNew)); - type_b_list_a1_y ^= type_b_list_a1_y.Canonicalize(thread, nullptr); + type_b_list_a1_y ^= type_b_list_a1_y.Canonicalize(thread); const auto& inst_b_a1 = Type::Handle(zone, class_a1.GetInstantiationOf(zone, class_b)); @@ -7800,18 +7799,18 @@ TEST_CASE(Class_GetInstantiationOf) { TypeParameter::CheckedHandle(zone, decl_type_args_a2.TypeAt(0)); auto& tav_a2_x = TypeArguments::Handle(TypeArguments::New(1)); tav_a2_x.SetTypeAt(0, type_arg_a2_x); - tav_a2_x = tav_a2_x.Canonicalize(thread, nullptr); + tav_a2_x = tav_a2_x.Canonicalize(thread); auto& type_list_a2_x = Type::CheckedHandle( zone, decl_type_list.InstantiateFrom(tav_a2_x, null_tav, kAllFree, Heap::kNew)); - type_list_a2_x ^= type_list_a2_x.Canonicalize(thread, nullptr); + type_list_a2_x ^= type_list_a2_x.Canonicalize(thread); auto& tav_list_a2_x = TypeArguments::Handle(TypeArguments::New(1)); tav_list_a2_x.SetTypeAt(0, type_list_a2_x); - tav_list_a2_x = tav_list_a2_x.Canonicalize(thread, nullptr); + tav_list_a2_x = tav_list_a2_x.Canonicalize(thread); auto& type_b_list_a2_x = Type::CheckedHandle( zone, decl_type_b.InstantiateFrom(tav_list_a2_x, null_tav, kAllFree, Heap::kNew)); - type_b_list_a2_x ^= type_b_list_a2_x.Canonicalize(thread, nullptr); + type_b_list_a2_x ^= type_b_list_a2_x.Canonicalize(thread); const auto& inst_b_a2 = Type::Handle(zone, class_a2.GetInstantiationOf(zone, class_b)); diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc index 307a0eb93dd..e4c5788e549 100644 --- a/runtime/vm/raw_object.cc +++ b/runtime/vm/raw_object.cc @@ -534,7 +534,6 @@ VARIABLE_COMPRESSED_VISITOR(WeakArray, Smi::Value(raw_obj->untag()->length())) COMPRESSED_VISITOR(Type) COMPRESSED_VISITOR(FunctionType) COMPRESSED_VISITOR(RecordType) -COMPRESSED_VISITOR(TypeRef) COMPRESSED_VISITOR(TypeParameter) COMPRESSED_VISITOR(Function) COMPRESSED_VISITOR(Closure) diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h index c2d56ec3ec6..e1f237d945d 100644 --- a/runtime/vm/raw_object.h +++ b/runtime/vm/raw_object.h @@ -2763,23 +2763,14 @@ class UntaggedRecordType : public UntaggedAbstractType { CompressedObjectPtr* to_snapshot(Snapshot::Kind kind) { return to(); } }; -class UntaggedTypeRef : public UntaggedAbstractType { - private: - RAW_HEAP_OBJECT_IMPLEMENTATION(TypeRef); - - COMPRESSED_POINTER_FIELD(AbstractTypePtr, type) // The referenced type. - VISIT_TO(type) - CompressedObjectPtr* to_snapshot(Snapshot::Kind kind) { return to(); } -}; - class UntaggedTypeParameter : public UntaggedAbstractType { private: RAW_HEAP_OBJECT_IMPLEMENTATION(TypeParameter); COMPRESSED_POINTER_FIELD(SmiPtr, hash) - // ObjectType if no explicit bound specified. - COMPRESSED_POINTER_FIELD(AbstractTypePtr, bound) - VISIT_TO(bound) + // Class or FunctionType. + COMPRESSED_POINTER_FIELD(ObjectPtr, owner) + VISIT_TO(owner) ClassIdTagType parameterized_class_id_; // Or kFunctionCid for function tp. uint16_t base_; // Number of enclosing function type parameters. uint16_t index_; // Keep size in sync with BuildTypeParameterTypeTestStub. diff --git a/runtime/vm/raw_object_fields.cc b/runtime/vm/raw_object_fields.cc index badf2418970..51fb5d6fbe6 100644 --- a/runtime/vm/raw_object_fields.cc +++ b/runtime/vm/raw_object_fields.cc @@ -142,11 +142,9 @@ namespace dart { F(FunctionType, parameter_types_) \ F(FunctionType, named_parameter_names_) \ F(FunctionType, type_parameters_) \ - F(TypeRef, type_test_stub_) \ - F(TypeRef, type_) \ F(TypeParameter, type_test_stub_) \ F(TypeParameter, hash_) \ - F(TypeParameter, bound_) \ + F(TypeParameter, owner_) \ F(TypeParameters, names_) \ F(TypeParameters, flags_) \ F(TypeParameters, bounds_) \ diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc index ec57ea89214..8bb0a1ea662 100644 --- a/runtime/vm/runtime_entry.cc +++ b/runtime/vm/runtime_entry.cc @@ -562,11 +562,6 @@ DEFINE_RUNTIME_ENTRY(InstantiateType, 3) { function_type_arguments.IsInstantiated()); type = type.InstantiateFrom(instantiator_type_arguments, function_type_arguments, kAllFree, Heap::kOld); - if (type.IsTypeRef()) { - type = TypeRef::Cast(type).type(); - ASSERT(!type.IsTypeRef()); - ASSERT(type.IsCanonical()); - } ASSERT(!type.IsNull() && type.IsInstantiated()); arguments.SetReturn(type); } @@ -642,20 +637,13 @@ DEFINE_RUNTIME_ENTRY(SubtypeCheck, 5) { AbstractType::CheckedHandle(zone, arguments.ArgAt(3)); const String& dst_name = String::CheckedHandle(zone, arguments.ArgAt(4)); - if (supertype.IsTypeRef()) { - supertype = TypeRef::Cast(supertype).type(); - } - ASSERT(!supertype.IsNull() && !supertype.IsTypeRef()); + ASSERT(!supertype.IsNull()); + ASSERT(!subtype.IsNull()); // Now that AssertSubtype may be checking types only available at runtime, // we can't guarantee the supertype isn't the top type. if (supertype.IsTopTypeForSubtyping()) return; - if (subtype.IsTypeRef()) { - subtype = TypeRef::Cast(subtype).type(); - } - ASSERT(!subtype.IsNull() && !subtype.IsTypeRef()); - // The supertype or subtype may not be instantiated. if (AbstractType::InstantiateAndTestSubtype( &subtype, &supertype, instantiator_type_args, function_type_args)) { diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc index d13f02aec56..60aaa6e6c22 100644 --- a/runtime/vm/service.cc +++ b/runtime/vm/service.cc @@ -2916,13 +2916,6 @@ static void CollectStringifiedType(Zone* zone, output.Add(instance); return; } - if (type.IsTypeRef()) { - // A TypeRef is used to break cycles in the representation of types - // calling type class on it will cause an infinite recursion. - // We use null instead. - output.Add(instance); - return; - } ASSERT(type.IsType()); const Class& cls = Class::Handle(type.type_class()); diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md index e290adbf1f3..b9688cbf947 100644 --- a/runtime/vm/service/service.md +++ b/runtime/vm/service/service.md @@ -2570,7 +2570,7 @@ class @Field extends @Object { // The declared type of this field. // // The value will always be of one of the kinds: - // Type, TypeRef, TypeParameter, BoundedType. + // Type, TypeParameter, RecordType, FunctionType, BoundedType. @Instance declaredType; // Is this field const? @@ -2607,7 +2607,7 @@ class Field extends Object { // The declared type of this field. // // The value will always be of one of the kinds: - // Type, TypeRef, TypeParameter, BoundedType. + // Type, TypeParameter, RecordType, FunctionType, BoundedType. @Instance declaredType; // Is this field const? @@ -3151,22 +3151,19 @@ class Instance extends Object { // TypeParameter int parameterIndex [optional]; - // The type bounded by a BoundedType instance - // - or - - // the referent of a TypeRef instance. + // The type bounded by a BoundedType instance. // // The value will always be of one of the kinds: - // Type, TypeRef, TypeParameter, BoundedType. + // Type, TypeParameter, RecordType, FunctionType, BoundedType. // // Provided for instance kinds: // BoundedType - // TypeRef @Instance targetType [optional]; // The bound of a TypeParameter or BoundedType. // // The value will always be of one of the kinds: - // Type, TypeRef, TypeParameter, BoundedType. + // Type, TypeParameter, RecordType, FunctionType, BoundedType. // // Provided for instance kinds: // BoundedType @@ -3285,9 +3282,6 @@ enum InstanceKind { // An instance of the Dart class TypeParameter. TypeParameter, - // An instance of the Dart class TypeRef. - TypeRef, - // An instance of the Dart class FunctionType. FunctionType, @@ -4369,7 +4363,7 @@ class TypeArguments extends Object { // A list of types. // // The value will always be one of the kinds: - // Type, TypeRef, TypeParameter, BoundedType. + // Type, TypeParameter, RecordType, FunctionType, BoundedType. @Instance[] types; } ``` diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h index c1c2e70862c..86013ad92a6 100644 --- a/runtime/vm/symbols.h +++ b/runtime/vm/symbols.h @@ -379,7 +379,6 @@ class ObjectPointerVisitor; V(_TransferableTypedDataImpl, "_TransferableTypedDataImpl") \ V(_Type, "_Type") \ V(_TypeParameter, "_TypeParameter") \ - V(_TypeRef, "_TypeRef") \ V(_TypeVariableMirror, "_TypeVariableMirror") \ V(_Uint16ArrayFactory, "Uint16List.") \ V(_Uint16ArrayView, "_Uint16ArrayView") \ diff --git a/runtime/vm/tagged_pointer.h b/runtime/vm/tagged_pointer.h index d0666d38135..c0c2ddb6a67 100644 --- a/runtime/vm/tagged_pointer.h +++ b/runtime/vm/tagged_pointer.h @@ -397,7 +397,6 @@ DEFINE_TAGGED_POINTER(AbstractType, Instance) DEFINE_TAGGED_POINTER(Type, AbstractType) DEFINE_TAGGED_POINTER(FunctionType, AbstractType) DEFINE_TAGGED_POINTER(RecordType, AbstractType) -DEFINE_TAGGED_POINTER(TypeRef, AbstractType) DEFINE_TAGGED_POINTER(TypeParameter, AbstractType) DEFINE_TAGGED_POINTER(Closure, Instance) DEFINE_TAGGED_POINTER(Number, Instance) diff --git a/runtime/vm/type_testing_stubs.cc b/runtime/vm/type_testing_stubs.cc index 0c3f2d010ba..54969aba232 100644 --- a/runtime/vm/type_testing_stubs.cc +++ b/runtime/vm/type_testing_stubs.cc @@ -114,14 +114,6 @@ void TypeTestingStubNamer::MakeNameAssemblerSafe(BaseTextBuffer* buffer) { CodePtr TypeTestingStubGenerator::DefaultCodeForType( const AbstractType& type, bool lazy_specialize /* = true */) { - auto isolate_group = IsolateGroup::Current(); - - if (type.IsTypeRef()) { - return isolate_group->use_strict_null_safety_checks() - ? StubCode::DefaultTypeTest().ptr() - : StubCode::DefaultNullableTypeTest().ptr(); - } - // During bootstrapping we have no access to stubs yet, so we'll just return // `null` and patch these later in `Object::FinishInit()`. if (!StubCode::HasBeenInitialized()) { @@ -181,7 +173,7 @@ CodePtr TypeTestingStubGenerator::OptimizedCodeForType( #if !defined(TARGET_ARCH_IA32) ASSERT(StubCode::HasBeenInitialized()); - if (type.IsTypeRef() || type.IsTypeParameter()) { + if (type.IsTypeParameter()) { return TypeTestingStubGenerator::DefaultCodeForType( type, /*lazy_specialize=*/false); } @@ -1054,26 +1046,6 @@ bool TypeTestingStubGenerator::BuildLoadInstanceTypeArguments( return !type_argument_checks.is_empty(); } -// Unwraps TypeRef in [type_reg] and loads class id of the unwrapped type to -// [class_id_reg]. -// -// [type_reg] must contain an AbstractType. Unwrapped TypeRef is written -// back to [type_reg]. [class_id_reg] must be distinct from [type_reg]. -static void UnwrapTypeRefAndLoadClassId(compiler::Assembler* assembler, - Register type_reg, - Register class_id_reg) { - ASSERT(class_id_reg != type_reg); - compiler::Label done; - // TypeRefs never wrap other TypeRefs, so we only need to unwrap once. - __ LoadClassId(class_id_reg, type_reg); - __ CompareImmediate(class_id_reg, kTypeRefCid); - __ BranchIf(NOT_EQUAL, &done, compiler::Assembler::kNearJump); - __ LoadCompressedFieldFromOffset(type_reg, type_reg, - compiler::target::TypeRef::type_offset()); - __ LoadClassId(class_id_reg, type_reg); - __ Bind(&done); -} - void TypeTestingStubGenerator::BuildOptimizedTypeParameterArgumentValueCheck( compiler::Assembler* assembler, HierarchyInfo* hi, @@ -1115,8 +1087,8 @@ void TypeTestingStubGenerator::BuildOptimizedTypeParameterArgumentValueCheck( __ Comment("Checking instantiated type parameter for possible top types"); compiler::Label check_subtype_type_class_ids; - UnwrapTypeRefAndLoadClassId(assembler, TTSInternalRegs::kSuperTypeArgumentReg, - TTSInternalRegs::kScratchReg); + __ LoadClassId(TTSInternalRegs::kScratchReg, + TTSInternalRegs::kSuperTypeArgumentReg); __ CompareImmediate(TTSInternalRegs::kScratchReg, kTypeCid); __ BranchIf(NOT_EQUAL, &check_subtype_type_class_ids); __ LoadTypeClassId(TTSInternalRegs::kScratchReg, @@ -1148,8 +1120,8 @@ void TypeTestingStubGenerator::BuildOptimizedTypeParameterArgumentValueCheck( __ Bind(&check_subtype_type_class_ids); __ Comment("Checking instance type argument for possible bottom types"); // Nothing else to check for non-Types, so fall back to the slow stub. - UnwrapTypeRefAndLoadClassId(assembler, TTSInternalRegs::kSubTypeArgumentReg, - TTSInternalRegs::kScratchReg); + __ LoadClassId(TTSInternalRegs::kScratchReg, + TTSInternalRegs::kSubTypeArgumentReg); __ CompareImmediate(TTSInternalRegs::kScratchReg, kTypeCid); __ BranchIf(NOT_EQUAL, check_failed); __ LoadTypeClassId(TTSInternalRegs::kScratchReg, @@ -1203,8 +1175,8 @@ void TypeTestingStubGenerator::BuildOptimizedTypeArgumentValueCheck( TTSInternalRegs::kInstanceTypeArgumentsReg, compiler::target::TypeArguments::type_at_offset( type_param_value_offset_i)); - UnwrapTypeRefAndLoadClassId(assembler, TTSInternalRegs::kSubTypeArgumentReg, - TTSInternalRegs::kScratchReg); + __ LoadClassId(TTSInternalRegs::kScratchReg, + TTSInternalRegs::kSubTypeArgumentReg); if (type.IsObjectType() || type.IsDartFunctionType() || type.IsDartRecordType()) { __ CompareImmediate(TTSInternalRegs::kScratchReg, kTypeCid); @@ -1537,12 +1509,8 @@ void TypeUsageInfo::AddTypeToSet(TypeSet* set, const AbstractType* type) { } bool TypeUsageInfo::IsUsedInTypeTest(const AbstractType& type) { - const AbstractType* dereferenced_type = &type; - if (type.IsTypeRef()) { - dereferenced_type = &AbstractType::Handle(TypeRef::Cast(type).type()); - } - if (dereferenced_type->IsFinalized()) { - return assert_assignable_types_.HasKey(dereferenced_type); + if (type.IsFinalized()) { + return assert_assignable_types_.HasKey(&type); } return false; } diff --git a/runtime/vm/type_testing_stubs_test.cc b/runtime/vm/type_testing_stubs_test.cc index 305f63a9f1d..347e31f330b 100644 --- a/runtime/vm/type_testing_stubs_test.cc +++ b/runtime/vm/type_testing_stubs_test.cc @@ -190,7 +190,7 @@ static void FinalizeAndCanonicalize(AbstractType* type) { } static void CanonicalizeTAV(TypeArguments* tav) { - *tav = tav->Canonicalize(Thread::Current(), nullptr); + *tav = tav->Canonicalize(Thread::Current()); } struct TTSTestCase {