Chromium Code Reviews| Index: runtime/vm/parser.cc |
| =================================================================== |
| --- runtime/vm/parser.cc (revision 1585) |
| +++ runtime/vm/parser.cc (working copy) |
| @@ -25,7 +25,7 @@ |
| DEFINE_FLAG(bool, enable_type_checks, false, "Enable type checks."); |
| DEFINE_FLAG(bool, trace_parser, false, "Trace parser operations."); |
| DEFINE_FLAG(bool, warning_as_error, false, "Treat warnings as errors."); |
| -DEFINE_FLAG(bool, silent_warnings, true, "Silence warnings."); |
| +DEFINE_FLAG(bool, silent_warnings, false, "Silence warnings."); |
| // All references to Dart names are listed here. |
| static const char* kAssertionErrorName = "AssertionError"; |
| @@ -280,13 +280,13 @@ |
| Clear(); |
| } |
| void Clear() { |
| - local_scope_ident = false; |
| + is_local_scope_ident = false; |
| lib_prefix = NULL; |
| qualifier = NULL; |
| ident_pos = 0; |
| ident = NULL; |
| } |
| - bool local_scope_ident; |
| + bool is_local_scope_ident; |
| LibraryPrefix* lib_prefix; |
| String* qualifier; |
| intptr_t ident_pos; |
| @@ -572,6 +572,7 @@ |
| case RawFunction::kGetterFunction: |
| case RawFunction::kSetterFunction: |
| case RawFunction::kConstructor: |
| + ASSERT(!func.IsFactory() || (func.signature_class() != Class::null())); |
| node_sequence = parser.ParseFunc(func, default_parameter_values); |
| break; |
| case RawFunction::kImplicitGetter: |
| @@ -641,7 +642,7 @@ |
| // fragment to evaluate the expression. Instead, we just make sure |
| // the static const field initializer is a constant expression and |
| // leave the evaluation to the getter function. |
| - intptr_t expr_pos = token_index_; |
| + const intptr_t expr_pos = token_index_; |
| AstNode* expr = ParseExpr(kAllowConst); |
| if (expr->EvalConstExpr() == NULL) { |
| ErrorMsg(expr_pos, "initializer must be a compile time constant"); |
| @@ -731,7 +732,7 @@ |
| void Parser::SkipBlock() { |
| ASSERT(CurrentToken() == Token::kLBRACE); |
| GrowableArray<Token::Kind> token_stack(8); |
| - intptr_t block_start_pos = token_index_; |
| + const intptr_t block_start_pos = token_index_; |
| bool is_match = true; |
| bool unexpected_token_found = false; |
| Token::Kind token; |
| @@ -1372,7 +1373,7 @@ |
| GrowableArray<FieldInitExpression>* initializers) { |
| const Array& fields = Array::Handle(cls.fields()); |
| Field& f = Field::Handle(); |
| - intptr_t saved_pos = token_index_; |
| + const intptr_t saved_pos = token_index_; |
| for (int i = 0; i < fields.Length(); i++) { |
| f ^= fields.At(i); |
| if (!f.is_static() && f.has_initializer()) { |
| @@ -1416,7 +1417,7 @@ |
| AstNode* init_statement; |
| if (CurrentToken() == Token::kSUPER) { |
| if (super_init_seen) { |
| - ErrorMsg("Duplicate call to super constructor"); |
| + ErrorMsg("duplicate call to super constructor"); |
| } |
| init_statement = ParseSuperInitializer(cls, receiver); |
| super_init_seen = true; |
| @@ -1438,7 +1439,7 @@ |
| void Parser::ParseConstructorRedirection(const Class& cls, |
| LocalVariable* receiver) { |
| ASSERT(CurrentToken() == Token::kTHIS); |
| - intptr_t call_pos = token_index_; |
| + const intptr_t call_pos = token_index_; |
| ConsumeToken(); |
| String& ctor_name = String::Handle(cls.Name()); |
| String& ctor_suffix = String::Handle(String::NewSymbol(".")); |
| @@ -1481,7 +1482,7 @@ |
| SequenceNode* Parser::MakeImplicitConstructor(const Function& func) { |
| ASSERT(func.IsConstructor()); |
| - intptr_t ctor_pos = token_index_; |
| + const intptr_t ctor_pos = token_index_; |
| // Implicit 'this' is the only parameter/local variable. |
| OpenFunctionBlock(func); |
| @@ -1843,7 +1844,7 @@ |
| ExpectToken(Token::kRBRACE); |
| } else if (CurrentToken() == Token::kARROW) { |
| ConsumeToken(); |
| - intptr_t expr_pos = token_index_; |
| + const intptr_t expr_pos = token_index_; |
| AstNode* expr = ParseExpr(kAllowConst); |
| ASSERT(expr != NULL); |
| current_block_->statements->Add(new ReturnNode(expr_pos, expr)); |
| @@ -1910,16 +1911,16 @@ |
| void Parser::ParseQualIdent(QualIdent* qual_ident) { |
| ASSERT(CurrentToken() == Token::kIDENT); |
| if (!is_top_level_) { |
| - bool local_ident = ResolveIdentInLocalScope(token_index_, |
| - *CurrentLiteral(), |
| - NULL); |
| + bool is_local_ident = ResolveIdentInLocalScope(token_index_, |
| + *CurrentLiteral(), |
| + NULL); |
| qual_ident->ident_pos = token_index_; |
| qual_ident->ident = CurrentLiteral(); |
| qual_ident->lib_prefix = NULL; |
| qual_ident->qualifier = NULL; |
| - qual_ident->local_scope_ident = local_ident; |
| + qual_ident->is_local_scope_ident = is_local_ident; |
| ConsumeToken(); |
| - if (!local_ident && (CurrentToken() == Token::kPERIOD)) { |
| + if (!is_local_ident && (CurrentToken() == Token::kPERIOD)) { |
| LibraryPrefix& lib_prefix = LibraryPrefix::ZoneHandle(); |
| lib_prefix = current_class().LookupLibraryPrefix(*(qual_ident->ident)); |
| if (!lib_prefix.IsNull()) { |
| @@ -1936,7 +1937,7 @@ |
| qual_ident->ident = CurrentLiteral(); |
| qual_ident->lib_prefix = NULL; |
| qual_ident->qualifier = NULL; |
| - qual_ident->local_scope_ident = false; |
| + qual_ident->is_local_scope_ident = false; |
| ConsumeToken(); |
| if (CurrentToken() == Token::kPERIOD) { |
| ConsumeToken(); // Consume the kPERIOD token. |
| @@ -2291,10 +2292,7 @@ |
| ConsumeToken(); |
| member.has_factory = true; |
| member.has_static = true; |
| - // The member result type is the type of this class. |
| - // TODO(regis): What are the type arguments? |
| - member.type = |
| - &Type::ZoneHandle(Type::NewRawType(Class::Handle(members->clazz()))); |
| + // The result type depends on the name of the factory method. |
| } |
| // Optionally parse a type. |
| if (CurrentToken() == Token::kVOID) { |
| @@ -2306,7 +2304,7 @@ |
| member.type = &Type::ZoneHandle(Type::VoidType()); |
| } else if (CurrentToken() == Token::kIDENT) { |
| // This is either a type name or the name of a method/constructor/field. |
| - if (member.type == NULL) { |
| + if ((member.type == NULL) && !member.has_factory) { |
| // We have not seen a member type yet, so we check if the next |
| // identifier could represent a type before parsing it. |
| Token::Kind follower = LookaheadToken(1); |
| @@ -2329,18 +2327,26 @@ |
| (CurrentLiteral()->Equals(members->class_name()) || member.has_factory)) { |
| member.name = CurrentLiteral(); |
| member.name_pos = this->token_index_; |
| - // Factory result type is the same as the type name of the factory. |
| - // TODO(srdjan): Implement checks in class finalization when all types have |
| - // been resolved. |
| - if (member.has_factory && !member.name->Equals(members->class_name())) { |
| - const UnresolvedClass& type = |
| + ConsumeToken(); |
| + // Resolution of the factory result type is always postponed until class |
| + // finalization, so that the list of type parameters in the factory |
| + // signature can be checked at the same time. |
| + if (member.has_factory) { |
| + const UnresolvedClass& unresolved_factory_class = |
| UnresolvedClass::Handle(UnresolvedClass::New(member.name_pos, |
| String::Handle(), |
| *(member.name))); |
| + const Class& signature_class = Class::Handle( |
| + Class::New(String::Handle(String::NewSymbol(":factory_signature")), |
| + Script::Handle())); |
| + signature_class.set_is_finalized(); |
| + unresolved_factory_class.set_factory_signature_class(signature_class); |
| + // The type arguments of the result type are set during finalization. |
| const TypeArguments& args = TypeArguments::Handle(); |
| - member.type = &Type::ZoneHandle(Type::NewParameterizedType(type, args)); |
| + member.type = &Type::ZoneHandle( |
| + Type::NewParameterizedType(unresolved_factory_class, args)); |
| + ParseTypeParameters(signature_class); |
| } |
| - ConsumeToken(); |
| // We must be dealing with a constructor or named constructor. |
| member.kind = RawFunction::kConstructor; |
| String& ctor_suffix = String::ZoneHandle(String::NewSymbol(".")); |
| @@ -2354,9 +2360,11 @@ |
| // Ensure that names are symbols. |
| *member.name = String::NewSymbol(*member.name); |
| if (member.type == NULL) { |
| - // TODO(regis): What are the type arguments? |
| - member.type = |
| - &Type::ZoneHandle(Type::NewRawType(Class::Handle(members->clazz()))); |
| + ASSERT(!member.has_factory); |
| + // The body of the constructor cannot modify the type arguments of the |
| + // constructed instance, which is passed in as an hidden parameter. |
|
srdjan
2011/11/16 23:02:26
a hidden
regis
2011/11/16 23:38:08
Merci :-)
|
| + // Therefore, there is no need to set the result type to be checked. |
| + member.type = &Type::ZoneHandle(Type::DynamicType()); |
| } else { |
| // The type can only be already set in the factory case. |
| if (!member.has_factory) { |
| @@ -2442,9 +2450,9 @@ |
| void Parser::ParseClassDefinition(GrowableArray<const Class*>* classes) { |
| TRACE_PARSER("ParseClassDefinition"); |
| - intptr_t class_pos = token_index_; |
| + const intptr_t class_pos = token_index_; |
| ExpectToken(Token::kCLASS); |
| - intptr_t classname_pos = token_index_; |
| + const intptr_t classname_pos = token_index_; |
| String& class_name = *ExpectIdentifier("class name expected"); |
| if (FLAG_trace_parser) { |
| OS::Print("TopLevel parsing class '%s'\n", class_name.ToCString()); |
| @@ -2537,9 +2545,10 @@ |
| &Type::ZoneHandle(Type::DynamicType())); |
| AddFormalParamsToFunction(¶ms, ctor); |
| - // TODO(regis): What are the type arguments? |
| - Type& result_type = Type::ZoneHandle( |
| - Type::NewRawType(Class::Handle(class_desc->clazz()))); |
| + // The body of the constructor cannot modify the type arguments of the |
| + // constructed instance, which is passed in as an hidden parameter. |
|
srdjan
2011/11/16 23:02:26
a hidden
regis
2011/11/16 23:38:08
Done.
|
| + // Therefore, there is no need to set the result type to be checked. |
| + const Type& result_type = Type::ZoneHandle(Type::DynamicType()); |
| ctor.set_result_type(result_type); |
| class_desc->AddFunction(&ctor); |
| } |
| @@ -2598,7 +2607,7 @@ |
| ExpectToken(Token::kTYPEDEF); |
| Type& result_type = Type::Handle(Type::DynamicType()); |
| - intptr_t result_type_pos = token_index_; |
| + const intptr_t result_type_pos = token_index_; |
| if (CurrentToken() == Token::kVOID) { |
| ConsumeToken(); |
| result_type = Type::VoidType(); |
| @@ -2627,8 +2636,8 @@ |
| // At this point, the type parameters have been parsed, so we can resolve the |
| // result type. |
| - if (!result_type.IsNull() && !result_type.IsResolved()) { |
| - ResolveTypeFromClass(result_type_pos, alias_owner, &result_type); |
| + if (!result_type.IsNull()) { |
| + TryResolveTypeFromClass(result_type_pos, alias_owner, &result_type); |
| } |
| ParamList func_params; |
| const bool no_explicit_default_values = false; |
| @@ -2685,9 +2694,9 @@ |
| void Parser::ParseInterfaceDefinition(GrowableArray<const Class*>* classes) { |
| TRACE_PARSER("ParseInterfaceDefinition"); |
| - intptr_t interface_pos = token_index_; |
| + const intptr_t interface_pos = token_index_; |
| ExpectToken(Token::kINTERFACE); |
| - intptr_t interfacename_pos = token_index_; |
| + const intptr_t interfacename_pos = token_index_; |
| String& interface_name = *ExpectIdentifier("interface name expected"); |
| if (FLAG_trace_parser) { |
| OS::Print("TopLevel parsing interface '%s'\n", interface_name.ToCString()); |
| @@ -2727,17 +2736,27 @@ |
| if (CurrentToken() == Token::kFACTORY) { |
| ConsumeToken(); |
| - Type& factory_type = Type::Handle(); |
| - const intptr_t factory_type_pos = token_index_; |
| - factory_type = ParseType(kCanResolve); |
| - if (factory_type.IsInterfaceType()) { |
| - ErrorMsg(factory_type_pos, |
| - "interface '%s' must have a factory class " |
| - "but '%s' is an interface", |
| - interface_name.ToCString(), |
| - String::Handle(factory_type.Name()).ToCString()); |
| + const intptr_t factory_pos = token_index_; |
| + QualIdent factory_name; |
| + ParseQualIdent(&factory_name); |
| + if (factory_name.is_local_scope_ident) { |
| + ErrorMsg(factory_pos, |
| + "using '%s' in this context is invalid", |
| + factory_name.ident->ToCString()); |
| } |
| - interface.set_factory_type(factory_type); |
| + String& qualifier = String::Handle(); |
| + if (factory_name.qualifier != NULL) { |
| + qualifier ^= factory_name.qualifier->raw(); |
| + } |
| + const UnresolvedClass& unresolved_factory_class = UnresolvedClass::Handle( |
| + UnresolvedClass::New(factory_pos, qualifier, *(factory_name.ident))); |
| + const Class& signature_class = Class::Handle( |
| + Class::New(String::Handle(String::NewSymbol(":factory_signature")), |
| + Script::Handle())); |
| + signature_class.set_is_finalized(); |
| + ParseTypeParameters(signature_class); |
| + unresolved_factory_class.set_factory_signature_class(signature_class); |
| + interface.set_factory_class(unresolved_factory_class); |
| } |
| ExpectToken(Token::kLBRACE); |
| @@ -2810,6 +2829,7 @@ |
| void Parser::ParseTypeParameters(const Class& cls) { |
| if (CurrentToken() == Token::kLT) { |
| + const intptr_t type_pos = token_index_; |
| GrowableArray<String*> type_parameters; |
| GrowableArray<Type*> type_parameter_extends; |
| do { |
| @@ -2836,8 +2856,18 @@ |
| ErrorMsg("right angle bracket expected"); |
| } |
| cls.set_type_parameters(Array::Handle(NewArray<String>(type_parameters))); |
| - cls.set_type_parameter_extends( |
| - TypeArray::Handle(NewTypeArray(type_parameter_extends))); |
| + const TypeArray& extends_array = |
| + TypeArray::Handle(NewTypeArray(type_parameter_extends)); |
| + cls.set_type_parameter_extends(extends_array); |
| + // Try to resolve the upper bounds, which will at least resolve the |
| + // referenced type parameters. |
| + Type& type_extends = Type::Handle(); |
| + const intptr_t num_types = extends_array.Length(); |
| + for (intptr_t i = 0; i < num_types; i++) { |
| + type_extends = extends_array.TypeAt(i); |
| + TryResolveTypeFromClass(type_pos, cls, &type_extends); |
| + extends_array.SetTypeAt(i, type_extends); |
| + } |
| } |
| } |
| @@ -3026,13 +3056,13 @@ |
| UnexpectedToken(); |
| } |
| } |
| - intptr_t name_pos = token_index_; |
| + const intptr_t name_pos = token_index_; |
| const String* field_name = ExpectIdentifier("accessor name expected"); |
| if (CurrentToken() != Token::kLPAREN) { |
| ErrorMsg("'(' expected"); |
| } |
| - intptr_t accessor_pos = token_index_; |
| + const intptr_t accessor_pos = token_index_; |
| ParamList params; |
| const bool allow_explicit_default_values = true; |
| ParseFormalParameterList(allow_explicit_default_values, ¶ms); |
| @@ -3114,7 +3144,7 @@ |
| void Parser::ParseLibraryImport() { |
| while (CurrentToken() == Token::kIMPORT) { |
| - intptr_t import_pos = token_index_; |
| + const intptr_t import_pos = token_index_; |
| ConsumeToken(); |
| ExpectToken(Token::kLPAREN); |
| if (CurrentToken() != Token::kSTRING) { |
| @@ -3171,7 +3201,7 @@ |
| void Parser::ParseLibraryInclude() { |
| while (CurrentToken() == Token::kSOURCE) { |
| - intptr_t source_pos = token_index_; |
| + const intptr_t source_pos = token_index_; |
| ConsumeToken(); |
| ExpectToken(Token::kLPAREN); |
| if (CurrentToken() != Token::kSTRING) { |
| @@ -3385,7 +3415,7 @@ |
| const int num_parameters = params->parameters->length(); |
| // Parse the function name out. |
| - intptr_t native_pos = token_index_; |
| + const intptr_t native_pos = token_index_; |
| const String& native_name = ParseNativeDeclaration(); |
| // Now resolve the native function to the corresponding native entrypoint. |
| @@ -3579,7 +3609,7 @@ |
| (LookaheadToken(1) != Token::kLPAREN)) { |
| result_type = ParseType(kMustResolve); |
| } |
| - intptr_t ident_pos = token_index_; |
| + const intptr_t ident_pos = token_index_; |
| if (CurrentToken() == Token::kIDENT) { |
| variable_name = CurrentLiteral(); |
| function_name = variable_name; |
| @@ -3779,7 +3809,7 @@ |
| ParseQualIdent(&type_name); |
| // Check if the type_name has been defined as a variable in a local scope, |
| // hiding the type. |
| - if (type_name.local_scope_ident) { |
| + if (type_name.is_local_scope_ident) { |
| return false; |
| } |
| if (CurrentToken() == Token::kLT && !IsTypeParameter()) { |
| @@ -3816,7 +3846,7 @@ |
| if (CurrentToken() != Token::kIDENT) { |
| return false; |
| } |
| - intptr_t saved_pos = token_index_; |
| + const intptr_t saved_pos = token_index_; |
| bool is_var_decl = false; |
| if (IsOptionalType()) { |
| if (CurrentToken() == Token::kIDENT) { |
| @@ -3853,7 +3883,7 @@ |
| if ((CurrentToken() == Token::kGET) || (CurrentToken() == Token::kSET)) { |
| return true; |
| } |
| - intptr_t saved_pos = token_index_; |
| + const intptr_t saved_pos = token_index_; |
| if (IsReturnType()) { |
| if ((CurrentToken() == Token::kGET) || (CurrentToken() == Token::kSET)) { |
| if (LookaheadToken(1) == Token::kIDENT) { // Accessor name. |
| @@ -3871,7 +3901,7 @@ |
| if (!allow_function_literals_) { |
| return false; |
| } |
| - intptr_t saved_pos = token_index_; |
| + const intptr_t saved_pos = token_index_; |
| bool is_function_literal = false; |
| if ((CurrentToken() == Token::kIDENT) && |
| (LookaheadToken(1) == Token::kLPAREN)) { |
| @@ -3899,7 +3929,7 @@ |
| // statement. Returns true if we recognize a for ( .. in expr) |
| // statement. |
| bool Parser::IsForInStatement() { |
| - intptr_t saved_pos = token_index_; |
| + const intptr_t saved_pos = token_index_; |
| bool result = false; |
| if (CurrentToken() == Token::kVAR || CurrentToken() == Token::kFINAL) { |
| ConsumeToken(); |
| @@ -3945,7 +3975,7 @@ |
| const bool dead_code_allowed = true; |
| bool abrupt_completing_seen = false; |
| while (CurrentToken() != Token::kRBRACE) { |
| - intptr_t statement_pos = token_index_; |
| + const intptr_t statement_pos = token_index_; |
| AstNode* statement = ParseStatement(); |
| if (statement != NULL) { |
| if (!dead_code_allowed && abrupt_completing_seen) { |
| @@ -3990,7 +4020,7 @@ |
| AstNode* Parser::ParseIfStatement(String* label_name) { |
| TRACE_PARSER("ParseIfStatement"); |
| ASSERT(CurrentToken() == Token::kIF); |
| - intptr_t if_pos = token_index_; |
| + const intptr_t if_pos = token_index_; |
| SourceLabel* label = NULL; |
| if (label_name != NULL) { |
| label = SourceLabel::New(if_pos, label_name, SourceLabel::kStatement); |
| @@ -4023,7 +4053,7 @@ |
| SourceLabel* case_label) { |
| TRACE_PARSER("ParseCaseStatement"); |
| bool default_seen = false; |
| - intptr_t case_pos = token_index_; |
| + const intptr_t case_pos = token_index_; |
| SequenceNode* case_expressions = |
| new SequenceNode(case_pos, current_block_->scope); |
| while (CurrentToken() == Token::kCASE || CurrentToken() == Token::kDEFAULT) { |
| @@ -4032,7 +4062,7 @@ |
| ErrorMsg("default clause must be last case"); |
| } |
| ConsumeToken(); // Keyword case. |
| - intptr_t expr_pos = token_index_; |
| + const intptr_t expr_pos = token_index_; |
| AstNode* expr = ParseExpr(kAllowConst); |
| AstNode* switch_expr_load = new LoadLocalNode(case_pos, |
| *switch_expr_value); |
| @@ -4097,7 +4127,7 @@ |
| AstNode* Parser::ParseSwitchStatement(String* label_name) { |
| TRACE_PARSER("ParseSwitchStatement"); |
| ASSERT(CurrentToken() == Token::kSWITCH); |
| - intptr_t switch_pos = token_index_; |
| + const intptr_t switch_pos = token_index_; |
| SourceLabel* label = |
| SourceLabel::New(switch_pos, label_name, SourceLabel::kSwitch); |
| ConsumeToken(); |
| @@ -4109,7 +4139,7 @@ |
| } else if (parens_are_mandatory) { |
| ErrorMsg("'(' expected"); |
| } |
| - intptr_t expr_pos = token_index_; |
| + const intptr_t expr_pos = token_index_; |
| AstNode* switch_expr = ParseExpr(kAllowConst); |
| if (paren_found) { |
| ExpectToken(Token::kRPAREN); |
| @@ -4137,7 +4167,7 @@ |
| LookaheadToken(1) == Token::kCOLON) { |
| // Case statements start with a label. |
| String* label_name = CurrentLiteral(); |
| - intptr_t label_pos = token_index_; |
| + const intptr_t label_pos = token_index_; |
| ConsumeToken(); // Consume label identifier. |
| ConsumeToken(); // Consume colon. |
| case_label = current_block_->scope->LocalLookupLabel(*label_name); |
| @@ -4189,7 +4219,7 @@ |
| AstNode* Parser::ParseWhileStatement(String* label_name) { |
| TRACE_PARSER("ParseWhileStatement"); |
| - intptr_t while_pos = token_index_; |
| + const intptr_t while_pos = token_index_; |
| SourceLabel* label = |
| SourceLabel::New(while_pos, label_name, SourceLabel::kWhile); |
| ConsumeToken(); |
| @@ -4204,7 +4234,7 @@ |
| AstNode* Parser::ParseDoWhileStatement(String* label_name) { |
| TRACE_PARSER("ParseDoWhileStatement"); |
| - intptr_t do_pos = token_index_; |
| + const intptr_t do_pos = token_index_; |
| SourceLabel* label = |
| SourceLabel::New(do_pos, label_name, SourceLabel::kDoWhile); |
| ConsumeToken(); |
| @@ -4240,7 +4270,7 @@ |
| } |
| } |
| ExpectToken(Token::kIN); |
| - intptr_t collection_pos = token_index_; |
| + const intptr_t collection_pos = token_index_; |
| AstNode* collection_expr = ParseExpr(kAllowConst); |
| ExpectToken(Token::kRPAREN); |
| @@ -4332,7 +4362,7 @@ |
| AstNode* Parser::ParseForStatement(String* label_name) { |
| TRACE_PARSER("ParseForStatement"); |
| - intptr_t for_pos = token_index_; |
| + const intptr_t for_pos = token_index_; |
| ConsumeToken(); |
| ExpectToken(Token::kLPAREN); |
| SourceLabel* label = SourceLabel::New(for_pos, label_name, SourceLabel::kFor); |
| @@ -4344,7 +4374,7 @@ |
| // the loop variable declarations. |
| current_block_->scope->AddLabel(label); |
| AstNode* initializer = NULL; |
| - intptr_t init_pos = token_index_; |
| + const intptr_t init_pos = token_index_; |
| LocalScope* init_scope = current_block_->scope; |
| if (CurrentToken() != Token::kSEMICOLON) { |
| if (IsVariableDeclaration()) { |
| @@ -4360,7 +4390,7 @@ |
| } |
| ExpectSemicolon(); |
| AstNode* increment = NULL; |
| - intptr_t incr_pos = token_index_; |
| + const intptr_t incr_pos = token_index_; |
| LocalScope* incr_scope = current_block_->scope; |
| if (CurrentToken() != Token::kRPAREN) { |
| increment = ParseExprList(); |
| @@ -4628,7 +4658,7 @@ |
| current_block_->scope->AddVariable(catch_trace_var); |
| } |
| - intptr_t try_pos = token_index_; |
| + const intptr_t try_pos = token_index_; |
| ConsumeToken(); // Consume the 'try'. |
| SourceLabel* try_label = NULL; |
| @@ -4658,12 +4688,12 @@ |
| bool catch_seen = false; |
| bool generic_catch_seen = false; |
| SequenceNode* catch_handler_list = NULL; |
| - intptr_t handler_pos = token_index_; |
| + const intptr_t handler_pos = token_index_; |
| OpenBlock(); // Start the catch block sequence. |
| current_block_->scope->AddLabel(end_catch_label); |
| while (CurrentToken() == Token::kCATCH) { |
| catch_seen = true; |
| - intptr_t catch_pos = token_index_; |
| + const intptr_t catch_pos = token_index_; |
| ConsumeToken(); // Consume the 'catch'. |
| ExpectToken(Token::kLPAREN); |
| CatchParamDesc exception_param; |
| @@ -4679,7 +4709,7 @@ |
| // subsequent catch statements are dead. We issue an error for now, |
| // it might make sense to turn this into a warning. |
| if (generic_catch_seen) { |
| - ErrorMsg("A generic 'catch all' statement already exists for this " |
| + ErrorMsg("a generic 'catch all' statement already exists for this " |
| "try block. All subsequent catch statements are dead code"); |
| } |
| OpenBlock(); |
| @@ -4755,7 +4785,7 @@ |
| if (CurrentToken() == Token::kFINALLY) { |
| current_function_.set_is_optimizable(false); |
| ConsumeToken(); // Consume the 'finally'. |
| - intptr_t finally_pos = token_index_; |
| + const intptr_t finally_pos = token_index_; |
| // Add the finally block to the exit points recorded so far. |
| intptr_t node_index = 0; |
| AstNode* node_to_inline = |
| @@ -4818,7 +4848,7 @@ |
| AstNode* Parser::ParseJump(String* label_name) { |
| ASSERT(CurrentToken() == Token::kBREAK || CurrentToken() == Token::kCONTINUE); |
| Token::Kind jump_kind = CurrentToken(); |
| - intptr_t jump_pos = token_index_; |
| + const intptr_t jump_pos = token_index_; |
| SourceLabel* target = NULL; |
| ConsumeToken(); |
| if (CurrentToken() == Token::kIDENT) { |
| @@ -5041,6 +5071,8 @@ |
| if (FLAG_warning_as_error) { |
| Isolate::Current()->long_jump_base()->Jump(1, error_msg_); |
| UNREACHABLE(); |
| + } else { |
| + OS::Print(error_msg_); |
| } |
| } |
| @@ -5338,7 +5370,7 @@ |
| case Token::kASSIGN_XOR: |
| return new BinaryOpNode(op_pos, Token::kBIT_XOR, lhs, rhs); |
| default: |
| - ErrorMsg(op_pos, "Internal error: ExpandAssignableOp '%s' unimplemented", |
| + ErrorMsg(op_pos, "internal error: ExpandAssignableOp '%s' unimplemented", |
| Token::Name(assignment_op)); |
| UNIMPLEMENTED(); |
| return NULL; |
| @@ -5386,7 +5418,7 @@ |
| AstNode* assign_expr = expr->MakeAssignmentNode(right_expr); |
| if (assign_expr == NULL) { |
| ErrorMsg(assignment_pos, |
| - "Left hand side of '%s' is not assignable", |
| + "left hand side of '%s' is not assignable", |
| Token::Str(assignment_op)); |
| } |
| return assign_expr; |
| @@ -5430,7 +5462,7 @@ |
| ConsumeToken(); |
| expr = ParseUnaryExpr(); |
| if (!IsAssignableExpr(expr)) { |
| - ErrorMsg("Expression is not assignable"); |
| + ErrorMsg("expression is not assignable"); |
| } |
| // is_prefix. |
| AstNode* incr_op_node = expr->MakeIncrOpNode(op_pos, incr_op, true); |
| @@ -5781,7 +5813,7 @@ |
| // Dynamic function call on implicit "this" parameter. |
| if (current_function().is_static()) { |
| ErrorMsg(primary_pos, |
| - "Cannot access instance method '%s' " |
| + "cannot access instance method '%s' " |
| "from static function", |
| func_name.ToCString()); |
| } |
| @@ -5801,7 +5833,7 @@ |
| } |
| } else if (primary->primary().IsClass()) { |
| ErrorMsg(left->token_index(), |
| - "must use 'new' or 'const' to construct new instance"); |
| + "must use 'new' or 'const' to construct new instance"); |
| } else { |
| // Internal parser error. |
| UNREACHABLE(); |
| @@ -5882,9 +5914,13 @@ |
| } |
| -bool Parser::ResolveTypeFromClass(intptr_t type_pos, |
| - const Class& cls, |
| - Type* type) { |
| +// Try to resolve the given type and its type arguments from the given class. |
| +// 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 |
| +// finalizer from resolving type parameters out of context. |
| +void Parser::TryResolveTypeFromClass(intptr_t type_pos, |
| + const Class& cls, |
| + Type* type) { |
| ASSERT(type != NULL); |
| // Resolve class. |
| if (!type->HasResolvedTypeClass()) { |
| @@ -5896,42 +5932,36 @@ |
| const TypeParameter& type_parameter = TypeParameter::Handle( |
| cls.LookupTypeParameter(unresolved_class_name)); |
| if (!type_parameter.IsNull()) { |
| - CheckTypeParameterReference(type_pos, unresolved_class_name); |
| // A type parameter cannot be parameterized, so report an error if type |
| // arguments have previously been parsed. |
| if (type->arguments() != TypeArguments::null()) { |
| ErrorMsg(type_pos, "type parameter '%s' cannot be parameterized", |
| type_parameter.ToCString()); |
| - return false; |
| } |
| *type = type_parameter.raw(); |
| - return true; |
| + return; |
| } |
| const Class& resolved_type_class = |
| Class::Handle(LookupClass(unresolved_class_name)); |
| - if (resolved_type_class.IsNull()) { |
| - return false; |
| + if (!resolved_type_class.IsNull()) { |
| + Object& type_class = Object::Handle(resolved_type_class.raw()); |
| + ASSERT(type->IsParameterizedType()); |
| + // Replace unresolved class with resolved type class. |
| + ParameterizedType& parameterized_type = ParameterizedType::Handle(); |
| + parameterized_type ^= type->raw(); |
| + parameterized_type.set_type_class(type_class); |
| } |
| - Object& type_class = Object::Handle(resolved_type_class.raw()); |
| - ASSERT(type->IsParameterizedType()); |
| - // Replace unresolved class with resolved type class. |
| - ParameterizedType& parameterized_type = ParameterizedType::Handle(); |
| - parameterized_type ^= type->raw(); |
| - parameterized_type.set_type_class(type_class); |
| } |
| // Resolve type arguments, if any. |
| const TypeArguments& arguments = TypeArguments::Handle(type->arguments()); |
| if (!arguments.IsNull()) { |
| - intptr_t num_arguments = arguments.Length(); |
| + const intptr_t num_arguments = arguments.Length(); |
| for (intptr_t i = 0; i < num_arguments; i++) { |
| Type& type_argument = Type::Handle(arguments.TypeAt(i)); |
| - if (!ResolveTypeFromClass(type_pos, cls, &type_argument)) { |
| - return false; |
| - } |
| + TryResolveTypeFromClass(type_pos, cls, &type_argument); |
| arguments.SetTypeAt(i, type_argument); |
| } |
| } |
| - return true; |
| } |
| @@ -5990,22 +6020,51 @@ |
| } |
| -void Parser::CheckTypeParameterReference(intptr_t type_parameter_pos, |
| - const String& type_parameter_name) { |
| +// If type parameters are currently in scope, return their declaring class, |
| +// otherwise return null. |
| +RawClass* Parser::TypeParametersScopeClass() { |
| // Type parameters cannot be referred to from a static function, except from |
| // a constructor or from a factory. |
| // A constructor is considered as non-static by the compiler. |
| - if ((is_top_level_ && |
| - (current_member_ != NULL) && |
| - current_member_->has_static && |
| - !current_member_->has_factory) || |
| - (!current_function().IsNull() && |
| - current_function().is_static() && |
| - !current_function().IsInFactoryScope())) { |
| - ErrorMsg(type_parameter_pos, |
| - "cannot refer to type parameter '%s' from a static function", |
| - type_parameter_name.ToCString()); |
| + if (is_top_level_) { |
| + if ((current_member_ != NULL) && current_member_->has_factory) { |
| + const Type& factory_result_type = *current_member_->type; |
| + ASSERT(!factory_result_type.IsNull()); |
| + const UnresolvedClass& unresolved_factory_class = |
| + UnresolvedClass::Handle(factory_result_type.unresolved_class()); |
| + // TODO(regis): For now, and until the core lib is fixed, we accept a |
| + // factory method with missing list of type parameters and use the |
| + // list of the enclosing class. |
| + // See bug 5408808. |
| + // Therefore, we temporarily return the current class instead of the |
| + // factory signature class if the latter one does not declare any type |
| + // parameters. |
| + const Class& factory_signature_class = |
| + Class::Handle(unresolved_factory_class.factory_signature_class()); |
| + if (factory_signature_class.NumTypeParameters() == 0) { |
| + return current_class().raw(); |
| + } else { |
| + return factory_signature_class.raw(); |
| + } |
| + } |
| + if ((current_member_ == NULL) || !current_member_->has_static) { |
| + return current_class().raw(); |
| + } |
| + } else { |
| + if (!current_function().IsNull()) { |
| + Function& outer_function = Function::Handle(current_function().raw()); |
| + while (outer_function.IsLocalFunction()) { |
| + outer_function = outer_function.parent_function(); |
| + } |
| + if (outer_function.IsFactory()) { |
| + return outer_function.signature_class(); |
| + } |
| + if (!outer_function.is_static()) { |
| + return current_class().raw(); |
| + } |
| + } |
| } |
| + return Class::null(); |
| } |
| @@ -6013,7 +6072,7 @@ |
| ASSERT(field.is_static()); |
| const Instance& value = Instance::Handle(field.value()); |
| if (value.raw() == Object::transition_sentinel()) { |
| - ErrorMsg("Circular dependency while initializing static field '%s'", |
| + ErrorMsg("circular dependency while initializing static field '%s'", |
| String::Handle(field.name()).ToCString()); |
| } else if (value.raw() == Object::sentinel()) { |
| @@ -6040,7 +6099,7 @@ |
| Instance& const_value = Instance::Handle( |
| DartEntry::InvokeStatic(func, arguments, kNoArgumentNames)); |
| if (const_value.IsUnhandledException()) { |
| - ErrorMsg("Exception thrown in Parser::RunStaticFieldInitializer"); |
| + ErrorMsg("exception thrown in Parser::RunStaticFieldInitializer"); |
| } |
| if (!const_value.IsNull()) { |
| const_value ^= const_value.Canonicalize(); |
| @@ -6339,10 +6398,10 @@ |
| ErrorMsg("type name expected"); |
| } |
| QualIdent type_name; |
| - intptr_t type_pos = token_index_; |
| + const intptr_t type_pos = token_index_; |
| ParseQualIdent(&type_name); |
| - if (type_name.local_scope_ident) { |
| - ErrorMsg(type_pos, "Using '%s' in this context is invalid", |
| + if (type_name.is_local_scope_ident) { |
| + ErrorMsg(type_pos, "using '%s' in this context is invalid", |
| type_name.ident->ToCString()); |
| } |
| Object& type_class = Object::Handle(); |
| @@ -6353,26 +6412,27 @@ |
| } |
| type_class = UnresolvedClass::New(type_pos, qualifier, *(type_name.ident)); |
| } else { |
| - TypeParameter& type_parameter = TypeParameter::Handle(); |
| - // Check if qualifier is a type parameter of the class we are parsing. |
| - if (type_name.qualifier != NULL) { |
| - type_parameter = |
| - current_class().LookupTypeParameter(*type_name.qualifier); |
| - if (!type_parameter.IsNull()) { |
| - ErrorMsg(type_pos, "Use of '%s' in this context is invalid", |
| - type_name.qualifier->ToCString()); |
| - } |
| - } else { |
| - // Check if ident is a type parameter of the class we are parsing. |
| - type_parameter = current_class().LookupTypeParameter(*type_name.ident); |
| - if (!type_parameter.IsNull()) { |
| - CheckTypeParameterReference(type_name.ident_pos, *type_name.ident); |
| - if (CurrentToken() == Token::kLT) { |
| - // A type parameter cannot be parameterized. |
| - ErrorMsg(type_pos, "type parameter '%s' cannot be parameterized", |
| - String::Handle(type_parameter.Name()).ToCString()); |
| + const Class& scope_class = Class::Handle(TypeParametersScopeClass()); |
| + if (!scope_class.IsNull()) { |
| + TypeParameter& type_parameter = TypeParameter::Handle(); |
| + // Check if qualifier is a type parameter in scope. |
| + if (type_name.qualifier != NULL) { |
| + type_parameter = scope_class.LookupTypeParameter(*type_name.qualifier); |
| + if (!type_parameter.IsNull()) { |
| + ErrorMsg(type_pos, "type Parameter '%s' cannot be used as qualifier", |
| + type_name.qualifier->ToCString()); |
| } |
| - return type_parameter.raw(); |
| + } else { |
| + // Check if ident is a type parameter in scope. |
| + type_parameter = scope_class.LookupTypeParameter(*type_name.ident); |
| + if (!type_parameter.IsNull()) { |
| + if (CurrentToken() == Token::kLT) { |
| + // A type parameter cannot be parameterized. |
| + ErrorMsg(type_pos, "type parameter '%s' cannot be parameterized", |
| + String::Handle(type_parameter.Name()).ToCString()); |
| + } |
| + return type_parameter.raw(); |
| + } |
| } |
| } |
| // Try to resolve the type class. |
| @@ -6396,12 +6456,20 @@ |
| void Parser::CheckConstructorCallTypeArguments( |
| intptr_t pos, Function& constructor, const TypeArguments& type_arguments) { |
| - if (!type_arguments.IsNull() && |
| - (type_arguments.Length() != |
| - Class::Handle(constructor.owner()).NumTypeArguments())) { |
| - ErrorMsg(pos, "Incorrect number of type arguments, expected %d got %d", |
| - Class::Handle(constructor.owner()).NumTypeArguments(), |
| - type_arguments.Length()); |
| + if (!type_arguments.IsNull()) { |
| + Class& signature_class = Class::Handle(); |
| + if (constructor.IsFactory()) { |
| + signature_class = constructor.signature_class(); |
| + } else { |
| + signature_class = constructor.owner(); |
| + } |
| + ASSERT(!signature_class.IsNull()); |
| + ASSERT(signature_class.is_finalized()); |
| + if (type_arguments.Length() != signature_class.NumTypeArguments()) { |
| + ErrorMsg(pos, "incorrect number of type arguments, expected %d got %d", |
| + signature_class.NumTypeArguments(), |
| + type_arguments.Length()); |
| + } |
| } |
| } |
| @@ -6414,7 +6482,7 @@ |
| bool is_const, |
| const TypeArguments& type_arguments) { |
| ASSERT(CurrentToken() == Token::kLBRACK || CurrentToken() == Token::kINDEX); |
| - intptr_t literal_pos = token_index_; |
| + const intptr_t literal_pos = token_index_; |
| bool is_empty_literal = CurrentToken() == Token::kINDEX; |
| ConsumeToken(); |
| @@ -6523,7 +6591,7 @@ |
| const TypeArguments& type_arguments) { |
| TRACE_PARSER("ParseMapLiteral"); |
| ASSERT(CurrentToken() == Token::kLBRACE); |
| - intptr_t literal_pos = token_index_; |
| + const intptr_t literal_pos = token_index_; |
| ConsumeToken(); |
| String& map_class_name = String::Handle( |
| @@ -6635,7 +6703,7 @@ |
| is_const = true; |
| ConsumeToken(); |
| } |
| - intptr_t type_pos = token_index_; |
| + const intptr_t type_pos = token_index_; |
| TypeArguments& type_arguments = |
| TypeArguments::ZoneHandle(ParseTypeArguments(kMustResolve)); |
| AstNode* primary = NULL; |
| @@ -6645,7 +6713,7 @@ |
| } else if (CurrentToken() == Token::kLBRACE) { |
| primary = ParseMapLiteral(type_pos, is_const, type_arguments); |
| } else { |
| - ErrorMsg("Unexpected token %s", Token::Str(CurrentToken())); |
| + ErrorMsg("unexpected token %s", Token::Str(CurrentToken())); |
| } |
| return primary; |
| } |
| @@ -6688,36 +6756,35 @@ |
| String& type_class_name = String::Handle(); |
| TypeArguments& type_arguments = TypeArguments::ZoneHandle(); |
| String* named_constructor = NULL; |
| - intptr_t type_pos = token_index_; |
| + const intptr_t type_pos = token_index_; |
| QualIdent type_name; |
| ParseQualIdent(&type_name); |
| - if (type_name.local_scope_ident) { |
| - ErrorMsg(type_pos, "Using '%s' in this context is invalid", |
| + if (type_name.is_local_scope_ident) { |
| + ErrorMsg(type_pos, "using '%s' in this context is invalid", |
| type_name.ident->ToCString()); |
| } |
| if (CurrentToken() == Token::kPERIOD) { |
| ConsumeToken(); |
| named_constructor = ExpectIdentifier("identifier expected after '.'"); |
| } |
| - TypeParameter& type_parameter = TypeParameter::Handle(); |
| - if (type_name.lib_prefix != NULL) { |
| - // TODO(regis): Ascertain that this check for shadowing is valid |
| - // See bug (490270). |
| - // Check if qualifier is a type parameter of the class we are parsing. |
| - type_parameter ^= current_class().LookupTypeParameter(*type_name.qualifier); |
| + const Class& scope_class = Class::Handle(TypeParametersScopeClass()); |
| + if (!scope_class.IsNull()) { |
| + TypeParameter& type_parameter = TypeParameter::Handle(); |
| + if (type_name.lib_prefix != NULL) { |
| + // Check if qualifier is a type parameter in scope. |
| + type_parameter ^= scope_class.LookupTypeParameter(*type_name.qualifier); |
| + if (!type_parameter.IsNull()) { |
| + ErrorMsg(type_pos, "type parameter '%s' cannot be used as qualifier", |
| + String::Handle(type_parameter.Name()).ToCString()); |
| + } |
| + } |
| + // Check if ident is a type parameter in scope. |
| + type_parameter = scope_class.LookupTypeParameter(*type_name.ident); |
| if (!type_parameter.IsNull()) { |
| - CheckTypeParameterReference(type_pos, *type_name.qualifier); |
| ErrorMsg(type_pos, "type parameter '%s' cannot be instantiated", |
| String::Handle(type_parameter.Name()).ToCString()); |
| } |
| } |
| - // Check if ident is a type parameter of the class we are parsing. |
| - type_parameter = current_class().LookupTypeParameter(*type_name.ident); |
| - if (!type_parameter.IsNull()) { |
| - CheckTypeParameterReference(type_name.ident_pos, *type_name.ident); |
| - ErrorMsg(type_pos, "type parameter '%s' cannot be instantiated", |
| - String::Handle(type_parameter.Name()).ToCString()); |
| - } |
| type_class ^= LookupTypeClass(type_name, kMustResolve); |
| type_class_name = type_class.Name(); |
| // Type arguments are not allowed after the optional constructor name. |
| @@ -6769,37 +6836,29 @@ |
| external_constructor_name.ToCString(), |
| type_class_name.ToCString()); |
| } |
| - |
| - // TODO(srdjan): Evaluate if the mapping should occur during code |
| - // generation or here in the parser. |
| - const Type& factory_type = Type::Handle(type_class.factory_type()); |
| - if (factory_type.IsNull()) { |
| + if (!type_class.HasFactoryClass()) { |
| ErrorMsg("cannot allocate interface '%s' without factory class", |
| type_class_name.ToCString()); |
| } |
| - if (!factory_type.HasResolvedTypeClass()) { |
| + if (!type_class.HasResolvedFactoryClass()) { |
| // This error can occur only with bootstrap classes. |
| const UnresolvedClass& unresolved = |
| - UnresolvedClass::Handle(factory_type.unresolved_class()); |
| + UnresolvedClass::Handle(type_class.UnresolvedFactoryClass()); |
| const String& missing_class_name = String::Handle(unresolved.ident()); |
| - ErrorMsg("Unresolved factory class '%s'", missing_class_name.ToCString()); |
| + ErrorMsg("unresolved factory class '%s'", missing_class_name.ToCString()); |
| } |
| - |
| // Only change the class of the constructor to the factory class if the |
| // factory class implements the interface 'type'. |
| - Class& factory_type_class = Class::Handle(factory_type.type_class()); |
| - // TODO(regis): Verify in the guide/spec that a factory class must have |
| - // identical type parameters as the interface. |
| - // TODO(regis): Do we check that in the parser? |
| - // Assuming that it has been checked, it is sufficient to test if the |
| - // raw factory type implements the raw interface type. |
| - if (factory_type_class.IsSubtypeOf(TypeArguments::Handle(), |
| - type_class, |
| - TypeArguments::Handle())) { |
| - type_class_name = factory_type_class.Name(); |
| + const Class& factory_class = Class::Handle(type_class.FactoryClass()); |
| + if (factory_class.IsSubtypeOf(TypeArguments::Handle(), |
| + type_class, |
| + TypeArguments::Handle())) { |
| + // Class finalization verifies that the factory class has identical type |
| + // parameters as the interface. |
| + type_class_name = factory_class.Name(); |
| } |
| // Always change the result type of the constructor to the factory type. |
| - type_class = factory_type_class.raw(); |
| + type_class = factory_class.raw(); |
| ASSERT(!type_class.is_interface()); |
| } |
| @@ -6868,7 +6927,7 @@ |
| // there are never two kSTRING tokens next to each other. |
| AstNode* Parser::ParseStringLiteral() { |
| AstNode* primary = NULL; |
| - intptr_t literal_start = token_index_; |
| + const intptr_t literal_start = token_index_; |
| if ((CurrentToken() == Token::kSTRING) && |
| (LookaheadToken(1) != Token::kINTERPOL_VAR) && |
| (LookaheadToken(1) != Token::kINTERPOL_START)) { |
| @@ -6927,7 +6986,7 @@ |
| } else if (CurrentToken() == Token::kIDENT) { |
| QualIdent qual_ident; |
| ParseQualIdent(&qual_ident); |
| - if (qual_ident.local_scope_ident) { |
| + if (qual_ident.is_local_scope_ident) { |
| ResolveIdentInLocalScope(qual_ident.ident_pos, |
| *qual_ident.ident, |
| &primary); |
| @@ -7028,7 +7087,7 @@ |
| Token::CanBeOverloaded(CurrentToken())) { |
| primary = ParseSuperOperator(); |
| } else { |
| - ErrorMsg("Illegal super call"); |
| + ErrorMsg("illegal super call"); |
| } |
| } else { |
| UnexpectedToken(); |