Index: runtime/vm/parser.cc |
=================================================================== |
--- runtime/vm/parser.cc (revision 415) |
+++ runtime/vm/parser.cc (working copy) |
@@ -838,10 +838,6 @@ |
ParseFormalParameterList(no_explicit_default_values, &func_params); |
// Change the name of the parameter type to be the signature of the |
// function type. |
- // Note that the function type signature may involve parameters of a type |
- // that is a type parameter of the enclosing class, so we parameterize the |
- // signature with the type parameters of the enclosing class, if any. |
- // TODO(regis): Revisit if this is not the right thing to do. |
const bool is_static = |
current_function().IsNull() || current_function().is_static(); |
const Function& signature_function = Function::Handle( |
@@ -1130,6 +1126,15 @@ |
if (receiver == NULL) { |
return new ImplicitStaticClosureNode(token_pos, implicit_closure_function); |
} else { |
+ // If we create an implicit instance closure from inside a closure of a |
+ // parameterized class, make sure that the receiver is captured as |
+ // instantiator. |
+ if (current_block_->scope->function_level() > 0) { |
+ const Class& signature_class = Class::Handle(func.signature_class()); |
+ if (signature_class.IsParameterized()) { |
+ CaptureReceiver(); |
+ } |
+ } |
return new ImplicitInstanceClosureNode(token_pos, |
implicit_closure_function, |
receiver); |
@@ -1601,10 +1606,10 @@ |
ParseInitializers(cls); |
} |
- if (current_block_->scope->function_level() > 0) { |
+ if (FLAG_enable_type_checks && |
+ (current_block_->scope->function_level() > 0)) { |
// We are parsing, but not compiling, a local function. |
- // The instantiator may be required at run time for generic type checks or |
- // allocation of generic types. |
+ // The instantiator may be required at run time for generic type checks. |
if (current_class().IsParameterized() && |
(!current_function().is_static() || |
current_function().IsInFactoryScope())) { |
@@ -1612,9 +1617,7 @@ |
// (or implicit first parameter of an enclosing factory) is marked as |
// captured if type checks are enabled, because they may access the |
// receiver to instantiate types. |
- if (FLAG_enable_type_checks) { |
- CaptureReceiver(); |
- } |
+ CaptureReceiver(); |
} |
} |
@@ -3378,22 +3381,28 @@ |
current_function(), |
token_index_)); |
function.set_result_type(result_type); |
+ |
+ // The function type does not need to be determined at compile time, unless |
+ // the closure is assigned to a function variable and type checks are enabled. |
+ // At run time, the function type is derived from the signature class of the |
+ // closure function and from the type arguments of the instantiator. |
+ |
LocalVariable* function_variable = NULL; |
ParameterizedType& function_type = ParameterizedType::ZoneHandle(); |
if (variable_name != NULL) { |
- // Add the function variable to the scope before parsing the function in |
- // order to allow self reference from inside the function. |
- // The type of the implicitly declared const variable is defined by the |
- // local function signature class and the type arguments of the current |
- // receiver (if in a non-static scope). However, the signature is not yet |
- // known, since the formal parameter list is not parsed yet. Therefore, we |
- // set the type to a new parameterized type to be patched after the actual |
- // type is known. We temporarily use the class of the Function interface. |
+ // Since the function type depends on the signature of the closure function, |
+ // it cannot be determined before the formal parameter list of the closure |
+ // function is parsed. Therefore, we set the function type to a new |
+ // parameterized type to be patched after the actual type is known. |
+ // We temporarily use the class of the Function interface. |
const Class& unknown_signature_class = Class::Handle( |
Type::Handle(Type::FunctionInterface()).type_class()); |
function_type = ParameterizedType::New(unknown_signature_class, |
TypeArguments::Handle()); |
function_type.set_is_finalized(); // No real finalization needed. |
+ |
+ // Add the function variable to the scope before parsing the function in |
+ // order to allow self reference from inside the function. |
function_variable = new LocalVariable(ident_pos, |
*variable_name, |
function_type); |
@@ -3431,23 +3440,53 @@ |
// finalized. |
ASSERT(current_class().is_finalized()); |
- if (function_variable != NULL) { |
- ASSERT(function_variable->type().raw() == function_type.raw()); |
- // Patch the function variable type now that the signature is known. |
+ // Make sure that the instantiator is captured. |
+ if (signature_class.IsParameterized() && |
+ (current_block_->scope->function_level() > 0)) { |
+ CaptureReceiver(); |
+ } |
+ |
+ if (variable_name != NULL) { |
+ // Patch the function type now that the signature is known. |
// We need to create a new type for proper finalization, since the existing |
// type is already marked as finalized. |
- // TODO(regis): Set proper signature_type_arguments if in non-static scope |
- // and if the signature involves generic types. |
- const TypeArguments& signature_type_arguments = TypeArguments::Handle(); |
+ TypeArguments& signature_type_arguments = TypeArguments::Handle(); |
+ if (signature_class.IsParameterized()) { |
+ const intptr_t num_type_params = signature_class.NumTypeParameters(); |
+ const Array& type_params = Array::Handle( |
+ signature_class.type_parameters()); |
+ signature_type_arguments = TypeArguments::NewTypeArray(num_type_params); |
+ String& type_param_name = String::Handle(); |
+ Type& type_param = Type::Handle(); |
+ for (int i = 0; i < num_type_params; i++) { |
+ type_param_name ^= type_params.At(i); |
+ type_param = Type::NewTypeParameter(i, type_param_name); |
+ signature_type_arguments.SetTypeAt(i, type_param); |
+ } |
+ } |
+ const ParameterizedType& actual_function_type = ParameterizedType::Handle( |
+ ParameterizedType::New(signature_class, signature_type_arguments)); |
const String& errmsg = String::Handle( |
- ClassFinalizer::FinalizeTypeWhileParsing(ParameterizedType::Handle( |
- ParameterizedType::New(signature_class, |
- signature_type_arguments)))); |
+ ClassFinalizer::FinalizeTypeWhileParsing(actual_function_type)); |
if (!errmsg.IsNull()) { |
ErrorMsg(errmsg.ToCString()); |
} |
+ // The call to ClassFinalizer::FinalizeTypeWhileParsing may have extended |
+ // the vector of type arguments. |
+ signature_type_arguments = actual_function_type.arguments(); |
+ ASSERT(signature_type_arguments.IsNull() || |
+ (signature_type_arguments.Length() == |
+ signature_class.NumTypeArguments())); |
+ // The signature_class should not have changed. |
+ ASSERT(actual_function_type.type_class() == signature_class.raw()); |
+ |
+ // Now patch the function type of the variable. |
function_type.set_type_class(signature_class); |
function_type.set_arguments(signature_type_arguments); |
+ |
+ // The function variable type should have been patched above. |
+ ASSERT((function_variable == NULL) || |
+ (function_variable->type().raw() == function_type.raw())); |
} |
// The code generator does not compile the closure function when visiting |