Index: runtime/vm/parser.cc |
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc |
index f139e766cd6bbf42eb0edac97db8a3e56d7772ed..739f604587b9ecd43ed82e7fae50098cd9e8fd2f 100644 |
--- a/runtime/vm/parser.cc |
+++ b/runtime/vm/parser.cc |
@@ -60,7 +60,7 @@ DEFINE_FLAG(bool, |
"Enable generic function syntax."); |
DEFINE_FLAG(bool, |
generic_method_semantics, |
- true, |
+ false, |
"Enable generic function semantics (not yet supported)."); |
DEFINE_FLAG(bool, |
initializing_formal_access, |
@@ -1163,7 +1163,7 @@ void Parser::ParseFunction(ParsedFunction* parsed_function) { |
} |
parsed_function->SetNodeSequence(node_sequence); |
- // The instantiator may be required at run time for generic type checks or |
+ // The instantiators may be required at run time for generic type checks or |
// allocation of generic types. |
if (parser.IsInstantiatorRequired()) { |
// In the case of a local function, only set the instantiator if the |
@@ -1181,6 +1181,16 @@ void Parser::ParseFunction(ParsedFunction* parsed_function) { |
parsed_function->set_instantiator(instantiator); |
} |
} |
+ if (FLAG_generic_method_semantics && parser.current_function().IsGeneric()) { |
+ const String* variable_name = &Symbols::FunctionInstantiatorVar(); |
+ const bool kTestOnly = true; |
+ LocalVariable* instantiator = |
+ node_sequence->scope()->LookupVariable(*variable_name, kTestOnly); |
+ ASSERT(instantiator != NULL); |
+ parsed_function->set_function_instantiator(instantiator); |
+ // Function instantiator variables of parent generic functions, if any, are |
+ // captured and accessible via the context. |
+ } |
} |
@@ -3460,6 +3470,14 @@ SequenceNode* Parser::ParseFunc(const Function& func, bool check_semicolon) { |
ASSERT(!func.IsGenerativeConstructor()); |
OpenFunctionBlock(func); // Build local scope for function. |
+ if (FLAG_generic_method_semantics && func.IsGeneric()) { |
+ // Insert function instantiator variable to scope. |
+ LocalVariable* function_instantiator = new (Z) LocalVariable( |
+ TokenPosition::kNoSource, TokenPosition::kNoSource, |
+ Symbols::FunctionInstantiatorVar(), Object::dynamic_type()); |
+ current_block_->scope->AddVariable(function_instantiator); |
+ } |
+ |
ParamList params; |
// An instance closure function may capture and access the receiver, but via |
// the context and not via the first formal parameter. |
@@ -3549,18 +3567,6 @@ SequenceNode* Parser::ParseFunc(const Function& func, bool check_semicolon) { |
// Populate function scope with the formal parameters. |
AddFormalParamsToScope(¶ms, current_block_->scope); |
- |
- if (I->type_checks() && (FunctionLevel() > 0)) { |
- // We are parsing, but not compiling, a local function. |
- // The instantiator may be required at run time for generic type checks. |
- if (IsInstantiatorRequired()) { |
- // Make sure that the receiver of the enclosing instance function |
- // (or implicit first parameter of an enclosing factory) is marked as |
- // captured if type checks are enabled, because they may access it to |
- // instantiate types. |
- CaptureInstantiator(); |
- } |
- } |
} |
const TokenPosition modifier_pos = TokenPos(); |
@@ -3620,6 +3626,22 @@ SequenceNode* Parser::ParseFunc(const Function& func, bool check_semicolon) { |
OpenAsyncGeneratorClosure(); |
} |
+ // Function level is now correctly set to parse the (possibly async) body. |
+ if (I->type_checks() && (FunctionLevel() > 0)) { |
+ // We are parsing, but not compiling, a local function. |
+ // The instantiator may be required at run time for generic type checks. |
+ // Note that the source of this local function may not reference the |
+ // generic type explicitly. However, it may assign a value to a captured |
+ // variable declared with its generic type in the enclosing function. |
+ // Make sure that the receiver of the enclosing instance function |
+ // (or implicit first parameter of an enclosing factory) is marked as |
+ // captured if type checks are enabled, because they may access it to |
+ // instantiate types. |
+ // If any enclosing parent of the function being parsed is generic, capture |
+ // their function instantiators. |
+ CaptureAllInstantiators(); |
+ } |
+ |
BoolScope allow_await(&this->await_is_keyword_, |
func.IsAsyncOrGenerator() || func.is_generated_body()); |
TokenPosition end_token_pos = TokenPosition::kNoSource; |
@@ -3792,10 +3814,8 @@ RawLibraryPrefix* Parser::ParsePrefix() { |
return LibraryPrefix::null(); |
} |
// Check whether the identifier is shadowed by a function type parameter. |
- // TODO(regis): Shortcut this lookup if no generic functions in scope. |
- if (!innermost_function().IsNull() && |
- (innermost_function().LookupTypeParameter(ident, NULL) != |
- TypeParameter::null())) { |
+ if (InGenericFunctionScope() && (innermost_function().LookupTypeParameter( |
+ ident, NULL) != TypeParameter::null())) { |
hausner
2017/03/08 06:19:36
Nit: weird formatting, but git cl format probably
regis
2017/03/08 16:18:49
Yes, I had to run git cl format. I'll try to fix i
|
return LibraryPrefix::null(); |
} |
// Check whether the identifier is shadowed by a class type parameter. |
@@ -5527,6 +5547,9 @@ void Parser::ParseTypeParameters(bool parameterizing_class) { |
parameterizing_class ? current_class() : Class::Handle(Z), |
parameterizing_class ? Function::Handle(Z) : innermost_function(), |
index, 0, type_parameter_name, type_parameter_bound, declaration_pos); |
+ if (!parameterizing_class) { |
+ type_parameter.SetIsFinalized(); |
+ } |
type_parameters_array.Add( |
&AbstractType::ZoneHandle(Z, type_parameter.raw())); |
if (FLAG_enable_mirrors && metadata_pos.IsReal()) { |
@@ -7022,13 +7045,6 @@ RawFunction* Parser::OpenAsyncFunction(TokenPosition async_func_pos) { |
OpenFunctionBlock(closure); |
AddFormalParamsToScope(&closure_params, current_block_->scope); |
async_temp_scope_ = current_block_->scope; |
- |
- // Capture instantiator in case it may be needed to generate the type |
- // check of the return value. (C.f. handling of Token::kRETURN.) |
- ASSERT(FunctionLevel() > 0); |
- if (I->type_checks() && IsInstantiatorRequired()) { |
- CaptureInstantiator(); |
- } |
return closure.raw(); |
} |
@@ -7717,11 +7733,45 @@ void Parser::CaptureInstantiator() { |
} |
-void Parser::CaptureFunctionInstantiator() { |
+void Parser::CaptureFunctionInstantiators() { |
+ ASSERT(InGenericFunctionScope()); |
ASSERT(FunctionLevel() > 0); |
+ if (!FLAG_generic_method_semantics) { |
+ return; |
+ } |
+ // Capture function instantiators starting at parent of innermost function. |
+ intptr_t variable_function_level = FunctionLevel() - 1; |
const String* variable_name = &Symbols::FunctionInstantiatorVar(); |
- current_block_->scope->CaptureVariable( |
- current_block_->scope->LookupVariable(*variable_name, true)); |
+ LocalScope* scope = current_block_->scope; |
+ do { |
+ while (scope->function_level() > variable_function_level) { |
+ scope = scope->parent(); |
+ } |
+ // Function instantiator is in top scope at that function level. |
+ LocalScope* parent_scope = scope->parent(); |
+ while ((parent_scope != NULL) && |
+ (parent_scope->function_level() == scope->function_level())) { |
+ scope = parent_scope; |
+ parent_scope = scope->parent(); |
+ } |
+ LocalVariable* function_instantiator_var = |
+ scope->LookupVariable(*variable_name, true); |
+ if (function_instantiator_var != NULL) { |
+ current_block_->scope->CaptureVariable(function_instantiator_var); |
+ } |
+ scope = scope->parent(); |
+ variable_function_level--; |
+ } while (variable_function_level >= 0); |
+} |
+ |
+ |
+void Parser::CaptureAllInstantiators() { |
+ if (IsInstantiatorRequired()) { |
+ CaptureInstantiator(); |
+ } |
+ if (AreFunctionInstantiatorsRequired()) { |
+ CaptureFunctionInstantiators(); |
+ } |
} |
@@ -8065,10 +8115,9 @@ AstNode* Parser::ParseFunctionStatement(bool is_literal) { |
ASSERT(current_class().is_finalized()); |
ASSERT(signature_type.IsFinalized()); |
- // Make sure that the instantiator is captured. |
- if ((FunctionLevel() > 0) && |
- Class::Handle(signature_type.type_class()).IsGeneric()) { |
- CaptureInstantiator(); |
+ // Make sure that the instantiators are captured. |
+ if ((FunctionLevel() > 0) && !signature_type.IsInstantiated()) { |
+ CaptureAllInstantiators(); |
} |
// A local signature type itself cannot be malformed or malbounded, only its |
@@ -9941,8 +9990,8 @@ SequenceNode* Parser::ParseCatchClauses( |
// Has a type specification that is not malformed or malbounded. Now |
// form an 'if type check' to guard the catch handler code. |
if (!exception_param.type->IsInstantiated() && (FunctionLevel() > 0)) { |
- // Make sure that the instantiator is captured. |
- CaptureInstantiator(); |
+ // Make sure that the instantiators are captured. |
+ CaptureAllInstantiators(); |
} |
TypeNode* exception_type = |
new (Z) TypeNode(catch_pos, *exception_param.type); |
@@ -10972,8 +11021,8 @@ AstNode* Parser::ParseBinaryExpr(int min_preced) { |
const AbstractType& type = AbstractType::ZoneHandle( |
Z, ParseTypeOrFunctionType(false, ClassFinalizer::kCanonicalize)); |
if (!type.IsInstantiated() && (FunctionLevel() > 0)) { |
- // Make sure that the instantiator is captured. |
- CaptureInstantiator(); |
+ // Make sure that the instantiators are captured. |
+ CaptureAllInstantiators(); |
} |
right_operand = new (Z) TypeNode(type_pos, type); |
// In production mode, the type may be malformed. |
@@ -11840,24 +11889,25 @@ AstNode* Parser::LoadTypeParameter(PrimaryNode* primary) { |
"from static function", |
name.ToCString()); |
} |
- // TODO(regis): Verify that CaptureInstantiator() was already called |
- // and remove call below. |
if (FunctionLevel() > 0) { |
// Make sure that the class instantiator is captured. |
CaptureInstantiator(); |
} |
type_parameter ^= CanonicalizeType(type_parameter); |
- ASSERT(!type_parameter.IsMalformed()); |
- return new (Z) TypeNode(primary_pos, type_parameter); |
} else { |
ASSERT(type_parameter.IsFunctionTypeParameter()); |
- // TODO(regis): Verify that CaptureFunctionInstantiator() was already |
- // called if necessary. |
- // TODO(regis): Finalize type parameter and return as type node. |
- // For now, map to dynamic type. |
- Type& type = Type::ZoneHandle(Z, Type::DynamicType()); |
- return new (Z) TypeNode(primary_pos, type); |
+ if (!FLAG_generic_method_semantics) { |
+ Type& type = Type::ZoneHandle(Z, Type::DynamicType()); |
+ return new (Z) TypeNode(primary_pos, type); |
+ } |
+ if (type_parameter.parent_level() > 0) { |
+ // Make sure that the function instantiators are captured. |
+ CaptureFunctionInstantiators(); |
+ } |
} |
+ ASSERT(type_parameter.IsFinalized()); |
+ ASSERT(!type_parameter.IsMalformed()); |
+ return new (Z) TypeNode(primary_pos, type_parameter); |
} |
@@ -12361,13 +12411,11 @@ void Parser::ResolveType(AbstractType* type) { |
String::Handle(Z, unresolved_class.ident()); |
if (unresolved_class.library_or_library_prefix() == Object::null()) { |
// First check if the type is a function type parameter. |
- if (!innermost_function().IsNull()) { |
- // TODO(regis): Shortcut this lookup if no generic functions in scope. |
- // A bit has_generic_parent() would be useful on Function. |
- // Unfortunately, all 32 kind bits are used in Function. |
+ if (InGenericFunctionScope()) { |
+ intptr_t type_param_func_level = FunctionLevel(); |
TypeParameter& type_parameter = TypeParameter::ZoneHandle( |
- Z, innermost_function().LookupTypeParameter(unresolved_class_name, |
- NULL)); |
+ Z, innermost_function().LookupTypeParameter( |
+ unresolved_class_name, &type_param_func_level)); |
if (!type_parameter.IsNull()) { |
// A type parameter cannot be parameterized, so make the type |
// malformed if type arguments have previously been parsed. |
@@ -12379,10 +12427,13 @@ void Parser::ResolveType(AbstractType* type) { |
String::Handle(Z, type_parameter.name()).ToCString()); |
return; |
} |
- // TODO(regis): Mark function type parameter as finalized (its index |
- // does not need adjustment upon finalization) and return it. |
- // For now, resolve the function type parameter to dynamic. |
- *type = Type::DynamicType(); |
+ if (FLAG_generic_method_semantics) { |
+ ASSERT(type_parameter.IsFinalized()); |
+ ASSERT(!type_parameter.IsMalformed()); |
+ *type = type_parameter.raw(); |
+ } else { |
+ *type = Type::DynamicType(); |
+ } |
return; |
} |
} |
@@ -12518,6 +12569,37 @@ bool Parser::IsInstantiatorRequired() const { |
} |
+bool Parser::AreFunctionInstantiatorsRequired() const { |
+ ASSERT(!innermost_function().IsNull()); |
+ Function& parent = Function::Handle(innermost_function().parent_function()); |
+ while (!parent.IsNull()) { |
+ if (parent.IsGeneric()) { |
+ return true; |
+ } |
+ parent = parent.parent_function(); |
+ } |
+ return false; |
+} |
+ |
+ |
+bool Parser::InGenericFunctionScope() const { |
+ if (!innermost_function().IsNull()) { |
+ // With one more free tag bit in Function, we could cache this information. |
+ if (innermost_function().IsGeneric()) { |
+ return true; |
+ } |
+ Function& parent = Function::Handle(innermost_function().parent_function()); |
+ while (!parent.IsNull()) { |
+ if (parent.IsGeneric()) { |
+ return true; |
+ } |
+ parent = parent.parent_function(); |
+ } |
+ } |
+ return false; |
+} |
+ |
+ |
void Parser::InsertCachedConstantValue(const Script& script, |
TokenPosition token_pos, |
const Instance& value) { |
@@ -12965,8 +13047,7 @@ AstNode* Parser::ResolveIdent(TokenPosition ident_pos, |
AstNode* resolved = NULL; |
intptr_t resolved_func_level = 0; |
ResolveIdentInLocalScope(ident_pos, ident, &resolved, &resolved_func_level); |
- if (!innermost_function().IsNull()) { |
- // TODO(regis): Shortcut this lookup if no generic functions in scope. |
+ if (InGenericFunctionScope()) { |
intptr_t type_param_func_level = FunctionLevel(); |
const TypeParameter& type_parameter = |
TypeParameter::ZoneHandle(Z, innermost_function().LookupTypeParameter( |
@@ -12975,16 +13056,13 @@ AstNode* Parser::ResolveIdent(TokenPosition ident_pos, |
if ((resolved == NULL) || (resolved_func_level < type_param_func_level)) { |
// The identifier is a function type parameter, possibly shadowing |
// 'resolved'. |
- if ((FunctionLevel() > 0) && |
- (type_param_func_level < FunctionLevel())) { |
- // Make sure that the function instantiator is captured. |
- CaptureFunctionInstantiator(); |
+ if (!FLAG_generic_method_semantics) { |
+ Type& type = Type::ZoneHandle(Z, Type::DynamicType()); |
+ return new (Z) TypeNode(ident_pos, type); |
} |
- // TODO(regis): Mark function type parameter as finalized (its index |
- // does not need adjustment upon finalization) and return as type node. |
- // For now, resolve the function type parameter to dynamic. |
- Type& type = Type::ZoneHandle(Z, Type::DynamicType()); |
- return new (Z) TypeNode(ident_pos, type); |
+ ASSERT(type_parameter.IsFinalized()); |
+ ASSERT(!type_parameter.IsMalformed()); |
+ return new (Z) TypeNode(ident_pos, type_parameter); |
} |
} |
} |
@@ -12994,10 +13072,6 @@ AstNode* Parser::ResolveIdent(TokenPosition ident_pos, |
TypeParameter& type_parameter = TypeParameter::ZoneHandle( |
Z, current_class().LookupTypeParameter(ident)); |
if (!type_parameter.IsNull()) { |
- if (FunctionLevel() > 0) { |
- // Make sure that the class instantiator is captured. |
- CaptureInstantiator(); |
- } |
type_parameter ^= CanonicalizeType(type_parameter); |
ASSERT(!type_parameter.IsMalformed()); |
return new (Z) TypeNode(ident_pos, type_parameter); |
@@ -13432,8 +13506,8 @@ AstNode* Parser::ParseListLiteral(TokenPosition type_pos, |
ASSERT(!factory_method.IsNull()); |
if (!list_type_arguments.IsNull() && |
!list_type_arguments.IsInstantiated() && (FunctionLevel() > 0)) { |
- // Make sure that the instantiator is captured. |
- CaptureInstantiator(); |
+ // Make sure that the instantiators are captured. |
+ CaptureAllInstantiators(); |
} |
TypeArguments& factory_type_args = |
TypeArguments::ZoneHandle(Z, list_type_arguments.raw()); |
@@ -13683,7 +13757,7 @@ AstNode* Parser::ParseMapLiteral(TokenPosition type_pos, |
if (!map_type_arguments.IsNull() && !map_type_arguments.IsInstantiated() && |
(FunctionLevel() > 0)) { |
// Make sure that the instantiator is captured. |
- CaptureInstantiator(); |
+ CaptureAllInstantiators(); |
} |
TypeArguments& factory_type_args = |
TypeArguments::ZoneHandle(Z, map_type_arguments.raw()); |
@@ -14168,10 +14242,9 @@ AstNode* Parser::ParseNewOperator(Token::Kind op_kind) { |
// enclosing function if necessary. |
OpenFunctionBlock(tearoff_func); |
// If there are type arguments in the tearoff expression that are |
- // not yet instantiated, capture the instantiator. |
- if (IsInstantiatorRequired() && !type_arguments.IsNull() && |
- !type_arguments.IsInstantiated()) { |
- CaptureInstantiator(); |
+ // not yet instantiated, capture the instantiators. |
+ if (!type_arguments.IsNull() && !type_arguments.IsInstantiated()) { |
+ CaptureAllInstantiators(); |
} |
SequenceNode* tearoff_body = CloseBlock(); |
ClosureNode* closure_obj = |
@@ -14255,8 +14328,8 @@ AstNode* Parser::ParseNewOperator(Token::Kind op_kind) { |
CheckConstructorCallTypeArguments(new_pos, constructor, type_arguments); |
if (!type_arguments.IsNull() && !type_arguments.IsInstantiated() && |
(FunctionLevel() > 0)) { |
- // Make sure that the instantiator is captured. |
- CaptureInstantiator(); |
+ // Make sure that the instantiators are captured. |
+ CaptureAllInstantiators(); |
} |
// If the type argument vector is not instantiated, we verify in checked |
// mode at runtime that it is within its declared bounds. |
@@ -14440,8 +14513,7 @@ AstNode* Parser::ParsePrimary() { |
ResolveIdentInLocalScope(qual_ident_pos, ident, &primary, |
&primary_func_level); |
// Check whether the identifier is shadowed by a function type parameter. |
- if (!innermost_function().IsNull()) { |
- // TODO(regis): Shortcut this lookup if no generic functions in scope. |
+ if (InGenericFunctionScope()) { |
intptr_t type_param_func_level = FunctionLevel(); |
TypeParameter& type_param = TypeParameter::ZoneHandle( |
Z, innermost_function().LookupTypeParameter( |
@@ -14451,11 +14523,6 @@ AstNode* Parser::ParsePrimary() { |
(primary_func_level < type_param_func_level)) { |
// The identifier is a function type parameter, possibly shadowing |
// already resolved 'primary'. |
- if ((FunctionLevel() > 0) && |
- (type_param_func_level < FunctionLevel())) { |
- // Make sure that the function instantiator is captured. |
- CaptureFunctionInstantiator(); |
- } |
return new (Z) PrimaryNode(qual_ident_pos, type_param); |
} |
} |