Index: runtime/vm/parser.cc |
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc |
index 883933f5f902e70f985cba880010c4905eb05c9a..29063788a885f149d9e0ee004e0e29e910e467f0 100644 |
--- a/runtime/vm/parser.cc |
+++ b/runtime/vm/parser.cc |
@@ -2049,9 +2049,10 @@ void Parser::ParseFormalParameter(bool allow_explicit_default_value, |
// mode, because they are part of the function type of closurized |
// functions appearing in type tests with typedefs. |
parameter.has_explicit_type = true; |
+ // It is too early to resolve the type here, since it can be a result type |
+ // referring to a not yet declared function type parameter. |
parameter.type = &AbstractType::ZoneHandle(Z, |
- ParseType(is_top_level_ ? ClassFinalizer::kResolveTypeParameters : |
- ClassFinalizer::kCanonicalize)); |
+ ParseType(ClassFinalizer::kDoNotResolve)); |
} else { |
// If this is an initializing formal, its type will be set to the type of |
// the respective field when the constructor is fully parsed. |
@@ -2101,21 +2102,31 @@ void Parser::ParseFormalParameter(bool allow_explicit_default_value, |
// metadata finalConstVarOrType? this ‘.’ identifier formalParameterList? ; |
if (!var_seen && !final_seen) { |
// The parsed parameter type is actually the function result type. |
- const AbstractType& result_type = |
+ AbstractType& result_type = |
AbstractType::Handle(Z, parameter.type->raw()); |
+ // In top-level and mixin functions, the source may be in a different |
+ // script than the script of the current class. However, we never reparse |
+ // signature functions (except typedef signature functions), therefore |
+ // we do not need to keep the correct script via a patch class. Use the |
+ // actual current class as owner of the signature function. |
+ const Function& signature_function = Function::Handle(Z, |
+ Function::NewSignatureFunction(current_class(), |
+ TokenPosition::kNoSource)); |
+ signature_function.set_parent_function(innermost_function()); |
+ innermost_function_ = signature_function.raw(); |
+ |
// Finish parsing the function type parameter. |
if (CurrentToken() == Token::kLT) { |
- // TODO(hausner): handle generic function types. |
if (!FLAG_generic_method_syntax) { |
ReportError("generic function types not supported"); |
} |
- TokenPosition type_param_pos = TokenPos(); |
- if (!TryParseTypeParameters()) { |
- ReportError(type_param_pos, "error in type parameters"); |
- } |
+ ParseTypeParameters(false); // Not parameterizing class, but function. |
} |
+ // Now that type parameters are declared, the result type can be resolved. |
+ ResolveType(ClassFinalizer::kResolveTypeParameters, &result_type); |
+ |
ASSERT(CurrentToken() == Token::kLPAREN); |
ParamList func_params; |
@@ -2128,16 +2139,13 @@ void Parser::ParseFormalParameter(bool allow_explicit_default_value, |
const bool no_explicit_default_values = false; |
ParseFormalParameterList(no_explicit_default_values, false, &func_params); |
- // In top-level and mixin functions, the source may be in a different |
- // script than the script of the current class. However, we never reparse |
- // signature functions (except typedef signature functions), therefore |
- // we do not need to keep the correct script via a patch class. Use the |
- // actual current class as owner of the signature function. |
- const Function& signature_function = Function::Handle(Z, |
- Function::NewSignatureFunction(current_class(), |
- TokenPosition::kNoSource)); |
signature_function.set_result_type(result_type); |
AddFormalParamsToFunction(&func_params, signature_function); |
+ |
+ ASSERT(innermost_function().raw() == signature_function.raw()); |
+ innermost_function_ = signature_function.parent_function(); |
+ signature_function.set_data(Object::Handle()); |
siva
2016/09/19 23:23:46
Handle(Z) possible here?
regis
2016/09/23 00:35:23
Done.
|
+ |
Type& signature_type = |
Type::ZoneHandle(Z, signature_function.SignatureType()); |
if (!is_top_level_) { |
@@ -2153,6 +2161,18 @@ void Parser::ParseFormalParameter(bool allow_explicit_default_value, |
// The type of the parameter is now the signature type. |
parameter.type = &signature_type; |
} |
+ } else { |
+ if (!parameter.type->IsFinalized()) { |
+ AbstractType& type = AbstractType::ZoneHandle(Z, parameter.type->raw()); |
+ ResolveType(ClassFinalizer::kResolveTypeParameters, &type); |
+ if (!is_top_level_) { |
+ type = ClassFinalizer::FinalizeType( |
+ Class::Handle(Z, innermost_function().origin()), |
+ type, |
+ ClassFinalizer::kCanonicalize); |
+ } |
+ parameter.type = &type; |
+ } |
} |
if ((CurrentToken() == Token::kASSIGN) || (CurrentToken() == Token::kCOLON)) { |
@@ -3397,9 +3417,7 @@ SequenceNode* Parser::ParseConstructor(const Function& func) { |
// Parse the formal parameters and code. |
SequenceNode* Parser::ParseFunc(const Function& func, bool check_semicolon) { |
TRACE_PARSER("ParseFunc"); |
- Function& saved_innermost_function = |
- Function::Handle(Z, innermost_function().raw()); |
- innermost_function_ = func.raw(); |
+ ASSERT(innermost_function().raw() == func.raw()); |
// Save current try index. Try index starts at zero for each function. |
intptr_t saved_try_index = last_used_try_index_; |
@@ -3411,7 +3429,6 @@ SequenceNode* Parser::ParseFunc(const Function& func, bool check_semicolon) { |
if (func.IsGenerativeConstructor()) { |
SequenceNode* statements = ParseConstructor(func); |
- innermost_function_ = saved_innermost_function.raw(); |
last_used_try_index_ = saved_try_index; |
return statements; |
} |
@@ -3647,7 +3664,6 @@ SequenceNode* Parser::ParseFunc(const Function& func, bool check_semicolon) { |
} |
EnsureHasReturnStatement(body, end_token_pos); |
current_block_->statements->Add(body); |
- innermost_function_ = saved_innermost_function.raw(); |
last_used_try_index_ = saved_try_index; |
async_temp_scope_ = saved_async_temp_scope; |
return CloseBlock(); |
@@ -3743,10 +3759,17 @@ RawLibraryPrefix* Parser::ParsePrefix() { |
// A library prefix with the name exists. Now check whether it is |
// shadowed by a local definition. |
if (!is_top_level_ && |
- ResolveIdentInLocalScope(TokenPos(), ident, NULL)) { |
+ ResolveIdentInLocalScope(TokenPos(), ident, NULL, NULL)) { |
return LibraryPrefix::null(); |
} |
- // Check whether the identifier is shadowed by a type parameter. |
+ // 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())) { |
+ return LibraryPrefix::null(); |
+ } |
+ // Check whether the identifier is shadowed by a class type parameter. |
ASSERT(!current_class().IsNull()); |
if (current_class().LookupTypeParameter(ident) != TypeParameter::null()) { |
return LibraryPrefix::null(); |
@@ -3765,7 +3788,7 @@ void Parser::ParseMethodOrConstructor(ClassDesc* members, MemberDesc* method) { |
ASSERT(CurrentToken() == Token::kLPAREN || |
CurrentToken() == Token::kLT || |
method->IsGetter()); |
- ASSERT(method->type != NULL); |
+ ASSERT(method->type != NULL); // May still be unresolved. |
ASSERT(current_member_ == method); |
if (method->has_var) { |
@@ -3789,9 +3812,21 @@ void Parser::ParseMethodOrConstructor(ClassDesc* members, MemberDesc* method) { |
current_class().set_is_const(); |
} |
+ Function& func = Function::Handle(Z, |
+ Function::New(*method->name, // May change. |
+ method->kind, |
+ method->has_static, |
+ method->has_const, |
+ method->has_abstract, // May change. |
+ method->has_external, |
+ method->has_native, // May change. |
+ current_class(), |
+ method->decl_begin_pos)); |
+ |
+ ASSERT(innermost_function().IsNull()); |
+ innermost_function_ = func.raw(); |
+ |
if (CurrentToken() == Token::kLT) { |
- // Parse type parameters, but ignore them. |
- // TODO(hausner): handle type parameters. |
if (!FLAG_generic_method_syntax) { |
ReportError("generic type arguments not supported."); |
} |
@@ -3803,9 +3838,14 @@ void Parser::ParseMethodOrConstructor(ClassDesc* members, MemberDesc* method) { |
ReportError(type_param_pos, "%s cannot be generic", |
method->IsGetter() ? "getter" : "setter"); |
} |
- if (!TryParseTypeParameters()) { |
- ReportError(type_param_pos, "error in type parameters"); |
- } |
+ ParseTypeParameters(false); // Not parameterizing class, but function. |
+ } |
+ |
+ // Now that type parameters are declared, the result type can be resolved. |
+ if (!method->type->IsResolved()) { |
+ AbstractType& type = AbstractType::ZoneHandle(Z, method->type->raw()); |
+ ResolveType(ClassFinalizer::kResolveTypeParameters, &type); |
+ method->type = &type; |
} |
// Parse the formal parameters. |
@@ -4079,26 +4119,10 @@ void Parser::ParseMethodOrConstructor(ClassDesc* members, MemberDesc* method) { |
method->name->ToCString()); |
} |
- RawFunction::Kind function_kind; |
- if (method->IsFactoryOrConstructor()) { |
- function_kind = RawFunction::kConstructor; |
- } else if (method->IsGetter()) { |
- function_kind = RawFunction::kGetterFunction; |
- } else if (method->IsSetter()) { |
- function_kind = RawFunction::kSetterFunction; |
- } else { |
- function_kind = RawFunction::kRegularFunction; |
- } |
- Function& func = Function::Handle(Z, |
- Function::New(*method->name, |
- function_kind, |
- method->has_static, |
- method->has_const, |
- method->has_abstract, |
- method->has_external, |
- method->has_native, |
- current_class(), |
- method->decl_begin_pos)); |
+ // Update function object. |
+ func.set_name(*method->name); |
+ func.set_is_abstract(method->has_abstract); |
+ func.set_is_native(method->has_native); |
func.set_result_type(*method->type); |
func.set_end_token_pos(method_end_pos); |
func.set_is_redirecting(is_redirecting); |
@@ -4131,6 +4155,8 @@ void Parser::ParseMethodOrConstructor(ClassDesc* members, MemberDesc* method) { |
// No need to resolve parameter types yet, or add parameters to local scope. |
ASSERT(is_top_level_); |
AddFormalParamsToFunction(&method->params, func); |
+ ASSERT(innermost_function().raw() == func.raw()); |
+ innermost_function_ = Function::null(); |
members->AddFunction(func); |
} |
@@ -4432,8 +4458,10 @@ void Parser::ParseClassMemberDefinition(ClassDesc* members, |
} |
} |
if (found_type) { |
+ // It is too early to resolve the type here, since it can be a result type |
+ // referring to a not yet declared function type parameter. |
member.type = &AbstractType::ZoneHandle(Z, |
- ParseType(ClassFinalizer::kResolveTypeParameters)); |
+ ParseType(ClassFinalizer::kDoNotResolve)); |
} |
} |
@@ -4546,6 +4574,7 @@ void Parser::ParseClassMemberDefinition(ClassDesc* members, |
member.type = &Object::dynamic_type(); |
} |
ASSERT(member.IsFactory() == member.has_factory); |
+ // Note that member.type may still be unresolved. |
ParseMethodOrConstructor(members, &member); |
} else if (CurrentToken() == Token::kSEMICOLON || |
CurrentToken() == Token::kCOMMA || |
@@ -4565,6 +4594,11 @@ void Parser::ParseClassMemberDefinition(ClassDesc* members, |
} else if (member.type->IsVoidType()) { |
ReportError(member.name_pos, "field may not be 'void'"); |
} |
+ if (!member.type->IsResolved()) { |
+ AbstractType& type = AbstractType::ZoneHandle(Z, member.type->raw()); |
+ ResolveType(ClassFinalizer::kResolveTypeParameters, &type); |
+ member.type = &type; |
+ } |
ParseFieldDefinition(members, &member); |
} else { |
UnexpectedToken(); |
@@ -4683,7 +4717,7 @@ void Parser::ParseClassDeclaration(const GrowableObjectArray& pending_classes, |
ASSERT(!cls.IsNull()); |
ASSERT(cls.functions() == Object::empty_array().raw()); |
set_current_class(cls); |
- ParseTypeParameters(cls); |
+ ParseTypeParameters(true); // Parameterizing current class. |
if (is_patch) { |
// Check that the new type parameters are identical to the original ones. |
const TypeArguments& new_type_parameters = |
@@ -5147,7 +5181,7 @@ void Parser::ParseMixinAppAlias( |
mixin_application.set_is_mixin_app_alias(); |
library_.AddClass(mixin_application); |
set_current_class(mixin_application); |
- ParseTypeParameters(mixin_application); |
+ ParseTypeParameters(true); // Parameterizing current class. |
ExpectToken(Token::kASSIGN); |
@@ -5275,14 +5309,12 @@ void Parser::ParseTypedef(const GrowableObjectArray& pending_classes, |
function_type_alias.set_is_prefinalized(); |
library_.AddClass(function_type_alias); |
set_current_class(function_type_alias); |
- // Parse the type parameters of the function type. |
- ParseTypeParameters(function_type_alias); |
+ // Parse the type parameters of the typedef class. |
+ ParseTypeParameters(true); // Parameterizing current class. |
// At this point, the type parameters have been parsed, so we can resolve the |
// result type. |
if (!result_type.IsNull()) { |
- ResolveTypeFromClass(function_type_alias, |
- ClassFinalizer::kResolveTypeParameters, |
- &result_type); |
+ ResolveType(ClassFinalizer::kResolveTypeParameters, &result_type); |
} |
// Parse the formal parameters of the function type. |
CheckToken(Token::kLPAREN, "formal parameter list expected"); |
@@ -5301,6 +5333,8 @@ void Parser::ParseTypedef(const GrowableObjectArray& pending_classes, |
Function& signature_function = |
Function::Handle(Z, Function::NewSignatureFunction(function_type_alias, |
alias_name_pos)); |
+ ASSERT(innermost_function().IsNull()); |
+ innermost_function_ = signature_function.raw(); |
// Set the signature function in the function type alias class. |
function_type_alias.set_signature_function(signature_function); |
@@ -5310,6 +5344,9 @@ void Parser::ParseTypedef(const GrowableObjectArray& pending_classes, |
signature_function.set_result_type(result_type); |
AddFormalParamsToFunction(&func_params, signature_function); |
+ ASSERT(innermost_function().raw() == signature_function.raw()); |
+ innermost_function_ = Function::null(); |
+ |
if (FLAG_trace_parser) { |
OS::Print("TopLevel parsing function type alias '%s'\n", |
String::Handle(Z, signature_function.Signature()).ToCString()); |
@@ -5409,7 +5446,7 @@ void Parser::SkipType(bool allow_void) { |
} |
-void Parser::ParseTypeParameters(const Class& cls) { |
+void Parser::ParseTypeParameters(bool parameterizing_class) { |
TRACE_PARSER("ParseTypeParameters"); |
if (CurrentToken() == Token::kLT) { |
GrowableArray<AbstractType*> type_parameters_array(Z, 2); |
@@ -5435,21 +5472,25 @@ void Parser::ParseTypeParameters(const Class& cls) { |
type_parameter_name.ToCString()); |
} |
} |
- if (CurrentToken() == Token::kEXTENDS) { |
+ if ((CurrentToken() == Token::kEXTENDS) || |
+ (!parameterizing_class && (CurrentToken() == Token::kSUPER))) { |
ConsumeToken(); |
+ // TODO(regis): Handle 'super' differently than 'extends'. |
// A bound may refer to the owner of the type parameter it applies to, |
- // i.e. to the class or interface currently being parsed. |
- // Postpone resolution in order to avoid resolving the class and its |
+ // i.e. to the class or function currently being parsed. |
+ // Postpone resolution in order to avoid resolving the owner and its |
// type parameters, as they are not fully parsed yet. |
type_parameter_bound = ParseType(ClassFinalizer::kDoNotResolve); |
} else { |
type_parameter_bound = I->object_store()->object_type(); |
} |
- type_parameter = TypeParameter::New(cls, |
- index, |
- type_parameter_name, |
- type_parameter_bound, |
- declaration_pos); |
+ type_parameter = TypeParameter::New( |
+ parameterizing_class ? current_class() : Class::Handle(Z), |
+ parameterizing_class ? Function::Handle(Z) : innermost_function(), |
+ index, |
+ type_parameter_name, |
+ type_parameter_bound, |
+ declaration_pos); |
type_parameters_array.Add( |
&AbstractType::ZoneHandle(Z, type_parameter.raw())); |
if (FLAG_enable_mirrors && metadata_pos.IsReal()) { |
@@ -5464,18 +5505,20 @@ void Parser::ParseTypeParameters(const Class& cls) { |
ReportError("right angle bracket expected"); |
} |
const TypeArguments& type_parameters = |
- TypeArguments::Handle(Z, |
- NewTypeArguments(type_parameters_array)); |
- cls.set_type_parameters(type_parameters); |
+ TypeArguments::Handle(Z, NewTypeArguments(type_parameters_array)); |
+ if (parameterizing_class) { |
+ current_class().set_type_parameters(type_parameters); |
+ } else { |
+ innermost_function().set_type_parameters(type_parameters); |
+ } |
// Try to resolve the upper bounds, which will at least resolve the |
// referenced type parameters. |
const intptr_t num_types = type_parameters.Length(); |
for (intptr_t i = 0; i < num_types; i++) { |
type_parameter ^= type_parameters.TypeAt(i); |
type_parameter_bound = type_parameter.bound(); |
- ResolveTypeFromClass(cls, |
- ClassFinalizer::kResolveTypeParameters, |
- &type_parameter_bound); |
+ ResolveType(ClassFinalizer::kResolveTypeParameters, |
+ &type_parameter_bound); |
type_parameter.set_bound(type_parameter_bound); |
} |
} |
@@ -5691,7 +5734,6 @@ void Parser::ParseTopLevelFunction(TopLevel* top_level, |
TRACE_PARSER("ParseTopLevelFunction"); |
const TokenPosition decl_begin_pos = TokenPos(); |
AbstractType& result_type = Type::Handle(Z, Type::DynamicType()); |
- const bool is_static = true; |
bool is_external = false; |
bool is_patch = false; |
if (is_patch_source() && IsPatchAnnotation(metadata_pos)) { |
@@ -5707,7 +5749,9 @@ void Parser::ParseTopLevelFunction(TopLevel* top_level, |
} else { |
// Parse optional type. |
if (IsFunctionReturnType()) { |
- result_type = ParseType(ClassFinalizer::kResolveTypeParameters); |
+ // It is too early to resolve the type here, since it can be a result type |
+ // referring to a not yet declared function type parameter. |
+ result_type = ParseType(ClassFinalizer::kDoNotResolve); |
} |
} |
const TokenPosition name_pos = TokenPos(); |
@@ -5728,16 +5772,30 @@ void Parser::ParseTopLevelFunction(TopLevel* top_level, |
// A setter named x= may co-exist with a function named x, thus we do |
// not need to check setters. |
+ Function& func = Function::Handle(Z, |
+ Function::New(func_name, |
+ RawFunction::kRegularFunction, |
+ /* is_static = */ true, |
+ /* is_const = */ false, |
+ /* is_abstract = */ false, |
+ is_external, |
+ /* is_native = */ false, // May change. |
+ owner, |
+ decl_begin_pos)); |
+ |
+ ASSERT(innermost_function().IsNull()); |
+ innermost_function_ = func.raw(); |
+ |
if (CurrentToken() == Token::kLT) { |
- // Type parameters of generic function. |
- // TODO(hausner): handle type parameters. |
if (!FLAG_generic_method_syntax) { |
ReportError("generic functions not supported"); |
} |
- TokenPosition type_arg_pos = TokenPos(); |
- if (!TryParseTypeParameters()) { |
- ReportError(type_arg_pos, "error in type parameters"); |
- } |
+ ParseTypeParameters(false); // Not parameterizing class, but function. |
+ } |
+ // At this point, the type parameters have been parsed, so we can resolve the |
+ // result type. |
+ if (!result_type.IsNull()) { |
+ ResolveType(ClassFinalizer::kResolveTypeParameters, &result_type); |
} |
CheckToken(Token::kLPAREN); |
@@ -5775,19 +5833,10 @@ void Parser::ParseTopLevelFunction(TopLevel* top_level, |
function_end_pos = TokenPos(); |
ExpectSemicolon(); |
is_native = true; |
+ func.set_is_native(true); |
} else { |
ReportError("function block expected"); |
} |
- Function& func = Function::Handle(Z, |
- Function::New(func_name, |
- RawFunction::kRegularFunction, |
- is_static, |
- /* is_const = */ false, |
- /* is_abstract = */ false, |
- is_external, |
- is_native, |
- owner, |
- decl_begin_pos)); |
func.set_result_type(result_type); |
func.set_end_token_pos(function_end_pos); |
func.set_modifier(func_modifier); |
@@ -5798,6 +5847,8 @@ void Parser::ParseTopLevelFunction(TopLevel* top_level, |
func.set_native_name(*native_name); |
} |
AddFormalParamsToFunction(¶ms, func); |
+ ASSERT(innermost_function().raw() == func.raw()); |
+ innermost_function_ = Function::null(); |
top_level->AddFunction(func); |
if (!is_patch) { |
library_.AddObject(func, func_name); |
@@ -7641,6 +7692,14 @@ void Parser::CaptureInstantiator() { |
} |
+void Parser::CaptureFunctionInstantiator() { |
+ ASSERT(FunctionLevel() > 0); |
+ const String* variable_name = &Symbols::FunctionInstantiatorVar(); |
+ current_block_->scope->CaptureVariable( |
+ current_block_->scope->LookupVariable(*variable_name, true)); |
+} |
+ |
+ |
AstNode* Parser::LoadReceiver(TokenPosition token_pos) { |
// A nested function may access 'this', referring to the receiver of the |
// outermost enclosing function. |
@@ -7840,7 +7899,9 @@ AstNode* Parser::ParseFunctionStatement(bool is_literal) { |
ConsumeToken(); |
result_type = Type::VoidType(); |
} else if (IsFunctionReturnType()) { |
- result_type = ParseType(ClassFinalizer::kCanonicalize); |
+ // It is too early to resolve the type here, since it can be a result type |
+ // referring to a not yet declared function type parameter. |
+ result_type = ParseType(ClassFinalizer::kDoNotResolve); |
} |
const TokenPosition name_pos = TokenPos(); |
variable_name = ExpectIdentifier("function name expected"); |
@@ -7862,19 +7923,6 @@ AstNode* Parser::ParseFunctionStatement(bool is_literal) { |
} |
} |
- if (CurrentToken() == Token::kLT) { |
- if (!FLAG_generic_method_syntax) { |
- ReportError("generic functions not supported"); |
- } |
- TokenPosition type_arg_pos = TokenPos(); |
- // TODO(hausner): handle type parameters of generic function. |
- if (!TryParseTypeParameters()) { |
- ReportError(type_arg_pos, "error in type parameters"); |
- } |
- } |
- |
- CheckToken(Token::kLPAREN); |
- |
// Check whether we have parsed this closure function before, in a previous |
// compilation. If so, reuse the function object, else create a new one |
// and register it in the current class. |
@@ -7900,6 +7948,31 @@ AstNode* Parser::ParseFunctionStatement(bool is_literal) { |
} |
} |
+ ASSERT(function.parent_function() == innermost_function_.raw()); |
+ innermost_function_ = function.raw(); |
+ |
+ if (CurrentToken() == Token::kLT) { |
+ if (!FLAG_generic_method_syntax) { |
+ ReportError("generic functions not supported"); |
+ } |
+ if (!found_func) { |
+ ParseTypeParameters(false); // Not parameterizing class, but function. |
+ } else { |
+ TryParseTypeParameters(); |
+ } |
+ } |
+ |
+ if (!found_func && !result_type.IsFinalized()) { |
+ // Now that type parameters are declared, the result type can be resolved |
+ // and finalized. |
+ ResolveType(ClassFinalizer::kResolveTypeParameters, &result_type); |
+ result_type = ClassFinalizer::FinalizeType( |
+ current_class(), result_type, ClassFinalizer::kCanonicalize); |
+ function.set_result_type(result_type); |
+ } |
+ |
+ CheckToken(Token::kLPAREN); |
+ |
// The function type needs to be finalized at compile time, since the closure |
// may be type checked at run time when assigned to a function variable, |
// passed as a function argument, or returned as a function result. |
@@ -7947,6 +8020,7 @@ AstNode* Parser::ParseFunctionStatement(bool is_literal) { |
// variables of this function's scope that are referenced by the local |
// function (and its inner nested functions) will be marked as captured. |
+ ASSERT(AbstractType::Handle(Z, function.result_type()).IsResolved()); |
statements = Parser::ParseFunc(function, !is_literal); |
INC_STAT(thread(), num_functions_parsed, 1); |
@@ -8032,6 +8106,9 @@ AstNode* Parser::ParseFunctionStatement(bool is_literal) { |
new(Z) ClosureNode(function_pos, function, NULL, |
statements != NULL ? statements->scope() : NULL); |
+ ASSERT(innermost_function_.raw() == function.raw()); |
+ innermost_function_ = function.parent_function(); |
+ |
if (function_variable == NULL) { |
ASSERT(is_literal); |
return closure; |
@@ -11799,6 +11876,46 @@ AstNode* Parser::LoadClosure(PrimaryNode* primary) { |
} |
+AstNode* Parser::LoadTypeParameter(PrimaryNode* primary) { |
+ const TokenPosition primary_pos = primary->token_pos(); |
+ TypeParameter& type_parameter = TypeParameter::ZoneHandle(Z); |
+ type_parameter = TypeParameter::Cast(primary->primary()).raw(); |
+ if (type_parameter.IsClassTypeParameter()) { |
+ if (ParsingStaticMember()) { |
+ const String& name = String::Handle(Z, type_parameter.name()); |
+ ReportError(primary_pos, |
+ "cannot access type parameter '%s' " |
+ "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 ^= ClassFinalizer::FinalizeType( |
+ current_class(), type_parameter, ClassFinalizer::kCanonicalize); |
+ 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, throw a type error. |
+ Type& malformed_type = Type::ZoneHandle(Z); |
+ malformed_type = ClassFinalizer::NewFinalizedMalformedType( |
+ Error::Handle(Z), // No previous error. |
+ script_, |
+ primary_pos, |
+ "function type parameter '%s' not yet supported", |
+ String::Handle(Z, type_parameter.name()).ToCString()); |
+ return ThrowTypeError(primary_pos, malformed_type); |
+ } |
+} |
+ |
+ |
AstNode* Parser::ParseSelectors(AstNode* primary, bool is_cascade) { |
AstNode* left = primary; |
while (true) { |
@@ -11810,29 +11927,10 @@ AstNode* Parser::ParseSelectors(AstNode* primary, bool is_cascade) { |
ConsumeToken(); |
if (left->IsPrimaryNode()) { |
PrimaryNode* primary_node = left->AsPrimaryNode(); |
- const TokenPosition primary_pos = primary_node->token_pos(); |
if (primary_node->primary().IsFunction()) { |
left = LoadClosure(primary_node); |
} else if (primary_node->primary().IsTypeParameter()) { |
- if (ParsingStaticMember()) { |
- const String& name = String::Handle(Z, |
- TypeParameter::Cast(primary_node->primary()).name()); |
- ReportError(primary_pos, |
- "cannot access type parameter '%s' " |
- "from static function", |
- name.ToCString()); |
- } |
- if (FunctionLevel() > 0) { |
- // Make sure that the instantiator is captured. |
- CaptureInstantiator(); |
- } |
- TypeParameter& type_parameter = TypeParameter::ZoneHandle(Z); |
- type_parameter ^= ClassFinalizer::FinalizeType( |
- current_class(), |
- TypeParameter::Cast(primary_node->primary()), |
- ClassFinalizer::kCanonicalize); |
- ASSERT(!type_parameter.IsMalformed()); |
- left = new(Z) TypeNode(primary->token_pos(), type_parameter); |
+ left = LoadTypeParameter(primary_node); |
} else { |
// Super field access handled in ParseSuperFieldAccess(), |
// super calls handled in ParseSuperCall(). |
@@ -11850,8 +11948,9 @@ AstNode* Parser::ParseSelectors(AstNode* primary, bool is_cascade) { |
if (!FLAG_generic_method_syntax) { |
ReportError("generic type arguments not supported."); |
} |
- // TODO(hausner): handle type arguments. |
- ParseTypeArguments(ClassFinalizer::kIgnore); |
+ // TODO(regis): Pass type arguments in generic call. |
+ // For now, resolve type arguments and ignore. |
+ ParseTypeArguments(ClassFinalizer::kCanonicalize); |
} |
if (left->IsPrimaryNode() && |
left->AsPrimaryNode()->primary().IsClass()) { |
@@ -11919,25 +12018,7 @@ AstNode* Parser::ParseSelectors(AstNode* primary, bool is_cascade) { |
ASSERT(!type.IsMalformed()); |
array = new(Z) TypeNode(primary_pos, type); |
} else if (primary_node->primary().IsTypeParameter()) { |
- if (ParsingStaticMember()) { |
- const String& name = String::ZoneHandle(Z, |
- TypeParameter::Cast(primary_node->primary()).name()); |
- ReportError(primary_pos, |
- "cannot access type parameter '%s' " |
- "from static function", |
- name.ToCString()); |
- } |
- if (FunctionLevel() > 0) { |
- // Make sure that the instantiator is captured. |
- CaptureInstantiator(); |
- } |
- TypeParameter& type_parameter = TypeParameter::ZoneHandle(Z); |
- type_parameter ^= ClassFinalizer::FinalizeType( |
- current_class(), |
- TypeParameter::Cast(primary_node->primary()), |
- ClassFinalizer::kCanonicalize); |
- ASSERT(!type_parameter.IsMalformed()); |
- array = new(Z) TypeNode(primary_pos, type_parameter); |
+ array = LoadTypeParameter(primary_node); |
} else { |
UNREACHABLE(); // Internal parser error. |
} |
@@ -11950,8 +12031,9 @@ AstNode* Parser::ParseSelectors(AstNode* primary, bool is_cascade) { |
if (!FLAG_generic_method_syntax) { |
ReportError("generic type arguments not supported."); |
} |
- // TODO(hausner): handle type arguments. |
- ParseTypeArguments(ClassFinalizer::kIgnore); |
+ // TODO(regis): Pass type arguments in generic call. |
+ // For now, resolve type arguments and ignore. |
+ ParseTypeArguments(ClassFinalizer::kCanonicalize); |
} |
if (left->IsPrimaryNode()) { |
PrimaryNode* primary_node = left->AsPrimaryNode(); |
@@ -11994,20 +12076,29 @@ AstNode* Parser::ParseSelectors(AstNode* primary, bool is_cascade) { |
false /* is_conditional */); |
} |
} else if (primary_node->primary().IsTypeParameter()) { |
- const String& name = String::ZoneHandle(Z, |
- TypeParameter::Cast(primary_node->primary()).name()); |
- if (ParsingStaticMember()) { |
- // Treat as this.T(), because T is in scope. |
+ TypeParameter& type_parameter = TypeParameter::ZoneHandle(Z); |
+ type_parameter = TypeParameter::Cast(primary_node->primary()).raw(); |
+ const String& name = String::ZoneHandle(Z, type_parameter.name()); |
+ if (type_parameter.IsClassTypeParameter()) { |
+ if (ParsingStaticMember()) { |
+ // Treat as this.T(), because T is in scope. |
+ ReportError(primary_pos, |
+ "cannot access type parameter '%s' " |
+ "from static function", |
+ name.ToCString()); |
+ } else { |
+ // Treat as call to unresolved (instance) method. |
+ selector = ParseInstanceCall(LoadReceiver(primary_pos), |
+ name, |
+ primary_pos, |
+ false /* is_conditional */); |
+ } |
+ } else { |
+ ASSERT(type_parameter.IsFunctionTypeParameter()); |
+ // TODO(regis): Should we throw a type error instead? |
ReportError(primary_pos, |
- "cannot access type parameter '%s' " |
- "from static function", |
+ "illegal use of function type parameter '%s'", |
name.ToCString()); |
- } else { |
- // Treat as call to unresolved (instance) method. |
- selector = ParseInstanceCall(LoadReceiver(primary_pos), |
- name, |
- primary_pos, |
- false /* is_conditional */); |
} |
} else if (primary_node->primary().IsClass()) { |
const Class& type_class = Class::Cast(primary_node->primary()); |
@@ -12045,25 +12136,7 @@ AstNode* Parser::ParseSelectors(AstNode* primary, bool is_cascade) { |
ASSERT(!type.IsMalformed()); |
left = new(Z) TypeNode(primary_pos, type); |
} else if (primary_node->primary().IsTypeParameter()) { |
- if (ParsingStaticMember()) { |
- const String& name = String::ZoneHandle(Z, |
- TypeParameter::Cast(primary_node->primary()).name()); |
- ReportError(primary_pos, |
- "cannot access type parameter '%s' " |
- "from static function", |
- name.ToCString()); |
- } |
- if (FunctionLevel() > 0) { |
- // Make sure that the instantiator is captured. |
- CaptureInstantiator(); |
- } |
- TypeParameter& type_parameter = TypeParameter::ZoneHandle(Z); |
- type_parameter ^= ClassFinalizer::FinalizeType( |
- current_class(), |
- TypeParameter::Cast(primary_node->primary()), |
- ClassFinalizer::kCanonicalize); |
- ASSERT(!type_parameter.IsMalformed()); |
- left = new(Z) TypeNode(primary_pos, type_parameter); |
+ left = LoadTypeParameter(primary_node); |
} else if (primary_node->IsSuper()) { |
// Return "super" to handle unary super operator calls, |
// or to report illegal use of "super" otherwise. |
@@ -12271,16 +12344,13 @@ AstNode* Parser::ParsePostfixExpr() { |
} |
-// Resolve the given type and its type arguments from the given scope class |
-// according to the given type finalization mode. |
-// If the given scope class is null, use the current library, but do not try to |
-// resolve type parameters. |
-// Not all involved type classes may get resolved yet, but at least the type |
-// parameters of the given class will get resolved, thereby relieving the class |
+// Resolve the given type and its type arguments from the current function and |
+// current class according to the given type finalization mode. |
+// Not all involved type classes may get resolved yet, but at least type |
+// parameters will get resolved, thereby relieving the class |
// finalizer from resolving type parameters out of context. |
-void Parser::ResolveTypeFromClass(const Class& scope_class, |
- ClassFinalizer::FinalizationKind finalization, |
- AbstractType* type) { |
+void Parser::ResolveType(ClassFinalizer::FinalizationKind finalization, |
+ AbstractType* type) { |
ASSERT(finalization >= ClassFinalizer::kResolveTypeParameters); |
ASSERT(type != NULL); |
if (type->IsResolved()) { |
@@ -12294,39 +12364,56 @@ void Parser::ResolveTypeFromClass(const Class& scope_class, |
String::Handle(Z, unresolved_class.ident()); |
Class& resolved_type_class = Class::Handle(Z); |
if (unresolved_class.library_prefix() == LibraryPrefix::null()) { |
- if (!scope_class.IsNull()) { |
- // First check if the type is a type parameter of the given scope class. |
- const TypeParameter& type_parameter = TypeParameter::Handle(Z, |
- scope_class.LookupTypeParameter(unresolved_class_name)); |
+ // 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. |
+ TypeParameter& type_parameter = TypeParameter::ZoneHandle(Z, |
+ innermost_function().LookupTypeParameter(unresolved_class_name, |
+ NULL)); |
if (!type_parameter.IsNull()) { |
- // A type parameter is considered to be a malformed type when |
- // referenced by a static member. |
- if (ParsingStaticMember()) { |
- ASSERT(scope_class.raw() == current_class().raw()); |
- *type = ClassFinalizer::NewFinalizedMalformedType( |
- Error::Handle(Z), // No previous error. |
- script_, |
- type->token_pos(), |
- "type parameter '%s' cannot be referenced " |
- "from static member", |
- String::Handle(Z, type_parameter.name()).ToCString()); |
- return; |
- } |
- // A type parameter cannot be parameterized, so make the type |
- // malformed if type arguments have previously been parsed. |
- if (type->arguments() != TypeArguments::null()) { |
- *type = ClassFinalizer::NewFinalizedMalformedType( |
- Error::Handle(Z), // No previous error. |
- script_, |
- type_parameter.token_pos(), |
- "type parameter '%s' cannot be parameterized", |
- String::Handle(Z, type_parameter.name()).ToCString()); |
- return; |
- } |
- *type = type_parameter.raw(); |
+ // TODO(regis): Check for absence of type arguments. |
+ // For now, return as malformed type. |
+ Type& malformed_type = Type::ZoneHandle(Z); |
+ malformed_type = ClassFinalizer::NewFinalizedMalformedType( |
+ Error::Handle(Z), // No previous error. |
+ script_, |
+ type->token_pos(), |
+ "function type parameter '%s' not yet supported", |
+ String::Handle(Z, type_parameter.name()).ToCString()); |
+ *type = malformed_type.raw(); |
return; |
} |
} |
+ // Then check if the type is a class type parameter. |
+ const TypeParameter& type_parameter = TypeParameter::Handle(Z, |
+ current_class().LookupTypeParameter(unresolved_class_name)); |
+ if (!type_parameter.IsNull()) { |
+ // A type parameter is considered to be a malformed type when |
+ // referenced by a static member. |
+ if (ParsingStaticMember()) { |
+ *type = ClassFinalizer::NewFinalizedMalformedType( |
+ Error::Handle(Z), // No previous error. |
+ script_, |
+ type->token_pos(), |
+ "type parameter '%s' cannot be referenced " |
+ "from static member", |
+ String::Handle(Z, type_parameter.name()).ToCString()); |
+ return; |
+ } |
+ // A type parameter cannot be parameterized, so make the type |
+ // malformed if type arguments have previously been parsed. |
+ if (type->arguments() != TypeArguments::null()) { |
+ *type = ClassFinalizer::NewFinalizedMalformedType( |
+ Error::Handle(Z), // No previous error. |
+ script_, |
+ type_parameter.token_pos(), |
+ "type parameter '%s' cannot be parameterized", |
+ String::Handle(Z, type_parameter.name()).ToCString()); |
+ return; |
+ } |
+ *type = type_parameter.raw(); |
+ return; |
+ } |
// The referenced class may not have been parsed yet. It would be wrong |
// to resolve it too early to an imported class of the same name. Only |
// resolve the class when a finalized type is requested. |
@@ -12362,7 +12449,7 @@ void Parser::ResolveTypeFromClass(const Class& scope_class, |
AbstractType& type_argument = AbstractType::Handle(Z); |
for (intptr_t i = 0; i < num_arguments; i++) { |
type_argument ^= arguments.TypeAt(i); |
- ResolveTypeFromClass(scope_class, finalization, &type_argument); |
+ ResolveType(finalization, &type_argument); |
arguments.SetTypeAt(i, type_argument); |
} |
} |
@@ -12644,7 +12731,8 @@ RawObject* Parser::EvaluateConstConstructorCall( |
// If node is non NULL return an AST node corresponding to the identifier. |
bool Parser::ResolveIdentInLocalScope(TokenPosition ident_pos, |
const String &ident, |
- AstNode** node) { |
+ AstNode** node, |
+ intptr_t* function_level) { |
TRACE_PARSER("ResolveIdentInLocalScope"); |
// First try to find the identifier in the nested local scopes. |
LocalVariable* local = LookupLocalScope(ident); |
@@ -12655,6 +12743,9 @@ bool Parser::ResolveIdentInLocalScope(TokenPosition ident_pos, |
if (node != NULL) { |
*node = new(Z) LoadLocalNode(ident_pos, local); |
} |
+ if (function_level != NULL) { |
+ *function_level = local->owner()->function_level(); |
+ } |
return true; |
} |
@@ -12691,6 +12782,9 @@ bool Parser::ResolveIdentInLocalScope(TokenPosition ident_pos, |
*node = GenerateStaticFieldLookup(field, ident_pos); |
} |
} |
+ if (function_level != NULL) { |
+ *function_level = 0; |
+ } |
return true; |
} |
@@ -12879,15 +12973,43 @@ AstNode* Parser::ResolveIdent(TokenPosition ident_pos, |
// First try to find the variable in the local scope (block scope or |
// class scope). |
AstNode* resolved = NULL; |
- ResolveIdentInLocalScope(ident_pos, ident, &resolved); |
+ 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. |
+ intptr_t type_param_func_level = FunctionLevel(); |
+ const TypeParameter& type_parameter = TypeParameter::ZoneHandle(Z, |
+ innermost_function().LookupTypeParameter(ident, |
+ &type_param_func_level)); |
+ if (!type_parameter.IsNull()) { |
+ if ((resolved == NULL) || (resolved_func_level < type_param_func_level)) { |
+ // The identifier is a function type parameter, possibly shadowing |
+ // 'resolved'. |
+ if (type_param_func_level < FunctionLevel()) { |
+ // Make sure that the function instantiator is captured. |
+ CaptureFunctionInstantiator(); |
+ } |
+ // TODO(regis): Finalize type parameter and return as type node. |
+ // For now, return as malformed type. |
+ Type& malformed_type = Type::ZoneHandle(Z); |
+ malformed_type = ClassFinalizer::NewFinalizedMalformedType( |
+ Error::Handle(Z), // No previous error. |
+ script_, |
+ ident_pos, |
+ "function type parameter '%s' not yet supported", |
+ ident.ToCString()); |
+ return new(Z) TypeNode(ident_pos, malformed_type); |
+ } |
+ } |
+ } |
if (resolved == NULL) { |
- // Check whether the identifier is a type parameter. |
+ // Check whether the identifier is a class type parameter. |
if (!current_class().IsNull()) { |
TypeParameter& type_parameter = TypeParameter::ZoneHandle(Z, |
current_class().LookupTypeParameter(ident)); |
if (!type_parameter.IsNull()) { |
if (FunctionLevel() > 0) { |
- // Make sure that the instantiator is captured. |
+ // Make sure that the class instantiator is captured. |
CaptureInstantiator(); |
} |
type_parameter ^= ClassFinalizer::FinalizeType( |
@@ -13015,7 +13137,7 @@ RawAbstractType* Parser::ParseType( |
// is shadowed by a local declaration. |
if (!is_top_level_ && |
(prefix->IsNull()) && |
- ResolveIdentInLocalScope(ident_pos, type_name, NULL)) { |
+ ResolveIdentInLocalScope(ident_pos, type_name, NULL, NULL)) { |
// The type is malformed. Skip over its type arguments. |
ParseTypeArguments(ClassFinalizer::kIgnore); |
return ClassFinalizer::NewFinalizedMalformedType( |
@@ -13066,7 +13188,7 @@ RawAbstractType* Parser::ParseType( |
AbstractType& type = AbstractType::Handle( |
Z, Type::New(type_class, type_arguments, ident_pos, Heap::kOld)); |
if (finalization >= ClassFinalizer::kResolveTypeParameters) { |
- ResolveTypeFromClass(current_class(), finalization, &type); |
+ ResolveType(finalization, &type); |
if (finalization >= ClassFinalizer::kCanonicalize) { |
type ^= ClassFinalizer::FinalizeType(current_class(), type, finalization); |
} |
@@ -14268,7 +14390,30 @@ AstNode* Parser::ParsePrimary() { |
String& ident = *CurrentLiteral(); |
ConsumeToken(); |
if (prefix.IsNull()) { |
- if (!ResolveIdentInLocalScope(qual_ident_pos, ident, &primary)) { |
+ intptr_t primary_func_level = 0; |
+ 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. |
+ intptr_t type_param_func_level = FunctionLevel(); |
+ TypeParameter& type_param = TypeParameter::ZoneHandle(Z, |
+ innermost_function().LookupTypeParameter(ident, |
+ &type_param_func_level)); |
+ if (!type_param.IsNull()) { |
+ if ((primary == NULL) || |
+ (primary_func_level < type_param_func_level)) { |
+ // The identifier is a function type parameter, possibly shadowing |
+ // already resolved 'primary'. |
+ if (type_param_func_level < FunctionLevel()) { |
+ // Make sure that the function instantiator is captured. |
+ CaptureFunctionInstantiator(); |
+ } |
+ return new(Z) PrimaryNode(qual_ident_pos, type_param); |
+ } |
+ } |
+ } |
+ if (primary == NULL) { |
// Check whether the identifier is a type parameter. |
if (!current_class().IsNull()) { |
TypeParameter& type_param = TypeParameter::ZoneHandle(Z, |