Chromium Code Reviews| Index: runtime/vm/object.cc |
| diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc |
| index 79b65d0679b5c3706861573a2cb8b45e7dbaf684..4e70608fde575ffaca700d6cc7193c61880d15bc 100644 |
| --- a/runtime/vm/object.cc |
| +++ b/runtime/vm/object.cc |
| @@ -52,6 +52,10 @@ |
| namespace dart { |
| +DEFINE_FLAG(bool, |
|
zra
2017/04/20 19:22:09
Should we put this in flag_list.h?
regis
2017/04/20 20:23:30
Done.
|
| + reify_generic_functions, |
| + false, |
| + "Enable reification of generic functions (not yet supported)."); |
| DEFINE_FLAG(int, |
| huge_method_cutoff_in_code_size, |
| 200000, |
| @@ -6432,19 +6436,17 @@ bool Function::HasCompatibleParametersWith(const Function& other, |
| ASSERT((bound_error != NULL) && bound_error->IsNull()); |
| // Check that this function's signature type is a subtype of the other |
| // function's signature type. |
| - // Map type parameters in the signature to dynamic before the test. |
| + // Map type parameters referred to by formal parameter types and result type |
| + // in the signature to dynamic before the test. |
| + // Note that type parameters declared by a generic signature are preserved. |
| Function& this_fun = Function::Handle(raw()); |
| if (!this_fun.HasInstantiatedSignature()) { |
| - // 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()); |
| if (!other_fun.HasInstantiatedSignature()) { |
| - // 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(), Object::null_type_arguments(), |
| Heap::kOld); |
| @@ -6484,8 +6486,6 @@ RawFunction* Function::InstantiateSignatureFrom( |
| Function& sig = Function::Handle( |
| zone, |
| Function::NewSignatureFunction(owner, TokenPosition::kNoSource, space)); |
| - // TODO(regis): If type parameter bounds are not IsInstantiated(kFunctions), |
| - // clone finalized type parameters and instantiate bounds. |
| sig.set_type_parameters(TypeArguments::Handle(zone, type_parameters())); |
| AbstractType& type = AbstractType::Handle(zone, result_type()); |
| if (!type.IsInstantiated()) { |
| @@ -6577,14 +6577,41 @@ bool Function::TypeTest(TypeTestKind test_kind, |
| (num_opt_named_params < other_num_opt_named_params)) { |
| return false; |
| } |
| - |
| - // TODO(regis): Check the type parameters and bounds of a generic function. |
| - |
| + Thread* thread = Thread::Current(); |
| + Zone* zone = thread->zone(); |
| + if (FLAG_reify_generic_functions) { |
| + // Check the type parameters and bounds of a generic function. |
| + const intptr_t num_type_params = NumTypeParameters(thread); |
| + if (num_type_params != other.NumTypeParameters(thread)) { |
| + return false; |
| + } |
| + if (num_type_params > 0) { |
| + const TypeArguments& type_params = |
| + TypeArguments::Handle(zone, type_parameters()); |
| + ASSERT(!type_params.IsNull()); |
| + const TypeArguments& other_type_params = |
| + TypeArguments::Handle(zone, other.type_parameters()); |
| + ASSERT(!other_type_params.IsNull()); |
| + TypeParameter& type_param = TypeParameter::Handle(zone); |
| + TypeParameter& other_type_param = TypeParameter::Handle(zone); |
| + AbstractType& bound = AbstractType::Handle(zone); |
| + AbstractType& other_bound = AbstractType::Handle(zone); |
| + for (intptr_t i = 0; i < num_type_params; i++) { |
| + type_param ^= type_params.TypeAt(i); |
| + other_type_param ^= other_type_params.TypeAt(i); |
| + bound = type_param.bound(); |
| + other_bound = other_type_param.bound(); |
|
siva
2017/04/20 20:32:08
Should we assert here that the two types are final
regis
2017/04/20 21:18:26
The Equals call should do the right thing in case
|
| + if (!bound.Equals(other_bound)) { |
| + return false; |
| + } |
| + } |
| + } |
| + } |
| // Check the result type. |
| const AbstractType& other_res_type = |
| - AbstractType::Handle(other.result_type()); |
| + AbstractType::Handle(zone, other.result_type()); |
| if (!other_res_type.IsDynamicType() && !other_res_type.IsVoidType()) { |
| - const AbstractType& res_type = AbstractType::Handle(result_type()); |
| + const AbstractType& res_type = AbstractType::Handle(zone, result_type()); |
| if (res_type.IsVoidType()) { |
| return false; |
| } |
| @@ -6626,13 +6653,13 @@ bool Function::TypeTest(TypeTestKind test_kind, |
| const int other_num_params = |
| other_num_fixed_params + other_num_opt_named_params; |
| bool found_param_name; |
| - String& other_param_name = String::Handle(); |
| + String& other_param_name = String::Handle(zone); |
| for (intptr_t i = other_num_fixed_params; i < other_num_params; i++) { |
| other_param_name = other.ParameterNameAt(i); |
| ASSERT(other_param_name.IsSymbol()); |
| found_param_name = false; |
| for (intptr_t j = num_fixed_params; j < num_params; j++) { |
| - ASSERT(String::Handle(ParameterNameAt(j)).IsSymbol()); |
| + ASSERT(String::Handle(zone, ParameterNameAt(j)).IsSymbol()); |
| if (ParameterNameAt(j) == other_param_name.raw()) { |
| found_param_name = true; |
| if (!TestParameterType(test_kind, j, i, other, bound_error, space)) { |
| @@ -6762,11 +6789,13 @@ RawFunction* Function::New(const String& name, |
| RawFunction* Function::Clone(const Class& new_owner) const { |
| ASSERT(!IsGenerativeConstructor()); |
| - Function& clone = Function::Handle(); |
| + Thread* thread = Thread::Current(); |
| + Zone* zone = thread->zone(); |
| + Function& clone = Function::Handle(zone); |
| clone ^= Object::Clone(*this, Heap::kOld); |
| - const Class& origin = Class::Handle(this->origin()); |
| + const Class& origin = Class::Handle(zone, this->origin()); |
| const PatchClass& clone_owner = |
| - PatchClass::Handle(PatchClass::New(new_owner, origin)); |
| + PatchClass::Handle(zone, PatchClass::New(new_owner, origin)); |
| clone.set_owner(clone_owner); |
| clone.ClearICDataArray(); |
| clone.ClearCode(); |
| @@ -6775,14 +6804,27 @@ RawFunction* Function::Clone(const Class& new_owner) const { |
| clone.set_optimized_instruction_count(0); |
| clone.set_optimized_call_site_count(0); |
| clone.set_kernel_function(kernel_function()); |
| - // TODO(regis): Clone function type parameters (their bounds may change). |
| if (new_owner.NumTypeParameters() > 0) { |
| // Adjust uninstantiated types to refer to type parameters of the new owner. |
| - AbstractType& type = AbstractType::Handle(clone.result_type()); |
| + const TypeArguments& type_params = |
| + TypeArguments::Handle(zone, type_parameters()); |
| + if (!type_params.IsNull()) { |
| + const intptr_t num_type_params = type_params.Length(); |
| + const TypeArguments& type_params_clone = |
| + TypeArguments::Handle(zone, TypeArguments::New(num_type_params)); |
| + TypeParameter& type_param = TypeParameter::Handle(zone); |
| + for (intptr_t i = 0; i < num_type_params; i++) { |
| + type_param ^= type_params.TypeAt(i); |
| + type_param ^= type_param.CloneUninstantiated(new_owner); |
| + type_params_clone.SetTypeAt(i, type_param); |
| + } |
| + clone.set_type_parameters(type_params_clone); |
| + } |
| + AbstractType& type = AbstractType::Handle(zone, clone.result_type()); |
| type ^= type.CloneUninstantiated(new_owner); |
| clone.set_result_type(type); |
| const intptr_t num_params = clone.NumParameters(); |
| - Array& array = Array::Handle(clone.parameter_types()); |
| + Array& array = Array::Handle(zone, clone.parameter_types()); |
| array ^= Object::Clone(array, Heap::kOld); |
| clone.set_parameter_types(array); |
| for (intptr_t i = 0; i < num_params; i++) { |
| @@ -6873,6 +6915,10 @@ RawFunction* Function::ImplicitClosureFunction() const { |
| closure_function.set_context_scope(context_scope); |
| } |
| + // Set closure function's type parameters. |
| + closure_function.set_type_parameters( |
| + TypeArguments::Handle(type_parameters())); |
| + |
| // Set closure function's result type to this result type. |
| closure_function.set_result_type(AbstractType::Handle(result_type())); |
| @@ -7065,12 +7111,37 @@ RawString* Function::BuildSignature(NameVisibility name_visibility) const { |
| Thread* thread = Thread::Current(); |
| Zone* zone = thread->zone(); |
| GrowableHandlePtrArray<const String> pieces(zone, 4); |
| + String& name = String::Handle(zone); |
| + if (FLAG_reify_generic_functions) { |
| + const TypeArguments& type_params = |
| + TypeArguments::Handle(zone, type_parameters()); |
| + if (!type_params.IsNull()) { |
| + const intptr_t num_type_params = type_params.Length(); |
| + TypeParameter& type_param = TypeParameter::Handle(zone); |
| + AbstractType& bound = AbstractType::Handle(zone); |
| + pieces.Add(Symbols::LAngleBracket()); |
| + for (intptr_t i = 0; i < num_type_params; i++) { |
| + type_param ^= type_params.TypeAt(i); |
| + name = type_param.name(); |
| + pieces.Add(name); |
| + bound = type_param.bound(); |
| + if (!bound.IsNull() && !bound.IsObjectType()) { |
| + pieces.Add(Symbols::SpaceExtendsSpace()); |
| + name = bound.BuildName(name_visibility); |
| + pieces.Add(name); |
| + } |
| + if (i < num_type_params - 1) { |
| + pieces.Add(Symbols::CommaSpace()); |
| + } |
| + } |
| + pieces.Add(Symbols::RAngleBracket()); |
|
siva
2017/04/20 20:32:08
Do we still want '<>' if num_type_params is 0? or
regis
2017/04/20 21:18:26
Yes, we should never see an empty array. I added a
|
| + } |
| + } |
| pieces.Add(Symbols::LParen()); |
| BuildSignatureParameters(thread, zone, name_visibility, &pieces); |
| pieces.Add(Symbols::RParenArrow()); |
| const AbstractType& res_type = AbstractType::Handle(zone, result_type()); |
| - const String& name = |
| - String::Handle(zone, res_type.BuildName(name_visibility)); |
| + name = res_type.BuildName(name_visibility); |
| pieces.Add(name); |
| return Symbols::FromConcatAll(thread, pieces); |
| } |
| @@ -15814,7 +15885,6 @@ bool Instance::IsInstanceOf( |
| if (!sig_fun.HasInstantiatedSignature()) { |
| 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, function_type_arguments, Heap::kOld); |
| @@ -17123,6 +17193,35 @@ bool Type::IsEquivalent(const Instance& other, TrailPtr trail) const { |
| const Function& other_sig_fun = |
| Function::Handle(zone, other_type.signature()); |
| + if (FLAG_reify_generic_functions) { |
| + // Compare function type parameters and their bounds. |
| + const intptr_t num_type_params = sig_fun.NumTypeParameters(thread); |
| + if (num_type_params != other_sig_fun.NumTypeParameters(thread)) { |
| + return false; |
| + } |
| + if (num_type_params > 0) { |
| + const TypeArguments& type_params = |
| + TypeArguments::Handle(zone, sig_fun.type_parameters()); |
| + ASSERT(!type_params.IsNull()); |
| + const TypeArguments& other_type_params = |
| + TypeArguments::Handle(zone, other_sig_fun.type_parameters()); |
| + ASSERT(!other_type_params.IsNull()); |
| + TypeParameter& type_param = TypeParameter::Handle(zone); |
| + TypeParameter& other_type_param = TypeParameter::Handle(zone); |
| + AbstractType& bound = AbstractType::Handle(zone); |
| + AbstractType& other_bound = AbstractType::Handle(zone); |
| + for (intptr_t i = 0; i < num_type_params; i++) { |
| + type_param ^= type_params.TypeAt(i); |
| + other_type_param ^= other_type_params.TypeAt(i); |
| + bound = type_param.bound(); |
| + other_bound = other_type_param.bound(); |
| + if (!bound.Equals(other_bound)) { |
| + return false; |
| + } |
| + } |
| + } |
|
siva
2017/04/20 20:32:08
This code here is very similar to the one in Funct
regis
2017/04/20 21:18:26
That was bugging me too, and then I forgot :-)
I a
|
| + } |
| + |
| // Compare number of function parameters. |
| const intptr_t num_fixed_params = sig_fun.num_fixed_parameters(); |
| const intptr_t other_num_fixed_params = other_sig_fun.num_fixed_parameters(); |
| @@ -17211,7 +17310,20 @@ RawAbstractType* Type::CloneUnfinalized() const { |
| const Class& owner = Class::Handle(zone, fun.Owner()); |
| Function& fun_clone = Function::Handle( |
| zone, Function::NewSignatureFunction(owner, TokenPosition::kNoSource)); |
| - // TODO(regis): Handle cloning of a generic function type. |
| + const TypeArguments& type_params = |
| + TypeArguments::Handle(zone, fun.type_parameters()); |
| + if (!type_params.IsNull()) { |
| + const intptr_t num_type_params = type_params.Length(); |
| + const TypeArguments& type_params_clone = |
| + TypeArguments::Handle(zone, TypeArguments::New(num_type_params)); |
| + TypeParameter& type_param = TypeParameter::Handle(zone); |
| + for (intptr_t i = 0; i < num_type_params; i++) { |
| + type_param ^= type_params.TypeAt(i); |
| + type_param ^= type_param.CloneUnfinalized(); |
| + type_params_clone.SetTypeAt(i, type_param); |
| + } |
| + fun_clone.set_type_parameters(type_params_clone); |
| + } |
|
siva
2017/04/20 20:32:08
ditto comment about this matching up with the one
regis
2017/04/20 21:18:25
This one cannot easily be factored out. One is cal
|
| AbstractType& type = AbstractType::Handle(zone, fun.result_type()); |
| type = type.CloneUnfinalized(); |
| fun_clone.set_result_type(type); |
| @@ -17267,6 +17379,20 @@ RawAbstractType* Type::CloneUninstantiated(const Class& new_owner, |
| Function& fun_clone = Function::Handle( |
| zone, |
| Function::NewSignatureFunction(new_owner, TokenPosition::kNoSource)); |
| + const TypeArguments& type_params = |
| + TypeArguments::Handle(zone, fun.type_parameters()); |
| + if (!type_params.IsNull()) { |
| + const intptr_t num_type_params = type_params.Length(); |
| + const TypeArguments& type_params_clone = |
| + TypeArguments::Handle(zone, TypeArguments::New(num_type_params)); |
| + TypeParameter& type_param = TypeParameter::Handle(zone); |
| + for (intptr_t i = 0; i < num_type_params; i++) { |
| + type_param ^= type_params.TypeAt(i); |
| + type_param ^= type_param.CloneUninstantiated(new_owner, trail); |
| + type_params_clone.SetTypeAt(i, type_param); |
| + } |
| + fun_clone.set_type_parameters(type_params_clone); |
| + } |
| AbstractType& type = AbstractType::Handle(zone, fun.result_type()); |
| type = type.CloneUninstantiated(new_owner, trail); |
| fun_clone.set_result_type(type); |
| @@ -17393,6 +17519,8 @@ RawAbstractType* Type::Canonicalize(TrailPtr trail) const { |
| Function& sig_fun = Function::Handle( |
| zone, |
| Function::NewSignatureFunction(cls, TokenPosition::kNoSource)); |
| + sig_fun.set_type_parameters( |
| + TypeArguments::Handle(zone, fun.type_parameters())); |
| type = fun.result_type(); |
| type = type.Canonicalize(trail); |
| sig_fun.set_result_type(type); |
| @@ -18025,18 +18153,19 @@ RawAbstractType* TypeParameter::CloneUninstantiated(const Class& new_owner, |
| if (!clone.IsNull()) { |
| return clone.raw(); |
| } |
| - const Class& old_owner = Class::Handle(parameterized_class()); |
| - if (old_owner.IsNull()) { |
| + intptr_t new_index = index(); |
| + AbstractType& upper_bound = AbstractType::Handle(bound()); |
| + const Function& fun = Function::Handle(parameterized_function()); |
| + Class& cls = Class::Handle(parameterized_class()); |
| + if (!cls.IsNull()) { |
| + ASSERT(fun.IsNull()); |
| + new_index += new_owner.NumTypeArguments() - cls.NumTypeArguments(); |
| + cls = new_owner.raw(); |
| + } else { |
| ASSERT(IsFunctionTypeParameter()); |
| - // Function type parameters do not need cloning. |
| - return raw(); |
| + // Only the bounds of function type parameters need cloning. |
| } |
| - const intptr_t new_index = |
| - index() + new_owner.NumTypeArguments() - old_owner.NumTypeArguments(); |
| - AbstractType& upper_bound = AbstractType::Handle(bound()); |
| - ASSERT(parameterized_function() == Function::null()); |
| - clone = TypeParameter::New(new_owner, Function::Handle(), new_index, |
| - String::Handle(name()), |
| + clone = TypeParameter::New(cls, fun, new_index, String::Handle(name()), |
| upper_bound, // Not cloned yet. |
| token_pos()); |
| clone.SetIsFinalized(); |