Chromium Code Reviews| Index: runtime/vm/parser.cc |
| diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc |
| index 923526885ecea9685b32b527aa03bcd12b6b9592..56669480c95683d1cafc1c7ee3945cc7180e16cc 100644 |
| --- a/runtime/vm/parser.cc |
| +++ b/runtime/vm/parser.cc |
| @@ -63,7 +63,6 @@ DEFINE_FLAG(bool, |
| warn_super, |
| false, |
| "Warning if super initializer not last in initializer list."); |
| -DEFINE_FLAG(bool, warn_patch, false, "Warn on old-style patch syntax."); |
| DEFINE_FLAG( |
| bool, |
| await_is_keyword, |
| @@ -995,8 +994,13 @@ RawObject* Parser::ParseFunctionParameters(const Function& func) { |
| new ParsedFunction(thread, Function::ZoneHandle(zone, func.raw())); |
| Parser parser(script, parsed_function, func.token_pos()); |
| parser.SkipFunctionPreamble(); |
| + const bool use_function_type_syntax = false; |
| + const bool allow_explicit_default_values = true; |
| + const bool evaluate_metadata = true; |
| ParamList params; |
| - parser.ParseFormalParameterList(true, true, ¶ms); |
| + parser.ParseFormalParameterList(use_function_type_syntax, |
| + allow_explicit_default_values, |
| + evaluate_metadata, ¶ms); |
| ParamDesc* param = params.parameters->data(); |
| const int param_cnt = |
| params.num_fixed_parameters + params.num_optional_parameters; |
| @@ -1051,7 +1055,12 @@ bool Parser::ParseFormalParameters(const Function& func, ParamList* params) { |
| new ParsedFunction(Thread::Current(), Function::ZoneHandle(func.raw())); |
| Parser parser(script, parsed_function, func.token_pos()); |
| parser.SkipFunctionPreamble(); |
| - parser.ParseFormalParameterList(true, true, params); |
| + const bool use_function_type_syntax = false; |
| + const bool allow_explicit_default_values = true; |
| + const bool evaluate_metadata = true; |
| + parser.ParseFormalParameterList(use_function_type_syntax, |
| + allow_explicit_default_values, |
| + evaluate_metadata, params); |
| return true; |
| } else { |
| Thread::Current()->clear_sticky_error(); |
| @@ -1358,15 +1367,10 @@ ParsedFunction* Parser::ParseStaticFieldInitializer(const Field& field) { |
| SequenceNode* Parser::ParseStaticFinalGetter(const Function& func) { |
| TRACE_PARSER("ParseStaticFinalGetter"); |
| - ParamList params; |
| ASSERT(func.num_fixed_parameters() == 0); // static. |
| ASSERT(!func.HasOptionalParameters()); |
| ASSERT(AbstractType::Handle(Z, func.result_type()).IsResolved()); |
| - |
| - // Build local scope for function and populate with the formal parameters. |
| OpenFunctionBlock(func); |
| - AddFormalParamsToScope(¶ms, current_block_->scope); |
| - |
| TokenPosition ident_pos = TokenPos(); |
| const String& field_name = *ExpectIdentifier("field name expected"); |
| const Class& field_class = Class::Handle(Z, func.Owner()); |
| @@ -1560,9 +1564,14 @@ SequenceNode* Parser::ParseImplicitClosure(const Function& func) { |
| } else if (!parent.IsGetterFunction() && !parent.IsImplicitGetterFunction()) { |
| // NOTE: For the `kernel -> flowgraph` we don't use the parser. |
| if (parent.kernel_function() == NULL) { |
| - const bool allow_explicit_default_values = true; |
| SkipFunctionPreamble(); |
| - ParseFormalParameterList(allow_explicit_default_values, false, ¶ms); |
| + const bool use_function_type_syntax = false; |
| + const bool allow_explicit_default_values = true; |
| + const bool evaluate_metadata = false; |
| + ParseFormalParameterList(use_function_type_syntax, |
| + allow_explicit_default_values, evaluate_metadata, |
| + ¶ms); |
| + FinalizeFormalParameterTypes(¶ms); |
| SetupDefaultsForOptionalParams(params); |
| } |
| } |
| @@ -1937,7 +1946,8 @@ void Parser::SkipToMatchingParenthesis() { |
| } |
| -void Parser::ParseFormalParameter(bool allow_explicit_default_value, |
| +void Parser::ParseFormalParameter(bool use_function_type_syntax, |
|
hausner
2017/01/18 18:54:53
I'd consider to duplicate this function and separa
regis
2017/01/18 20:24:24
Agreed. I have added a TODO.
|
| + bool allow_explicit_default_value, |
| bool evaluate_metadata, |
| ParamList* params) { |
| TRACE_PARSER("ParseFormalParameter"); |
| @@ -1946,113 +1956,134 @@ void Parser::ParseFormalParameter(bool allow_explicit_default_value, |
| bool final_seen = false; |
| bool this_seen = false; |
| - if (evaluate_metadata && (CurrentToken() == Token::kAT)) { |
| - parameter.metadata = &Array::ZoneHandle(Z, EvaluateMetadata()); |
| + if (use_function_type_syntax) { |
| + parameter.has_explicit_type = true; // The type is required by the syntax. |
| + // 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, ParseTypeOrFunctionType(false, ClassFinalizer::kDoNotResolve)); |
| } else { |
| - SkipMetadata(); |
| - } |
| - |
| - if (CurrentToken() == Token::kCOVARIANT && |
| - (LookaheadToken(1) == Token::kFINAL || LookaheadToken(1) == Token::kVAR || |
| - Token::IsIdentifier(LookaheadToken(1)))) { |
| - parameter.is_covariant = true; |
| - ConsumeToken(); |
| - } |
| - if (CurrentToken() == Token::kFINAL) { |
| - ConsumeToken(); |
| - final_seen = true; |
| - parameter.is_final = true; |
| - } else if (CurrentToken() == Token::kVAR) { |
| - ConsumeToken(); |
| - var_seen = true; |
| - // The parameter type is the 'dynamic' type. |
| - // If this is an initializing formal, its type will be set to the type of |
| - // the respective field when the constructor is fully parsed. |
| - parameter.type = &Object::dynamic_type(); |
| - } |
| - if (CurrentToken() == Token::kTHIS) { |
| - ConsumeToken(); |
| - ExpectToken(Token::kPERIOD); |
| - this_seen = true; |
| - parameter.is_field_initializer = true; |
| - if (FLAG_initializing_formal_access) { |
| + if (evaluate_metadata && (CurrentToken() == Token::kAT)) { |
| + parameter.metadata = &Array::ZoneHandle(Z, EvaluateMetadata()); |
| + } else { |
| + SkipMetadata(); |
| + } |
| + if (CurrentToken() == Token::kCOVARIANT && |
| + (LookaheadToken(1) == Token::kFINAL || |
| + LookaheadToken(1) == Token::kVAR || |
| + Token::IsIdentifier(LookaheadToken(1)))) { |
| + parameter.is_covariant = true; |
| + ConsumeToken(); |
| + } |
| + if (CurrentToken() == Token::kFINAL) { |
| + ConsumeToken(); |
| + final_seen = true; |
| parameter.is_final = true; |
| + } else if (CurrentToken() == Token::kVAR) { |
| + ConsumeToken(); |
| + var_seen = true; |
| + // The parameter type is the 'dynamic' type. |
| + // If this is an initializing formal, its type will be set to the type of |
| + // the respective field when the constructor is fully parsed. |
| + parameter.type = &Object::dynamic_type(); |
| } |
| - } |
| - if ((parameter.type == NULL) && (CurrentToken() == Token::kVOID)) { |
| - ConsumeToken(); |
| - // This must later be changed to a closure type if we recognize |
| - // a closure/function type parameter. We check this at the end |
| - // of ParseFormalParameter. |
| - parameter.type = &Object::void_type(); |
| - } |
| - if (parameter.type == NULL) { |
| - // At this point, we must see an identifier for the type or the |
| - // function parameter. |
| - if (!IsIdentifier()) { |
| - ReportError("parameter name or type expected"); |
| + if (CurrentToken() == Token::kTHIS) { |
| + ConsumeToken(); |
| + ExpectToken(Token::kPERIOD); |
| + this_seen = true; |
| + parameter.is_field_initializer = true; |
| + if (FLAG_initializing_formal_access) { |
| + parameter.is_final = true; |
| + } |
| } |
| - |
| - // Lookahead to determine whether the next tokens are a return type |
| - // followed by a parameter name. |
| - bool found_type = false; |
| - { |
| - TokenPosScope saved_pos(this); |
| - if (TryParseReturnType()) { |
| - if (IsIdentifier() || (CurrentToken() == Token::kTHIS)) { |
| - found_type = true; |
| + if ((parameter.type == NULL) && (CurrentToken() == Token::kVOID)) { |
| + ConsumeToken(); |
| + // This must later be changed to a closure type if we recognize |
| + // a closure/function type parameter. We check this at the end |
| + // of ParseFormalParameter. |
| + parameter.type = &Object::void_type(); |
| + } |
| + if (parameter.type == NULL) { |
| + // At this point, we must see an identifier for the type or the |
| + // function parameter. The identifier may be 'Function'. |
| + if (!IsIdentifier()) { |
| + ReportError("parameter name or type expected"); |
| + } |
| + |
| + // Lookahead to determine whether the next tokens are a return type |
| + // followed by a parameter name. |
| + bool found_type = false; |
| + { |
| + TokenPosScope saved_pos(this); |
| + if (TryParseType(true)) { |
| + if (IsIdentifier() || (CurrentToken() == Token::kTHIS)) { |
| + found_type = true; |
| + } |
| } |
| } |
| + if (found_type) { |
| + // The types of formal parameters are never ignored, even in unchecked |
| + // 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, ParseTypeOrFunctionType(true, 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. |
| + parameter.type = &Object::dynamic_type(); |
| + } |
| } |
| - if (found_type) { |
| - // The types of formal parameters are never ignored, even in unchecked |
| - // 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(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. |
| - parameter.type = &Object::dynamic_type(); |
| + if (!this_seen && (CurrentToken() == Token::kTHIS)) { |
| + ConsumeToken(); |
| + ExpectToken(Token::kPERIOD); |
| + this_seen = true; |
| + parameter.is_field_initializer = true; |
| + if (FLAG_initializing_formal_access) { |
| + parameter.is_final = true; |
| + } |
| } |
| } |
| - if (!this_seen && (CurrentToken() == Token::kTHIS)) { |
| + |
| + // At this point, we must see an identifier for the parameter name, unless |
| + // we are using the function type syntax (in which case the name is optional, |
| + // unless we expect optional named parameters). |
| + if (IsIdentifier()) { |
| + parameter.name_pos = TokenPos(); |
| + parameter.name = CurrentLiteral(); |
| ConsumeToken(); |
| - ExpectToken(Token::kPERIOD); |
| - this_seen = true; |
| - parameter.is_field_initializer = true; |
| - if (FLAG_initializing_formal_access) { |
| - parameter.is_final = true; |
| + if (parameter.is_field_initializer) { |
| + ASSERT(!use_function_type_syntax); |
| + params->has_field_initializer = true; |
| } |
| - } |
| - // At this point, we must see an identifier for the parameter name. |
| - parameter.name_pos = TokenPos(); |
| - parameter.name = ExpectIdentifier("parameter name expected"); |
| - if (parameter.is_field_initializer) { |
| - params->has_field_initializer = true; |
| - } |
| - |
| - if (params->has_optional_named_parameters && |
| - (parameter.name->CharAt(0) == Library::kPrivateIdentifierStart)) { |
| - ReportError(parameter.name_pos, "named parameter must not be private"); |
| - } |
| + if (params->has_optional_named_parameters && |
| + (parameter.name->CharAt(0) == Library::kPrivateIdentifierStart)) { |
| + ReportError(parameter.name_pos, "named parameter must not be private"); |
| + } |
| - // Check for duplicate formal parameters. |
| - const intptr_t num_existing_parameters = |
| - params->num_fixed_parameters + params->num_optional_parameters; |
| - for (intptr_t i = 0; i < num_existing_parameters; i++) { |
| - ParamDesc& existing_parameter = (*params->parameters)[i]; |
| - if (existing_parameter.name->Equals(*parameter.name)) { |
| - ReportError(parameter.name_pos, "duplicate formal parameter '%s'", |
| - parameter.name->ToCString()); |
| + // Check for duplicate formal parameters. |
| + const intptr_t num_existing_parameters = |
| + params->num_fixed_parameters + params->num_optional_parameters; |
| + for (intptr_t i = 0; i < num_existing_parameters; i++) { |
| + ParamDesc& existing_parameter = (*params->parameters)[i]; |
| + if (existing_parameter.name->Equals(*parameter.name)) { |
| + ReportError(parameter.name_pos, "duplicate formal parameter '%s'", |
| + parameter.name->ToCString()); |
| + } |
| } |
| + } else if (!use_function_type_syntax || |
| + params->has_optional_named_parameters) { |
| + ExpectIdentifier("parameter name expected"); |
| + } else { |
| + parameter.name_pos = TokenPos(); |
| + parameter.name = &Symbols::NotNamed(); |
| } |
| - if (IsParameterPart()) { |
| + // The function type syntax does not allow the signature type syntax. |
| + if (!use_function_type_syntax && IsParameterPart()) { |
| // This parameter is probably a closure. If we saw the keyword 'var' |
| // or 'final', a closure is not legal here and we ignore the |
| // opening parens. |
| @@ -2084,11 +2115,6 @@ void Parser::ParseFormalParameter(bool allow_explicit_default_value, |
| ParseTypeParameters(false); // Not parameterizing class, but function. |
| } |
| - // Now that type parameters are declared, the result type can be resolved. |
| - ResolveType(is_top_level_ ? ClassFinalizer::kResolveTypeParameters |
| - : ClassFinalizer::kCanonicalize, |
| - &result_type); |
| - |
| ASSERT(CurrentToken() == Token::kLPAREN); |
| ParamList func_params; |
| @@ -2096,8 +2122,12 @@ void Parser::ParseFormalParameter(bool allow_explicit_default_value, |
| func_params.AddFinalParameter(TokenPos(), &Symbols::ClosureParameter(), |
| &Object::dynamic_type()); |
| - const bool no_explicit_default_values = false; |
| - ParseFormalParameterList(no_explicit_default_values, false, &func_params); |
| + const bool use_function_type_syntax = false; |
| + const bool allow_explicit_default_values = false; |
| + const bool evaluate_metadata = false; |
| + ParseFormalParameterList(use_function_type_syntax, |
| + allow_explicit_default_values, evaluate_metadata, |
| + &func_params); |
| signature_function.set_result_type(result_type); |
| AddFormalParamsToFunction(&func_params, signature_function); |
| @@ -2107,14 +2137,7 @@ void Parser::ParseFormalParameter(bool allow_explicit_default_value, |
| Type& signature_type = |
| Type::ZoneHandle(Z, signature_function.SignatureType()); |
| - if (!is_top_level_) { |
| - signature_type ^= ClassFinalizer::FinalizeType( |
| - current_class(), signature_type, ClassFinalizer::kCanonicalize); |
| - // Do not refer to signature_function anymore, since it may have been |
| - // replaced during canonicalization. |
| - signature_function = Function::null(); |
| - } |
| - ASSERT(is_top_level_ || signature_type.IsFinalized()); |
| + |
| // A signature type itself cannot be malformed or malbounded, only its |
| // signature function's result type or parameter types may be. |
| ASSERT(!signature_type.IsMalformed()); |
| @@ -2122,18 +2145,6 @@ 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()); |
| - if (is_top_level_) { |
| - ResolveType(ClassFinalizer::kResolveTypeParameters, &type); |
| - } else { |
| - ResolveType(ClassFinalizer::kCanonicalize, &type); |
| - type = ClassFinalizer::FinalizeType(current_class(), type, |
| - ClassFinalizer::kCanonicalize); |
| - } |
| - parameter.type = &type; |
| - } |
| } |
| if ((CurrentToken() == Token::kASSIGN) || (CurrentToken() == Token::kCOLON)) { |
| @@ -2182,7 +2193,8 @@ void Parser::ParseFormalParameter(bool allow_explicit_default_value, |
| // Parses a sequence of normal or optional formal parameters. |
| -void Parser::ParseFormalParameters(bool allow_explicit_default_values, |
| +void Parser::ParseFormalParameters(bool use_function_type_syntax, |
| + bool allow_explicit_default_values, |
| bool evaluate_metadata, |
| ParamList* params) { |
| TRACE_PARSER("ParseFormalParameters"); |
| @@ -2214,14 +2226,16 @@ void Parser::ParseFormalParameters(bool allow_explicit_default_values, |
| // Allow a trailing comma. |
| break; |
| } |
| - ParseFormalParameter(allow_explicit_default_values, evaluate_metadata, |
| + ParseFormalParameter(use_function_type_syntax, |
| + allow_explicit_default_values, evaluate_metadata, |
| params); |
| has_seen_parameter = true; |
| } while (CurrentToken() == Token::kCOMMA); |
| } |
| -void Parser::ParseFormalParameterList(bool allow_explicit_default_values, |
| +void Parser::ParseFormalParameterList(bool use_function_type_syntax, |
| + bool allow_explicit_default_values, |
| bool evaluate_metadata, |
| ParamList* params) { |
| TRACE_PARSER("ParseFormalParameterList"); |
| @@ -2229,12 +2243,14 @@ void Parser::ParseFormalParameterList(bool allow_explicit_default_values, |
| if (LookaheadToken(1) != Token::kRPAREN) { |
| // Parse fixed parameters. |
| - ParseFormalParameters(allow_explicit_default_values, evaluate_metadata, |
| + ParseFormalParameters(use_function_type_syntax, |
| + allow_explicit_default_values, evaluate_metadata, |
| params); |
| if (params->has_optional_positional_parameters || |
| params->has_optional_named_parameters) { |
| // Parse optional parameters. |
| - ParseFormalParameters(allow_explicit_default_values, evaluate_metadata, |
| + ParseFormalParameters(use_function_type_syntax, |
| + allow_explicit_default_values, evaluate_metadata, |
| params); |
| if (params->has_optional_positional_parameters) { |
| CheckToken(Token::kRBRACK, "',' or ']' expected"); |
| @@ -3190,7 +3206,6 @@ SequenceNode* Parser::ParseConstructor(const Function& func) { |
| OpenFunctionBlock(func); |
| ParamList params; |
| - const bool allow_explicit_default_values = true; |
| ASSERT(CurrentToken() == Token::kLPAREN); |
| // Add implicit receiver parameter which is passed the allocated |
| @@ -3201,11 +3216,16 @@ SequenceNode* Parser::ParseConstructor(const Function& func) { |
| if (func.is_const()) { |
| params.SetImplicitlyFinal(); |
| } |
| - ParseFormalParameterList(allow_explicit_default_values, false, ¶ms); |
| + const bool use_function_type_syntax = false; |
| + const bool allow_explicit_default_values = true; |
| + const bool evaluate_metadata = false; |
| + ParseFormalParameterList(use_function_type_syntax, |
| + allow_explicit_default_values, evaluate_metadata, |
| + ¶ms); |
| + FinalizeFormalParameterTypes(¶ms); |
| SetupDefaultsForOptionalParams(params); |
| ASSERT(AbstractType::Handle(Z, func.result_type()).IsResolved()); |
| - ASSERT(func.NumParameters() == params.parameters->length()); |
| // Now populate function scope with the formal parameters. |
| AddFormalParamsToScope(¶ms, current_block_->scope); |
| @@ -3383,7 +3403,6 @@ SequenceNode* Parser::ParseFunc(const Function& func, bool check_semicolon) { |
| ASSERT((CurrentToken() == Token::kLPAREN) || func.IsGetterFunction() || |
| (func.is_generated_body() && |
| Function::Handle(func.parent_function()).IsGetterFunction())); |
| - const bool allow_explicit_default_values = true; |
| if (func.IsGetterFunction()) { |
| // Populate function scope with the formal parameters. Since in this case |
| // we are compiling a getter this will at most populate the receiver. |
| @@ -3424,7 +3443,15 @@ SequenceNode* Parser::ParseFunc(const Function& func, bool check_semicolon) { |
| SkipToMatchingParenthesis(); |
| } |
| } else { |
| - ParseFormalParameterList(allow_explicit_default_values, false, ¶ms); |
| + const bool use_function_type_syntax = false; |
| + const bool allow_explicit_default_values = true; |
| + const bool evaluate_metadata = false; |
| + ParseFormalParameterList(use_function_type_syntax, |
| + allow_explicit_default_values, evaluate_metadata, |
| + ¶ms); |
| + if (!is_top_level_) { |
| + FinalizeFormalParameterTypes(¶ms); |
| + } |
| // The number of parameters and their type are not yet set in local |
| // functions, since they are not 'top-level' parsed. |
| @@ -3433,9 +3460,12 @@ SequenceNode* Parser::ParseFunc(const Function& func, bool check_semicolon) { |
| if (func.parameter_types() == Object::empty_array().raw()) { |
| AddFormalParamsToFunction(¶ms, func); |
| } |
| + ResolveSignature(ClassFinalizer::kResolveTypeParameters, func); |
| + if (!is_top_level_) { |
| + ClassFinalizer::FinalizeSignature(current_class(), func); |
| + } |
| SetupDefaultsForOptionalParams(params); |
| ASSERT(AbstractType::Handle(Z, func.result_type()).IsResolved()); |
| - ASSERT(func.NumParameters() == params.parameters->length()); |
| // Populate function scope with the formal parameters. |
| AddFormalParamsToScope(¶ms, current_block_->scope); |
| @@ -3740,16 +3770,7 @@ void Parser::ParseMethodOrConstructor(ClassDesc* members, MemberDesc* method) { |
| 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. |
| - const bool are_implicitly_final = method->has_const; |
| - const bool allow_explicit_default_values = true; |
| const TokenPosition formal_param_pos = TokenPos(); |
| method->params.Clear(); |
| // Static functions do not have a receiver. |
| @@ -3762,11 +3783,15 @@ void Parser::ParseMethodOrConstructor(ClassDesc* members, MemberDesc* method) { |
| &Symbols::TypeArgumentsParameter(), |
| &Object::dynamic_type()); |
| } |
| - if (are_implicitly_final) { |
| + if (method->has_const) { |
| method->params.SetImplicitlyFinal(); |
| } |
| if (!method->IsGetter()) { |
| - ParseFormalParameterList(allow_explicit_default_values, false, |
| + const bool use_function_type_syntax = false; |
| + const bool allow_explicit_default_values = true; |
| + const bool evaluate_metadata = false; |
| + ParseFormalParameterList(use_function_type_syntax, |
| + allow_explicit_default_values, evaluate_metadata, |
| &method->params); |
| } |
| @@ -4010,7 +4035,7 @@ void Parser::ParseMethodOrConstructor(ClassDesc* members, MemberDesc* method) { |
| 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_result_type(*method->type); // May set parent_function in type. |
| func.set_end_token_pos(method_end_pos); |
| func.set_is_redirecting(is_redirecting); |
| func.set_modifier(async_modifier); |
| @@ -4039,11 +4064,11 @@ 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(); |
| + ResolveSignature(ClassFinalizer::kResolveTypeParameters, func); |
| members->AddFunction(func); |
| } |
| @@ -4183,6 +4208,7 @@ void Parser::ParseFieldDefinition(ClassDesc* members, MemberDesc* field) { |
| getter.set_result_type(*field->type); |
| getter.set_is_debuggable(false); |
| AddFormalParamsToFunction(¶ms, getter); |
| + ResolveSignature(ClassFinalizer::kResolveTypeParameters, getter); |
| members->AddFunction(getter); |
| if (!field->has_final) { |
| // Build a setter accessor for non-const fields. |
| @@ -4204,6 +4230,7 @@ void Parser::ParseFieldDefinition(ClassDesc* members, MemberDesc* field) { |
| setter.set_is_reflectable(false); |
| } |
| AddFormalParamsToFunction(¶ms, setter); |
| + ResolveSignature(ClassFinalizer::kResolveTypeParameters, setter); |
| members->AddFunction(setter); |
| } |
| } |
| @@ -4324,7 +4351,7 @@ void Parser::ParseClassMemberDefinition(ClassDesc* members, |
| { |
| // Lookahead to determine whether the next tokens are a return type. |
| TokenPosScope saved_pos(this); |
| - if (TryParseReturnType()) { |
| + if (TryParseType(true)) { |
| if (IsIdentifier() || (CurrentToken() == Token::kGET) || |
| (CurrentToken() == Token::kSET) || |
| (CurrentToken() == Token::kOPERATOR)) { |
| @@ -4336,7 +4363,7 @@ void Parser::ParseClassMemberDefinition(ClassDesc* members, |
| // 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::kDoNotResolve)); |
| + Z, ParseTypeOrFunctionType(false, ClassFinalizer::kDoNotResolve)); |
| } |
| } |
| @@ -4449,7 +4476,8 @@ void Parser::ParseClassMemberDefinition(ClassDesc* members, |
| member.type = &Object::dynamic_type(); |
| } |
| ASSERT(member.IsFactory() == member.has_factory); |
| - // Note that member.type may still be unresolved. |
| + // Note that member.type may still be unresolved and may refer to not yet |
| + // parsed function type parameters. |
| ParseMethodOrConstructor(members, &member); |
| } else if (CurrentToken() == Token::kSEMICOLON || |
| CurrentToken() == Token::kCOMMA || |
| @@ -4828,6 +4856,7 @@ void Parser::ParseEnumDefinition(const Class& cls) { |
| ParamList params; |
| params.AddReceiver(&Object::dynamic_type(), cls.token_pos()); |
| AddFormalParamsToFunction(¶ms, getter); |
| + ResolveSignature(ClassFinalizer::kResolveTypeParameters, getter); |
| enum_members.AddFunction(getter); |
| ASSERT(IsIdentifier()); |
| @@ -4942,6 +4971,7 @@ void Parser::ParseEnumDefinition(const Class& cls) { |
| ParamList name_params; |
| name_params.AddReceiver(&Object::dynamic_type(), cls.token_pos()); |
| AddFormalParamsToFunction(&name_params, name_getter); |
| + ResolveSignature(ClassFinalizer::kResolveTypeParameters, name_getter); |
| enum_members.AddFunction(name_getter); |
| // Clone the toString() function from the helper class. |
| @@ -4991,6 +5021,8 @@ void Parser::AddImplicitConstructor(const Class& cls) { |
| params.AddReceiver(receiver_type, cls.token_pos()); |
| AddFormalParamsToFunction(¶ms, ctor); |
| + ctor.set_result_type(Object::dynamic_type()); |
| + ResolveSignature(ClassFinalizer::kResolveTypeParameters, ctor); |
| // The body of the constructor cannot modify the type of the constructed |
| // instance, which is passed in as the receiver. |
| ctor.set_result_type(*receiver_type); |
| @@ -5087,21 +5119,30 @@ void Parser::ParseMixinAppAlias(const GrowableObjectArray& pending_classes, |
| } |
| -// Look ahead to detect if we are seeing ident [ TypeParameters ] "(". |
| +// Look ahead to detect if we are seeing ident [ TypeParameters ] ("(" | "="). |
| // We need this lookahead to distinguish between the optional return type |
| // and the alias name of a function type alias. |
| // Token position remains unchanged. |
| -bool Parser::IsFunctionTypeAliasName() { |
| - if (IsIdentifier() && (LookaheadToken(1) == Token::kLPAREN)) { |
| - return true; |
| +bool Parser::IsFunctionTypeAliasName(bool* use_function_type_syntax) { |
| + if (IsIdentifier()) { |
| + const Token::Kind ahead = LookaheadToken(1); |
| + if ((ahead == Token::kLPAREN) || (ahead == Token::kASSIGN)) { |
| + *use_function_type_syntax = (ahead == Token::kASSIGN); |
| + return true; |
| + } |
| } |
| const TokenPosScope saved_pos(this); |
| if (IsIdentifier() && (LookaheadToken(1) == Token::kLT)) { |
| ConsumeToken(); |
| - if (TryParseTypeParameters() && (CurrentToken() == Token::kLPAREN)) { |
| - return true; |
| + if (TryParseTypeParameters()) { |
| + const Token::Kind current = CurrentToken(); |
| + if ((current == Token::kLPAREN) || (current == Token::kASSIGN)) { |
| + *use_function_type_syntax = (current == Token::kASSIGN); |
| + return true; |
| + } |
| } |
| } |
| + *use_function_type_syntax = false; |
| return false; |
| } |
| @@ -5114,15 +5155,23 @@ void Parser::ParseTypedef(const GrowableObjectArray& pending_classes, |
| metadata_pos.IsReal() ? metadata_pos : TokenPos(); |
| ExpectToken(Token::kTYPEDEF); |
| - // Parse the result type of the function type. |
| - AbstractType& result_type = Type::Handle(Z, Type::DynamicType()); |
| + // Distinguish between two possible typedef forms: |
| + // 1) returnType? identifier typeParameters? formalParameterList ’;’ |
| + // 2) identifier typeParameters? '=' functionType ’;’ |
| + |
| + bool use_function_type_syntax; // Set to false for form 1, true for form 2. |
| + |
| + // If present, parse the result type of the function type. |
| + AbstractType& result_type = Type::Handle(Z); |
| if (CurrentToken() == Token::kVOID) { |
| ConsumeToken(); |
| result_type = Type::VoidType(); |
| - } else if (!IsFunctionTypeAliasName()) { |
| + use_function_type_syntax = false; |
| + } else if (!IsFunctionTypeAliasName(&use_function_type_syntax)) { |
| // Type annotations in typedef are never ignored, even in production mode. |
| // Wait until we have an owner class before resolving the result type. |
| result_type = ParseType(ClassFinalizer::kDoNotResolve); |
| + ASSERT(!use_function_type_syntax); |
| } |
| const TokenPosition alias_name_pos = TokenPos(); |
| @@ -5148,41 +5197,59 @@ void Parser::ParseTypedef(const GrowableObjectArray& pending_classes, |
| function_type_alias.set_is_abstract(); |
| function_type_alias.set_is_prefinalized(); |
| library_.AddClass(function_type_alias); |
| + ASSERT(current_class().IsTopLevel()); |
| set_current_class(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()) { |
| - ResolveType(ClassFinalizer::kResolveTypeParameters, &result_type); |
| - } |
| - // Parse the formal parameters of the function type. |
| - CheckToken(Token::kLPAREN, "formal parameter list expected"); |
| - ParamList func_params; |
| - |
| - // Add implicit closure object parameter. |
| - func_params.AddFinalParameter(TokenPos(), &Symbols::ClosureParameter(), |
| - &Object::dynamic_type()); |
| - |
| - // Mark the current class as a typedef class (by setting its signature |
| - // function field to a non-null function) before parsing its formal parameters |
| - // so that parsed function types are aware that their owner class is a |
| - // typedef class. |
| - Function& signature_function = Function::Handle( |
| - Z, Function::NewSignatureFunction(function_type_alias, alias_name_pos)); |
| + Function& signature_function = Function::Handle(Z); |
| ASSERT(innermost_function().IsNull()); |
| - innermost_function_ = signature_function.raw(); |
| + if (use_function_type_syntax) { |
| + ExpectToken(Token::kASSIGN); |
| + ASSERT(result_type.IsNull()); // Not parsed yet. |
| + // Do not resolve types before the function type alias can be recognized as |
| + // a typedef class, so that correct promotion of function types can occur. |
| + const Type& function_type = Type::Handle( |
| + Z, ParseFunctionType(result_type, ClassFinalizer::kDoNotResolve)); |
| + signature_function = function_type.signature(); |
| + } else { |
| + signature_function = |
| + Function::NewSignatureFunction(function_type_alias, alias_name_pos); |
| + innermost_function_ = signature_function.raw(); |
| + ParamList params; |
| + // Parse the formal parameters of the function type. |
| + CheckToken(Token::kLPAREN, "formal parameter list expected"); |
| + // Add implicit closure object parameter. |
| + params.AddFinalParameter(TokenPos(), &Symbols::ClosureParameter(), |
| + &Object::dynamic_type()); |
| + const bool allow_explicit_default_values = false; |
| + const bool evaluate_metadata = false; |
| + ParseFormalParameterList(use_function_type_syntax, |
| + allow_explicit_default_values, evaluate_metadata, |
| + ¶ms); |
| + if (result_type.IsNull()) { |
| + result_type = Type::DynamicType(); |
| + } |
| + signature_function.set_result_type(result_type); |
| + AddFormalParamsToFunction(¶ms, signature_function); |
| + ASSERT(innermost_function().raw() == signature_function.raw()); |
| + innermost_function_ = Function::null(); |
| + } |
| + ExpectSemicolon(); |
| + ASSERT(innermost_function().IsNull()); |
| + |
| // Set the signature function in the function type alias class. |
| function_type_alias.set_signature_function(signature_function); |
| - const bool no_explicit_default_values = false; |
| - ParseFormalParameterList(no_explicit_default_values, false, &func_params); |
| - ExpectSemicolon(); |
| - signature_function.set_result_type(result_type); |
| - AddFormalParamsToFunction(&func_params, signature_function); |
| - |
| - ASSERT(innermost_function().raw() == signature_function.raw()); |
| - innermost_function_ = Function::null(); |
| + // At this point, all function type parameters have been parsed and the class |
| + // function_type_alias is recognized as a typedef, so we can resolve all type |
| + // parameters in the signature type defined by the typedef. |
| + AbstractType& function_type = |
| + Type::Handle(Z, signature_function.SignatureType()); |
| + ASSERT(current_class().raw() == function_type_alias.raw()); |
| + ResolveType(ClassFinalizer::kResolveTypeParameters, &function_type); |
| + // Resolving does not replace type or signature. |
| + ASSERT(function_type_alias.signature_function() == |
| + Type::Cast(function_type).signature()); |
| if (FLAG_trace_parser) { |
| OS::Print("TopLevel parsing function type alias '%s'\n", |
| @@ -5252,7 +5319,7 @@ void Parser::SkipTypeArguments() { |
| if (CurrentToken() == Token::kLT) { |
| do { |
| ConsumeToken(); |
| - SkipType(false); |
| + SkipTypeOrFunctionType(false); |
| } while (CurrentToken() == Token::kCOMMA); |
| Token::Kind token = CurrentToken(); |
| if ((token == Token::kGT) || (token == Token::kSHR)) { |
| @@ -5281,6 +5348,30 @@ void Parser::SkipType(bool allow_void) { |
| } |
| +void Parser::SkipTypeOrFunctionType(bool allow_void) { |
| + if (CurrentToken() == Token::kVOID) { |
| + TokenPosition void_pos = TokenPos(); |
| + ConsumeToken(); |
| + // 'void' is always allowed as result type of a function type. |
| + if (!allow_void && !IsFunctionTypeSymbol()) { |
| + ReportError(void_pos, "'void' not allowed here"); |
| + } |
| + } else if (!IsFunctionTypeSymbol()) { |
| + // Including 'Function' not followed by '(' or '<'. |
| + SkipType(false); |
| + } |
| + while (IsSymbol(Symbols::Function())) { |
| + ConsumeToken(); |
| + SkipTypeArguments(); |
| + if (CurrentToken() == Token::kLPAREN) { |
| + SkipToMatchingParenthesis(); |
| + } else { |
| + ReportError("'(' expected"); |
| + } |
| + } |
| +} |
| + |
| + |
| void Parser::ParseTypeParameters(bool parameterizing_class) { |
| TRACE_PARSER("ParseTypeParameters"); |
| if (CurrentToken() == Token::kLT) { |
| @@ -5376,7 +5467,7 @@ RawTypeArguments* Parser::ParseTypeArguments( |
| AbstractType& type = AbstractType::Handle(Z); |
| do { |
| ConsumeToken(); |
| - type = ParseType(finalization); |
| + type = ParseTypeOrFunctionType(false, finalization); |
| // Map a malformed type argument to dynamic. |
| if (type.IsMalformed()) { |
| type = Type::DynamicType(); |
| @@ -5582,16 +5673,11 @@ void Parser::ParseTopLevelFunction(TopLevel* top_level, |
| ConsumeToken(); |
| is_external = true; |
| } |
| - if (CurrentToken() == Token::kVOID) { |
| - ConsumeToken(); |
| - result_type = Type::VoidType(); |
| - } else { |
| - // Parse optional type. |
| - if (IsFunctionReturnType()) { |
| - // 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); |
| - } |
| + // Parse optional result type. |
| + if (IsFunctionReturnType()) { |
| + // 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 = ParseTypeOrFunctionType(true, ClassFinalizer::kDoNotResolve); |
| } |
| const TokenPosition name_pos = TokenPos(); |
| const String& func_name = *ExpectIdentifier("function name expected"); |
| @@ -5628,17 +5714,16 @@ void Parser::ParseTopLevelFunction(TopLevel* top_level, |
| } |
| 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); |
| const TokenPosition function_pos = TokenPos(); |
| ParamList params; |
| + const bool use_function_type_syntax = false; |
| const bool allow_explicit_default_values = true; |
| - ParseFormalParameterList(allow_explicit_default_values, false, ¶ms); |
| + const bool evaluate_metadata = false; |
| + ParseFormalParameterList(use_function_type_syntax, |
| + allow_explicit_default_values, evaluate_metadata, |
| + ¶ms); |
| const TokenPosition modifier_pos = TokenPos(); |
| RawFunction::AsyncModifier func_modifier = ParseFunctionModifier(); |
| @@ -5685,6 +5770,7 @@ void Parser::ParseTopLevelFunction(TopLevel* top_level, |
| AddFormalParamsToFunction(¶ms, func); |
| ASSERT(innermost_function().raw() == func.raw()); |
| innermost_function_ = Function::null(); |
| + ResolveSignature(ClassFinalizer::kResolveTypeParameters, func); |
| top_level->AddFunction(func); |
| if (!is_patch) { |
| library_.AddObject(func, func_name); |
| @@ -5724,12 +5810,8 @@ void Parser::ParseTopLevelAccessor(TopLevel* top_level, |
| ConsumeToken(); |
| result_type = Type::DynamicType(); |
| } else { |
| - if (CurrentToken() == Token::kVOID) { |
| - ConsumeToken(); |
| - result_type = Type::VoidType(); |
| - } else { |
| - result_type = ParseType(ClassFinalizer::kResolveTypeParameters); |
| - } |
| + result_type = |
| + ParseTypeOrFunctionType(true, ClassFinalizer::kResolveTypeParameters); |
| is_getter = (CurrentToken() == Token::kGET); |
| if (CurrentToken() == Token::kGET || CurrentToken() == Token::kSET) { |
| ConsumeToken(); |
| @@ -5744,8 +5826,12 @@ void Parser::ParseTopLevelAccessor(TopLevel* top_level, |
| ParamList params; |
| if (!is_getter) { |
| + const bool use_function_type_syntax = false; |
| const bool allow_explicit_default_values = true; |
| - ParseFormalParameterList(allow_explicit_default_values, false, ¶ms); |
| + const bool evaluate_metadata = false; |
| + ParseFormalParameterList(use_function_type_syntax, |
| + allow_explicit_default_values, evaluate_metadata, |
| + ¶ms); |
| } |
| String& accessor_name = String::ZoneHandle(Z); |
| int expected_num_parameters = -1; |
| @@ -5839,6 +5925,7 @@ void Parser::ParseTopLevelAccessor(TopLevel* top_level, |
| func.set_is_reflectable(false); |
| } |
| AddFormalParamsToFunction(¶ms, func); |
| + ResolveSignature(ClassFinalizer::kResolveTypeParameters, func); |
| top_level->AddFunction(func); |
| if (!is_patch) { |
| library_.AddObject(func, accessor_name); |
| @@ -6689,7 +6776,7 @@ RawFunction* Parser::OpenSyncGeneratorFunction(TokenPosition func_pos) { |
| if (is_new_closure) { |
| // Add the parameters to the newly created closure. |
| AddFormalParamsToFunction(&closure_params, body); |
| - |
| + ResolveSignature(ClassFinalizer::kResolveTypeParameters, body); |
| // Finalize function type. |
| Type& signature_type = Type::Handle(Z, body.SignatureType()); |
| signature_type ^= ClassFinalizer::FinalizeType( |
| @@ -6817,6 +6904,7 @@ RawFunction* Parser::OpenAsyncFunction(TokenPosition async_func_pos) { |
| if (is_new_closure) { |
| // Add the parameters to the newly created closure. |
| AddFormalParamsToFunction(&closure_params, closure); |
| + ResolveSignature(ClassFinalizer::kResolveTypeParameters, closure); |
| // Finalize function type. |
| Type& signature_type = Type::Handle(Z, closure.SignatureType()); |
| @@ -6946,6 +7034,7 @@ RawFunction* Parser::OpenAsyncGeneratorFunction(TokenPosition async_func_pos) { |
| if (is_new_closure) { |
| // Add the parameters to the newly created closure. |
| AddFormalParamsToFunction(&closure_params, closure); |
| + ResolveSignature(ClassFinalizer::kResolveTypeParameters, closure); |
| // Finalize function type. |
| Type& signature_type = Type::Handle(Z, closure.SignatureType()); |
| @@ -7308,6 +7397,23 @@ void Parser::SetupDefaultsForOptionalParams(const ParamList& params) { |
| } |
| +void Parser::FinalizeFormalParameterTypes(const ParamList* params) { |
| + ASSERT((params != NULL) && (params->parameters != NULL)); |
| + const int num_parameters = params->parameters->length(); |
| + AbstractType& type = AbstractType::Handle(Z); |
| + for (int i = 0; i < num_parameters; i++) { |
| + ParamDesc& param_desc = (*params->parameters)[i]; |
| + type = param_desc.type->raw(); |
| + ResolveType(ClassFinalizer::kCanonicalize, &type); |
| + type = ClassFinalizer::FinalizeType(current_class(), type, |
| + ClassFinalizer::kCanonicalize); |
| + if (type.raw() != param_desc.type->raw()) { |
| + param_desc.type = &AbstractType::ZoneHandle(Z, type.raw()); |
| + } |
| + } |
| +} |
| + |
| + |
| // Populate the parameter type array and parameter name array of the function |
| // with the formal parameter types and names. |
| void Parser::AddFormalParamsToFunction(const ParamList* params, |
| @@ -7362,7 +7468,6 @@ void Parser::AddFormalParamsToScope(const ParamList* params, |
| const int num_parameters = params->parameters->length(); |
| for (int i = 0; i < num_parameters; i++) { |
| ParamDesc& param_desc = (*params->parameters)[i]; |
| - ASSERT(!is_top_level_ || param_desc.type->IsResolved()); |
| const String* name = param_desc.name; |
| LocalVariable* parameter = new (Z) LocalVariable( |
| param_desc.name_pos, param_desc.name_pos, *name, *param_desc.type); |
| @@ -7541,6 +7646,9 @@ RawAbstractType* Parser::ParseConstFinalVarOrType( |
| ConsumeToken(); |
| type_is_optional = true; |
| } |
| + if ((CurrentToken() == Token::kVOID) || IsFunctionTypeSymbol()) { |
| + return ParseFunctionType(AbstractType::Handle(Z), finalization); |
| + } |
| if (CurrentToken() != Token::kIDENT) { |
| if (type_is_optional) { |
| return Type::DynamicType(); |
| @@ -7559,7 +7667,7 @@ RawAbstractType* Parser::ParseConstFinalVarOrType( |
| return Type::DynamicType(); |
| } |
| } |
| - return ParseType(finalization); |
| + return ParseTypeOrFunctionType(false, finalization); |
| } |
| @@ -7611,11 +7719,8 @@ AstNode* Parser::ParseVariableDeclarationList() { |
| AstNode* Parser::ParseFunctionStatement(bool is_literal) { |
| TRACE_PARSER("ParseFunctionStatement"); |
| - AbstractType& result_type = AbstractType::Handle(Z); |
| + AbstractType& result_type = AbstractType::Handle(Z, Type::DynamicType()); |
| const String* function_name = NULL; |
| - |
| - result_type = Type::DynamicType(); |
| - |
| const TokenPosition function_pos = TokenPos(); |
| TokenPosition function_name_pos = TokenPosition::kNoSource; |
| TokenPosition metadata_pos = TokenPosition::kNoSource; |
| @@ -7624,13 +7729,12 @@ AstNode* Parser::ParseFunctionStatement(bool is_literal) { |
| function_name = &Symbols::AnonymousClosure(); |
| } else { |
| metadata_pos = SkipMetadata(); |
| - if (CurrentToken() == Token::kVOID) { |
| - ConsumeToken(); |
| - result_type = Type::VoidType(); |
| - } else if (IsFunctionReturnType()) { |
| + // Parse optional result type. |
| + if (IsFunctionReturnType()) { |
| // 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); |
| + result_type = |
| + ParseTypeOrFunctionType(true, ClassFinalizer::kDoNotResolve); |
| } |
| function_name_pos = TokenPos(); |
| function_name = ExpectIdentifier("function name expected"); |
| @@ -8000,6 +8104,15 @@ bool Parser::IsSymbol(const String& symbol) { |
| } |
| +// Returns true if the current token is 'Function' followed by '<' or '('. |
| +// 'Function' not followed by '<' or '(' denotes the Function class. |
| +bool Parser::IsFunctionTypeSymbol() { |
| + return IsSymbol(Symbols::Function()) && |
| + ((LookaheadToken(1) == Token::kLPAREN) || |
| + (LookaheadToken(1) == Token::kLT)); |
| +} |
| + |
| + |
| // Returns true if the next tokens can be parsed as a an optionally |
| // qualified identifier: [ident '.'] ident. |
| // Current token position is not restored. |
| @@ -8021,30 +8134,41 @@ bool Parser::TryParseQualIdent() { |
| // Returns true if the next tokens can be parsed as a type with optional |
| // type parameters. Current token position is not restored. |
| -bool Parser::TryParseOptionalType() { |
| - if (CurrentToken() == Token::kIDENT) { |
| +// Allow 'void' as type if 'allow_void' is true. |
| +// Note that 'void Function()' is always allowed, since it is a function type |
| +// and not the void type. |
| +bool Parser::TryParseType(bool allow_void) { |
| + bool found = false; |
| + if (CurrentToken() == Token::kVOID) { |
| + ConsumeToken(); |
| + if (allow_void) { |
| + found = true; |
| + } else if (!IsFunctionTypeSymbol()) { |
| + return false; |
| + } |
| + } else if ((CurrentToken() == Token::kIDENT) && !IsFunctionTypeSymbol()) { |
| + // 'Function' not followed by '(' or '<' means the Function class. |
| if (!TryParseQualIdent()) { |
| return false; |
| } |
| if ((CurrentToken() == Token::kLT) && !TryParseTypeParameters()) { |
| return false; |
| } |
| + found = true; |
| } |
| - return true; |
| -} |
| - |
| - |
| -// Returns true if the next tokens can be parsed as a type with optional |
| -// type parameters, or keyword "void". |
| -// Current token position is not restored. |
| -bool Parser::TryParseReturnType() { |
| - if (CurrentToken() == Token::kVOID) { |
| + while (IsSymbol(Symbols::Function())) { |
| ConsumeToken(); |
| - return true; |
| - } else if (CurrentToken() == Token::kIDENT) { |
| - return TryParseOptionalType(); |
| + if ((CurrentToken() == Token::kLT) && !TryParseTypeParameters()) { |
| + return false; |
| + } |
| + if (CurrentToken() == Token::kLPAREN) { |
| + SkipToMatchingParenthesis(); |
| + } else { |
| + return false; |
| + } |
| + found = true; |
| } |
| - return false; |
| + return found; |
| } |
| @@ -8068,8 +8192,10 @@ bool Parser::IsVariableDeclaration() { |
| SetPosition(saved_pos); |
| return is_var_decl; |
| } |
| - if ((CurrentToken() != Token::kIDENT) && (CurrentToken() != Token::kCONST)) { |
| - // Not a legal type identifier or const keyword or metadata. |
| + if ((CurrentToken() != Token::kIDENT) && (CurrentToken() != Token::kVOID) && |
| + (CurrentToken() != Token::kCONST)) { |
| + // Not a legal type identifier or void (result type of function type) |
| + // or const keyword or metadata. |
| return false; |
| } |
| const TokenPosition saved_pos = TokenPos(); |
| @@ -8077,28 +8203,32 @@ bool Parser::IsVariableDeclaration() { |
| bool have_type = false; |
| if (CurrentToken() == Token::kCONST) { |
| ConsumeToken(); |
| - have_type = true; // Type is dynamic. |
| + have_type = true; // Type is dynamic if 'const' is not followed by a type. |
| } |
| - if (IsIdentifier()) { // Type or variable name. |
| + if ((CurrentToken() == Token::kVOID) || IsFunctionTypeSymbol()) { |
| + if (TryParseType(false)) { |
| + have_type = true; |
| + } |
| + } else if (IsIdentifier()) { // Type or variable name. |
| Token::Kind follower = LookaheadToken(1); |
| if ((follower == Token::kLT) || // Parameterized type. |
| (follower == Token::kPERIOD) || // Qualified class name of type. |
| Token::IsIdentifier(follower)) { // Variable name following a type. |
| // We see the beginning of something that could be a type. |
| const TokenPosition type_pos = TokenPos(); |
| - if (TryParseOptionalType()) { |
| + if (TryParseType(false)) { |
| have_type = true; |
| } else { |
| SetPosition(type_pos); |
| } |
| } |
| - if (have_type && IsIdentifier()) { |
| - ConsumeToken(); |
| - if ((CurrentToken() == Token::kSEMICOLON) || |
| - (CurrentToken() == Token::kCOMMA) || |
| - (CurrentToken() == Token::kASSIGN)) { |
| - is_var_decl = true; |
| - } |
| + } |
| + if (have_type && IsIdentifier()) { |
| + ConsumeToken(); |
| + if ((CurrentToken() == Token::kSEMICOLON) || |
| + (CurrentToken() == Token::kCOMMA) || |
| + (CurrentToken() == Token::kASSIGN)) { |
| + is_var_decl = true; |
| } |
| } |
| SetPosition(saved_pos); |
| @@ -8110,7 +8240,7 @@ bool Parser::IsVariableDeclaration() { |
| // by an identifier. |
| bool Parser::IsFunctionReturnType() { |
| TokenPosScope decl_pos(this); |
| - if (TryParseReturnType()) { |
| + if (TryParseType(true)) { |
| if (IsIdentifier()) { |
| // Return type followed by function name. |
| return true; |
| @@ -8132,7 +8262,7 @@ bool Parser::IsFunctionDeclaration() { |
| ConsumeToken(); |
| } |
| const TokenPosition type_or_name_pos = TokenPos(); |
| - if (TryParseReturnType()) { |
| + if (TryParseType(true)) { |
| if (!IsIdentifier()) { |
| SetPosition(type_or_name_pos); |
| } |
| @@ -8172,7 +8302,7 @@ bool Parser::IsTopLevelAccessor() { |
| if ((CurrentToken() == Token::kGET) || (CurrentToken() == Token::kSET)) { |
| return true; |
| } |
| - if (TryParseReturnType()) { |
| + if (TryParseType(true)) { |
| if ((CurrentToken() == Token::kGET) || (CurrentToken() == Token::kSET)) { |
| if (Token::IsIdentifier(LookaheadToken(1))) { // Accessor name. |
| return true; |
| @@ -8221,7 +8351,7 @@ bool Parser::IsForInStatement() { |
| if (IsIdentifier()) { |
| if (LookaheadToken(1) == Token::kIN) { |
| return true; |
| - } else if (TryParseOptionalType()) { |
| + } else if (TryParseType(false)) { |
| if (IsIdentifier()) { |
| ConsumeToken(); |
| } |
| @@ -9520,7 +9650,7 @@ SequenceNode* Parser::ParseCatchClauses( |
| if (IsSymbol(Symbols::On())) { |
| ConsumeToken(); |
| exception_param.type = &AbstractType::ZoneHandle( |
| - Z, ParseType(ClassFinalizer::kCanonicalize)); |
| + Z, ParseTypeOrFunctionType(false, ClassFinalizer::kCanonicalize)); |
| } else { |
| exception_param.type = &Object::dynamic_type(); |
| } |
| @@ -10626,7 +10756,7 @@ AstNode* Parser::ParseBinaryExpr(int min_preced) { |
| } |
| const TokenPosition type_pos = TokenPos(); |
| const AbstractType& type = AbstractType::ZoneHandle( |
| - Z, ParseType(ClassFinalizer::kCanonicalize)); |
| + Z, ParseTypeOrFunctionType(false, ClassFinalizer::kCanonicalize)); |
| if (!type.IsInstantiated() && (FunctionLevel() > 0)) { |
| // Make sure that the instantiator is captured. |
| CaptureInstantiator(); |
| @@ -11955,6 +12085,32 @@ AstNode* Parser::ParsePostfixExpr() { |
| } |
| +// Resolve the types of the given signature from the 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. |
| +// TODO(regis): Refactor this code which is partially duplicated in the class |
| +// finalizer, paying attention to type parameter resolution and mixin library. |
| +void Parser::ResolveSignature(ClassFinalizer::FinalizationKind finalization, |
| + const Function& signature) { |
| + const Function& saved_innermost_function = |
| + Function::Handle(Z, innermost_function().raw()); |
| + innermost_function_ = signature.raw(); |
| + // TODO(regis): Resolve upper bounds of function type parameters. |
| + AbstractType& type = AbstractType::Handle(signature.result_type()); |
| + ResolveType(finalization, &type); |
| + signature.set_result_type(type); |
| + const intptr_t num_parameters = signature.NumParameters(); |
| + for (intptr_t i = 0; i < num_parameters; i++) { |
| + type = signature.ParameterTypeAt(i); |
| + ResolveType(finalization, &type); |
| + signature.SetParameterTypeAt(i, type); |
| + } |
| + innermost_function_ = saved_innermost_function.raw(); |
| +} |
| + |
| + |
| // 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 |
| @@ -12082,15 +12238,7 @@ void Parser::ResolveType(ClassFinalizer::FinalizationKind finalization, |
| if (signature_type.raw() != type->raw()) { |
| ResolveType(finalization, &signature_type); |
| } else { |
| - AbstractType& type = AbstractType::Handle(signature.result_type()); |
| - ResolveType(finalization, &type); |
| - signature.set_result_type(type); |
| - const intptr_t num_parameters = signature.NumParameters(); |
| - for (intptr_t i = 0; i < num_parameters; i++) { |
| - type = signature.ParameterTypeAt(i); |
| - ResolveType(finalization, &type); |
| - signature.SetParameterTypeAt(i, type); |
| - } |
| + ResolveSignature(finalization, signature); |
| if (signature.IsSignatureFunction()) { |
| // Drop fields that are not necessary anymore after resolution. |
| // The parent function, owner, and token position of a shared |
| @@ -12104,11 +12252,21 @@ void Parser::ResolveType(ClassFinalizer::FinalizationKind finalization, |
| // preventing sharing of canonical function types between typedefs. |
| // Not being shared, these fields are therefore always meaningful for |
| // typedefs. |
| - if (type.HasResolvedTypeClass()) { |
| - const Class& scope_class = Class::Handle(Z, type.type_class()); |
| + if (type->HasResolvedTypeClass()) { |
| + const Class& scope_class = Class::Handle(Z, type->type_class()); |
| if (!scope_class.IsTypedefClass()) { |
| signature.set_owner(Object::Handle(Z)); |
| signature.set_token_pos(TokenPosition::kNoSource); |
| + if ((type->arguments() != TypeArguments::null()) && |
| + signature.HasInstantiatedSignature()) { |
| + ASSERT(scope_class.IsGeneric()); |
| + // Although the scope class of this function type is generic, |
| + // the signature of this function type does not refer to any |
| + // of its type parameters. Reset its scope class to _Closure. |
| + Type::Cast(*type).set_type_class(Class::Handle( |
| + Z, Isolate::Current()->object_store()->closure_class())); |
| + type->set_arguments(Object::null_type_arguments()); |
| + } |
| } |
| } |
| } |
| @@ -12721,8 +12879,123 @@ RawAbstractType* Parser::ParseType( |
| &prefix); |
| } |
| + |
| +// Parses and returns a type or a functionType. |
|
hausner
2017/01/18 18:54:53
function type
regis
2017/01/18 20:24:24
Done.
|
| +RawAbstractType* Parser::ParseTypeOrFunctionType( |
| + bool allow_void, |
| + ClassFinalizer::FinalizationKind finalization) { |
| + TRACE_PARSER("ParseTypeOrFunctionType"); |
| + AbstractType& type = AbstractType::Handle(Z); |
| + if (CurrentToken() == Token::kVOID) { |
| + TokenPosition void_pos = TokenPos(); |
| + type = Type::VoidType(); |
| + ConsumeToken(); |
| + // 'void' is always allowed as result type of a function type. |
| + if (!allow_void && !IsFunctionTypeSymbol()) { |
| + ReportError(void_pos, "'void' not allowed here"); |
| + } |
| + } else if (!IsFunctionTypeSymbol()) { |
| + // Including 'Function' not followed by '(' or '<'. |
| + // It is too early to resolve the type here, since it can |
| + // refer to a not yet declared function type parameter. |
| + type = ParseType(ClassFinalizer::kDoNotResolve); |
| + } |
| + while (IsSymbol(Symbols::Function())) { |
|
hausner
2017/01/18 18:54:53
Would it make sense to change this to while(IsFunc
regis
2017/01/18 20:24:24
No, I had it that way and changed it to this, beca
|
| + if (type.IsNull()) { |
| + type = Type::DynamicType(); |
| + } |
| + // 'type' is the result type of the function type. |
| + type = ParseFunctionType(type, ClassFinalizer::kDoNotResolve); |
| + } |
| + // At this point, all type parameters have been parsed, resolve the type. |
| + if (finalization == ClassFinalizer::kIgnore) { |
| + return Type::DynamicType(); |
| + } |
| + if (finalization >= ClassFinalizer::kResolveTypeParameters) { |
| + ResolveType(finalization, &type); |
| + if (finalization >= ClassFinalizer::kCanonicalize) { |
| + type ^= ClassFinalizer::FinalizeType(current_class(), type, finalization); |
| + } |
| + } |
| + return type.raw(); |
| +} |
| + |
| + |
| +// Parses and returns a function type. |
| +// If 'result_type' is not null, parsing of the result type is skipped. |
| +RawType* Parser::ParseFunctionType( |
| + const AbstractType& result_type, |
| + ClassFinalizer::FinalizationKind finalization) { |
| + TRACE_PARSER("ParseFunctionType"); |
| + AbstractType& type = AbstractType::Handle(Z, result_type.raw()); |
| + if (type.IsNull()) { |
| + if (CurrentToken() == Token::kVOID) { |
| + ConsumeToken(); |
| + type = Type::VoidType(); |
| + } else if (IsFunctionTypeSymbol()) { |
| + type = Type::DynamicType(); |
| + } else { |
| + // Including 'Function' not followed by '(' or '<'. |
| + // It is too early to resolve the type here, since it can |
| + // refer to a not yet declared function type parameter. |
| + type = ParseType(ClassFinalizer::kDoNotResolve); |
| + } |
| + } |
| + if (!IsSymbol(Symbols::Function())) { |
| + ReportError("'Function' expected"); |
| + } |
| + do { |
| + ConsumeToken(); |
| + 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(); |
| + signature_function.set_result_type(type); |
| + // Parse optional type parameters. |
| + if (CurrentToken() == Token::kLT) { |
| + if (!FLAG_generic_method_syntax) { |
| + ReportError("generic type arguments not supported."); |
| + } |
| + ParseTypeParameters(false); // Not parameterizing class, but function. |
| + } |
| + ParamList params; |
| + // We do not yet allow Function of any arity, so expect parameter list. |
| + CheckToken(Token::kLPAREN, "formal parameter list expected"); |
| + |
| + // Add implicit closure object parameter. Do not specify a token position, |
| + // since it would make no sense after function type canonicalization. |
| + params.AddFinalParameter(TokenPosition::kNoSource, |
| + &Symbols::ClosureParameter(), |
| + &Object::dynamic_type()); |
| + |
| + const bool use_function_type_syntax = true; |
| + const bool allow_explicit_default_values = false; |
| + const bool evaluate_metadata = false; |
| + ParseFormalParameterList(use_function_type_syntax, |
| + allow_explicit_default_values, evaluate_metadata, |
| + ¶ms); |
| + AddFormalParamsToFunction(¶ms, signature_function); |
| + innermost_function_ = innermost_function_.parent_function(); |
| + type = signature_function.SignatureType(); |
| + } while (IsSymbol(Symbols::Function())); |
| + // At this point, all type parameters have been parsed, resolve the type. |
| + if (finalization == ClassFinalizer::kIgnore) { |
| + return Type::DynamicType(); |
| + } |
| + if (finalization >= ClassFinalizer::kResolveTypeParameters) { |
| + ResolveType(finalization, &type); |
| + if (finalization >= ClassFinalizer::kCanonicalize) { |
| + type ^= ClassFinalizer::FinalizeType(current_class(), type, finalization); |
| + } |
| + } |
| + return Type::RawCast(type.raw()); |
| +} |
| + |
| + |
| // Parses type = [ident "."] ident ["<" type { "," type } ">"], then resolve and |
| -// finalize it according to the given type finalization mode. Returns prefix. |
| +// finalize it according to the given type finalization mode. |
| +// Returns type and sets prefix. |
| RawAbstractType* Parser::ParseType( |
| ClassFinalizer::FinalizationKind finalization, |
| bool allow_deferred_type, |
| @@ -13372,6 +13645,7 @@ RawFunction* Parser::BuildConstructorClosureFunction(const Function& ctr, |
| closure.set_is_visible(false); |
| closure.set_result_type(Object::dynamic_type()); |
| AddFormalParamsToFunction(¶ms, closure); |
| + ResolveSignature(ClassFinalizer::kResolveTypeParameters, closure); |
| // Finalize function type. |
| Type& signature_type = Type::Handle(Z, closure.SignatureType()); |
| @@ -14216,7 +14490,7 @@ const Instance& Parser::EvaluateConstExpr(TokenPosition expr_pos, |
| void Parser::SkipFunctionLiteral() { |
| if (IsIdentifier()) { |
| if (LookaheadToken(1) != Token::kLPAREN) { |
| - SkipType(true); |
| + SkipTypeOrFunctionType(true); |
| } |
| ExpectIdentifier("function name expected"); |
| } |
| @@ -14242,6 +14516,12 @@ void Parser::SkipFunctionLiteral() { |
| void Parser::SkipFunctionPreamble() { |
| while (true) { |
| const Token::Kind token = CurrentToken(); |
| + if (IsFunctionTypeSymbol()) { |
| + ConsumeToken(); |
| + SkipTypeArguments(); |
| + SkipToMatchingParenthesis(); |
| + continue; |
| + } |
| if (token == Token::kLPAREN) { |
| return; |
| } |
| @@ -14516,10 +14796,10 @@ void Parser::SkipBinaryExpr() { |
| if (CurrentToken() == Token::kNOT) { |
| ConsumeToken(); |
| } |
| - SkipType(false); |
| + SkipTypeOrFunctionType(false); |
| } else if (CurrentToken() == Token::kAS) { |
| ConsumeToken(); |
| - SkipType(false); |
| + SkipTypeOrFunctionType(false); |
| } else { |
| ConsumeToken(); |
| SkipUnaryExpr(); |