Reland "[VM/runtime] Refactor the representation of type parameters in the VM."

This is a reland of 8a21ab195a

Original change's description:
> [VM/runtime] Refactor the representation of type parameters in the VM.
>
> This introduces a new VM internal class 'TypeParameters' representing the declaration of a list of type parameters, either in a class or function.
> The reference to (or use of) a type parameter is still represented by the existing 'TypeParameter' class.
>
> Fixes https://github.com/dart-lang/sdk/issues/43901
> Fixes https://github.com/dart-lang/sdk/issues/45763
>
> TEST=existing ones and a regression test
>
> Change-Id: I1fde808bf753cc1cb829f2c4383c1836651cee80
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/189942
> Commit-Queue: Régis Crelier <regis@google.com>
> Reviewed-by: Alexander Markov <alexmarkov@google.com>

This fixes https://github.com/dart-lang/sdk/issues/45911

TEST=existing ones and a regression test

Change-Id: I709d38b1df3d73fe3c9796d5aca3cbbdcf77fd38
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/198380
Commit-Queue: Régis Crelier <regis@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Regis Crelier 2021-05-05 23:43:14 +00:00 committed by commit-bot@chromium.org
parent df3bb63a13
commit 1f55b7ca10
65 changed files with 1749 additions and 1527 deletions

View file

@ -191,7 +191,7 @@ static InstancePtr CreateTypeVariableMirror(const TypeParameter& param,
const Instance& owner_mirror) {
const Array& args = Array::Handle(Array::New(3));
args.SetAt(0, param);
args.SetAt(1, String::Handle(param.name()));
args.SetAt(1, String::Handle(param.UserVisibleName()));
args.SetAt(2, owner_mirror);
return CreateMirror(Symbols::_TypeVariableMirror(), args);
}
@ -199,18 +199,17 @@ static InstancePtr CreateTypeVariableMirror(const TypeParameter& param,
// We create a list in native code and let Dart code create the type mirror
// object and the ordered map.
static InstancePtr CreateTypeVariableList(const Class& cls) {
const TypeArguments& args = TypeArguments::Handle(cls.type_parameters());
if (args.IsNull()) {
const intptr_t num_type_params = cls.NumTypeParameters();
if (num_type_params == 0) {
return Object::empty_array().ptr();
}
const Array& result = Array::Handle(Array::New(args.Length() * 2));
const Array& result = Array::Handle(Array::New(num_type_params * 2));
TypeParameter& type = TypeParameter::Handle();
String& name = String::Handle();
for (intptr_t i = 0; i < args.Length(); i++) {
type ^= args.TypeAt(i);
ASSERT(type.IsTypeParameter());
for (intptr_t i = 0; i < num_type_params; i++) {
type = cls.TypeParameterAt(i, Nullability::kLegacy);
ASSERT(type.IsFinalized());
name = type.name();
name = type.UserVisibleName();
result.SetAt(2 * i, name);
result.SetAt(2 * i + 1, type);
}

View file

@ -449,18 +449,19 @@ DEFINE_NATIVE_ENTRY(Internal_boundsCheckForPartialInstantiation, 0, 2) {
const Closure& closure =
Closure::CheckedHandle(zone, arguments->NativeArgAt(0));
const Function& target = Function::Handle(zone, closure.function());
const TypeArguments& bounds =
TypeArguments::Handle(zone, target.type_parameters());
// Either the bounds are all-dynamic or the function is not generic.
if (bounds.IsNull()) return Object::null();
const TypeParameters& type_params =
TypeParameters::Handle(zone, target.type_parameters());
if (type_params.IsNull() || type_params.AllDynamicBounds()) {
// The function is not generic or the bounds are all dynamic.
return Object::null();
}
const TypeArguments& type_args_to_check =
TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(1));
// This should be guaranteed by the front-end.
ASSERT(type_args_to_check.IsNull() ||
bounds.Length() <= type_args_to_check.Length());
type_params.Length() <= type_args_to_check.Length());
// The bounds on the closure may need instantiation.
const TypeArguments& instantiator_type_args =
@ -470,10 +471,8 @@ DEFINE_NATIVE_ENTRY(Internal_boundsCheckForPartialInstantiation, 0, 2) {
AbstractType& supertype = AbstractType::Handle(zone);
AbstractType& subtype = AbstractType::Handle(zone);
TypeParameter& parameter = TypeParameter::Handle(zone);
for (intptr_t i = 0; i < bounds.Length(); ++i) {
parameter ^= bounds.TypeAt(i);
supertype = parameter.bound();
for (intptr_t i = 0; i < type_params.Length(); ++i) {
supertype = type_params.BoundAt(i);
subtype = type_args_to_check.IsNull() ? Object::dynamic_type().ptr()
: type_args_to_check.TypeAt(i);
@ -492,7 +491,7 @@ DEFINE_NATIVE_ENTRY(Internal_boundsCheckForPartialInstantiation, 0, 2) {
ASSERT(caller_frame != NULL);
location = caller_frame->GetTokenPos();
}
String& parameter_name = String::Handle(zone, parameter.Name());
const auto& parameter_name = String::Handle(zone, type_params.NameAt(i));
Exceptions::CreateAndThrowTypeError(location, subtype, supertype,
parameter_name);
UNREACHABLE();

View file

@ -40,11 +40,6 @@ bool MetadataMapTraits::IsMatch(const Object& a, const Object& b) {
const Object& owner_b = Object::Handle(Field::Cast(b).Owner());
return IsMatch(owner_a, owner_b);
} else if (a.IsTypeParameter() && b.IsTypeParameter()) {
const String& name_a = String::Handle(TypeParameter::Cast(a).name());
const String& name_b = String::Handle(TypeParameter::Cast(b).name());
if (!name_a.Equals(name_b)) {
return false;
}
if (TypeParameter::Cast(a).index() != TypeParameter::Cast(b).index() ||
TypeParameter::Cast(a).base() != TypeParameter::Cast(b).base()) {
return false;

View file

@ -294,31 +294,41 @@ void ClassFinalizer::VerifyBootstrapClasses() {
}
IsolateGroup::Current()->heap()->Verify();
}
#endif // defined(DART_PRECOMPILED_RUNTIME)
void ClassFinalizer::FinalizeTypeParameters(const Class& cls,
FinalizationKind finalization) {
void ClassFinalizer::FinalizeTypeParameters(Zone* zone,
const Class& cls,
const FunctionType& signature,
FinalizationKind finalization,
PendingTypes* pending_types) {
if (FLAG_trace_type_finalization) {
THR_Print("%s type parameters of '%s'\n",
String::Handle(cls.Name()).ToCString(),
finalization == kFinalize ? "Finalizing" : "Canonicalizing");
THR_Print(
"%s type parameters of %s '%s'\n",
finalization == kFinalize ? "Finalizing" : "Canonicalizing",
!cls.IsNull() ? "class" : "signature",
String::Handle(zone, !cls.IsNull() ? cls.Name() : signature.Name())
.ToCString());
}
const TypeArguments& type_params =
TypeArguments::Handle(cls.type_parameters());
const TypeParameters& type_params =
TypeParameters::Handle(zone, !cls.IsNull() ? cls.type_parameters()
: signature.type_parameters());
if (!type_params.IsNull()) {
const intptr_t num_type_params = type_params.Length();
TypeParameter& type_param = TypeParameter::Handle();
for (intptr_t i = 0; i < num_type_params; i++) {
type_param ^= type_params.TypeAt(i);
if (!type_param.IsBeingFinalized()) {
type_param ^= FinalizeType(type_param, finalization);
type_params.SetTypeAt(i, type_param);
}
}
TypeArguments& type_args = TypeArguments::Handle(zone);
type_args = type_params.bounds();
type_args =
FinalizeTypeArguments(zone, type_args, finalization, pending_types);
type_params.set_bounds(type_args);
type_args = type_params.defaults();
type_args =
FinalizeTypeArguments(zone, type_args, finalization, pending_types);
type_params.set_defaults(type_args);
type_params.OptimizeFlags();
}
}
#endif // defined(DART_PRECOMPILED_RUNTIME)
// This function reports a compilation error if the recursive 'type' T being
// finalized is a non-contractive type, i.e. if the induced type set S of P is
// not finite, where P is the instantiation of T with its own type parameters.
@ -407,9 +417,9 @@ void ClassFinalizer::CheckRecursiveType(const AbstractType& type,
// Expand the type arguments of the given type and finalize its full type
// argument vector. Return the number of type arguments (0 for a raw type).
intptr_t ClassFinalizer::ExpandAndFinalizeTypeArguments(
Zone* zone,
const AbstractType& type,
PendingTypes* pending_types) {
Zone* zone = Thread::Current()->zone();
// The type class does not need to be finalized in order to finalize the type.
// Also, the type parameters of the type class must be finalized.
Class& type_class = Class::Handle(zone, type.type_class());
@ -483,8 +493,8 @@ intptr_t ClassFinalizer::ExpandAndFinalizeTypeArguments(
}
if (offset > 0) {
TrailPtr trail = new Trail(zone, 4);
FinalizeTypeArguments(type_class, full_arguments, offset, pending_types,
trail);
FillAndFinalizeTypeArguments(zone, type_class, full_arguments, offset,
pending_types, trail);
}
if (full_arguments.IsRaw(0, num_type_arguments)) {
// The parameterized_type is raw. Set its argument vector to null, which
@ -535,22 +545,24 @@ intptr_t ClassFinalizer::ExpandAndFinalizeTypeArguments(
// same time. Canonicalization happens when pending types are processed.
// The trail is required to correctly instantiate a recursive type argument
// of the super type.
void ClassFinalizer::FinalizeTypeArguments(const Class& cls,
const TypeArguments& arguments,
intptr_t num_uninitialized_arguments,
PendingTypes* pending_types,
TrailPtr trail) {
void ClassFinalizer::FillAndFinalizeTypeArguments(
Zone* zone,
const Class& cls,
const TypeArguments& arguments,
intptr_t num_uninitialized_arguments,
PendingTypes* pending_types,
TrailPtr trail) {
ASSERT(arguments.Length() >= cls.NumTypeArguments());
if (!cls.is_type_finalized()) {
#if defined(DART_PRECOMPILED_RUNTIME)
UNREACHABLE();
#else
FinalizeTypeParameters(cls, kFinalize);
FinalizeTypeParameters(zone, cls, Object::null_function_type(), kFinalize);
#endif // defined(DART_PRECOMPILED_RUNTIME)
}
AbstractType& super_type = AbstractType::Handle(cls.super_type());
AbstractType& super_type = AbstractType::Handle(zone, cls.super_type());
if (!super_type.IsNull()) {
const Class& super_class = Class::Handle(super_type.type_class());
const Class& super_class = Class::Handle(zone, super_type.type_class());
const intptr_t num_super_type_params = super_class.NumTypeParameters();
const intptr_t num_super_type_args = super_class.NumTypeArguments();
if (!super_type.IsFinalized() && !super_type.IsBeingFinalized()) {
@ -558,11 +570,12 @@ void ClassFinalizer::FinalizeTypeArguments(const Class& cls,
cls.set_super_type(super_type);
}
TypeArguments& super_type_args =
TypeArguments::Handle(super_type.arguments());
TypeArguments::Handle(zone, super_type.arguments());
// Offset of super type's type parameters in cls' type argument vector.
const intptr_t super_offset = num_super_type_args - num_super_type_params;
// If the super type is raw (i.e. super_type_args is null), set to dynamic.
AbstractType& super_type_arg = AbstractType::Handle(Type::DynamicType());
AbstractType& super_type_arg =
AbstractType::Handle(zone, Type::DynamicType());
for (intptr_t i = super_offset; i < num_uninitialized_arguments; i++) {
if (!super_type_args.IsNull()) {
super_type_arg = super_type_args.TypeAt(i);
@ -581,9 +594,10 @@ void ClassFinalizer::FinalizeTypeArguments(const Class& cls,
ASSERT(super_type_arg.IsFunctionType());
}
if (FLAG_trace_type_finalization) {
THR_Print("Creating TypeRef '%s': '%s'\n",
String::Handle(super_type_arg.Name()).ToCString(),
super_type_arg.ToCString());
THR_Print(
"Creating TypeRef '%s': '%s'\n",
String::Handle(zone, super_type_arg.Name()).ToCString(),
super_type_arg.ToCString());
}
super_type_arg = TypeRef::New(super_type_arg);
}
@ -601,12 +615,12 @@ void ClassFinalizer::FinalizeTypeArguments(const Class& cls,
// Instantiate super_type_arg with the current argument vector.
if (!super_type_arg.IsInstantiated()) {
if (FLAG_trace_type_finalization && super_type_arg.IsTypeRef()) {
AbstractType& ref_type =
AbstractType::Handle(TypeRef::Cast(super_type_arg).type());
AbstractType& ref_type = AbstractType::Handle(
zone, TypeRef::Cast(super_type_arg).type());
THR_Print(
"Instantiating TypeRef '%s': '%s'\n"
" instantiator: '%s'\n",
String::Handle(super_type_arg.Name()).ToCString(),
String::Handle(zone, super_type_arg.Name()).ToCString(),
ref_type.ToCString(), arguments.ToCString());
}
// In the typical case of an F-bounded type, the instantiation of the
@ -628,7 +642,7 @@ void ClassFinalizer::FinalizeTypeArguments(const Class& cls,
// The super_type_arg was instantiated from a type being finalized.
// We need to finish finalizing its type arguments, unless it is a
// type parameter, in which case there is nothing more to do.
AbstractType& unfinalized_type = AbstractType::Handle();
AbstractType& unfinalized_type = AbstractType::Handle(zone);
if (super_type_arg.IsTypeRef()) {
unfinalized_type = TypeRef::Cast(super_type_arg).type();
} else {
@ -636,18 +650,19 @@ void ClassFinalizer::FinalizeTypeArguments(const Class& cls,
unfinalized_type = super_type_arg.ptr();
}
if (FLAG_trace_type_finalization) {
THR_Print("Instantiated unfinalized '%s': '%s'\n",
String::Handle(unfinalized_type.Name()).ToCString(),
unfinalized_type.ToCString());
THR_Print(
"Instantiated unfinalized '%s': '%s'\n",
String::Handle(zone, unfinalized_type.Name()).ToCString(),
unfinalized_type.ToCString());
}
if (unfinalized_type.IsType()) {
CheckRecursiveType(unfinalized_type, pending_types);
pending_types->Add(unfinalized_type);
}
const Class& super_cls =
Class::Handle(unfinalized_type.type_class());
Class::Handle(zone, unfinalized_type.type_class());
const TypeArguments& super_args =
TypeArguments::Handle(unfinalized_type.arguments());
TypeArguments::Handle(zone, unfinalized_type.arguments());
// Mark as finalized before finalizing to avoid cycles.
unfinalized_type.SetIsFinalized();
// Although the instantiator is different between cls and super_cls,
@ -655,25 +670,53 @@ void ClassFinalizer::FinalizeTypeArguments(const Class& cls,
// divergence. Finalizing the type arguments of super_cls may indeed
// recursively require instantiating the same type_refs already
// present in the trail (see issue #29949).
FinalizeTypeArguments(
super_cls, super_args,
FillAndFinalizeTypeArguments(
zone, super_cls, super_args,
super_cls.NumTypeArguments() - super_cls.NumTypeParameters(),
pending_types, trail);
if (FLAG_trace_type_finalization) {
THR_Print("Finalized instantiated '%s': '%s'\n",
String::Handle(unfinalized_type.Name()).ToCString(),
unfinalized_type.ToCString());
THR_Print(
"Finalized instantiated '%s': '%s'\n",
String::Handle(zone, unfinalized_type.Name()).ToCString(),
unfinalized_type.ToCString());
}
}
}
}
arguments.SetTypeAt(i, super_type_arg);
}
FinalizeTypeArguments(super_class, arguments, super_offset, pending_types,
trail);
FillAndFinalizeTypeArguments(zone, super_class, arguments, super_offset,
pending_types, trail);
}
}
TypeArgumentsPtr ClassFinalizer::FinalizeTypeArguments(
Zone* zone,
const TypeArguments& type_args,
FinalizationKind finalization,
PendingTypes* pending_types) {
if (type_args.IsNull()) return TypeArguments::null();
ASSERT(type_args.ptr() != Object::empty_type_arguments().ptr());
const intptr_t len = type_args.Length();
AbstractType& type = AbstractType::Handle(zone);
AbstractType& finalized_type = AbstractType::Handle(zone);
for (intptr_t i = 0; i < len; i++) {
type = type_args.TypeAt(i);
if (type.IsBeingFinalized()) {
ASSERT(finalization < kCanonicalize);
continue;
}
finalized_type = FinalizeType(type, kFinalize, pending_types);
if (type.ptr() != finalized_type.ptr()) {
type_args.SetTypeAt(i, finalized_type);
}
}
if (finalization >= kCanonicalize) {
return type_args.Canonicalize(Thread::Current(), nullptr);
}
return type_args.ptr();
}
AbstractTypePtr ClassFinalizer::FinalizeType(const AbstractType& type,
FinalizationKind finalization,
PendingTypes* pending_types) {
@ -701,8 +744,8 @@ AbstractTypePtr ClassFinalizer::FinalizeType(const AbstractType& type,
return type.ptr();
}
// Recursive types must be processed in FinalizeTypeArguments() and cannot be
// encountered here.
// Recursive types must be processed in FillAndFinalizeTypeArguments() and
// cannot be encountered here.
ASSERT(!type.IsBeingFinalized());
// Mark the type as being finalized in order to detect self reference.
@ -737,17 +780,20 @@ AbstractTypePtr ClassFinalizer::FinalizeType(const AbstractType& type,
type_parameter.set_parameterized_class_id(kClassCid);
}
AbstractType& t = AbstractType::Handle(zone);
t = type_parameter.bound();
if (!t.IsBeingFinalized()) {
t = FinalizeType(t, kFinalize);
type_parameter.set_bound(t);
AbstractType& upper_bound = AbstractType::Handle(zone);
upper_bound = type_parameter.bound();
if (upper_bound.IsBeingFinalized()) {
if (upper_bound.IsTypeRef()) {
// Nothing to do.
} else {
upper_bound = TypeRef::New(upper_bound);
type_parameter.set_bound(upper_bound);
upper_bound = FinalizeType(upper_bound, kFinalize);
}
} else {
upper_bound = FinalizeType(upper_bound, kFinalize);
type_parameter.set_bound(upper_bound);
}
t = type_parameter.default_argument();
// The default argument cannot create a cycle with the type parameter.
t = FinalizeType(t, kFinalize);
type_parameter.set_default_argument(t);
type_parameter.SetIsFinalized();
if (FLAG_trace_type_finalization) {
@ -781,7 +827,7 @@ AbstractTypePtr ClassFinalizer::FinalizeType(const AbstractType& type,
pending_types->Add(type);
const intptr_t num_expanded_type_arguments =
ExpandAndFinalizeTypeArguments(type, pending_types);
ExpandAndFinalizeTypeArguments(zone, type, pending_types);
// Self referencing types may get finalized indirectly.
if (!type.IsFinalized()) {
@ -819,23 +865,12 @@ AbstractTypePtr ClassFinalizer::FinalizeSignature(Zone* zone,
const FunctionType& signature,
FinalizationKind finalization,
PendingTypes* pending_types) {
// Finalize signature type parameter upper bounds and default args.
FinalizeTypeParameters(zone, Object::null_class(), signature, finalization,
pending_types);
AbstractType& type = AbstractType::Handle(zone);
AbstractType& finalized_type = AbstractType::Handle(zone);
// Finalize signature type parameters, their upper bounds and default args.
const intptr_t num_type_params = signature.NumTypeParameters();
if (num_type_params > 0) {
TypeParameter& type_param = TypeParameter::Handle(zone);
const TypeArguments& type_params =
TypeArguments::Handle(zone, signature.type_parameters());
for (intptr_t i = 0; i < num_type_params; i++) {
type_param ^= type_params.TypeAt(i);
finalized_type ^= FinalizeType(type_param, kFinalize, pending_types);
if (type_param.ptr() != finalized_type.ptr()) {
type_params.SetTypeAt(i, TypeParameter::Cast(finalized_type));
}
}
}
// Finalize result type.
type = signature.result_type();
finalized_type = FinalizeType(type, kFinalize, pending_types);
@ -984,6 +1019,7 @@ void ClassFinalizer::FinalizeTypesInClass(const Class& cls) {
#if defined(DART_PRECOMPILED_RUNTIME)
UNREACHABLE();
#else
Zone* zone = thread->zone();
SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
if (cls.is_type_finalized()) {
return;
@ -993,24 +1029,24 @@ void ClassFinalizer::FinalizeTypesInClass(const Class& cls) {
THR_Print("Finalize types in %s\n", cls.ToCString());
}
// Finalize super class.
Class& super_class = Class::Handle(cls.SuperClass());
Class& super_class = Class::Handle(zone, cls.SuperClass());
if (!super_class.IsNull()) {
FinalizeTypesInClass(super_class);
}
// Finalize type parameters before finalizing the super type.
FinalizeTypeParameters(cls, kFinalize);
FinalizeTypeParameters(zone, cls, Object::null_function_type(),
kCanonicalize);
ASSERT(super_class.ptr() == cls.SuperClass()); // Not modified.
ASSERT(super_class.IsNull() || super_class.is_type_finalized());
FinalizeTypeParameters(cls, kCanonicalize);
// Finalize super type.
AbstractType& super_type = AbstractType::Handle(cls.super_type());
AbstractType& super_type = AbstractType::Handle(zone, cls.super_type());
if (!super_type.IsNull()) {
super_type = FinalizeType(super_type);
cls.set_super_type(super_type);
}
// Finalize interface types (but not necessarily interface classes).
Array& interface_types = Array::Handle(cls.interfaces());
AbstractType& interface_type = AbstractType::Handle();
Array& interface_types = Array::Handle(zone, cls.interfaces());
AbstractType& interface_type = AbstractType::Handle(zone);
for (intptr_t i = 0; i < interface_types.Length(); i++) {
interface_type ^= interface_types.At(i);
interface_type = FinalizeType(interface_type);
@ -1343,8 +1379,7 @@ void ClassFinalizer::VerifyImplicitFieldOffsets() {
error = cls.EnsureIsFinalized(thread);
ASSERT(error.IsNull());
ASSERT(cls.NumTypeParameters() == 1);
type_param ^= TypeParameter::RawCast(
TypeArguments::Handle(cls.type_parameters()).TypeAt(0));
type_param = cls.TypeParameterAt(0);
ASSERT(Pointer::kNativeTypeArgPos == type_param.index());
#endif
}
@ -1660,7 +1695,8 @@ void ClassFinalizer::RehashTypes() {
for (intptr_t i = 0; i < typeparams.Length(); i++) {
typeparam ^= typeparams.At(i);
bool present = typeparams_table.Insert(typeparam);
ASSERT(!present);
// Two recursive types with different topology (and hashes) may be equal.
ASSERT(!present || typeparam.IsRecursive());
}
object_store->set_canonical_type_parameters(typeparams_table.Release());

View file

@ -79,6 +79,13 @@ class ClassFinalizer : public AllStatic {
#endif // !defined(DART_PRECOMPILED_RUNTIME)
private:
// Finalize given type argument vector.
static TypeArgumentsPtr FinalizeTypeArguments(
Zone* zone,
const TypeArguments& type_args,
FinalizationKind finalization = kCanonicalize,
PendingTypes* pending_types = NULL);
// Finalize the types in the signature and the signature itself.
static AbstractTypePtr FinalizeSignature(
Zone* zone,
@ -88,18 +95,24 @@ class ClassFinalizer : public AllStatic {
#if !defined(DART_PRECOMPILED_RUNTIME)
static void AllocateEnumValues(const Class& enum_cls);
static void FinalizeTypeParameters(
const Class& cls,
FinalizationKind finalization = kCanonicalize);
#endif // !defined(DART_PRECOMPILED_RUNTIME)
static intptr_t ExpandAndFinalizeTypeArguments(const AbstractType& type,
static void FinalizeTypeParameters(
Zone* zone,
const Class& cls,
const FunctionType& signature,
FinalizationKind finalization = kCanonicalize,
PendingTypes* pending_types = NULL);
static intptr_t ExpandAndFinalizeTypeArguments(Zone* zone,
const AbstractType& type,
PendingTypes* pending_types);
static void FinalizeTypeArguments(const Class& cls,
const TypeArguments& arguments,
intptr_t num_uninitialized_arguments,
PendingTypes* pending_types,
TrailPtr trail);
static void FillAndFinalizeTypeArguments(Zone* zone,
const Class& cls,
const TypeArguments& arguments,
intptr_t num_uninitialized_arguments,
PendingTypes* pending_types,
TrailPtr trail);
static void CheckRecursiveType(const AbstractType& type,
PendingTypes* pending_types);

View file

@ -21,6 +21,7 @@ typedef uint16_t ClassIdTagType;
V(Class) \
V(PatchClass) \
V(Function) \
V(TypeParameters) \
V(ClosureData) \
V(FfiTrampolineData) \
V(Field) \

View file

@ -533,8 +533,14 @@ class CanonicalSetSerializationCluster : public SerializationCluster {
element ^= ptr;
intptr_t entry = -1;
const bool present = table.FindKeyOrDeletedOrUnused(element, &entry);
ASSERT(!present);
table.InsertKey(entry, element);
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;
}
} else {
objects_[num_occupied++] = ptr;
}
@ -685,6 +691,74 @@ class CanonicalSetDeserializationCluster : public DeserializationCluster {
}
};
#if !defined(DART_PRECOMPILED_RUNTIME)
class TypeParametersSerializationCluster : public SerializationCluster {
public:
TypeParametersSerializationCluster()
: SerializationCluster("TypeParameters",
kTypeParametersCid,
compiler::target::TypeParameters::InstanceSize()) {
}
~TypeParametersSerializationCluster() {}
void Trace(Serializer* s, ObjectPtr object) {
TypeParametersPtr type_params = TypeParameters::RawCast(object);
objects_.Add(type_params);
PushFromTo(type_params);
}
void WriteAlloc(Serializer* s) {
const intptr_t count = objects_.length();
s->WriteUnsigned(count);
for (intptr_t i = 0; i < count; i++) {
TypeParametersPtr type_params = objects_[i];
s->AssignRef(type_params);
}
}
void WriteFill(Serializer* s) {
const intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
TypeParametersPtr type_params = objects_[i];
AutoTraceObject(type_params);
WriteFromTo(type_params);
}
}
private:
GrowableArray<TypeParametersPtr> objects_;
};
#endif // !DART_PRECOMPILED_RUNTIME
class TypeParametersDeserializationCluster : public DeserializationCluster {
public:
TypeParametersDeserializationCluster()
: DeserializationCluster("TypeParameters") {}
~TypeParametersDeserializationCluster() {}
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(
AllocateUninitialized(old_space, TypeParameters::InstanceSize()));
}
stop_index_ = d->next_index();
}
void ReadFill(Deserializer* d, bool primary) {
ASSERT(!is_canonical()); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
TypeParametersPtr type_params =
static_cast<TypeParametersPtr>(d->Ref(id));
Deserializer::InitializeHeader(type_params, kTypeParametersCid,
TypeParameters::InstanceSize());
ReadFromTo(type_params);
}
}
};
#if !defined(DART_PRECOMPILED_RUNTIME)
class TypeArgumentsSerializationCluster
: public CanonicalSetSerializationCluster<CanonicalTypeArgumentsSet,
@ -1088,7 +1162,6 @@ class ClosureDataSerializationCluster : public SerializationCluster {
}
s->Push(data->untag()->parent_function());
s->Push(data->untag()->closure());
s->Push(data->untag()->default_type_arguments());
}
void WriteAlloc(Serializer* s) {
@ -1110,7 +1183,6 @@ class ClosureDataSerializationCluster : public SerializationCluster {
}
WriteCompressedField(data, parent_function);
WriteCompressedField(data, closure);
WriteCompressedField(data, default_type_arguments);
s->WriteUnsigned(
static_cast<intptr_t>(data->untag()->default_type_arguments_kind_));
}
@ -1151,8 +1223,6 @@ class ClosureDataDeserializationCluster : public DeserializationCluster {
}
data->untag()->parent_function_ = static_cast<FunctionPtr>(d->ReadRef());
data->untag()->closure_ = static_cast<InstancePtr>(d->ReadRef());
data->untag()->default_type_arguments_ =
static_cast<TypeArgumentsPtr>(d->ReadRef());
data->untag()->default_type_arguments_kind_ =
static_cast<ClosureData::DefaultTypeArgumentsKind>(d->ReadUnsigned());
}
@ -4218,8 +4288,8 @@ class TypeParameterSerializationCluster
AutoTraceObject(type);
WriteFromTo(type);
s->Write<int32_t>(type->untag()->parameterized_class_id_);
s->Write<uint16_t>(type->untag()->base_);
s->Write<uint16_t>(type->untag()->index_);
s->Write<uint8_t>(type->untag()->base_);
s->Write<uint8_t>(type->untag()->index_);
ASSERT(type->untag()->flags_ < (1 << UntaggedTypeParameter::kFlagsBitSize));
ASSERT(type->untag()->nullability_ < (1 << kNullabilityBitSize));
static_assert(UntaggedTypeParameter::kFlagsBitSize + kNullabilityBitSize <=
@ -4264,8 +4334,8 @@ class TypeParameterDeserializationCluster
primary && is_canonical());
ReadFromTo(type);
type->untag()->parameterized_class_id_ = d->Read<int32_t>();
type->untag()->base_ = d->Read<uint16_t>();
type->untag()->index_ = d->Read<uint16_t>();
type->untag()->base_ = d->Read<uint8_t>();
type->untag()->index_ = d->Read<uint8_t>();
const uint8_t combined = d->Read<uint8_t>();
type->untag()->flags_ = combined >> kNullabilityBitSize;
type->untag()->nullability_ = combined & kNullabilityBitMask;
@ -6536,6 +6606,8 @@ SerializationCluster* Serializer::NewClusterForClass(intptr_t cid,
switch (cid) {
case kClassCid:
return new (Z) ClassSerializationCluster(num_cids_ + num_tlc_cids_);
case kTypeParametersCid:
return new (Z) TypeParametersSerializationCluster();
case kTypeArgumentsCid:
return new (Z) TypeArgumentsSerializationCluster(
is_canonical, cluster_represents_canonical_set);
@ -7388,6 +7460,8 @@ DeserializationCluster* Deserializer::ReadCluster() {
case kClassCid:
ASSERT(!is_canonical);
return new (Z) ClassDeserializationCluster();
case kTypeParametersCid:
return new (Z) TypeParametersDeserializationCluster();
case kTypeArgumentsCid:
return new (Z)
TypeArgumentsDeserializationCluster(is_canonical, !is_non_root_unit_);

View file

@ -962,7 +962,7 @@ void Precompiler::AddTypesOf(const Class& cls) {
AddType(type);
}
AddTypeArguments(TypeArguments::Handle(Z, cls.type_parameters()));
AddTypeParameters(TypeParameters::Handle(Z, cls.type_parameters()));
type = cls.super_type();
AddType(type);
@ -991,15 +991,6 @@ void Precompiler::AddTypesOf(const Function& function) {
const FunctionType& signature = FunctionType::Handle(Z, function.signature());
AddType(signature);
// At this point, ensure any cached default type arguments are canonicalized.
function.UpdateCachedDefaultTypeArguments(thread());
if (function.CachesDefaultTypeArguments()) {
const auto& defaults = TypeArguments::Handle(
Z, function.default_type_arguments(/*kind_out=*/nullptr));
ASSERT(defaults.IsCanonical());
AddTypeArguments(defaults);
}
// A class may have all functions inlined except a local function.
const Class& owner = Class::Handle(Z, function.Owner());
AddTypesOf(owner);
@ -1054,10 +1045,8 @@ void Precompiler::AddType(const AbstractType& abstype) {
if (typeparams_to_retain_.HasKey(&param)) return;
typeparams_to_retain_.Insert(&TypeParameter::ZoneHandle(Z, param.ptr()));
auto& type = AbstractType::Handle(Z, param.bound());
AddType(type);
type = param.default_argument();
AddType(type);
auto& bound = AbstractType::Handle(Z, param.bound());
AddType(bound);
return;
}
@ -1067,7 +1056,7 @@ void Precompiler::AddType(const AbstractType& abstype) {
FunctionType::ZoneHandle(Z, FunctionType::Cast(abstype).ptr());
functiontypes_to_retain_.Insert(&signature);
AddTypeArguments(TypeArguments::Handle(Z, signature.type_parameters()));
AddTypeParameters(TypeParameters::Handle(Z, signature.type_parameters()));
AbstractType& type = AbstractType::Handle(Z);
type = signature.result_type();
@ -1095,6 +1084,16 @@ void Precompiler::AddType(const AbstractType& abstype) {
}
}
void Precompiler::AddTypeParameters(const TypeParameters& params) {
if (params.IsNull()) return;
TypeArguments& args = TypeArguments::Handle();
args = params.bounds();
AddTypeArguments(args);
args = params.defaults();
AddTypeArguments(args);
}
void Precompiler::AddTypeArguments(const TypeArguments& args) {
if (args.IsNull()) return;

View file

@ -298,6 +298,7 @@ class Precompiler : public ValueObject {
void AddType(const AbstractType& type);
void AddTypesOf(const Class& cls);
void AddTypesOf(const Function& function);
void AddTypeParameters(const TypeParameters& params);
void AddTypeArguments(const TypeArguments& args);
void AddCalleesOf(const Function& function, intptr_t gop_offset);
void AddCalleesOfHelper(const Object& entry,

View file

@ -2694,7 +2694,6 @@ bool LoadFieldInstr::IsImmutableLengthLoad() const {
case Slot::Kind::kClosure_function_type_arguments:
case Slot::Kind::kClosure_instantiator_type_arguments:
case Slot::Kind::kClosure_hash:
case Slot::Kind::kClosureData_default_type_arguments:
case Slot::Kind::kCapturedVariable:
case Slot::Kind::kDartField:
case Slot::Kind::kFunction_data:
@ -2705,8 +2704,11 @@ bool LoadFieldInstr::IsImmutableLengthLoad() const {
case Slot::Kind::kPointerBase_data_field:
case Slot::Kind::kType_arguments:
case Slot::Kind::kTypeArgumentsIndex:
case Slot::Kind::kTypeParameters_names:
case Slot::Kind::kTypeParameters_flags:
case Slot::Kind::kTypeParameters_bounds:
case Slot::Kind::kTypeParameters_defaults:
case Slot::Kind::kTypeParameter_bound:
case Slot::Kind::kTypeParameter_name:
case Slot::Kind::kUnhandledException_exception:
case Slot::Kind::kUnhandledException_stacktrace:
case Slot::Kind::kWeakProperty_key:

View file

@ -52,18 +52,14 @@ ClassPtr GetClass(const Library& lib, const char* name) {
return cls.ptr();
}
TypeParameterPtr GetClassTypeParameter(const Class& klass, const char* name) {
const auto& param = TypeParameter::Handle(
klass.LookupTypeParameter(String::Handle(String::New(name))));
TypeParameterPtr GetClassTypeParameter(const Class& klass, intptr_t index) {
const auto& param = TypeParameter::Handle(klass.TypeParameterAt(index));
EXPECT(!param.IsNull());
return param.ptr();
}
TypeParameterPtr GetFunctionTypeParameter(const Function& fun,
const char* name) {
intptr_t fun_level = 0;
const auto& param = TypeParameter::Handle(
fun.LookupTypeParameter(String::Handle(String::New(name)), &fun_level));
TypeParameterPtr GetFunctionTypeParameter(const Function& fun, intptr_t index) {
const auto& param = TypeParameter::Handle(fun.TypeParameterAt(index));
EXPECT(!param.IsNull());
return param.ptr();
}

View file

@ -58,9 +58,8 @@ LibraryPtr LoadTestScript(const char* script,
FunctionPtr GetFunction(const Library& lib, const char* name);
ClassPtr GetClass(const Library& lib, const char* name);
TypeParameterPtr GetClassTypeParameter(const Class& klass, const char* name);
TypeParameterPtr GetFunctionTypeParameter(const Function& fun,
const char* name);
TypeParameterPtr GetClassTypeParameter(const Class& klass, intptr_t index);
TypeParameterPtr GetFunctionTypeParameter(const Function& fun, intptr_t index);
ObjectPtr Invoke(const Library& lib, const char* name);

View file

@ -2797,7 +2797,6 @@ void LoadFieldInstr::InferRange(RangeAnalysis* analysis, Range* range) {
case Slot::Kind::kClosure_function:
case Slot::Kind::kClosure_function_type_arguments:
case Slot::Kind::kClosure_instantiator_type_arguments:
case Slot::Kind::kClosureData_default_type_arguments:
case Slot::Kind::kFunction_data:
case Slot::Kind::kFunction_signature:
case Slot::Kind::kFunctionType_parameter_names:
@ -2807,8 +2806,11 @@ void LoadFieldInstr::InferRange(RangeAnalysis* analysis, Range* range) {
case Slot::Kind::kTypedDataView_data:
case Slot::Kind::kType_arguments:
case Slot::Kind::kTypeArgumentsIndex:
case Slot::Kind::kTypeParameters_names:
case Slot::Kind::kTypeParameters_flags:
case Slot::Kind::kTypeParameters_bounds:
case Slot::Kind::kTypeParameters_defaults:
case Slot::Kind::kTypeParameter_bound:
case Slot::Kind::kTypeParameter_name:
case Slot::Kind::kUnhandledException_exception:
case Slot::Kind::kUnhandledException_stacktrace:
case Slot::Kind::kWeakProperty_key:

View file

@ -58,10 +58,13 @@ class ParsedFunction;
FINAL) \
V(Closure, UntaggedClosure, delayed_type_arguments, TypeArguments, FINAL) \
V(Closure, UntaggedClosure, function_type_arguments, TypeArguments, FINAL) \
V(ClosureData, UntaggedClosureData, default_type_arguments, TypeArguments, \
FINAL_COMPRESSED) \
V(Type, UntaggedType, arguments, TypeArguments, FINAL_COMPRESSED) \
V(FunctionType, UntaggedFunctionType, type_parameters, TypeArguments, \
V(FunctionType, UntaggedFunctionType, type_parameters, TypeParameters, \
FINAL_COMPRESSED) \
V(TypeParameters, UntaggedTypeParameters, flags, Array, FINAL_COMPRESSED) \
V(TypeParameters, UntaggedTypeParameters, bounds, TypeArguments, \
FINAL_COMPRESSED) \
V(TypeParameters, UntaggedTypeParameters, defaults, TypeArguments, \
FINAL_COMPRESSED) \
V(WeakProperty, UntaggedWeakProperty, key, Dynamic, VAR) \
V(WeakProperty, UntaggedWeakProperty, value, Dynamic, VAR)
@ -107,8 +110,8 @@ class ParsedFunction;
V(ArgumentsDescriptor, UntaggedArray, size, Smi, FINAL) \
V(PointerBase, UntaggedPointerBase, data_field, Dynamic, FINAL) \
V(TypeArguments, UntaggedTypeArguments, length, Smi, FINAL_COMPRESSED) \
V(TypeParameters, UntaggedTypeParameters, names, Array, FINAL_COMPRESSED) \
V(TypeParameter, UntaggedTypeParameter, bound, Dynamic, FINAL_COMPRESSED) \
V(TypeParameter, UntaggedTypeParameter, name, Dynamic, FINAL_COMPRESSED) \
V(UnhandledException, UntaggedUnhandledException, exception, Dynamic, \
FINAL_COMPRESSED) \
V(UnhandledException, UntaggedUnhandledException, stacktrace, Dynamic, \

View file

@ -1387,14 +1387,12 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfRecognizedMethod(
ASSERT(class_table->HasValidClassAt(kFfiPointerCid));
const auto& pointer_class =
Class::ZoneHandle(H.zone(), class_table->At(kFfiPointerCid));
const auto& pointer_type_args =
TypeArguments::Handle(pointer_class.type_parameters());
const auto& pointer_type_arg =
AbstractType::ZoneHandle(pointer_type_args.TypeAt(0));
const auto& pointer_type_param =
TypeParameter::ZoneHandle(pointer_class.TypeParameterAt(0));
// But we type check it as a method on a generic class at runtime.
body += LoadLocal(arg_value); // value.
body += Constant(pointer_type_arg); // dst_type.
body += LoadLocal(arg_value); // value.
body += Constant(pointer_type_param); // dst_type.
// We pass the Pointer type argument as instantiator_type_args.
//
// Call sites to this recognized method are guaranteed to pass a
@ -1767,26 +1765,27 @@ void FlowGraphBuilder::BuildTypeArgumentTypeChecks(TypeChecksToBuild mode,
ASSERT(!forwarding_target->IsNull());
}
TypeArguments& type_parameters = TypeArguments::Handle(Z);
TypeParameters& type_parameters = TypeParameters::Handle(Z);
if (dart_function.IsFactory()) {
type_parameters = Class::Handle(Z, dart_function.Owner()).type_parameters();
} else {
type_parameters = dart_function.type_parameters();
}
intptr_t num_type_params = type_parameters.Length();
const intptr_t num_type_params = type_parameters.Length();
if (num_type_params == 0) return;
if (forwarding_target != nullptr) {
type_parameters = forwarding_target->type_parameters();
ASSERT(type_parameters.Length() == num_type_params);
}
if (type_parameters.AllDynamicBounds()) {
return; // All bounds are dynamic.
}
TypeParameter& type_param = TypeParameter::Handle(Z);
String& name = String::Handle(Z);
AbstractType& bound = AbstractType::Handle(Z);
Fragment check_bounds;
for (intptr_t i = 0; i < num_type_params; ++i) {
type_param ^= type_parameters.TypeAt(i);
bound = type_param.bound();
bound = type_parameters.BoundAt(i);
if (bound.IsTopTypeForSubtyping()) {
continue;
}
@ -1795,19 +1794,26 @@ void FlowGraphBuilder::BuildTypeArgumentTypeChecks(TypeChecksToBuild mode,
case TypeChecksToBuild::kCheckAllTypeParameterBounds:
break;
case TypeChecksToBuild::kCheckCovariantTypeParameterBounds:
if (!type_param.IsGenericCovariantImpl()) {
if (!type_parameters.IsGenericCovariantImplAt(i)) {
continue;
}
break;
case TypeChecksToBuild::kCheckNonCovariantTypeParameterBounds:
if (type_param.IsGenericCovariantImpl()) {
if (type_parameters.IsGenericCovariantImplAt(i)) {
continue;
}
break;
}
name = type_param.name();
name = type_parameters.NameAt(i);
if (forwarding_target != nullptr) {
type_param = forwarding_target->TypeParameterAt(i);
} else if (dart_function.IsFactory()) {
type_param = Class::Handle(Z, dart_function.Owner()).TypeParameterAt(i);
} else {
type_param = dart_function.TypeParameterAt(i);
}
ASSERT(type_param.IsFinalized());
check_bounds +=
AssertSubtype(TokenPosition::kNoSource, type_param, bound, name);
@ -2076,8 +2082,8 @@ struct FlowGraphBuilder::ClosureCallInfo {
const ArgumentsDescriptor descriptor;
ParsedFunction::DynamicClosureCallVars* const vars;
// Set up by BuildDynamicCallChecks() when needed. These values are
// read-only, so they don't need real local variables and are created
// Set up by BuildClosureCallDefaultTypeHandling() when needed. These values
// are read-only, so they don't need real local variables and are created
// using MakeTemporary().
LocalVariable* signature = nullptr;
LocalVariable* num_fixed_params = nullptr;
@ -2087,8 +2093,11 @@ struct FlowGraphBuilder::ClosureCallInfo {
LocalVariable* parameter_names = nullptr;
LocalVariable* parameter_types = nullptr;
LocalVariable* type_parameters = nullptr;
LocalVariable* num_type_parameters = nullptr;
LocalVariable* type_parameter_flags = nullptr;
LocalVariable* instantiator_type_args = nullptr;
LocalVariable* parent_function_type_args = nullptr;
LocalVariable* num_parent_type_args = nullptr;
};
Fragment FlowGraphBuilder::TestClosureFunctionGeneric(
@ -2239,8 +2248,8 @@ Fragment FlowGraphBuilder::BuildClosureCallDefaultTypeHandling(
store_default += BranchIfEqual(&can_share_instantiator, &can_share_function);
Fragment instantiated(is_instantiated);
instantiated += LoadLocal(closure_data);
instantiated += LoadNativeField(Slot::ClosureData_default_type_arguments());
instantiated += LoadLocal(info.type_parameters);
instantiated += LoadNativeField(Slot::TypeParameters_defaults());
instantiated += StoreLocal(info.vars->function_type_args);
instantiated += Drop();
instantiated += Goto(done);
@ -2252,9 +2261,8 @@ Fragment FlowGraphBuilder::BuildClosureCallDefaultTypeHandling(
// can be used within the defaults).
do_instantiation += LoadLocal(info.parent_function_type_args);
// Load the default type arguments to instantiate.
do_instantiation += LoadLocal(closure_data);
do_instantiation +=
LoadNativeField(Slot::ClosureData_default_type_arguments());
do_instantiation += LoadLocal(info.type_parameters);
do_instantiation += LoadNativeField(Slot::TypeParameters_defaults());
do_instantiation += InstantiateDynamicTypeArguments();
do_instantiation += StoreLocal(info.vars->function_type_args);
do_instantiation += Drop();
@ -2433,7 +2441,8 @@ Fragment FlowGraphBuilder::BuildClosureCallArgumentsValidCheck(
check_type_args_length += BranchIfNull(&null, &not_null);
check_type_args_length.current = not_null; // Continue in non-error case.
check_type_args_length += LoadLocal(info.type_parameters);
check_type_args_length += LoadNativeField(Slot::TypeArguments_length());
check_type_args_length += LoadNativeField(Slot::TypeParameters_names());
check_type_args_length += LoadNativeField(Slot::Array_length());
check_type_args_length += IntConstant(info.descriptor.TypeArgsLen());
TargetEntryInstr *equal, *not_equal;
check_type_args_length += BranchIfEqual(&equal, &not_equal);
@ -2522,6 +2531,16 @@ Fragment FlowGraphBuilder::BuildClosureCallTypeArgumentsTypeCheck(
// We assume that the value stored in :t_type_parameters is not null (i.e.,
// the function stored in :t_function is generic).
Fragment loop_init;
// A null bounds vector represents a vector of dynamic and no check is needed.
loop_init += LoadLocal(info.type_parameters);
loop_init += LoadNativeField(Slot::TypeParameters_bounds());
TargetEntryInstr *null_bounds, *non_null_bounds;
loop_init += BranchIfNull(&null_bounds, &non_null_bounds);
Fragment(null_bounds) + Goto(done);
loop_init.current = non_null_bounds;
// Loop over the type parameters array.
loop_init += IntConstant(0);
loop_init += StoreLocal(info.vars->current_param_index);
@ -2530,54 +2549,93 @@ Fragment FlowGraphBuilder::BuildClosureCallTypeArgumentsTypeCheck(
Fragment loop_check(loop);
loop_check += LoadLocal(info.vars->current_param_index);
loop_check += LoadLocal(info.type_parameters);
loop_check += LoadNativeField(Slot::TypeArguments_length());
loop_check += LoadLocal(info.num_type_parameters);
loop_check += SmiRelationalOp(Token::kLT);
TargetEntryInstr *more, *no_more;
loop_check += BranchIfTrue(&more, &no_more);
Fragment(no_more) + Goto(done);
Fragment loop_body(more);
loop_body += LoadLocal(info.type_parameters);
loop_body += LoadLocal(info.vars->current_param_index);
loop_body += LoadIndexed(
kTypeArgumentsCid, /*index_scale*/ compiler::target::kCompressedWordSize);
LocalVariable* current_param = MakeTemporary("current_param"); // Read-only.
// One read-only local variable on stack (param) to drop after joining.
Fragment loop_test_flag(more);
JoinEntryInstr* next = BuildJoinEntry();
JoinEntryInstr* check = BuildJoinEntry();
loop_test_flag += LoadLocal(info.type_parameter_flags);
TargetEntryInstr *null_flags, *non_null_flags;
loop_test_flag += BranchIfNull(&null_flags, &non_null_flags);
loop_body += LoadLocal(current_param);
loop_body += LoadNativeField(Slot::TypeParameter_flags());
loop_body += Box(kUnboxedUint8);
loop_body += IntConstant(
UntaggedTypeParameter::GenericCovariantImplBit::mask_in_place());
loop_body += SmiBinaryOp(Token::kBIT_AND);
loop_body += IntConstant(0);
Fragment(null_flags) + Goto(check); // Check type if null (non-covariant).
loop_test_flag.current = non_null_flags; // Test flags if not null.
loop_test_flag += LoadLocal(info.type_parameter_flags);
loop_test_flag += LoadLocal(info.vars->current_param_index);
loop_test_flag += IntConstant(TypeParameters::kFlagsPerSmiShift);
loop_test_flag += SmiBinaryOp(Token::kSHR);
loop_test_flag += LoadIndexed(kArrayCid);
loop_test_flag += LoadLocal(info.vars->current_param_index);
loop_test_flag += IntConstant(TypeParameters::kFlagsPerSmiMask);
loop_test_flag += SmiBinaryOp(Token::kBIT_AND);
loop_test_flag += SmiBinaryOp(Token::kSHR);
loop_test_flag += IntConstant(1);
loop_test_flag += SmiBinaryOp(Token::kBIT_AND);
loop_test_flag += IntConstant(0);
TargetEntryInstr *is_noncovariant, *is_covariant;
loop_body += BranchIfEqual(&is_noncovariant, &is_covariant);
loop_test_flag += BranchIfEqual(&is_noncovariant, &is_covariant);
Fragment(is_covariant) + Goto(next); // Continue if covariant.
Fragment(is_noncovariant) + Goto(check); // Check type if non-covariant.
loop_body.current = is_noncovariant; // Type check if non-covariant.
loop_body += LoadLocal(info.instantiator_type_args);
loop_body += LoadLocal(info.vars->function_type_args);
// Load parameter.
loop_body += LoadLocal(current_param);
// Load bounds from parameter.
loop_body += LoadLocal(current_param);
loop_body += LoadNativeField(Slot::TypeParameter_bound());
// Load name from parameter.
loop_body += LoadLocal(current_param);
loop_body += LoadNativeField(Slot::TypeParameter_name());
// Assert that the type the parameter is instantiated as is consistent with
// the bounds of the parameter.
loop_body += AssertSubtype(TokenPosition::kNoSource);
loop_body += Goto(next);
Fragment loop_prep_type_param(check);
JoinEntryInstr* dynamic_type_param = BuildJoinEntry();
JoinEntryInstr* call = BuildJoinEntry();
// Load type argument already stored in function_type_args if non null.
loop_prep_type_param += LoadLocal(info.vars->function_type_args);
TargetEntryInstr *null_ftav, *non_null_ftav;
loop_prep_type_param += BranchIfNull(&null_ftav, &non_null_ftav);
Fragment(null_ftav) + Goto(dynamic_type_param);
loop_prep_type_param.current = non_null_ftav;
loop_prep_type_param += LoadLocal(info.vars->function_type_args);
loop_prep_type_param += LoadLocal(info.vars->current_param_index);
loop_prep_type_param += LoadLocal(info.num_parent_type_args);
loop_prep_type_param += SmiBinaryOp(Token::kADD, /*is_truncating=*/true);
loop_prep_type_param += LoadIndexed(
kTypeArgumentsCid, /*index_scale*/ compiler::target::kCompressedWordSize);
loop_prep_type_param += StoreLocal(info.vars->current_type_param);
loop_prep_type_param += Drop();
loop_prep_type_param += Goto(call);
Fragment loop_dynamic_type_param(dynamic_type_param);
// If function_type_args is null, the instantiated type param is dynamic.
loop_dynamic_type_param += Constant(Type::ZoneHandle(Type::DynamicType()));
loop_dynamic_type_param += StoreLocal(info.vars->current_type_param);
loop_dynamic_type_param += Drop();
loop_dynamic_type_param += Goto(call);
Fragment loop_call_check(call);
// Load instantiators.
loop_call_check += LoadLocal(info.instantiator_type_args);
loop_call_check += LoadLocal(info.vars->function_type_args);
// Load instantiated type parameter.
loop_call_check += LoadLocal(info.vars->current_type_param);
// Load bound from type parameters.
loop_call_check += LoadLocal(info.type_parameters);
loop_call_check += LoadNativeField(Slot::TypeParameters_bounds());
loop_call_check += LoadLocal(info.vars->current_param_index);
loop_call_check += LoadIndexed(
kTypeArgumentsCid, /*index_scale*/ compiler::target::kCompressedWordSize);
// Load (canonicalized) name of type parameter in signature.
loop_call_check += LoadLocal(info.type_parameters);
loop_call_check += LoadNativeField(Slot::TypeParameters_names());
loop_call_check += LoadLocal(info.vars->current_param_index);
loop_call_check += LoadIndexed(kArrayCid);
// Assert that the passed-in type argument is consistent with the bound of
// the corresponding type parameter.
loop_call_check += AssertSubtype(TokenPosition::kNoSource);
loop_call_check += Goto(next);
Fragment loop_incr(next);
loop_incr += DropTemporary(&current_param);
loop_incr += LoadLocal(info.vars->current_param_index);
loop_incr += IntConstant(1);
loop_incr += SmiBinaryOp(Token::kADD, /*is_truncating=*/true);
@ -2717,23 +2775,38 @@ Fragment FlowGraphBuilder::BuildDynamicClosureCallChecks(
// full set of function type arguments, then check the local function type
// arguments against the closure function's type parameter bounds.
Fragment generic;
// Calculate the number of parent type arguments and store them in
// info.num_parent_type_args.
generic += LoadLocal(info.signature);
generic += BuildExtractUnboxedSlotBitFieldIntoSmi<
UntaggedFunctionType::PackedNumParentTypeArguments>(
Slot::FunctionType_packed_fields());
info.num_parent_type_args = MakeTemporary("num_parent_type_args");
// Hoist number of type parameters.
generic += LoadLocal(info.type_parameters);
generic += LoadNativeField(Slot::TypeParameters_names());
generic += LoadNativeField(Slot::Array_length());
info.num_type_parameters = MakeTemporary("num_type_parameters");
// Hoist type parameter flags.
generic += LoadLocal(info.type_parameters);
generic += LoadNativeField(Slot::TypeParameters_flags());
info.type_parameter_flags = MakeTemporary("type_parameter_flags");
// Calculate the local function type arguments and store them in
// info.vars->function_type_args.
generic += BuildClosureCallDefaultTypeHandling(info);
// Load the local function type args.
generic += LoadLocal(info.vars->function_type_args);
// Load the parent function type args.
generic += LoadLocal(info.parent_function_type_args);
// Load the number of parent type parameters.
generic += LoadLocal(info.signature);
generic += BuildExtractUnboxedSlotBitFieldIntoSmi<
UntaggedFunctionType::PackedNumParentTypeArguments>(
Slot::FunctionType_packed_fields());
generic += LoadLocal(info.num_parent_type_args);
// Load the number of total type parameters.
LocalVariable* num_parents = MakeTemporary();
generic += LoadLocal(info.type_parameters);
generic += LoadNativeField(Slot::TypeArguments_length());
generic += LoadLocal(num_parents);
generic += LoadLocal(info.num_parent_type_args);
generic += LoadLocal(info.num_type_parameters);
generic += SmiBinaryOp(Token::kADD, /*is_truncating=*/true);
// Call the static function for prepending type arguments.
@ -2753,6 +2826,9 @@ Fragment FlowGraphBuilder::BuildDynamicClosureCallChecks(
} else {
generic += check_bounds;
}
generic += DropTemporary(&info.type_parameter_flags);
generic += DropTemporary(&info.num_type_parameters);
generic += DropTemporary(&info.num_parent_type_args);
// Call the appropriate fragment for setting up the function type arguments
// and performing any needed type argument checking.

View file

@ -710,7 +710,18 @@ Type& TranslationHelper::GetDeclarationType(const Class& klass) {
type = klass.DeclarationType();
} else {
// Note that the type argument vector is not yet extended.
type = Type::New(klass, TypeArguments::Handle(Z, klass.type_parameters()));
TypeArguments& type_args = TypeArguments::Handle(Z);
const intptr_t num_type_params = klass.NumTypeParameters();
if (num_type_params > 0) {
type_args = TypeArguments::New(num_type_params);
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);
}
}
type = Type::New(klass, type_args, Nullability::kNonNullable);
}
return type;
}
@ -2916,19 +2927,13 @@ ExternalTypedDataPtr KernelReaderHelper::GetConstantCoverageFor(
intptr_t ActiveClass::MemberTypeParameterCount(Zone* zone) {
ASSERT(member != NULL);
if (member->IsFactory()) {
TypeArguments& class_types =
TypeArguments::Handle(zone, klass->type_parameters());
return class_types.Length();
return klass->NumTypeParameters();
} else if (member->IsMethodExtractor()) {
Function& extracted =
Function::Handle(zone, member->extracted_method_closure());
TypeArguments& function_types =
TypeArguments::Handle(zone, extracted.type_parameters());
return function_types.Length();
return extracted.NumTypeParameters();
} else {
TypeArguments& function_types =
TypeArguments::Handle(zone, member->type_parameters());
return function_types.Length();
return member->NumTypeParameters();
}
}
@ -2937,17 +2942,15 @@ ActiveTypeParametersScope::ActiveTypeParametersScope(
const Function& innermost,
const FunctionType* innermost_signature,
Zone* Z)
: active_class_(active_class), saved_(*active_class) {
: active_class_(active_class), saved_(*active_class), zone_(Z) {
active_class_->enclosing = innermost_signature;
intptr_t num_params = 0;
Function& f = Function::Handle(Z);
TypeArguments& f_params = TypeArguments::Handle(Z);
for (f = innermost.ptr(); f.parent_function() != Object::null();
f = f.parent_function()) {
f_params = f.type_parameters();
num_params += f_params.Length();
num_params += f.NumTypeParameters();
}
if (num_params == 0) return;
@ -2957,9 +2960,10 @@ ActiveTypeParametersScope::ActiveTypeParametersScope(
intptr_t index = num_params;
for (f = innermost.ptr(); f.parent_function() != Object::null();
f = f.parent_function()) {
f_params = f.type_parameters();
for (intptr_t j = f_params.Length() - 1; j >= 0; --j) {
params.SetTypeAt(--index, AbstractType::Handle(Z, f_params.TypeAt(j)));
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);
}
}
@ -2969,32 +2973,55 @@ ActiveTypeParametersScope::ActiveTypeParametersScope(
ActiveTypeParametersScope::ActiveTypeParametersScope(
ActiveClass* active_class,
const FunctionType* innermost_signature,
const TypeArguments& new_params,
Zone* Z)
: active_class_(active_class), saved_(*active_class) {
: active_class_(active_class), saved_(*active_class), zone_(Z) {
active_class_->enclosing = innermost_signature;
if (new_params.IsNull()) return;
const intptr_t num_new_params =
innermost_signature == nullptr ? active_class->klass->NumTypeParameters()
: innermost_signature->NumTypeParameters();
if (num_new_params == 0) return;
const TypeArguments* old_params = active_class->local_type_parameters;
const intptr_t old_param_count =
old_params == NULL ? 0 : old_params->Length();
const TypeArguments& extended_params = TypeArguments::Handle(
Z, TypeArguments::New(old_param_count + new_params.Length()));
Z, TypeArguments::New(old_param_count + num_new_params));
intptr_t index = 0;
for (intptr_t i = 0; i < old_param_count; ++i) {
extended_params.SetTypeAt(
index++, AbstractType::ZoneHandle(Z, old_params->TypeAt(i)));
extended_params.SetTypeAt(index++,
AbstractType::Handle(Z, old_params->TypeAt(i)));
}
for (intptr_t i = 0; i < new_params.Length(); ++i) {
extended_params.SetTypeAt(
index++, AbstractType::ZoneHandle(Z, new_params.TypeAt(i)));
for (intptr_t i = 0; i < num_new_params; ++i) {
const auto& type_param =
TypeParameter::Handle(Z, innermost_signature == nullptr
? 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,
ConstantReader* constant_reader,
ActiveClass* active_class,
@ -3135,14 +3162,12 @@ void TypeTranslator::BuildFunctionType(bool simple) {
if (!simple) {
type_parameter_count = helper_->ReadListLength();
LoadAndSetupTypeParameters(
active_class_, Object::null_function(), Object::null_class(), signature,
type_parameter_count, active_class_->klass->nnbd_mode());
LoadAndSetupTypeParameters(active_class_, Object::null_function(),
Object::null_class(), signature,
type_parameter_count);
}
ActiveTypeParametersScope scope(
active_class_, &signature,
TypeArguments::Handle(Z, signature.type_parameters()), Z);
ActiveTypeParametersScope scope(active_class_, &signature, Z);
if (!simple) {
LoadAndSetupBounds(active_class_, Object::null_function(),
@ -3230,19 +3255,16 @@ void TypeTranslator::BuildTypeParameterType() {
// If the type is from a constant, the parameter index isn't offset by the
// enclosing context.
if (!in_constant_context_) {
const TypeArguments& class_types =
TypeArguments::Handle(Z, active_class_->klass->type_parameters());
if (parameter_index < class_types.Length()) {
// The index of the type parameter in [parameters] is
// the same index into the `klass->type_parameters()` array.
const auto& type_param =
TypeParameter::CheckedHandle(Z, class_types.TypeAt(parameter_index));
result_ = type_param.ToNullability(nullability, Heap::kOld);
active_class_->RecordDerivedTypeParameter(Z, type_param,
const intptr_t class_type_parameter_count =
active_class_->klass->NumTypeParameters();
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_types.Length();
parameter_index -= class_type_parameter_count;
if (active_class_->HasMember()) {
if (active_class_->MemberIsFactoryProcedure()) {
@ -3263,33 +3285,32 @@ void TypeTranslator::BuildTypeParameterType() {
// static A.x<T'>() { return new B<T'>(); }
// }
//
if (class_types.Length() > parameter_index) {
const auto& type_param = TypeParameter::CheckedHandle(
Z, class_types.TypeAt(parameter_index));
result_ = type_param.ToNullability(nullability, Heap::kOld);
if (class_type_parameter_count > parameter_index) {
result_ = active_class_->klass->TypeParameterAt(parameter_index,
nullability);
active_class_->RecordDerivedTypeParameter(
Z, type_param, TypeParameter::Cast(result_));
Z, TypeParameter::Cast(result_));
return;
}
parameter_index -= class_types.Length();
parameter_index -= class_type_parameter_count;
}
// Factory function should not be considered as procedure.
intptr_t procedure_type_parameter_count =
const intptr_t procedure_type_parameter_count =
(active_class_->MemberIsProcedure() &&
!active_class_->MemberIsFactoryProcedure())
? active_class_->MemberTypeParameterCount(Z)
: 0;
if (procedure_type_parameter_count > 0) {
if (procedure_type_parameter_count > parameter_index) {
const auto& type_param = TypeParameter::CheckedHandle(
Z,
TypeArguments::Handle(Z, active_class_->member->type_parameters())
.TypeAt(parameter_index));
result_ = type_param.ToNullability(nullability, Heap::kOld);
active_class_->RecordDerivedTypeParameter(
Z, type_param, TypeParameter::Cast(result_));
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;
}
@ -3302,10 +3323,12 @@ void TypeTranslator::BuildTypeParameterType() {
const auto& type_param = TypeParameter::CheckedHandle(
Z, active_class_->local_type_parameters->TypeAt(parameter_index));
result_ = type_param.ToNullability(nullability, Heap::kOld);
active_class_->RecordDerivedTypeParameter(Z, type_param,
TypeParameter::Cast(result_));
if (finalize_) {
ASSERT(TypeParameter::Cast(result_).bound() != AbstractType::null());
result_ = ClassFinalizer::FinalizeType(result_);
} else {
active_class_->RecordDerivedTypeParameter(Z,
TypeParameter::Cast(result_));
}
return;
}
@ -3381,8 +3404,7 @@ void TypeTranslator::LoadAndSetupTypeParameters(
const Function& function,
const Class& parameterized_class,
const FunctionType& parameterized_signature,
intptr_t type_parameter_count,
const NNBDMode nnbd_mode) {
intptr_t type_parameter_count) {
ASSERT(parameterized_class.IsNull() != parameterized_signature.IsNull());
ASSERT(type_parameter_count >= 0);
if (type_parameter_count == 0) {
@ -3398,23 +3420,18 @@ void TypeTranslator::LoadAndSetupTypeParameters(
// First setup the type parameters, so if any of the following code uses it
// (in a recursive way) we're fine.
TypeArguments& type_parameters = TypeArguments::Handle(Z);
TypeParameter& parameter = TypeParameter::Handle(Z);
// - Create a [ TypeParameters ] object.
const TypeParameters& type_parameters =
TypeParameters::Handle(Z, TypeParameters::New(type_parameter_count));
const Type& null_bound = Type::Handle(Z);
const Nullability nullability = (nnbd_mode == NNBDMode::kOptedInLib)
? Nullability::kNonNullable
: Nullability::kLegacy;
// - Create array of [TypeParameter] objects (without bound).
// - Create array of [String] objects.
type_parameters = TypeArguments::New(type_parameter_count);
intptr_t offset = 0;
if (!parameterized_class.IsNull()) {
ASSERT(parameterized_class.type_parameters() == TypeArguments::null());
ASSERT(parameterized_class.type_parameters() == TypeParameters::null());
parameterized_class.set_type_parameters(type_parameters);
} else {
ASSERT(parameterized_signature.type_parameters() == TypeArguments::null());
ASSERT(parameterized_signature.type_parameters() == TypeParameters::null());
parameterized_signature.set_type_parameters(type_parameters);
offset = parameterized_signature.NumParentTypeArguments();
if (!function.IsNull()) {
@ -3425,22 +3442,15 @@ void TypeTranslator::LoadAndSetupTypeParameters(
const Library& lib = Library::Handle(Z, active_class->klass->library());
{
AlternativeReadingScope alt(&helper_->reader_);
String& name = String::Handle(Z);
for (intptr_t i = 0; i < type_parameter_count; i++) {
TypeParameterHelper helper(helper_);
helper.Finish();
if (parameterized_class.IsNull() && function.IsNull()) {
// Erase provided name and use a canonical one instead.
name = Symbols::NewFormatted(H.thread(), "X%" Pd, offset + i);
} else {
name = H.DartIdentifier(lib, helper.name_index_).ptr();
}
type_parameters.SetNameAt(i, H.DartIdentifier(lib, helper.name_index_));
type_parameters.SetIsGenericCovariantImplAt(
i, helper.IsGenericCovariantImpl());
// Bounds are filled later in LoadAndSetupBounds as bound types may
// reference type parameters which are not created yet.
parameter = TypeParameter::New(
parameterized_class, offset, offset + i, name, null_bound,
helper.IsGenericCovariantImpl(), nullability);
type_parameters.SetTypeAt(i, parameter);
type_parameters.SetBoundAt(i, null_bound);
}
}
}
@ -3457,52 +3467,45 @@ void TypeTranslator::LoadAndSetupBounds(
return;
}
const TypeArguments& type_parameters =
TypeArguments::Handle(Z, !parameterized_class.IsNull()
? parameterized_class.type_parameters()
: parameterized_signature.type_parameters());
TypeParameter& parameter = TypeParameter::Handle(Z);
const TypeParameters& type_parameters = TypeParameters::Handle(
Z, !parameterized_class.IsNull()
? parameterized_class.type_parameters()
: parameterized_signature.type_parameters());
// Fill in the bounds and default arguments of all [TypeParameter]s.
for (intptr_t i = 0; i < type_parameter_count; i++) {
TypeParameterHelper helper(helper_);
helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kBound);
parameter ^= type_parameters.TypeAt(i);
AbstractType& bound = BuildTypeWithoutFinalization(); // read ith bound.
parameter.set_bound(bound);
ASSERT(!bound.IsNull());
type_parameters.SetBoundAt(i, bound);
helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kDefaultType);
AbstractType& default_arg = BuildTypeWithoutFinalization();
parameter.set_default_argument(default_arg);
ASSERT(!default_arg.IsNull());
type_parameters.SetDefaultAt(i, default_arg);
helper.Finish();
}
// Note that function.UpdateCachedDefaultTypeArguments() is called in
// function.set_signature() and is not required here.
// Fix bounds and default arguments in all derived type parameters (with
// different nullabilities).
// 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& type = AbstractType::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() == parameterized_class.ptr()) ||
derived.parameterized_class_id() == parameterized_class.id()) ||
(!parameterized_signature.IsNull() &&
derived.parameterized_class() == Class::null() &&
derived.parameterized_class_id() == kFunctionCid &&
derived.index() >= offset &&
derived.index() < offset + type_parameter_count))) {
parameter ^= type_parameters.TypeAt(derived.index() - offset);
type = parameter.bound();
derived.set_bound(type);
type = parameter.default_argument();
derived.set_default_argument(type);
bound = type_parameters.BoundAt(derived.index() - offset);
derived.set_bound(bound);
}
}
}
@ -3516,8 +3519,18 @@ const Type& TypeTranslator::ReceiverType(const Class& klass) {
if (finalize_ || klass.is_type_finalized()) {
type = klass.DeclarationType();
} else {
type = Type::New(klass, TypeArguments::Handle(Z, klass.type_parameters()),
Nullability::kNonNullable);
TypeArguments& type_args = TypeArguments::Handle(Z);
const intptr_t num_type_params = klass.NumTypeParameters();
if (num_type_params > 0) {
type_args = TypeArguments::New(num_type_params);
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);
}
}
type = Type::New(klass, type_args, Nullability::kNonNullable);
}
return type;
}
@ -3631,8 +3644,8 @@ void TypeTranslator::SetupFunctionParameters(
if (!is_factory) {
type_parameter_count = helper_->ReadListLength();
LoadAndSetupTypeParameters(active_class_, function, Class::Handle(Z),
signature, type_parameter_count,
function.nnbd_mode());
signature, type_parameter_count);
function_node_helper->SetJustRead(FunctionNodeHelper::kTypeParameters);
}
ActiveTypeParametersScope scope(active_class_, function, &signature, Z);

View file

@ -1344,11 +1344,8 @@ class ActiveClass {
return klass->NumTypeArguments();
}
void RecordDerivedTypeParameter(Zone* zone,
const TypeParameter& original,
const TypeParameter& derived) {
if (original.ptr() != derived.ptr() &&
original.bound() == AbstractType::null()) {
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));
@ -1442,14 +1439,14 @@ class ActiveTypeParametersScope {
// Also, the enclosing signature is set to 'signature'.
ActiveTypeParametersScope(ActiveClass* active_class,
const FunctionType* innermost_signature,
const TypeArguments& new_params,
Zone* Z);
~ActiveTypeParametersScope() { *active_class_ = saved_; }
~ActiveTypeParametersScope();
private:
ActiveClass* active_class_;
ActiveClass saved_;
Zone* zone_;
DISALLOW_COPY_AND_ASSIGN(ActiveTypeParametersScope);
};
@ -1476,8 +1473,7 @@ class TypeTranslator {
const Function& function,
const Class& parameterized_class,
const FunctionType& parameterized_signature,
intptr_t type_parameter_count,
const NNBDMode nnbd_mode);
intptr_t type_parameter_count);
void LoadAndSetupBounds(ActiveClass* active_class,
const Function& function,

View file

@ -1180,6 +1180,10 @@ word Field::NextFieldOffset() {
return -kWordSize;
}
word TypeParameters::NextFieldOffset() {
return -kWordSize;
}
word TypeArguments::NextFieldOffset() {
return -kWordSize;
}

View file

@ -922,7 +922,6 @@ class TypeParameter : public AllStatic {
public:
static word bound_offset();
static word flags_offset();
static word name_offset();
static word InstanceSize();
static word NextFieldOffset();
static word parameterized_class_id_offset();
@ -1303,7 +1302,6 @@ class Closure : public AllStatic {
class ClosureData : public AllStatic {
public:
static word default_type_arguments_offset();
static word default_type_arguments_kind_offset();
static word InstanceSize();
static word NextFieldOffset();
@ -1373,6 +1371,16 @@ class Field : public AllStatic {
static word NextFieldOffset();
};
class TypeParameters : public AllStatic {
public:
static word names_offset();
static word flags_offset();
static word bounds_offset();
static word defaults_offset();
static word InstanceSize();
static word NextFieldOffset();
};
class TypeArguments : public AllStatic {
public:
static word instantiations_offset();

File diff suppressed because it is too large Load diff

View file

@ -110,7 +110,6 @@
FIELD(Closure, function_type_arguments_offset) \
FIELD(Closure, hash_offset) \
FIELD(Closure, instantiator_type_arguments_offset) \
FIELD(ClosureData, default_type_arguments_offset) \
FIELD(ClosureData, default_type_arguments_kind_offset) \
FIELD(Code, object_pool_offset) \
FIELD(Code, saved_instructions_offset) \
@ -301,9 +300,12 @@
FIELD(TypeArguments, length_offset) \
FIELD(TypeArguments, nullability_offset) \
FIELD(TypeArguments, types_offset) \
FIELD(TypeParameters, names_offset) \
FIELD(TypeParameters, flags_offset) \
FIELD(TypeParameters, bounds_offset) \
FIELD(TypeParameters, defaults_offset) \
FIELD(TypeParameter, bound_offset) \
FIELD(TypeParameter, flags_offset) \
FIELD(TypeParameter, name_offset) \
FIELD(TypeRef, type_offset) \
FIELD(TypedDataBase, length_offset) \
FIELD(TypedDataView, data_offset) \
@ -384,6 +386,7 @@
SIZEOF(TransferableTypedData, InstanceSize, UntaggedTransferableTypedData) \
SIZEOF(Type, InstanceSize, UntaggedType) \
SIZEOF(TypeParameter, InstanceSize, UntaggedTypeParameter) \
SIZEOF(TypeParameters, InstanceSize, UntaggedTypeParameters) \
SIZEOF(TypeRef, InstanceSize, UntaggedTypeRef) \
SIZEOF(TypedData, HeaderSize, UntaggedTypedData) \
SIZEOF(TypedDataBase, InstanceSize, UntaggedTypedDataBase) \

View file

@ -482,7 +482,8 @@ static void GenerateNullIsAssignableToType(Assembler* assembler,
__ BranchIf(EQUAL, &is_assignable, Assembler::kNearJump);
// Resolve the type parameter to its instantiated type and loop.
__ LoadFieldFromOffset(kIndexReg, kCurrentTypeReg,
target::TypeParameter::index_offset(), kTwoBytes);
target::TypeParameter::index_offset(),
kUnsignedByte);
__ LoadIndexedCompressed(kCurrentTypeReg, tav,
target::TypeArguments::types_offset(),
kIndexReg);
@ -597,7 +598,8 @@ static void BuildTypeParameterTypeTestStub(Assembler* assembler,
// Resolve the type parameter to its instantiated type and tail call the
// instantiated type's TTS.
__ LoadFieldFromOffset(TypeTestABI::kScratchReg, TypeTestABI::kDstTypeReg,
target::TypeParameter::index_offset(), kTwoBytes);
target::TypeParameter::index_offset(),
kUnsignedByte);
__ LoadIndexedCompressed(TypeTestABI::kScratchReg, tav,
target::TypeArguments::types_offset(),
TypeTestABI::kScratchReg);

View file

@ -1328,20 +1328,19 @@ TypeArgumentsPtr ActivationFrame::BuildParameters(
intptr_t num_vars = function().NumTypeArguments();
type_params_names.Grow(num_vars);
type_params_names.SetLength(num_vars);
TypeArguments& type_params = TypeArguments::Handle();
TypeParameter& type_param = TypeParameter::Handle();
TypeParameters& type_params = TypeParameters::Handle();
Function& current = Function::Handle(function().ptr());
intptr_t mapping_offset = num_vars;
for (intptr_t i = 0; !current.IsNull(); i += current.NumTypeParameters(),
current = current.parent_function()) {
type_params = current.type_parameters();
if (type_params.IsNull()) continue;
intptr_t size = current.NumTypeParameters();
ASSERT(size == 0 || type_params.Length() == size);
ASSERT(size > 0 && type_params.Length() == size);
ASSERT(mapping_offset >= size);
mapping_offset -= size;
for (intptr_t j = 0; j < size; ++j) {
type_param = TypeParameter::RawCast(type_params.TypeAt(j));
name = type_param.name();
name = type_params.NameAt(j);
// Write the names in backwards in terms of chain of functions.
// But keep the order of names within the same function. so they
// match up with the order of the types in 'type_arguments'.

View file

@ -703,15 +703,13 @@ bool NeedsDynamicInvocationForwarder(const Function& function) {
}
const auto& type_params =
TypeArguments::Handle(zone, function.type_parameters());
TypeParameters::Handle(zone, function.type_parameters());
if (!type_params.IsNull()) {
auto& type_param = TypeParameter::Handle(zone);
auto& bound = AbstractType::Handle(zone);
for (intptr_t i = 0, n = type_params.Length(); i < n; ++i) {
type_param ^= type_params.TypeAt(i);
bound = type_param.bound();
bound = type_params.BoundAt(i);
if (!bound.IsTopTypeForSubtyping() &&
!type_param.IsGenericCovariantImpl()) {
!type_params.IsGenericCovariantImplAt(i)) {
return true;
}
}

View file

@ -830,6 +830,18 @@ ObjectPtr KernelLoader::LoadExpressionEvaluationFunction(
function.set_owner(real_class);
ASSERT(real_class.is_finalized());
// The owner class has already been marked as finalized so the signature of
// this added function must be finalized here, since finalization of member
// types will not be called anymore.
FunctionType& signature = FunctionType::Handle(Z, function.signature());
if (!function.is_static()) {
// Patch the illegal receiver type (type class with kIllegalCid) to dynamic.
signature.SetParameterTypeAt(0, Object::dynamic_type());
}
signature ^= ClassFinalizer::FinalizeType(signature);
function.set_signature(signature);
return function.ptr();
}
@ -1425,7 +1437,9 @@ void KernelLoader::LoadPreliminaryClass(ClassHelper* class_helper,
// Set type parameters.
T.LoadAndSetupTypeParameters(&active_class_, Object::null_function(), *klass,
Object::null_function_type(),
type_parameter_count, klass->nnbd_mode());
type_parameter_count);
ActiveTypeParametersScope scope(&active_class_, nullptr, Z);
T.LoadAndSetupBounds(&active_class_, Object::null_function(), *klass,
Object::null_function_type(), type_parameter_count);

File diff suppressed because it is too large Load diff

View file

@ -460,6 +460,7 @@ class Object {
static ClassPtr class_class() { return class_class_; }
static ClassPtr dynamic_class() { return dynamic_class_; }
static ClassPtr void_class() { return void_class_; }
static ClassPtr type_parameters_class() { return type_parameters_class_; }
static ClassPtr type_arguments_class() { return type_arguments_class_; }
static ClassPtr patch_class_class() { return patch_class_class_; }
static ClassPtr function_class() { return function_class_; }
@ -774,13 +775,14 @@ class Object {
static BoolPtr true_;
static BoolPtr false_;
static ClassPtr class_class_; // Class of the Class vm object.
static ClassPtr dynamic_class_; // Class of the 'dynamic' type.
static ClassPtr void_class_; // Class of the 'void' type.
static ClassPtr type_arguments_class_; // Class of TypeArguments vm object.
static ClassPtr patch_class_class_; // Class of the PatchClass vm object.
static ClassPtr function_class_; // Class of the Function vm object.
static ClassPtr closure_data_class_; // Class of ClosureData vm obj.
static ClassPtr class_class_; // Class of the Class vm object.
static ClassPtr dynamic_class_; // Class of the 'dynamic' type.
static ClassPtr void_class_; // Class of the 'void' type.
static ClassPtr type_parameters_class_; // Class of TypeParameters vm object.
static ClassPtr type_arguments_class_; // Class of TypeArguments vm object.
static ClassPtr patch_class_class_; // Class of the PatchClass vm object.
static ClassPtr function_class_; // Class of the Function vm object.
static ClassPtr closure_data_class_; // Class of ClosureData vm obj.
static ClassPtr ffi_trampoline_data_class_; // Class of FfiTrampolineData
// vm obj.
static ClassPtr field_class_; // Class of the Field vm object.
@ -1103,21 +1105,22 @@ class Class : public Object {
LibraryPtr library() const { return untag()->library(); }
void set_library(const Library& value) const;
// The type parameters (and their bounds) are specified as an array of
// TypeParameter.
TypeArgumentsPtr type_parameters() const {
// The formal type parameters and their bounds (no defaults), are specified as
// an object of type TypeParameters.
TypeParametersPtr type_parameters() const {
ASSERT(is_declaration_loaded());
return untag()->type_parameters();
}
void set_type_parameters(const TypeArguments& value) const;
void set_type_parameters(const TypeParameters& value) const;
intptr_t NumTypeParameters(Thread* thread) const;
intptr_t NumTypeParameters() const {
return NumTypeParameters(Thread::Current());
}
// Return a TypeParameter if the type_name is a type parameter of this class.
// Return null otherwise.
TypeParameterPtr LookupTypeParameter(const String& type_name) const;
// Return the type parameter declared at index.
TypeParameterPtr TypeParameterAt(
intptr_t index,
Nullability nullability = Nullability::kNonNullable) const;
// The type argument vector is flattened and includes the type arguments of
// the super class.
@ -2614,9 +2617,9 @@ class Function : public Object {
// are packed into SMIs, but omitted if they're 0.
bool IsRequiredAt(intptr_t index) const;
// The type parameters (and their bounds) are specified as an array of
// TypeParameter stored in the signature. They are part of the function type.
TypeArgumentsPtr type_parameters() const {
// The formal type parameters, their bounds, and defaults, are specified as an
// object of type TypeParameters stored in the signature.
TypeParametersPtr type_parameters() const {
return untag()->signature()->untag()->type_parameters();
}
@ -2635,12 +2638,10 @@ class Function : public Object {
return NumParentTypeArguments() + NumTypeParameters();
}
// Return a TypeParameter if the type_name is a type parameter of this
// function or of one of its parent functions.
// Unless NULL, adjust function_level accordingly (in and out parameter).
// Return null otherwise.
TypeParameterPtr LookupTypeParameter(const String& type_name,
intptr_t* function_level) const;
// Return the type parameter declared at index.
TypeParameterPtr TypeParameterAt(
intptr_t index,
Nullability nullability = Nullability::kNonNullable) const;
// Return true if this function declares type parameters.
// Generic dispatchers only set the number without actual type parameters.
@ -2735,21 +2736,9 @@ class Function : public Object {
Thread* thread,
DefaultTypeArgumentsKind* kind_out = nullptr) const;
// Whether this function should have a cached type arguments vector for the
// instantiated-to-bounds version of the type parameters.
bool CachesDefaultTypeArguments() const { return IsClosureFunction(); }
// Updates the cached default type arguments vector for this function if it
// caches and for its implicit closure function if it has one. If the
// default arguments are all canonical, the cached default type arguments
// vector is canonicalized. Should be run any time the type parameters vector
// is changed or if the default arguments of any type parameters are updated.
void UpdateCachedDefaultTypeArguments(Thread* thread) const;
// These are only usable for functions that cache the default type arguments.
TypeArgumentsPtr default_type_arguments(
DefaultTypeArgumentsKind* kind_out = nullptr) const;
void set_default_type_arguments(const TypeArguments& value) const;
// Only usable for closure functions.
DefaultTypeArgumentsKind default_type_arguments_kind() const;
void set_default_type_arguments_kind(DefaultTypeArgumentsKind value) const;
// Enclosing outermost function of this local function.
FunctionPtr GetOutermostFunction() const;
@ -3787,9 +3776,6 @@ class ClosureData : public Object {
return RoundedAllocationSize(sizeof(UntaggedClosureData));
}
static intptr_t default_type_arguments_offset() {
return OFFSET_OF(UntaggedClosureData, default_type_arguments_);
}
static intptr_t default_type_arguments_kind_offset() {
return OFFSET_OF(UntaggedClosureData, default_type_arguments_kind_);
}
@ -3816,11 +3802,6 @@ class ClosureData : public Object {
}
void set_implicit_static_closure(const Instance& closure) const;
TypeArgumentsPtr default_type_arguments() const {
return untag()->default_type_arguments();
}
void set_default_type_arguments(const TypeArguments& value) const;
DefaultTypeArgumentsKind default_type_arguments_kind() const;
void set_default_type_arguments_kind(DefaultTypeArgumentsKind value) const;
@ -4222,7 +4203,7 @@ class Field : public Object {
// Returns false if any value read from this field is guaranteed to be
// not null.
// Internally we is_nullable_ field contains either kNullCid (nullable) or
// kInvalidCid (non-nullable) instead of boolean. This is done to simplify
// kIllegalCid (non-nullable) instead of boolean. This is done to simplify
// guarding sequence in the generated code.
bool is_nullable() const;
void set_is_nullable(bool val) const {
@ -7483,6 +7464,90 @@ class LibraryPrefix : public Instance {
friend class Class;
};
// TypeParameters represents a list of formal type parameters with their bounds
// and their default values as calculated by CFE.
class TypeParameters : public Object {
public:
intptr_t Length() const;
static intptr_t names_offset() {
return OFFSET_OF(UntaggedTypeParameters, names_);
}
StringPtr NameAt(intptr_t index) const;
void SetNameAt(intptr_t index, const String& value) const;
static intptr_t flags_offset() {
return OFFSET_OF(UntaggedTypeParameters, flags_);
}
static intptr_t bounds_offset() {
return OFFSET_OF(UntaggedTypeParameters, bounds_);
}
AbstractTypePtr BoundAt(intptr_t index) const;
void SetBoundAt(intptr_t index, const AbstractType& value) const;
bool AllDynamicBounds() const;
static intptr_t defaults_offset() {
return OFFSET_OF(UntaggedTypeParameters, defaults_);
}
AbstractTypePtr DefaultAt(intptr_t index) const;
void SetDefaultAt(intptr_t index, const AbstractType& value) const;
bool AllDynamicDefaults() const;
// The isGenericCovariantImpl bits are packed into SMIs in the flags array,
// but omitted if they're 0.
bool IsGenericCovariantImplAt(intptr_t index) const;
void SetIsGenericCovariantImplAt(intptr_t index, bool value) const;
// The number of flags per Smi should be a power of 2 in order to simplify the
// generated code accessing the flags array.
#if !defined(DART_COMPRESSED_POINTERS)
static const intptr_t kFlagsPerSmiShift = kBitsPerWordLog2 - 1;
#else
static const intptr_t kFlagsPerSmiShift = kBitsPerWordLog2 - 2;
#endif
static const intptr_t kFlagsPerSmi = 1LL << kFlagsPerSmiShift;
COMPILE_ASSERT(kFlagsPerSmi < kSmiBits);
static const intptr_t kFlagsPerSmiMask = kFlagsPerSmi - 1;
void Print(Thread* thread,
Zone* zone,
bool are_class_type_parameters,
intptr_t base,
NameVisibility name_visibility,
BaseTextBuffer* printer) const;
static intptr_t InstanceSize() {
return RoundedAllocationSize(sizeof(UntaggedTypeParameters));
}
static TypeParametersPtr New(Heap::Space space = Heap::kOld);
static TypeParametersPtr New(intptr_t count, Heap::Space space = Heap::kOld);
private:
ArrayPtr names() const { return untag()->names(); }
void set_names(const Array& value) const;
ArrayPtr flags() const { return untag()->flags(); }
void set_flags(const Array& value) const;
TypeArgumentsPtr bounds() const { return untag()->bounds(); }
void set_bounds(const TypeArguments& value) const;
TypeArgumentsPtr defaults() const { return untag()->defaults(); }
void set_defaults(const TypeArguments& value) const;
// Allocate and initialize the flags array to zero.
void AllocateFlags(Heap::Space space) const;
// Reset the flags array to null if all flags are zero.
void OptimizeFlags() const;
FINAL_HEAP_OBJECT_IMPLEMENTATION(TypeParameters, Object);
friend class Class;
friend class ClassFinalizer;
friend class Function;
friend class FunctionType;
friend class Object;
friend class Precompiler;
};
// A TypeArguments is an array of AbstractType.
class TypeArguments : public Instance {
public:
@ -8307,6 +8372,8 @@ class FunctionType : public AbstractType {
}
// Reexported so they can be used by the flow graph builders.
using PackedNumParentTypeArguments =
UntaggedFunctionType::PackedNumParentTypeArguments;
using PackedHasNamedOptionalParameters =
UntaggedFunctionType::PackedHasNamedOptionalParameters;
using PackedNumFixedParameters =
@ -8314,6 +8381,11 @@ class FunctionType : public AbstractType {
using PackedNumOptionalParameters =
UntaggedFunctionType::PackedNumOptionalParameters;
// Return the type parameter declared at index.
TypeParameterPtr TypeParameterAt(
intptr_t index,
Nullability nullability = Nullability::kNonNullable) const;
AbstractTypePtr result_type() const { return untag()->result_type(); }
void set_result_type(const AbstractType& value) const;
@ -8369,12 +8441,12 @@ class FunctionType : public AbstractType {
// parameters don't have flags.
static intptr_t NameArrayLengthIncludingFlags(intptr_t num_parameters);
// The type parameters (and their bounds) are specified as an array of
// TypeParameter.
TypeArgumentsPtr type_parameters() const {
// The formal type parameters, their bounds, and defaults, are specified as an
// object of type TypeParameters.
TypeParametersPtr type_parameters() const {
return untag()->type_parameters();
}
void set_type_parameters(const TypeArguments& value) const;
void set_type_parameters(const TypeParameters& value) const;
static intptr_t type_parameters_offset() {
return OFFSET_OF(UntaggedFunctionType, type_parameters_);
}
@ -8536,11 +8608,6 @@ class TypeParameter : public AbstractType {
return UntaggedTypeParameter::BeingFinalizedBit::decode(untag()->flags_);
}
virtual void SetIsBeingFinalized() const;
bool IsGenericCovariantImpl() const {
return UntaggedTypeParameter::GenericCovariantImplBit::decode(
untag()->flags_);
}
void SetGenericCovariantImpl(bool value) const;
static intptr_t flags_offset() {
return OFFSET_OF(UntaggedTypeParameter, flags_);
}
@ -8575,21 +8642,12 @@ class TypeParameter : public AbstractType {
return OFFSET_OF(UntaggedTypeParameter, index_);
}
StringPtr name() const { return untag()->name(); }
static intptr_t name_offset() {
return OFFSET_OF(UntaggedTypeParameter, name_);
}
AbstractTypePtr bound() const { return untag()->bound(); }
void set_bound(const AbstractType& value) const;
static intptr_t bound_offset() {
return OFFSET_OF(UntaggedTypeParameter, bound_);
}
AbstractTypePtr default_argument() const {
return untag()->default_argument();
}
void set_default_argument(const AbstractType& value) const;
virtual bool IsInstantiated(Genericity genericity = kAny,
intptr_t num_free_fun_type_params = kAllFree,
TrailPtr trail = nullptr) const;
@ -8625,6 +8683,15 @@ class TypeParameter : public AbstractType {
const TypeArguments& instantiator_type_arguments,
const TypeArguments& function_type_arguments) const;
// Return a constructed name for this nameless type parameter.
const char* CanonicalNameCString() const {
return CanonicalNameCString(IsClassTypeParameter(), base(), index());
}
static const char* CanonicalNameCString(bool is_class_type_parameter,
intptr_t base,
intptr_t index);
static intptr_t InstanceSize() {
return RoundedAllocationSize(sizeof(UntaggedTypeParameter));
}
@ -8633,9 +8700,7 @@ class TypeParameter : public AbstractType {
static TypeParameterPtr New(const Class& parameterized_class,
intptr_t base,
intptr_t index,
const String& name,
const AbstractType& bound,
bool is_generic_covariant_impl,
Nullability nullability);
private:
@ -8993,6 +9058,8 @@ 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);

View file

@ -169,6 +169,15 @@ void Class::PrintJSONImpl(JSONStream* stream, bool ref) const {
}
}
void TypeParameters::PrintJSONImpl(JSONStream* stream, bool ref) const {
JSONObject jsobj(stream);
jsobj.AddProperty("kind", "TypeParameters");
jsobj.AddProperty("flags", Array::Handle(flags()));
jsobj.AddProperty("names", Array::Handle(names()));
jsobj.AddProperty("bounds", TypeArguments::Handle(bounds()));
jsobj.AddProperty("defaults", TypeArguments::Handle(defaults()));
}
void TypeArguments::PrintJSONImpl(JSONStream* stream, bool ref) const {
JSONObject jsobj(stream);
// The index in the canonical_type_arguments table cannot be used as part of

View file

@ -244,6 +244,7 @@ class ParsedFunction : public ZoneAllocated {
V(current_function, Function, CurrentFunction) \
V(current_num_processed, Smi, CurrentNumProcessed) \
V(current_param_index, Smi, CurrentParamIndex) \
V(current_type_param, Dynamic, CurrentTypeParam) \
V(function_type_args, Dynamic, FunctionTypeArgs)
#define DEFINE_FIELD(Name, _, __) LocalVariable* Name = nullptr;

View file

@ -572,6 +572,7 @@ COMPRESSED_VISITOR(MirrorReference)
COMPRESSED_VISITOR(UserTag)
REGULAR_VISITOR(SubtypeTestCache)
COMPRESSED_VISITOR(LoadingUnit)
COMPRESSED_VISITOR(TypeParameters)
VARIABLE_COMPRESSED_VISITOR(TypeArguments,
Smi::Value(raw_obj->untag()->length()))
VARIABLE_COMPRESSED_VISITOR(LocalVarDescriptors, raw_obj->untag()->num_entries_)

View file

@ -954,8 +954,7 @@ class UntaggedClass : public UntaggedObject {
COMPRESSED_POINTER_FIELD(ArrayPtr, interfaces) // Array of AbstractType.
COMPRESSED_POINTER_FIELD(ScriptPtr, script)
COMPRESSED_POINTER_FIELD(LibraryPtr, library)
// Array of TypeParameter.
COMPRESSED_POINTER_FIELD(TypeArgumentsPtr, type_parameters)
COMPRESSED_POINTER_FIELD(TypeParametersPtr, type_parameters)
COMPRESSED_POINTER_FIELD(AbstractTypePtr, super_type)
// Canonicalized const instances of this class.
COMPRESSED_POINTER_FIELD(ArrayPtr, constants)
@ -1358,9 +1357,7 @@ class UntaggedClosureData : public UntaggedObject {
#endif
// Closure object for static implicit closures.
COMPRESSED_POINTER_FIELD(InstancePtr, closure)
// Instantiate-to-bounds TAV for use when no TAV is provided.
COMPRESSED_POINTER_FIELD(TypeArgumentsPtr, default_type_arguments)
VISIT_TO(CompressedObjectPtr, default_type_arguments)
VISIT_TO(CompressedObjectPtr, closure)
enum class DefaultTypeArgumentsKind : uint8_t {
// Only here to make sure it's explicitly set appropriately.
@ -1458,7 +1455,7 @@ class UntaggedField : public UntaggedObject {
TokenPosition end_token_pos_;
ClassIdTagType guarded_cid_;
ClassIdTagType is_nullable_; // kNullCid if field can contain null value and
// kInvalidCid otherwise.
// kIllegalCid otherwise.
#if !defined(DART_PRECOMPILED_RUNTIME)
uint32_t kernel_offset_;
@ -2503,6 +2500,25 @@ class UntaggedTypeArguments : public UntaggedInstance {
friend class SnapshotReader;
};
class UntaggedTypeParameters : public UntaggedObject {
private:
RAW_HEAP_OBJECT_IMPLEMENTATION(TypeParameters);
VISIT_FROM(CompressedObjectPtr, names)
// Length of names reflects the number of type parameters.
COMPRESSED_POINTER_FIELD(ArrayPtr, names)
// flags: isGenericCovariantImpl and (todo) variance.
COMPRESSED_POINTER_FIELD(ArrayPtr, flags)
COMPRESSED_POINTER_FIELD(TypeArgumentsPtr, bounds)
// defaults is the instantiation to bounds (calculated by CFE).
COMPRESSED_POINTER_FIELD(TypeArgumentsPtr, defaults)
VISIT_TO(CompressedObjectPtr, defaults)
CompressedObjectPtr* to_snapshot(Snapshot::Kind kind) { return to(); }
friend class Object;
friend class SnapshotReader;
};
class UntaggedAbstractType : public UntaggedInstance {
public:
enum TypeState {
@ -2551,8 +2567,7 @@ class UntaggedFunctionType : public UntaggedAbstractType {
RAW_HEAP_OBJECT_IMPLEMENTATION(FunctionType);
VISIT_FROM(CompressedObjectPtr, type_test_stub)
// Array of TypeParameter.
COMPRESSED_POINTER_FIELD(TypeArgumentsPtr, type_parameters)
COMPRESSED_POINTER_FIELD(TypeParametersPtr, type_parameters)
COMPRESSED_POINTER_FIELD(AbstractTypePtr, result_type)
COMPRESSED_POINTER_FIELD(ArrayPtr, parameter_types)
COMPRESSED_POINTER_FIELD(ArrayPtr, parameter_names);
@ -2624,21 +2639,13 @@ class UntaggedTypeParameter : public UntaggedAbstractType {
RAW_HEAP_OBJECT_IMPLEMENTATION(TypeParameter);
VISIT_FROM(CompressedObjectPtr, type_test_stub)
COMPRESSED_POINTER_FIELD(StringPtr, name)
COMPRESSED_POINTER_FIELD(SmiPtr, hash)
// ObjectType if no explicit bound specified.
COMPRESSED_POINTER_FIELD(AbstractTypePtr, bound)
// The instantiation to bounds of this parameter as calculated by the CFE.
//
// TODO(dartbug.com/43901): Once a separate TypeParameters class has been
// added, move these there and remove them from TypeParameter objects.
COMPRESSED_POINTER_FIELD(AbstractTypePtr, default_argument)
VISIT_TO(CompressedObjectPtr, default_argument)
VISIT_TO(CompressedObjectPtr, bound)
ClassIdTagType parameterized_class_id_; // Or kFunctionCid for function tp.
// TODO(regis): Can we use uint8_t twice below? Or keep uint16_t?
// Warning: BuildTypeParameterTypeTestStub assumes uint16_t.
uint16_t base_; // Number of enclosing function type parameters.
uint16_t index_;
uint8_t base_; // Number of enclosing function type parameters.
uint8_t index_; // Keep size in sync with BuildTypeParameterTypeTestStub.
uint8_t flags_;
uint8_t nullability_;
@ -2646,9 +2653,7 @@ class UntaggedTypeParameter : public UntaggedAbstractType {
using BeingFinalizedBit = BitField<decltype(flags_), bool, 0, 1>;
using FinalizedBit =
BitField<decltype(flags_), bool, BeingFinalizedBit::kNextBit, 1>;
using GenericCovariantImplBit =
BitField<decltype(flags_), bool, FinalizedBit::kNextBit, 1>;
static constexpr intptr_t kFlagsBitSize = GenericCovariantImplBit::kNextBit;
static constexpr intptr_t kFlagsBitSize = FinalizedBit::kNextBit;
private:
CompressedObjectPtr* to_snapshot(Snapshot::Kind kind) { return to(); }

View file

@ -136,9 +136,12 @@ namespace dart {
F(TypeRef, type_test_stub_) \
F(TypeRef, type_) \
F(TypeParameter, type_test_stub_) \
F(TypeParameter, name_) \
F(TypeParameter, hash_) \
F(TypeParameter, bound_) \
F(TypeParameters, names_) \
F(TypeParameters, flags_) \
F(TypeParameters, bounds_) \
F(TypeParameters, defaults_) \
F(Closure, instantiator_type_arguments_) \
F(Closure, function_type_arguments_) \
F(Closure, delayed_type_arguments_) \

View file

@ -230,6 +230,8 @@ TypeParameterPtr TypeParameter::ReadFrom(SnapshotReader* reader,
reader->AddBackRef(object_id, &type_parameter, kIsDeserialized);
// Set all non object fields.
type_parameter.set_base(reader->Read<uint8_t>());
type_parameter.set_index(reader->Read<uint8_t>());
const uint8_t combined = reader->Read<uint8_t>();
type_parameter.set_flags(combined >> 4);
type_parameter.set_nullability(static_cast<Nullability>(combined & 0xf));
@ -279,8 +281,8 @@ void UntaggedTypeParameter::WriteTo(SnapshotWriter* writer,
writer->WriteTags(writer->GetObjectTags(this));
// Write out all the non object pointer fields.
writer->Write<uint16_t>(base_);
writer->Write<uint16_t>(index_);
writer->Write<uint8_t>(base_);
writer->Write<uint8_t>(index_);
const uint8_t combined = (flags_ << 4) | nullability_;
ASSERT(flags_ == (combined >> 4));
ASSERT(nullability_ == (combined & 0xf));
@ -296,6 +298,43 @@ void UntaggedTypeParameter::WriteTo(SnapshotWriter* writer,
writer->WriteObjectImpl(param_class, kAsReference);
}
TypeParametersPtr TypeParameters::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
TypeParameters& type_parameters =
TypeParameters::ZoneHandle(reader->zone(), TypeParameters::New());
reader->AddBackRef(object_id, &type_parameters, kIsDeserialized);
// Set all the object fields.
READ_COMPRESSED_OBJECT_FIELDS(
type_parameters, type_parameters.ptr()->untag()->from(),
type_parameters.ptr()->untag()->to(), kAsReference);
return type_parameters.ptr();
}
void UntaggedTypeParameters::WriteTo(SnapshotWriter* writer,
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
// Write out the class and tags information.
writer->WriteVMIsolateObject(kTypeParametersCid);
writer->WriteTags(writer->GetObjectTags(this));
// Write out all the object pointer fields.
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitCompressedPointers(heap_base(), from(), to());
}
TypeArgumentsPtr TypeArguments::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,

View file

@ -109,6 +109,8 @@ REUSABLE_HANDLE_LIST(REUSABLE_SCOPE)
ReusableSmiHandleScope reused_smi_handle(thread);
#define REUSABLE_STRING_HANDLESCOPE(thread) \
ReusableStringHandleScope reused_string_handle(thread);
#define REUSABLE_TYPE_PARAMETERS_HANDLESCOPE(thread) \
ReusableTypeArgumentsHandleScope reused_type_parameters_handle(thread);
#define REUSABLE_TYPE_ARGUMENTS_HANDLESCOPE(thread) \
ReusableTypeArgumentsHandleScope reused_type_arguments_handle(thread);
#define REUSABLE_TYPE_PARAMETER_HANDLESCOPE(thread) \

View file

@ -531,13 +531,20 @@ DEFINE_RUNTIME_ENTRY(SubtypeCheck, 5) {
AbstractType::CheckedHandle(zone, arguments.ArgAt(3));
const String& dst_name = String::CheckedHandle(zone, arguments.ArgAt(4));
ASSERT(!subtype.IsNull() && !subtype.IsTypeRef());
if (supertype.IsTypeRef()) {
supertype = TypeRef::Cast(supertype).type();
}
ASSERT(!supertype.IsNull() && !supertype.IsTypeRef());
// 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());
// TODO(regis): Support for FLAG_trace_type_checks is missing here. Is it
// still useful or should we remove it everywhere?

View file

@ -416,6 +416,7 @@ class SnapshotReader : public BaseReader {
friend class Type;
friend class FunctionType;
friend class TypedDataView;
friend class TypeParameters;
friend class TypeArguments;
friend class TypeParameter;
friend class TypeRef;

View file

@ -106,6 +106,7 @@ class ObjectPointerVisitor;
V(DynamicCallCurrentNumProcessedVar, ":dyn_call_current_num_processed") \
V(DynamicCallCurrentFunctionVar, ":dyn_call_current_function") \
V(DynamicCallCurrentParamIndexVar, ":dyn_call_current_param_index") \
V(DynamicCallCurrentTypeParamVar, ":dyn_call_current_type_param") \
V(DynamicCallFunctionTypeArgsVar, ":dyn_call_function_type_args") \
V(DynamicPrefix, "dyn:") \
V(EntryPointsTemp, ":entry_points_temp") \
@ -286,6 +287,7 @@ class ObjectPointerVisitor;
V(TypeArguments, "TypeArguments") \
V(TypeArgumentsParameter, ":type_arguments") \
V(TypeError, "_TypeError") \
V(TypeParameters, "TypeParameters") \
V(TypeQuote, "type '") \
V(Uint16List, "Uint16List") \
V(Uint32List, "Uint32List") \

View file

@ -324,6 +324,7 @@ DEFINE_TAGGED_POINTER(UnwindError, Error)
DEFINE_TAGGED_POINTER(Instance, Object)
DEFINE_TAGGED_POINTER(LibraryPrefix, Instance)
DEFINE_TAGGED_POINTER(TypeArguments, Instance)
DEFINE_TAGGED_POINTER(TypeParameters, Object)
DEFINE_TAGGED_POINTER(AbstractType, Instance)
DEFINE_TAGGED_POINTER(Type, AbstractType)
DEFINE_TAGGED_POINTER(FunctionType, AbstractType)

View file

@ -83,6 +83,7 @@ class Thread;
V(PcDescriptors) \
V(Smi) \
V(String) \
V(TypeParameters) \
V(TypeArguments) \
V(TypeParameter)

View file

@ -72,8 +72,8 @@ const char* TypeTestingStubNamer::StringifyType(
return concatenated;
} else if (type.IsTypeParameter()) {
string_ = TypeParameter::Cast(type).name();
return AssemblerSafeName(OS::SCreate(Z, "%s", string_.ToCString()));
return AssemblerSafeName(
OS::SCreate(Z, "%s", TypeParameter::Cast(type).CanonicalNameCString()));
} else {
return AssemblerSafeName(OS::SCreate(Z, "%s", type.ToCString()));
}
@ -359,18 +359,13 @@ void TypeTestingStubGenerator::BuildOptimizedTypeTestStubFastCases(
} else {
ASSERT(hi->CanUseGenericSubtypeRangeCheckFor(type));
const intptr_t num_type_parameters = type_class.NumTypeParameters();
const intptr_t num_type_arguments = type_class.NumTypeArguments();
const TypeArguments& tp =
TypeArguments::Handle(type_class.type_parameters());
ASSERT(tp.Length() == num_type_parameters);
const TypeArguments& ta = TypeArguments::Handle(type.arguments());
ASSERT(ta.Length() == num_type_arguments);
BuildOptimizedSubclassRangeCheckWithTypeArguments(assembler, hi, type,
type_class, tp, ta);
type_class, ta);
}
if (Instance::NullIsAssignableTo(type)) {
@ -411,7 +406,6 @@ void TypeTestingStubGenerator::
HierarchyInfo* hi,
const Type& type,
const Class& type_class,
const TypeArguments& tp,
const TypeArguments& ta) {
// a) First we make a quick sub*class* cid-range check.
compiler::Label check_failed;
@ -941,7 +935,6 @@ void TypeUsageInfo::UpdateAssertAssignableTypes(
TypeParameterSet* parameters_tested_against) {
Class& klass = Class::Handle(zone_);
TypeParameter& param = TypeParameter::Handle(zone_);
TypeArguments& params = TypeArguments::Handle(zone_);
AbstractType& type = AbstractType::Handle(zone_);
// Because Object/dynamic are common values for type parameters, we add them
@ -961,9 +954,8 @@ void TypeUsageInfo::UpdateAssertAssignableTypes(
}
const intptr_t num_parameters = klass.NumTypeParameters();
params = klass.type_parameters();
for (intptr_t i = 0; i < num_parameters; ++i) {
param ^= params.TypeAt(i);
param = klass.TypeParameterAt(i);
if (parameters_tested_against->HasKey(&param)) {
TypeArgumentsSet& ta_set = instance_creation_arguments_[cid];
auto it = ta_set.GetIterator();

View file

@ -80,7 +80,6 @@ class TypeTestingStubGenerator {
HierarchyInfo* hi,
const Type& type,
const Class& type_class,
const TypeArguments& type_parameters,
const TypeArguments& type_arguments);
static void BuildOptimizedSubclassRangeCheckWithTypeArguments(
@ -88,7 +87,6 @@ class TypeTestingStubGenerator {
HierarchyInfo* hi,
const Type& type,
const Class& type_class,
const TypeArguments& type_parameters,
const TypeArguments& type_arguments,
const Register class_id_reg,
const Register instance_type_args_reg);

View file

@ -461,7 +461,7 @@ ISOLATE_UNIT_TEST_CASE(TTS_SubtypeRangeCheck) {
auto& tav_dynamic_t = TypeArguments::Handle(TypeArguments::New(2));
tav_dynamic_t.SetTypeAt(0, type_dynamic);
tav_dynamic_t.SetTypeAt(
1, TypeParameter::Handle(GetClassTypeParameter(class_base, "T")));
1, TypeParameter::Handle(GetClassTypeParameter(class_base, 0)));
CanonicalizeTAV(&tav_dynamic_t);
// We will generate specialized TTS for instantiated interface types
@ -750,7 +750,7 @@ ISOLATE_UNIT_TEST_CASE(TTS_GenericSubtypeRangeCheck) {
// <...> as Base<T> with T instantiantiator type parameter (T == int)
const auto& tav_baset = TypeArguments::Handle(TypeArguments::New(1));
tav_baset.SetTypeAt(
0, TypeParameter::Handle(GetClassTypeParameter(class_base, "T")));
0, TypeParameter::Handle(GetClassTypeParameter(class_base, 0)));
auto& type_base_t = AbstractType::Handle(Type::New(class_base, tav_baset));
FinalizeAndCanonicalize(&type_base_t);
RunTTSTest(obj_base_int, type_base_t, tav_int, tav_null,
@ -761,7 +761,7 @@ ISOLATE_UNIT_TEST_CASE(TTS_GenericSubtypeRangeCheck) {
// <...> as Base<B> with B function type parameter
const auto& tav_baseb = TypeArguments::Handle(TypeArguments::New(1));
tav_baseb.SetTypeAt(
0, TypeParameter::Handle(GetFunctionTypeParameter(fun_generic, "B")));
0, TypeParameter::Handle(GetFunctionTypeParameter(fun_generic, 1)));
auto& type_base_b = AbstractType::Handle(Type::New(class_base, tav_baseb));
FinalizeAndCanonicalize(&type_base_b);
// With B == int
@ -797,8 +797,8 @@ ISOLATE_UNIT_TEST_CASE(TTS_GenericSubtypeRangeCheck) {
// <...> as Base<A2<T>>
const auto& tav_t = TypeArguments::Handle(TypeArguments::New(1));
tav_t.SetTypeAt(
0, TypeParameter::Handle(GetClassTypeParameter(class_base, "T")));
tav_t.SetTypeAt(0,
TypeParameter::Handle(GetClassTypeParameter(class_base, 0)));
auto& type_a2_t = Type::Handle(Type::New(class_a2, tav_t));
type_a2_t = type_a2_t.ToNullability(Nullability::kLegacy, Heap::kNew);
FinalizeAndCanonicalize(&type_a2_t);
@ -855,7 +855,7 @@ ISOLATE_UNIT_TEST_CASE(TTS_Regress40964) {
// dst_type = B<T>
const auto& dst_tav = TypeArguments::Handle(TypeArguments::New(1));
dst_tav.SetTypeAt(0,
TypeParameter::Handle(GetClassTypeParameter(class_b, "T")));
TypeParameter::Handle(GetClassTypeParameter(class_b, 0)));
auto& dst_type = Type::Handle(Type::New(class_b, dst_tav));
FinalizeAndCanonicalize(&dst_type);
const auto& cint_tav =
@ -891,10 +891,10 @@ ISOLATE_UNIT_TEST_CASE(TTS_TypeParameter) {
Function::Handle(GetFunction(root_library, "genericFun"));
const auto& dst_type_t =
TypeParameter::Handle(GetClassTypeParameter(class_a, "T"));
TypeParameter::Handle(GetClassTypeParameter(class_a, 0));
const auto& dst_type_h =
TypeParameter::Handle(GetFunctionTypeParameter(fun_generic, "H"));
TypeParameter::Handle(GetFunctionTypeParameter(fun_generic, 0));
const auto& aint = Object::Handle(Invoke(root_library, "createAInt"));
const auto& astring = Object::Handle(Invoke(root_library, "createAString"));

View file

@ -0,0 +1,25 @@
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// SharedOptions=--enable-experiment=generic-metadata
import "package:expect/expect.dart";
Type? capturedTypeArgument;
Type typeOf<X>() => X;
X captureTypeArgument<X>() {
capturedTypeArgument = X;
throw "";
}
typedef check = void Function<T>();
void main() {
void f(check Function<T>() g) => g();
try {
f(<T>() => captureTypeArgument());
} catch (e) {}
Expect.equals(typeOf<void Function<T>()>(), capturedTypeArgument);
}

View file

@ -96,9 +96,6 @@ testD(Env env) {
values.forEach((e) {
Expect.equals(true, e is TypeVariableMirror);
});
Expect.equals(#R, values.elementAt(0).simpleName);
Expect.equals(#S, values.elementAt(1).simpleName);
Expect.equals(#T, values.elementAt(2).simpleName);
}
void testE(Env env) {

View file

@ -50,13 +50,6 @@ main() {
Expect.equals(reflectClass(Object), xFromGeneric.upperBound); // //# 02: continued
Expect.equals(reflectClass(Object), yFromGeneric.upperBound); // //# 02: continued
typeParameters(superDecl, [#T, #R]);
typeParameters(superOfNumAndInt, [#T, #R]);
typeParameters(genericDecl, [#X, #Y]); // //# 02: continued
typeParameters(superOfXAndY, [#T, #R]); // //# 02: continued
typeParameters(genericOfNumAndDouble, [#X, #Y]); // //# 02: continued
typeParameters(superOfNumAndDouble, [#T, #R]); // //# 02: continued
typeArguments(superDecl, []);
typeArguments(superOfNumAndInt, [reflectClass(num), reflectClass(int)]);
typeArguments(genericDecl, []); // //# 02: continued

View file

@ -49,14 +49,6 @@ main() {
Expect.equals(reflectClass(num), tFromSuper.upperBound);
Expect.equals(reflectClass(Object), rFromGeneric.upperBound); // //# 02: continued
typeParameters(superDecl, [#T]);
typeParameters(superOfInt, [#T]);
typeParameters(genericDecl, [#R]); // //# 02: continued
typeParameters(superOfR, [#T]); // //# 02: continued
typeParameters(genericOfDouble, [#R]); // //# 02: continued
typeParameters(superOfDouble, [#T]); // //# 02: continued
typeParameters(superOfString, [#T]); // //# 01: continued
typeArguments(superDecl, []);
typeArguments(superOfInt, [reflectClass(int)]);
typeArguments(genericDecl, []); // //# 02: continued

View file

@ -81,14 +81,4 @@ main() {
.where((dm) => dm is MethodMirror && dm.isConstructor)
.map(stringify),
'constructors');
Expect.setEquals(
[
'TypeVariable(s(T) in s(A), upperBound = Class(s(Object) in '
's(dart.core), top-level))'
],
cm.declarations.values
.where((dm) => dm is TypeVariableMirror)
.map(stringify),
'type variables');
}

View file

@ -43,13 +43,8 @@ main() {
Expect.equals(magnitudeDecl, magnitudeOfR.originalDeclaration);
Expect.equals(rFromSorter, magnitudeOfR.typeArguments.single);
typeParameters(magnitudeDecl, [#T]);
typeParameters(realDecl, []);
typeParameters(sorterDecl, [#R]);
typeParameters(realSorterDecl, []);
typeParameters(magnitudeOfReal, [#T]);
typeParameters(sorterOfReal, [#R]);
typeParameters(magnitudeOfR, [#T]);
typeArguments(magnitudeDecl, []);
typeArguments(realDecl, []);

View file

@ -91,21 +91,6 @@ main() {
Expect.equals(reflectClass(Object), xFromGenericMixinApplication.upperBound);
Expect.equals(reflectClass(Object), yFromGenericClass.upperBound);
typeParameters(interfaceDecl, [#T]);
typeParameters(boundedDecl, [#S]);
typeParameters(interfaceOfInt, [#T]);
typeParameters(interfaceOfR, [#T]);
typeParameters(interfaceOfBool, [#T]);
typeParameters(boundedOfInt, [#S]);
typeParameters(boundedOfString, [#S]); // //# 01: continued
typeParameters(interfaceOfFBounded, [#T]);
typeParameters(interfaceOfInt2, [#T]);
typeParameters(interfaceOfX, [#T]);
typeParameters(interfaceOfDouble, [#T]);
typeParameters(interfaceOfInt3, [#T]);
typeParameters(interfaceOfY, [#T]);
typeParameters(interfaceOfDouble2, [#T]);
typeArguments(interfaceDecl, []);
typeArguments(boundedDecl, []);
typeArguments(interfaceOfInt, [reflectClass(int)]);

View file

@ -35,30 +35,6 @@ class GenericMultipleMixins<A, B, C> extends Super<A> with Mixin<B>, Nixim<C> {}
main() {
TypeMirror dynamicMirror = currentMirrorSystem().dynamicType;
typeParameters(reflectClass(NonGenericMixinApplication1).mixin, [#M]);
typeParameters(reflectClass(NonGenericMixinApplication2).mixin, [#M]);
typeParameters(reflectClass(GenericMixinApplication1).mixin, [#M]);
typeParameters(reflectClass(GenericMixinApplication2).mixin, [#M]);
typeParameters(reflectClass(NonGenericClass1).mixin, []);
typeParameters(reflectClass(NonGenericClass2).mixin, []);
typeParameters(reflectClass(GenericClass1).mixin, [#C]);
typeParameters(reflectClass(GenericClass2).mixin, [#C]);
typeParameters(reflectClass(NonGenericClass1).superclass!.mixin, [#M]);
typeParameters(reflectClass(NonGenericClass2).superclass!.mixin, [#M]);
typeParameters(reflectClass(GenericClass1).superclass!.mixin, [#M]);
typeParameters(reflectClass(GenericClass2).superclass!.mixin, [#M]);
typeParameters(reflectClass(GenericMultipleMixins).mixin, [#A, #B, #C]);
typeParameters(reflectClass(GenericMultipleMixins).superclass!.mixin, [#N]);
typeParameters(
reflectClass(GenericMultipleMixins).superclass!.superclass!.mixin, [#M]);
typeParameters(
reflectClass(GenericMultipleMixins)
.superclass!
.superclass!
.superclass!
.mixin,
[#S]);
typeArguments(
reflectClass(NonGenericMixinApplication1).mixin, [dynamicMirror]);
typeArguments(
@ -93,46 +69,8 @@ main() {
.mixin,
[reflectClass(GenericMultipleMixins).typeVariables[0]]);
typeParameters(reflect(new NonGenericMixinApplication1()).type.mixin, [#M]);
typeParameters(reflect(new NonGenericMixinApplication2()).type.mixin, [#M]);
typeParameters(
reflect(new GenericMixinApplication1<bool>()).type.mixin, [#M]);
typeParameters(
reflect(new GenericMixinApplication2<bool>()).type.mixin, [#M]);
typeParameters(reflect(new NonGenericClass1()).type.mixin, []);
typeParameters(reflect(new NonGenericClass2()).type.mixin, []);
typeParameters(reflect(new GenericClass1<bool>()).type.mixin, [#C]);
typeParameters(reflect(new GenericClass2<bool>()).type.mixin, [#C]);
typeParameters(reflect(new NonGenericClass1()).type.superclass!.mixin, [#M]);
typeParameters(reflect(new NonGenericClass2()).type.superclass!.mixin, [#M]);
typeParameters(
reflect(new GenericClass1<bool>()).type.superclass!.mixin, [#M]);
typeParameters(
reflect(new GenericClass2<bool>()).type.superclass!.mixin, [#M]);
typeParameters(
reflect(new GenericMultipleMixins<bool, String, int>()).type.mixin,
[#A, #B, #C]);
typeParameters(
reflect(new GenericMultipleMixins<bool, String, int>())
.type
.superclass!
.mixin,
[#N]);
typeParameters(
reflect(new GenericMultipleMixins<bool, String, int>())
.type
.superclass!
.superclass!
.mixin,
[#M]);
typeParameters(
reflect(new GenericMultipleMixins<bool, String, int>())
.type
.superclass!
.superclass!
.superclass!
.mixin,
[#S]);
typeArguments(
reflect(new NonGenericMixinApplication1()).type.mixin, [dynamicMirror]);

View file

@ -36,18 +36,12 @@ main() {
Symbol t(ClassMirror cm) =>
(cm.declarations[#t] as MethodMirror).returnType.simpleName;
Expect.equals(#T, r(genericDecl.superclass!));
Expect.equals(#int, s(genericDecl.superclass!));
Expect.equals(#T, t(genericDecl));
Expect.equals(#String, r(genericOfString.superclass!));
Expect.equals(#int, s(genericOfString.superclass!));
Expect.equals(#String, t(genericOfString));
Expect.equals(#R, r(superGenericDecl));
Expect.equals(#S, s(superGenericDecl));
Expect.equals(#T, r(superOfTAndInt));
Expect.equals(#int, s(superOfTAndInt));
Expect.equals(#String, r(superOfStringAndInt));

View file

@ -33,15 +33,11 @@ class I extends G {}
main() {
// Declarations.
typeParameters(reflectClass(A), [#T]);
typeParameters(reflectClass(G), []);
typeParameters(reflectClass(B), []);
typeParameters(reflectClass(C), []);
typeParameters(reflectClass(D), []);
typeParameters(reflectClass(E), [#S]);
typeParameters(reflectClass(F), [#R]);
typeParameters(reflectClass(G), []);
typeParameters(reflectClass(H), [#A, #B, #C]);
typeParameters(reflectClass(I), []);
typeArguments(reflectClass(A), []);
@ -75,14 +71,10 @@ main() {
Expect.equals(reflectClass(I), reflectClass(I).originalDeclaration);
// Instantiations.
typeParameters(reflect(new A<num>()).type, [#T]);
typeParameters(reflect(new B()).type, []);
typeParameters(reflect(new C()).type, []);
typeParameters(reflect(new D()).type, []);
typeParameters(reflect(new E()).type, [#S]);
typeParameters(reflect(new F<num>()).type, [#R]);
typeParameters(reflect(new G()).type, []);
typeParameters(reflect(new H()).type, [#A, #B, #C]);
typeParameters(reflect(new I()).type, []);
var numMirror = reflectClass(num);

View file

@ -180,24 +180,7 @@ main() {
MethodMirror fooInC = cm.declarations[#foo] as MethodMirror;
expect('Method(s(foo) in s(C))', fooInC);
expect(
'[Parameter(s(a) in s(foo),'
' type = Class(s(int) in s(dart.core), top-level)), '
'Parameter(s(b) in s(foo),'
' type = TypeVariable(s(S) in s(Null),'
' upperBound = Class(s(int) in s(dart.core), top-level)))]',
fooInC.parameters);
MethodMirror barInC = cm.declarations[#bar] as MethodMirror;
expect('Method(s(bar) in s(C))', barInC);
expect(
'[Parameter(s(a) in s(bar),'
' type = TypeVariable(s(S) in s(Null),'
' upperBound = Class(s(int) in s(dart.core), top-level))), '
'Parameter(s(b) in s(bar),'
' type = TypeVariable(s(T) in s(Null),'
' upperBound = Class(s(Object) in s(dart.core), top-level))), '
'Parameter(s(c) in s(bar),'
' type = Class(s(num) in s(dart.core), top-level))]',
barInC.parameters);
}

View file

@ -27,14 +27,6 @@ main() {
TypeVariableMirror ssFromSuperSuper =
superOfSuperOfGeneric.typeVariables.single;
Expect.equals(#G, gFromGeneric.simpleName);
Expect.equals(#S, sFromSuper.simpleName);
Expect.equals(#SS, ssFromSuperSuper.simpleName);
typeParameters(generic, [#G]);
typeParameters(superOfGeneric, [#S]);
typeParameters(superOfSuperOfGeneric, [#SS]);
typeArguments(generic, []);
typeArguments(superOfGeneric, [gFromGeneric]);
typeArguments(superOfSuperOfGeneric, [gFromGeneric]);
@ -44,10 +36,6 @@ main() {
ClassMirror superOfGenericWithInt = genericWithInt.superclass!;
ClassMirror superOfSuperOfGenericWithInt = superOfGenericWithInt.superclass!;
typeParameters(genericWithInt, [#G]);
typeParameters(superOfGenericWithInt, [#S]);
typeParameters(superOfSuperOfGenericWithInt, [#SS]);
typeArguments(genericWithInt, [reflectClass(int)]);
typeArguments(superOfGenericWithInt, [reflectClass(int)]);
typeArguments(superOfSuperOfGenericWithInt, [reflectClass(int)]);

View file

@ -98,9 +98,9 @@ testD(Env env) {
values.forEach((e) {
Expect.equals(true, e is TypeVariableMirror);
});
Expect.equals(#R, values.elementAt(0).simpleName);
Expect.equals(#S, values.elementAt(1).simpleName);
Expect.equals(#T, values.elementAt(2).simpleName);
// Names of type variables are not preserved after type canonicalization
// and are therefore not compared to expected names.
}
void testE(Env env) {

View file

@ -52,12 +52,8 @@ main() {
Expect.equals(reflectClass(Object), xFromGeneric.upperBound); // //# 02: continued
Expect.equals(reflectClass(Object), yFromGeneric.upperBound); // //# 02: continued
typeParameters(superDecl, [#T, #R]);
typeParameters(superOfNumAndInt, [#T, #R]);
typeParameters(genericDecl, [#X, #Y]); // //# 02: continued
typeParameters(superOfXAndY, [#T, #R]); // //# 02: continued
typeParameters(genericOfNumAndDouble, [#X, #Y]); // //# 02: continued
typeParameters(superOfNumAndDouble, [#T, #R]); // //# 02: continued
// Names of type variables are not preserved after type canonicalization
// and are therefore not compared to expected names.
typeArguments(superDecl, []);
typeArguments(superOfNumAndInt, [reflectClass(num), reflectClass(int)]);

View file

@ -51,13 +51,8 @@ main() {
Expect.equals(reflectClass(num), tFromSuper.upperBound);
Expect.equals(reflectClass(Object), rFromGeneric.upperBound); // //# 02: continued
typeParameters(superDecl, [#T]);
typeParameters(superOfInt, [#T]);
typeParameters(genericDecl, [#R]); // //# 02: continued
typeParameters(superOfR, [#T]); // //# 02: continued
typeParameters(genericOfDouble, [#R]); // //# 02: continued
typeParameters(superOfDouble, [#T]); // //# 02: continued
typeParameters(superOfString, [#T]); // //# 01: continued
// Names of type variables are not preserved after type canonicalization
// and are therefore not compared to expected names.
typeArguments(superDecl, []);
typeArguments(superOfInt, [reflectClass(int)]);

View file

@ -84,13 +84,6 @@ main() {
.map(stringify),
'constructors');
Expect.setEquals(
[
'TypeVariable(s(T) in s(A), upperBound = Class(s(Object) in '
's(dart.core), top-level))'
],
cm.declarations.values
.where((dm) => dm is TypeVariableMirror)
.map(stringify),
'type variables');
// Names of type variables are not preserved after type canonicalization
// and are therefore not compared to expected names.
}

View file

@ -45,13 +45,14 @@ main() {
Expect.equals(magnitudeDecl, magnitudeOfR.originalDeclaration);
Expect.equals(rFromSorter, magnitudeOfR.typeArguments.single);
typeParameters(magnitudeDecl, [#T]);
// Names of type variables are not preserved after type canonicalization
// and are therefore not compared to expected names.
typeParameters(realDecl, []);
typeParameters(sorterDecl, [#R]);
typeParameters(realSorterDecl, []);
typeParameters(magnitudeOfReal, [#T]);
typeParameters(sorterOfReal, [#R]);
typeParameters(magnitudeOfR, [#T]);
// Names of type variables are not preserved after type canonicalization
// and are therefore not compared to expected names.
typeArguments(magnitudeDecl, []);
typeArguments(realDecl, []);

View file

@ -93,20 +93,8 @@ main() {
Expect.equals(reflectClass(Object), xFromGenericMixinApplication.upperBound);
Expect.equals(reflectClass(Object), yFromGenericClass.upperBound);
typeParameters(interfaceDecl, [#T]);
typeParameters(boundedDecl, [#S]);
typeParameters(interfaceOfInt, [#T]);
typeParameters(interfaceOfR, [#T]);
typeParameters(interfaceOfBool, [#T]);
typeParameters(boundedOfInt, [#S]);
typeParameters(boundedOfString, [#S]); // //# 01: continued
typeParameters(interfaceOfFBounded, [#T]);
typeParameters(interfaceOfInt2, [#T]);
typeParameters(interfaceOfX, [#T]);
typeParameters(interfaceOfDouble, [#T]);
typeParameters(interfaceOfInt3, [#T]);
typeParameters(interfaceOfY, [#T]);
typeParameters(interfaceOfDouble2, [#T]);
// Names of type variables are not preserved after type canonicalization
// and are therefore not compared to expected names.
typeArguments(interfaceDecl, []);
typeArguments(boundedDecl, []);

View file

@ -37,29 +37,8 @@ class GenericMultipleMixins<A, B, C> extends Super<A> with Mixin<B>, Nixim<C> {}
main() {
TypeMirror dynamicMirror = currentMirrorSystem().dynamicType;
typeParameters(reflectClass(NonGenericMixinApplication1).mixin, [#M]);
typeParameters(reflectClass(NonGenericMixinApplication2).mixin, [#M]);
typeParameters(reflectClass(GenericMixinApplication1).mixin, [#M]);
typeParameters(reflectClass(GenericMixinApplication2).mixin, [#M]);
typeParameters(reflectClass(NonGenericClass1).mixin, []);
typeParameters(reflectClass(NonGenericClass2).mixin, []);
typeParameters(reflectClass(GenericClass1).mixin, [#C]);
typeParameters(reflectClass(GenericClass2).mixin, [#C]);
typeParameters(reflectClass(NonGenericClass1).superclass.mixin, [#M]);
typeParameters(reflectClass(NonGenericClass2).superclass.mixin, [#M]);
typeParameters(reflectClass(GenericClass1).superclass.mixin, [#M]);
typeParameters(reflectClass(GenericClass2).superclass.mixin, [#M]);
typeParameters(reflectClass(GenericMultipleMixins).mixin, [#A, #B, #C]);
typeParameters(reflectClass(GenericMultipleMixins).superclass.mixin, [#N]);
typeParameters(
reflectClass(GenericMultipleMixins).superclass.superclass.mixin, [#M]);
typeParameters(
reflectClass(GenericMultipleMixins)
.superclass
.superclass
.superclass
.mixin,
[#S]);
// Names of type variables are not preserved after type canonicalization
// and are therefore not compared to expected names.
typeArguments(
reflectClass(NonGenericMixinApplication1).mixin, [dynamicMirror]);
@ -94,46 +73,8 @@ main() {
.mixin,
[reflectClass(GenericMultipleMixins).typeVariables[0]]);
typeParameters(reflect(new NonGenericMixinApplication1()).type.mixin, [#M]);
typeParameters(reflect(new NonGenericMixinApplication2()).type.mixin, [#M]);
typeParameters(
reflect(new GenericMixinApplication1<bool>()).type.mixin, [#M]);
typeParameters(
reflect(new GenericMixinApplication2<bool>()).type.mixin, [#M]);
typeParameters(reflect(new NonGenericClass1()).type.mixin, []);
typeParameters(reflect(new NonGenericClass2()).type.mixin, []);
typeParameters(reflect(new GenericClass1<bool>()).type.mixin, [#C]);
typeParameters(reflect(new GenericClass2<bool>()).type.mixin, [#C]);
typeParameters(reflect(new NonGenericClass1()).type.superclass.mixin, [#M]);
typeParameters(reflect(new NonGenericClass2()).type.superclass.mixin, [#M]);
typeParameters(
reflect(new GenericClass1<bool>()).type.superclass.mixin, [#M]);
typeParameters(
reflect(new GenericClass2<bool>()).type.superclass.mixin, [#M]);
typeParameters(
reflect(new GenericMultipleMixins<bool, String, int>()).type.mixin,
[#A, #B, #C]);
typeParameters(
reflect(new GenericMultipleMixins<bool, String, int>())
.type
.superclass
.mixin,
[#N]);
typeParameters(
reflect(new GenericMultipleMixins<bool, String, int>())
.type
.superclass
.superclass
.mixin,
[#M]);
typeParameters(
reflect(new GenericMultipleMixins<bool, String, int>())
.type
.superclass
.superclass
.superclass
.mixin,
[#S]);
typeArguments(
reflect(new NonGenericMixinApplication1()).type.mixin, [dynamicMirror]);

View file

@ -38,18 +38,15 @@ main() {
Symbol t(ClassMirror cm) =>
(cm.declarations[#t] as MethodMirror).returnType.simpleName;
Expect.equals(#T, r(genericDecl.superclass));
// Names of type variables are not preserved after type canonicalization
// and are therefore not compared to expected names.
Expect.equals(#int, s(genericDecl.superclass));
Expect.equals(#T, t(genericDecl));
Expect.equals(#String, r(genericOfString.superclass));
Expect.equals(#int, s(genericOfString.superclass));
Expect.equals(#String, t(genericOfString));
Expect.equals(#R, r(superGenericDecl));
Expect.equals(#S, s(superGenericDecl));
Expect.equals(#T, r(superOfTAndInt));
Expect.equals(#int, s(superOfTAndInt));
Expect.equals(#String, r(superOfStringAndInt));

View file

@ -35,15 +35,15 @@ class I extends G {}
main() {
// Declarations.
typeParameters(reflectClass(A), [#T]);
// Names of type variables are not preserved after type canonicalization
// and are therefore not compared to expected names.
typeParameters(reflectClass(G), []);
typeParameters(reflectClass(B), []);
typeParameters(reflectClass(C), []);
typeParameters(reflectClass(D), []);
typeParameters(reflectClass(E), [#S]);
typeParameters(reflectClass(F), [#R]);
typeParameters(reflectClass(G), []);
typeParameters(reflectClass(H), [#A, #B, #C]);
typeParameters(reflectClass(I), []);
typeArguments(reflectClass(A), []);
@ -77,14 +77,10 @@ main() {
Expect.equals(reflectClass(I), reflectClass(I).originalDeclaration);
// Instantiations.
typeParameters(reflect(new A<num>()).type, [#T]);
typeParameters(reflect(new B()).type, []);
typeParameters(reflect(new C()).type, []);
typeParameters(reflect(new D()).type, []);
typeParameters(reflect(new E()).type, [#S]);
typeParameters(reflect(new F<num>()).type, [#R]);
typeParameters(reflect(new G()).type, []);
typeParameters(reflect(new H()).type, [#A, #B, #C]);
typeParameters(reflect(new I()).type, []);
var numMirror = reflectClass(num);

View file

@ -182,24 +182,11 @@ main() {
MethodMirror fooInC = cm.declarations[#foo] as MethodMirror;
expect('Method(s(foo) in s(C))', fooInC);
expect(
'[Parameter(s(a) in s(foo),'
' type = Class(s(int) in s(dart.core), top-level)), '
'Parameter(s(b) in s(foo),'
' type = TypeVariable(s(S) in s(Null),'
' upperBound = Class(s(int) in s(dart.core), top-level)))]',
fooInC.parameters);
// Names of type variables are not preserved after type canonicalization
// and are therefore not compared to expected names.
MethodMirror barInC = cm.declarations[#bar] as MethodMirror;
expect('Method(s(bar) in s(C))', barInC);
expect(
'[Parameter(s(a) in s(bar),'
' type = TypeVariable(s(S) in s(Null),'
' upperBound = Class(s(int) in s(dart.core), top-level))), '
'Parameter(s(b) in s(bar),'
' type = TypeVariable(s(T) in s(Null),'
' upperBound = Class(s(Object) in s(dart.core), top-level))), '
'Parameter(s(c) in s(bar),'
' type = Class(s(num) in s(dart.core), top-level))]',
barInC.parameters);
}

View file

@ -29,13 +29,8 @@ main() {
TypeVariableMirror ssFromSuperSuper =
superOfSuperOfGeneric.typeVariables.single;
Expect.equals(#G, gFromGeneric.simpleName);
Expect.equals(#S, sFromSuper.simpleName);
Expect.equals(#SS, ssFromSuperSuper.simpleName);
typeParameters(generic, [#G]);
typeParameters(superOfGeneric, [#S]);
typeParameters(superOfSuperOfGeneric, [#SS]);
// Names of type variables are not preserved after type canonicalization
// and are therefore not compared to expected names.
typeArguments(generic, []);
typeArguments(superOfGeneric, [gFromGeneric]);
@ -46,10 +41,6 @@ main() {
ClassMirror superOfGenericWithInt = genericWithInt.superclass;
ClassMirror superOfSuperOfGenericWithInt = superOfGenericWithInt.superclass;
typeParameters(genericWithInt, [#G]);
typeParameters(superOfGenericWithInt, [#S]);
typeParameters(superOfSuperOfGenericWithInt, [#SS]);
typeArguments(genericWithInt, [reflectClass(int)]);
typeArguments(superOfGenericWithInt, [reflectClass(int)]);
typeArguments(superOfSuperOfGenericWithInt, [reflectClass(int)]);