Index: runtime/vm/object.cc |
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc |
index f6177b2809b670ae68a2c8e3fc1f3a0635834a97..69cd625ca603190014f9cf4a1be04b87a4b4d0bd 100644 |
--- a/runtime/vm/object.cc |
+++ b/runtime/vm/object.cc |
@@ -3898,7 +3898,8 @@ bool Class::TypeTestNonRecursive(const Class& cls, |
// The index of the type parameters is adjusted upon finalization. |
error = Error::null(); |
interface_args = interface_args.InstantiateFrom( |
- type_arguments, &error, NULL, bound_trail, space); |
+ type_arguments, Object::null_type_arguments(), &error, NULL, |
+ bound_trail, space); |
if (!error.IsNull()) { |
// Return the first bound error to the caller if it requests it. |
if ((bound_error != NULL) && bound_error->IsNull()) { |
@@ -4716,9 +4717,14 @@ bool TypeArguments::IsDynamicTypes(bool raw_instantiated, |
type = TypeAt(from_index + i); |
if (!type.HasResolvedTypeClass()) { |
if (raw_instantiated && type.IsTypeParameter()) { |
- // An uninstantiated type parameter is equivalent to dynamic (even in |
- // the presence of a malformed bound in checked mode). |
- continue; |
+ const TypeParameter& type_param = TypeParameter::Cast(type); |
+ if (type_param.IsClassTypeParameter() || |
+ (type_param.IsFunctionTypeParameter() && |
+ type_param.parent_level() == 0)) { |
+ // An uninstantiated type parameter is equivalent to dynamic (even in |
+ // the presence of a malformed bound in checked mode). |
+ continue; |
+ } |
} |
return false; |
} |
@@ -4767,11 +4773,13 @@ bool TypeArguments::HasInstantiations() const { |
intptr_t TypeArguments::NumInstantiations() const { |
const Array& prior_instantiations = Array::Handle(instantiations()); |
ASSERT(prior_instantiations.Length() > 0); // Always at least a sentinel. |
+ intptr_t num = 0; |
intptr_t i = 0; |
while (prior_instantiations.At(i) != Smi::New(StubCode::kNoInstantiator)) { |
- i += 2; |
+ i += StubCode::kInstantiationSizeInWords; |
+ num++; |
} |
- return i / 2; |
+ return num; |
} |
@@ -4980,6 +4988,7 @@ bool TypeArguments::IsBounded() const { |
RawTypeArguments* TypeArguments::InstantiateFrom( |
const TypeArguments& instantiator_type_arguments, |
+ const TypeArguments& function_type_arguments, |
Error* bound_error, |
TrailPtr instantiation_trail, |
TrailPtr bound_trail, |
@@ -5002,7 +5011,8 @@ RawTypeArguments* TypeArguments::InstantiateFrom( |
// solely on the type parameters of A and will be replaced by a non-null |
// type before A is marked as finalized. |
if (!type.IsNull() && !type.IsInstantiated()) { |
- type = type.InstantiateFrom(instantiator_type_arguments, bound_error, |
+ type = type.InstantiateFrom(instantiator_type_arguments, |
+ function_type_arguments, bound_error, |
instantiation_trail, bound_trail, space); |
} |
instantiated_array.SetTypeAt(i, type); |
@@ -5013,10 +5023,13 @@ RawTypeArguments* TypeArguments::InstantiateFrom( |
RawTypeArguments* TypeArguments::InstantiateAndCanonicalizeFrom( |
const TypeArguments& instantiator_type_arguments, |
+ const TypeArguments& function_type_arguments, |
Error* bound_error) const { |
ASSERT(!IsInstantiated()); |
ASSERT(instantiator_type_arguments.IsNull() || |
instantiator_type_arguments.IsCanonical()); |
+ ASSERT(function_type_arguments.IsNull() || |
+ function_type_arguments.IsCanonical()); |
// Lookup instantiator and, if found, return paired instantiated result. |
Array& prior_instantiations = Array::Handle(instantiations()); |
ASSERT(!prior_instantiations.IsNull() && prior_instantiations.IsArray()); |
@@ -5025,18 +5038,19 @@ RawTypeArguments* TypeArguments::InstantiateAndCanonicalizeFrom( |
ASSERT(prior_instantiations.Length() > 0); // Always at least a sentinel. |
intptr_t index = 0; |
while (true) { |
- if (prior_instantiations.At(index) == instantiator_type_arguments.raw()) { |
- return TypeArguments::RawCast(prior_instantiations.At(index + 1)); |
+ if ((prior_instantiations.At(index) == instantiator_type_arguments.raw()) && |
+ (prior_instantiations.At(index + 1) == function_type_arguments.raw())) { |
+ return TypeArguments::RawCast(prior_instantiations.At(index + 2)); |
} |
if (prior_instantiations.At(index) == Smi::New(StubCode::kNoInstantiator)) { |
break; |
} |
- index += 2; |
+ index += StubCode::kInstantiationSizeInWords; |
} |
// Cache lookup failed. Instantiate the type arguments. |
TypeArguments& result = TypeArguments::Handle(); |
- result = InstantiateFrom(instantiator_type_arguments, bound_error, NULL, NULL, |
- Heap::kOld); |
+ result = InstantiateFrom(instantiator_type_arguments, function_type_arguments, |
+ bound_error, NULL, NULL, Heap::kOld); |
if ((bound_error != NULL) && !bound_error->IsNull()) { |
return result.raw(); |
} |
@@ -5045,21 +5059,30 @@ RawTypeArguments* TypeArguments::InstantiateAndCanonicalizeFrom( |
// InstantiateAndCanonicalizeFrom is not reentrant. It cannot have been called |
// indirectly, so the prior_instantiations array cannot have grown. |
ASSERT(prior_instantiations.raw() == instantiations()); |
- // Add instantiator and result to instantiations array. |
+ // Do not cache result if the context is required to instantiate the |
+ // type arguments, i.e. they refer to the type parameters of parent functions. |
+ if (!IsInstantiated(kParentFunctions)) { |
+ return result.raw(); |
+ } |
+ // Add instantiator and function type args and result to instantiations array. |
intptr_t length = prior_instantiations.Length(); |
- if ((index + 2) >= length) { |
+ if ((index + StubCode::kInstantiationSizeInWords) >= length) { |
+ // TODO(regis): Should we limit the number of cached instantiations? |
// Grow the instantiations array. |
// The initial array is Object::zero_array() of length 1. |
- length = (length > 64) ? (length + 64) |
- : ((length == 1) ? 3 : ((length - 1) * 2 + 1)); |
+ length = (length > 64) |
+ ? (length + 64) |
+ : ((length == 1) ? StubCode::kInstantiationSizeInWords + 1 |
+ : ((length - 1) * 2 + 1)); |
prior_instantiations = |
Array::Grow(prior_instantiations, length, Heap::kOld); |
set_instantiations(prior_instantiations); |
- ASSERT((index + 2) < length); |
+ ASSERT((index + StubCode::kInstantiationSizeInWords) < length); |
} |
- prior_instantiations.SetAt(index, instantiator_type_arguments); |
- prior_instantiations.SetAt(index + 1, result); |
- prior_instantiations.SetAt(index + 2, |
+ prior_instantiations.SetAt(index + 0, instantiator_type_arguments); |
+ prior_instantiations.SetAt(index + 1, function_type_arguments); |
+ prior_instantiations.SetAt(index + 2, result); |
+ prior_instantiations.SetAt(index + 3, |
Smi::Handle(Smi::New(StubCode::kNoInstantiator))); |
return result.raw(); |
} |
@@ -5960,6 +5983,8 @@ intptr_t Function::NumTypeParameters(Thread* thread) const { |
REUSABLE_TYPE_ARGUMENTS_HANDLESCOPE(thread); |
TypeArguments& type_params = thread->TypeArgumentsHandle(); |
type_params = type_parameters(); |
+ // We require null to represent a non-generic function. |
+ ASSERT(type_params.Length() != 0); |
return type_params.Length(); |
} |
@@ -6387,6 +6412,7 @@ bool Function::HasCompatibleParametersWith(const Function& other, |
// TODO(regis): Should we pass the context explicitly here (i.e. null) once |
// we support generic functions? |
this_fun = this_fun.InstantiateSignatureFrom(Object::null_type_arguments(), |
+ Object::null_type_arguments(), |
Heap::kOld); |
} |
Function& other_fun = Function::Handle(other.raw()); |
@@ -6394,7 +6420,8 @@ bool Function::HasCompatibleParametersWith(const Function& other, |
// TODO(regis): Should we pass the context explicitly here (i.e. null) once |
// we support generic functions? |
other_fun = other_fun.InstantiateSignatureFrom( |
- Object::null_type_arguments(), Heap::kOld); |
+ Object::null_type_arguments(), Object::null_type_arguments(), |
+ Heap::kOld); |
} |
if (!this_fun.TypeTest(kIsSubtypeOf, other_fun, bound_error, Heap::kOld)) { |
// For more informative error reporting, use the location of the other |
@@ -6423,6 +6450,7 @@ bool Function::HasCompatibleParametersWith(const Function& other, |
RawFunction* Function::InstantiateSignatureFrom( |
const TypeArguments& instantiator_type_arguments, |
+ const TypeArguments& function_type_arguments, |
Heap::Space space) const { |
Zone* zone = Thread::Current()->zone(); |
const Object& owner = Object::Handle(zone, RawOwner()); |
@@ -6434,8 +6462,9 @@ RawFunction* Function::InstantiateSignatureFrom( |
sig.set_type_parameters(TypeArguments::Handle(zone, type_parameters())); |
AbstractType& type = AbstractType::Handle(zone, result_type()); |
if (!type.IsInstantiated()) { |
- type = type.InstantiateFrom(instantiator_type_arguments, NULL, NULL, NULL, |
- space); |
+ type = |
+ type.InstantiateFrom(instantiator_type_arguments, |
+ function_type_arguments, NULL, NULL, NULL, space); |
} |
sig.set_result_type(type); |
const intptr_t num_params = NumParameters(); |
@@ -6446,7 +6475,8 @@ RawFunction* Function::InstantiateSignatureFrom( |
for (intptr_t i = 0; i < num_params; i++) { |
type = ParameterTypeAt(i); |
if (!type.IsInstantiated()) { |
- type = type.InstantiateFrom(instantiator_type_arguments, NULL, NULL, NULL, |
+ type = type.InstantiateFrom(instantiator_type_arguments, |
+ function_type_arguments, NULL, NULL, NULL, |
space); |
} |
sig.SetParameterTypeAt(i, type); |
@@ -15079,6 +15109,7 @@ void SubtypeTestCache::AddCheck( |
const Object& instance_class_id_or_function, |
const TypeArguments& instance_type_arguments, |
const TypeArguments& instantiator_type_arguments, |
+ const TypeArguments& function_type_arguments, |
const Bool& test_result) const { |
intptr_t old_num = NumberOfChecks(); |
Array& data = Array::Handle(cache()); |
@@ -15091,6 +15122,7 @@ void SubtypeTestCache::AddCheck( |
data.SetAt(data_pos + kInstanceTypeArguments, instance_type_arguments); |
data.SetAt(data_pos + kInstantiatorTypeArguments, |
instantiator_type_arguments); |
+ data.SetAt(data_pos + kFunctionTypeArguments, function_type_arguments); |
data.SetAt(data_pos + kTestResult, test_result); |
} |
@@ -15099,6 +15131,7 @@ void SubtypeTestCache::GetCheck(intptr_t ix, |
Object* instance_class_id_or_function, |
TypeArguments* instance_type_arguments, |
TypeArguments* instantiator_type_arguments, |
+ TypeArguments* function_type_arguments, |
Bool* test_result) const { |
Array& data = Array::Handle(cache()); |
intptr_t data_pos = ix * kTestEntryLength; |
@@ -15107,6 +15140,7 @@ void SubtypeTestCache::GetCheck(intptr_t ix, |
*instance_type_arguments ^= data.At(data_pos + kInstanceTypeArguments); |
*instantiator_type_arguments ^= |
data.At(data_pos + kInstantiatorTypeArguments); |
+ *function_type_arguments ^= data.At(data_pos + kFunctionTypeArguments); |
*test_result ^= data.At(data_pos + kTestResult); |
} |
@@ -15616,10 +15650,13 @@ RawAbstractType* Instance::GetType(Heap::Space space) const { |
if (!type.IsInstantiated()) { |
TypeArguments& instantiator_type_arguments = |
TypeArguments::Handle(Closure::Cast(*this).instantiator()); |
- // TODO(regis): Should we pass the context explicitly here (i.e. null) |
- // once we support generic functions? |
- type ^= type.InstantiateFrom(instantiator_type_arguments, NULL, NULL, |
- NULL, space); |
+ const TypeArguments& function_type_arguments = |
+ TypeArguments::Handle(signature.type_parameters()); |
+ // TODO(regis): Pass the closure context to InstantiateSignatureFrom(). |
+ // No bound error possible, since the instance exists. |
+ type ^= type.InstantiateFrom(instantiator_type_arguments, |
+ function_type_arguments, NULL, NULL, NULL, |
+ space); |
} |
type ^= type.Canonicalize(); |
return type.raw(); |
@@ -15660,9 +15697,11 @@ void Instance::SetTypeArguments(const TypeArguments& value) const { |
} |
-bool Instance::IsInstanceOf(const AbstractType& other, |
- const TypeArguments& other_instantiator, |
- Error* bound_error) const { |
+bool Instance::IsInstanceOf( |
+ const AbstractType& other, |
+ const TypeArguments& other_instantiator_type_arguments, |
+ const TypeArguments& other_function_type_arguments, |
+ Error* bound_error) const { |
ASSERT(other.IsFinalized()); |
ASSERT(!other.IsDynamicType()); |
ASSERT(!other.IsTypeRef()); // Must be dereferenced at compile time. |
@@ -15682,7 +15721,8 @@ bool Instance::IsInstanceOf(const AbstractType& other, |
// Note that we may encounter a bound error in checked mode. |
if (!other.IsInstantiated()) { |
instantiated_other = other.InstantiateFrom( |
- other_instantiator, bound_error, NULL, NULL, Heap::kOld); |
+ other_instantiator_type_arguments, other_function_type_arguments, |
+ bound_error, NULL, NULL, Heap::kOld); |
if ((bound_error != NULL) && !bound_error->IsNull()) { |
ASSERT(Isolate::Current()->type_checks()); |
return false; |
@@ -15705,12 +15745,11 @@ bool Instance::IsInstanceOf(const AbstractType& other, |
if (!sig_fun.HasInstantiatedSignature()) { |
const TypeArguments& instantiator_type_arguments = |
TypeArguments::Handle(zone, Closure::Cast(*this).instantiator()); |
- // TODO(regis): If sig_fun is generic, pass its type parameters |
- // as function instantiator, otherwise pass null. |
- // Pass the closure context as well to InstantiateSignatureFrom(). |
- // No bound error possible, since the instance exists. |
- sig_fun = sig_fun.InstantiateSignatureFrom(instantiator_type_arguments, |
- Heap::kOld); |
+ const TypeArguments& function_type_arguments = |
+ TypeArguments::Handle(zone, sig_fun.type_parameters()); |
+ // TODO(regis): Pass the closure context to InstantiateSignatureFrom(). |
+ sig_fun = sig_fun.InstantiateSignatureFrom( |
+ instantiator_type_arguments, function_type_arguments, Heap::kOld); |
} |
return sig_fun.IsSubtypeOf(other_signature, bound_error, Heap::kOld); |
} |
@@ -15734,8 +15773,9 @@ bool Instance::IsInstanceOf(const AbstractType& other, |
AbstractType& instantiated_other = AbstractType::Handle(zone, other.raw()); |
// Note that we may encounter a bound error in checked mode. |
if (!other.IsInstantiated()) { |
- instantiated_other = other.InstantiateFrom(other_instantiator, bound_error, |
- NULL, NULL, Heap::kOld); |
+ instantiated_other = other.InstantiateFrom( |
+ other_instantiator_type_arguments, other_function_type_arguments, |
+ bound_error, NULL, NULL, Heap::kOld); |
if ((bound_error != NULL) && !bound_error->IsNull()) { |
ASSERT(Isolate::Current()->type_checks()); |
return false; |
@@ -15758,11 +15798,12 @@ bool Instance::IsInstanceOf(const AbstractType& other, |
return true; |
} |
if (!sig_fun.HasInstantiatedSignature()) { |
- // TODO(regis): If sig_fun is generic, pass its type parameters |
- // as function instantiator, otherwise pass null. |
- // Pass the closure context as well to InstantiateSignatureFrom(). |
+ const TypeArguments& function_type_arguments = |
+ TypeArguments::Handle(zone, sig_fun.type_parameters()); |
+ // TODO(regis): Pass the closure context to InstantiateSignatureFrom(). |
// No bound error possible, since the instance exists. |
- sig_fun = sig_fun.InstantiateSignatureFrom(type_arguments, Heap::kOld); |
+ sig_fun = sig_fun.InstantiateSignatureFrom( |
+ type_arguments, function_type_arguments, Heap::kOld); |
} |
const Function& other_signature = |
Function::Handle(zone, Type::Cast(instantiated_other).signature()); |
@@ -16117,6 +16158,7 @@ bool AbstractType::IsRecursive() const { |
RawAbstractType* AbstractType::InstantiateFrom( |
const TypeArguments& instantiator_type_arguments, |
+ const TypeArguments& function_type_arguments, |
Error* bound_error, |
TrailPtr instantiation_trail, |
TrailPtr bound_trail, |
@@ -16890,6 +16932,7 @@ bool Type::IsInstantiated(Genericity genericity, TrailPtr trail) const { |
RawAbstractType* Type::InstantiateFrom( |
const TypeArguments& instantiator_type_arguments, |
+ const TypeArguments& function_type_arguments, |
Error* bound_error, |
TrailPtr instantiation_trail, |
TrailPtr bound_trail, |
@@ -16914,9 +16957,9 @@ RawAbstractType* Type::InstantiateFrom( |
// Note that the type arguments of a function type merely document the |
// parameterization of a generic typedef. They are otherwise ignored. |
ASSERT(type_arguments.Length() == cls.NumTypeArguments()); |
- type_arguments = |
- type_arguments.InstantiateFrom(instantiator_type_arguments, bound_error, |
- instantiation_trail, bound_trail, space); |
+ type_arguments = type_arguments.InstantiateFrom( |
+ instantiator_type_arguments, function_type_arguments, bound_error, |
+ instantiation_trail, bound_trail, space); |
} |
// This uninstantiated type is not modified, as it can be instantiated |
// with different instantiators. Allocate a new instantiated version of it. |
@@ -16936,8 +16979,8 @@ RawAbstractType* Type::InstantiateFrom( |
if (IsFinalized()) { |
// A generic typedef may actually declare an instantiated signature. |
if (!sig_fun.HasInstantiatedSignature()) { |
- sig_fun = sig_fun.InstantiateSignatureFrom(instantiator_type_arguments, |
- space); |
+ sig_fun = sig_fun.InstantiateSignatureFrom( |
+ instantiator_type_arguments, function_type_arguments, space); |
} |
} else { |
// The Kernel frontend does not keep the information that a function type |
@@ -17595,6 +17638,7 @@ bool TypeRef::IsEquivalent(const Instance& other, TrailPtr trail) const { |
RawTypeRef* TypeRef::InstantiateFrom( |
const TypeArguments& instantiator_type_arguments, |
+ const TypeArguments& function_type_arguments, |
Error* bound_error, |
TrailPtr instantiation_trail, |
TrailPtr bound_trail, |
@@ -17610,9 +17654,9 @@ RawTypeRef* TypeRef::InstantiateFrom( |
AbstractType& ref_type = AbstractType::Handle(type()); |
ASSERT(!ref_type.IsTypeRef()); |
AbstractType& instantiated_ref_type = AbstractType::Handle(); |
- instantiated_ref_type = |
- ref_type.InstantiateFrom(instantiator_type_arguments, bound_error, |
- instantiation_trail, bound_trail, space); |
+ instantiated_ref_type = ref_type.InstantiateFrom( |
+ instantiator_type_arguments, function_type_arguments, bound_error, |
+ instantiation_trail, bound_trail, space); |
ASSERT(!instantiated_ref_type.IsTypeRef()); |
instantiated_type_ref.set_type(instantiated_ref_type); |
return instantiated_type_ref.raw(); |
@@ -17834,16 +17878,29 @@ void TypeParameter::set_bound(const AbstractType& value) const { |
RawAbstractType* TypeParameter::InstantiateFrom( |
const TypeArguments& instantiator_type_arguments, |
+ const TypeArguments& function_type_arguments, |
Error* bound_error, |
TrailPtr instantiation_trail, |
TrailPtr bound_trail, |
Heap::Space space) const { |
ASSERT(IsFinalized()); |
+ if (IsFunctionTypeParameter()) { |
+ if (parent_level() == 0) { |
+ if (function_type_arguments.IsNull()) { |
+ return Type::DynamicType(); |
+ } |
+ return function_type_arguments.TypeAt(index()); |
+ } |
+ // We need to find the type argument vector of the parent function at |
+ // parent_level() in the context. |
+ UNIMPLEMENTED(); |
+ return function_type_arguments.TypeAt(index()); |
+ } |
+ ASSERT(IsClassTypeParameter()); |
if (instantiator_type_arguments.IsNull()) { |
return Type::DynamicType(); |
} |
- const AbstractType& type_arg = |
- AbstractType::Handle(instantiator_type_arguments.TypeAt(index())); |
+ return instantiator_type_arguments.TypeAt(index()); |
// There is no need to canonicalize the instantiated type parameter, since all |
// type arguments are canonicalized at type finalization time. It would be too |
// early to canonicalize the returned type argument here, since instantiation |
@@ -17854,7 +17911,6 @@ RawAbstractType* TypeParameter::InstantiateFrom( |
// time (i.e. compile time). |
// Indeed, the instantiator (type arguments of an instance) is always |
// instantiated at run time and any bounds were checked during allocation. |
- return type_arg.raw(); |
} |
@@ -18165,6 +18221,7 @@ void BoundedType::set_type_parameter(const TypeParameter& value) const { |
RawAbstractType* BoundedType::InstantiateFrom( |
const TypeArguments& instantiator_type_arguments, |
+ const TypeArguments& function_type_arguments, |
Error* bound_error, |
TrailPtr instantiation_trail, |
TrailPtr bound_trail, |
@@ -18175,9 +18232,9 @@ RawAbstractType* BoundedType::InstantiateFrom( |
AbstractType& instantiated_bounded_type = |
AbstractType::Handle(bounded_type.raw()); |
if (!bounded_type.IsInstantiated()) { |
- instantiated_bounded_type = |
- bounded_type.InstantiateFrom(instantiator_type_arguments, bound_error, |
- instantiation_trail, bound_trail, space); |
+ instantiated_bounded_type = bounded_type.InstantiateFrom( |
+ instantiator_type_arguments, function_type_arguments, bound_error, |
+ instantiation_trail, bound_trail, space); |
// In case types of instantiator_type_arguments are not finalized |
// (or instantiated), then the instantiated_bounded_type is not finalized |
// (or instantiated) either. |
@@ -18190,9 +18247,9 @@ RawAbstractType* BoundedType::InstantiateFrom( |
AbstractType& instantiated_upper_bound = |
AbstractType::Handle(upper_bound.raw()); |
if (upper_bound.IsFinalized() && !upper_bound.IsInstantiated()) { |
- instantiated_upper_bound = |
- upper_bound.InstantiateFrom(instantiator_type_arguments, bound_error, |
- instantiation_trail, bound_trail, space); |
+ instantiated_upper_bound = upper_bound.InstantiateFrom( |
+ instantiator_type_arguments, function_type_arguments, bound_error, |
+ instantiation_trail, bound_trail, space); |
// The instantiated_upper_bound may not be finalized or instantiated. |
// See comment above. |
} |