mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 23:59:47 +00:00
[VM/runtime] Insert TypeRef when type parameter bound refers to type parameters.
Fixes https://github.com/dart-lang/sdk/issues/46276 TEST=added regression test Change-Id: Iecdccd4af02c374d4d17d0c0d7985fdaeec5e42a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/202820 Reviewed-by: Alexander Markov <alexmarkov@google.com> Commit-Queue: Régis Crelier <regis@google.com>
This commit is contained in:
parent
f00c3ded30
commit
bae9560c8a
|
@ -732,15 +732,19 @@ AbstractTypePtr ClassFinalizer::FinalizeType(const AbstractType& type,
|
|||
return type.ptr();
|
||||
}
|
||||
|
||||
if (type.IsTypeRef()) {
|
||||
// The referenced type will be finalized later by the code that set the
|
||||
// is_being_finalized mark bit.
|
||||
return type.ptr();
|
||||
}
|
||||
Thread* thread = Thread::Current();
|
||||
Zone* zone = thread->zone();
|
||||
|
||||
if (type.IsTypeParameter() && type.IsBeingFinalized()) {
|
||||
// The base and index have already been adjusted, but the bound referring
|
||||
// back to the type parameter is still being finalized.
|
||||
if (type.IsTypeRef()) {
|
||||
if (type.IsBeingFinalized()) {
|
||||
// The referenced type will be finalized later by the code that set the
|
||||
// is_being_finalized mark bit.
|
||||
return type.ptr();
|
||||
}
|
||||
AbstractType& ref_type =
|
||||
AbstractType::Handle(zone, TypeRef::Cast(type).type());
|
||||
ref_type = FinalizeType(ref_type, finalization, pending_types);
|
||||
TypeRef::Cast(type).set_type(ref_type);
|
||||
return type.ptr();
|
||||
}
|
||||
|
||||
|
@ -751,9 +755,6 @@ AbstractTypePtr ClassFinalizer::FinalizeType(const AbstractType& type,
|
|||
// Mark the type as being finalized in order to detect self reference.
|
||||
type.SetIsBeingFinalized();
|
||||
|
||||
Thread* thread = Thread::Current();
|
||||
Zone* zone = thread->zone();
|
||||
|
||||
if (FLAG_trace_type_finalization) {
|
||||
THR_Print("Finalizing type '%s'\n",
|
||||
String::Handle(zone, type.Name()).ToCString());
|
||||
|
@ -780,21 +781,13 @@ AbstractTypePtr ClassFinalizer::FinalizeType(const AbstractType& type,
|
|||
type_parameter.set_parameterized_class_id(kClassCid);
|
||||
}
|
||||
|
||||
type_parameter.SetIsFinalized();
|
||||
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 {
|
||||
if (!upper_bound.IsBeingFinalized()) {
|
||||
upper_bound = FinalizeType(upper_bound, kFinalize);
|
||||
type_parameter.set_bound(upper_bound);
|
||||
}
|
||||
type_parameter.SetIsFinalized();
|
||||
|
||||
if (FLAG_trace_type_finalization) {
|
||||
THR_Print("Done finalizing type parameter at index %" Pd "\n",
|
||||
|
|
|
@ -917,7 +917,8 @@ static bool CanPotentiallyBeSmi(const AbstractType& type, bool recurse) {
|
|||
// Comparable<int>).
|
||||
if (type.IsFutureOrType() ||
|
||||
type.type_class() == CompilerState::Current().ComparableClass().ptr()) {
|
||||
const auto& args = TypeArguments::Handle(Type::Cast(type).arguments());
|
||||
// Type may be a TypeRef.
|
||||
const auto& args = TypeArguments::Handle(type.arguments());
|
||||
const auto& arg0 = AbstractType::Handle(args.TypeAt(0));
|
||||
return !recurse || CanPotentiallyBeSmi(arg0, /*recurse=*/true);
|
||||
}
|
||||
|
|
|
@ -1815,6 +1815,9 @@ void FlowGraphBuilder::BuildTypeArgumentTypeChecks(TypeChecksToBuild mode,
|
|||
type_param = dart_function.TypeParameterAt(i);
|
||||
}
|
||||
ASSERT(type_param.IsFinalized());
|
||||
if (bound.IsTypeRef()) {
|
||||
bound = TypeRef::Cast(bound).type();
|
||||
}
|
||||
check_bounds +=
|
||||
AssertSubtype(TokenPosition::kNoSource, type_param, bound, name);
|
||||
}
|
||||
|
@ -4507,6 +4510,10 @@ bool FlowGraphBuilder::NeedsNullAssertion(const AbstractType& type) {
|
|||
if (!type.IsNonNullable()) {
|
||||
return false;
|
||||
}
|
||||
if (type.IsTypeRef()) {
|
||||
return NeedsNullAssertion(
|
||||
AbstractType::Handle(Z, TypeRef::Cast(type).type()));
|
||||
}
|
||||
if (type.IsTypeParameter()) {
|
||||
return NeedsNullAssertion(
|
||||
AbstractType::Handle(Z, TypeParameter::Cast(type).bound()));
|
||||
|
|
|
@ -3038,6 +3038,7 @@ TypeTranslator::TypeTranslator(KernelReaderHelper* helper,
|
|||
zone_(translation_helper_.zone()),
|
||||
result_(AbstractType::Handle(translation_helper_.zone())),
|
||||
finalize_(finalize),
|
||||
refers_to_derived_type_param_(false),
|
||||
apply_canonical_type_erasure_(apply_canonical_type_erasure),
|
||||
in_constant_context_(in_constant_context) {}
|
||||
|
||||
|
@ -3094,6 +3095,10 @@ void TypeTranslator::BuildTypeInternal() {
|
|||
break;
|
||||
case kTypeParameterType:
|
||||
BuildTypeParameterType();
|
||||
if (result_.IsTypeParameter() &&
|
||||
TypeParameter::Cast(result_).bound() == AbstractType::null()) {
|
||||
refers_to_derived_type_param_ = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
helper_->ReportUnexpectedTag("type", tag);
|
||||
|
@ -3475,8 +3480,14 @@ void TypeTranslator::LoadAndSetupBounds(
|
|||
TypeParameterHelper helper(helper_);
|
||||
helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kBound);
|
||||
|
||||
bool saved_refers_to_derived_type_param = refers_to_derived_type_param_;
|
||||
refers_to_derived_type_param_ = false;
|
||||
AbstractType& bound = BuildTypeWithoutFinalization(); // read ith bound.
|
||||
ASSERT(!bound.IsNull());
|
||||
if (refers_to_derived_type_param_) {
|
||||
bound = TypeRef::New(bound);
|
||||
}
|
||||
refers_to_derived_type_param_ = saved_refers_to_derived_type_param;
|
||||
type_parameters.SetBoundAt(i, bound);
|
||||
helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kDefaultType);
|
||||
AbstractType& default_arg = BuildTypeWithoutFinalization();
|
||||
|
@ -3503,6 +3514,7 @@ void TypeTranslator::LoadAndSetupBounds(
|
|||
derived.index() >= offset &&
|
||||
derived.index() < offset + type_parameter_count))) {
|
||||
bound = type_parameters.BoundAt(derived.index() - offset);
|
||||
ASSERT(!bound.IsNull());
|
||||
derived.set_bound(bound);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1538,6 +1538,7 @@ class TypeTranslator {
|
|||
Zone* zone_;
|
||||
AbstractType& result_;
|
||||
bool finalize_;
|
||||
bool refers_to_derived_type_param_;
|
||||
const bool apply_canonical_type_erasure_;
|
||||
const bool in_constant_context_;
|
||||
|
||||
|
|
|
@ -19562,6 +19562,10 @@ bool AbstractType::IsStrictlyNonNullable() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (IsTypeRef()) {
|
||||
return AbstractType::Handle(zone, TypeRef::Cast(*this).type())
|
||||
.IsStrictlyNonNullable();
|
||||
}
|
||||
if (IsTypeParameter()) {
|
||||
const auto& bound =
|
||||
AbstractType::Handle(zone, TypeParameter::Cast(*this).bound());
|
||||
|
@ -19911,10 +19915,12 @@ void AbstractType::PrintName(NameVisibility name_visibility,
|
|||
const TypeArguments& args = TypeArguments::Handle(zone, arguments());
|
||||
const intptr_t num_args = args.IsNull() ? 0 : args.Length();
|
||||
intptr_t first_type_param_index;
|
||||
intptr_t num_type_params; // Number of type parameters to print.
|
||||
intptr_t num_type_params = num_args; // Number of type parameters to print.
|
||||
cls = type_class();
|
||||
// Do not print the full vector, but only the declared type parameters.
|
||||
num_type_params = cls.NumTypeParameters();
|
||||
if (cls.is_declaration_loaded()) {
|
||||
// Do not print the full vector, but only the declared type parameters.
|
||||
num_type_params = cls.NumTypeParameters();
|
||||
}
|
||||
printer->AddString(cls.NameCString(name_visibility));
|
||||
if (num_type_params > num_args) {
|
||||
first_type_param_index = 0;
|
||||
|
@ -20055,6 +20061,7 @@ bool AbstractType::IsFfiPointerType() const {
|
|||
}
|
||||
|
||||
AbstractTypePtr AbstractType::UnwrapFutureOr() const {
|
||||
// Works properly for a TypeRef without dereferencing it.
|
||||
if (!IsFutureOrType()) {
|
||||
return ptr();
|
||||
}
|
||||
|
@ -20982,8 +20989,13 @@ uword FunctionType::ComputeHash() const {
|
|||
if (num_type_params > 0) {
|
||||
const TypeParameters& type_params =
|
||||
TypeParameters::Handle(type_parameters());
|
||||
const TypeArguments& bounds = TypeArguments::Handle(type_params.bounds());
|
||||
result = CombineHashes(result, bounds.Hash());
|
||||
// Do not calculate the hash of the bounds using TypeArguments::Hash(),
|
||||
// because HashForRange() dereferences TypeRefs which should not be here.
|
||||
AbstractType& bound = AbstractType::Handle();
|
||||
for (intptr_t i = 0; i < num_type_params; i++) {
|
||||
bound = type_params.BoundAt(i);
|
||||
result = CombineHashes(result, bound.Hash());
|
||||
}
|
||||
// Since the default arguments are ignored when comparing two generic
|
||||
// function types for type equality, the hash does not depend on them.
|
||||
}
|
||||
|
@ -21705,7 +21717,9 @@ AbstractTypePtr TypeParameter::InstantiateFrom(
|
|||
upper_bound = upper_bound.InstantiateFrom(
|
||||
instantiator_type_arguments, function_type_arguments,
|
||||
num_free_fun_type_params, space, trail);
|
||||
if (upper_bound.ptr() == Type::NeverType()) {
|
||||
if ((upper_bound.IsTypeRef() &&
|
||||
TypeRef::Cast(upper_bound).type() == Type::NeverType()) ||
|
||||
(upper_bound.ptr() == Type::NeverType())) {
|
||||
// Normalize 'X extends Never' to 'Never'.
|
||||
result = Type::NeverType();
|
||||
} else if (upper_bound.ptr() != bound()) {
|
||||
|
|
15
tests/language/regress/regress46276_test.dart
Normal file
15
tests/language/regress/regress46276_test.dart
Normal file
|
@ -0,0 +1,15 @@
|
|||
// 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.
|
||||
|
||||
abstract class Base<A, B> {}
|
||||
|
||||
extension on Object {
|
||||
B? foo<A extends Base<A, B>, B extends Base<A, B>>(B? orig) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
main() {
|
||||
print(Object().foo);
|
||||
}
|
Loading…
Reference in a new issue