Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1459)

Unified Diff: runtime/vm/parser.cc

Issue 2736733005: Manage and capture class and function instantiators in the parser. (Closed)
Patch Set: work in progress Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/parser.h ('k') | runtime/vm/unit_test.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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(&params, 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);
}
}
« no previous file with comments | « runtime/vm/parser.h ('k') | runtime/vm/unit_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698