Chromium Code Reviews| 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); |
| } |
| } |