Index: runtime/vm/object.cc |
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc |
index 4d9b87c7dcac5ecf194c992817356f290f8186f3..76f9a2a167a512c8dd5ffceb1e1f7e9fb18ec3b2 100644 |
--- a/runtime/vm/object.cc |
+++ b/runtime/vm/object.cc |
@@ -6525,10 +6525,11 @@ RawFunction* Function::InstantiateSignatureFrom( |
Heap::Space space) const { |
Zone* zone = Thread::Current()->zone(); |
const Object& owner = Object::Handle(zone, RawOwner()); |
+ const Function& parent = Function::Handle(zone, parent_function()); |
ASSERT(!HasInstantiatedSignature()); |
Function& sig = Function::Handle( |
- zone, |
- Function::NewSignatureFunction(owner, TokenPosition::kNoSource, space)); |
+ zone, Function::NewSignatureFunction(owner, parent, |
+ TokenPosition::kNoSource, space)); |
sig.set_type_parameters(TypeArguments::Handle(zone, type_parameters())); |
AbstractType& type = AbstractType::Handle(zone, result_type()); |
if (!type.IsInstantiated()) { |
@@ -6919,6 +6920,7 @@ RawFunction* Function::NewClosureFunction(const String& name, |
RawFunction* Function::NewSignatureFunction(const Object& owner, |
+ const Function& parent, |
TokenPosition token_pos, |
Heap::Space space) { |
const Function& result = Function::Handle(Function::New( |
@@ -6930,6 +6932,7 @@ RawFunction* Function::NewSignatureFunction(const Object& owner, |
/* is_native = */ false, |
owner, // Same as function type scope class. |
token_pos, space)); |
+ result.set_parent_function(parent); |
result.set_is_reflectable(false); |
result.set_is_visible(false); |
result.set_is_debuggable(false); |
@@ -16815,9 +16818,22 @@ bool AbstractType::TypeTest(TypeTestKind test_kind, |
// TODO(regis): Should we update TypeParameter::IsEquivalent() instead? |
if (type_param.IsFunctionTypeParameter() && |
other_type_param.IsFunctionTypeParameter() && |
- type_param.IsFinalized() && other_type_param.IsFinalized() && |
- (type_param.index() == other_type_param.index())) { |
- return true; |
+ type_param.IsFinalized() && other_type_param.IsFinalized()) { |
+ // To be compatible, the function type parameters should be declared at |
+ // the same position in the generic function. Their index therefore |
+ // needs adjustement before comparison. |
+ // Example: 'foo<F>(bar<B>(B b)) { }' and 'baz<Z>(Z z) { }', baz can be |
+ // assigned to bar, although B has index 1 and Z index 0. |
+ const Function& sig_fun = |
+ Function::Handle(zone, type_param.parameterized_function()); |
+ const Function& other_sig_fun = |
+ Function::Handle(zone, other_type_param.parameterized_function()); |
+ const int offset = sig_fun.NumParentTypeParameters(); |
+ const int other_offset = other_sig_fun.NumParentTypeParameters(); |
+ if (type_param.index() - offset == |
+ other_type_param.index() - other_offset) { |
+ return true; |
+ } |
} |
} |
const AbstractType& bound = AbstractType::Handle(zone, type_param.bound()); |
@@ -17445,8 +17461,10 @@ RawAbstractType* Type::CloneUnfinalized() const { |
Function& fun = Function::Handle(zone, signature()); |
if (!fun.IsNull()) { |
const Class& owner = Class::Handle(zone, fun.Owner()); |
- Function& fun_clone = Function::Handle( |
- zone, Function::NewSignatureFunction(owner, TokenPosition::kNoSource)); |
+ const Function& parent = Function::Handle(zone, fun.parent_function()); |
+ Function& fun_clone = |
+ Function::Handle(zone, Function::NewSignatureFunction( |
+ owner, parent, TokenPosition::kNoSource)); |
const TypeArguments& type_params = |
TypeArguments::Handle(zone, fun.type_parameters()); |
if (!type_params.IsNull()) { |
@@ -17513,9 +17531,11 @@ RawAbstractType* Type::CloneUninstantiated(const Class& new_owner, |
ASSERT(type_cls.IsTypedefClass() || type_cls.IsClosureClass()); |
// If the scope class is not a typedef and if it is generic, it must be the |
// mixin class, set it to the new owner. |
+ const Function& parent = Function::Handle(zone, fun.parent_function()); |
+ // TODO(regis): Is it safe to reuse the parent function with the old owner? |
Function& fun_clone = Function::Handle( |
- zone, |
- Function::NewSignatureFunction(new_owner, TokenPosition::kNoSource)); |
+ zone, Function::NewSignatureFunction(new_owner, parent, |
+ TokenPosition::kNoSource)); |
const TypeArguments& type_params = |
TypeArguments::Handle(zone, fun.type_parameters()); |
if (!type_params.IsNull()) { |
@@ -17660,11 +17680,18 @@ RawAbstractType* Type::Canonicalize(TrailPtr trail) const { |
if (IsFunctionType()) { |
const Function& fun = Function::Handle(zone, signature()); |
if (!fun.IsSignatureFunction()) { |
- Function& sig_fun = Function::Handle( |
- zone, |
- Function::NewSignatureFunction(cls, TokenPosition::kNoSource)); |
+ // In case of a generic function, the function type parameters in the |
+ // signature will still refer to the original function. This should not |
+ // be a problem, since they are finalized and the indices remain |
+ // unchanged. |
+ const Function& parent = Function::Handle(zone, fun.parent_function()); |
+ Function& sig_fun = |
+ Function::Handle(zone, Function::NewSignatureFunction( |
+ cls, parent, TokenPosition::kNoSource)); |
sig_fun.set_type_parameters( |
TypeArguments::Handle(zone, fun.type_parameters())); |
+ ASSERT(fun.HasGenericParent() == sig_fun.HasGenericParent()); |
+ ASSERT(fun.IsGeneric() == sig_fun.IsGeneric()); |
type = fun.result_type(); |
type = type.Canonicalize(trail); |
sig_fun.set_result_type(type); |