Chromium Code Reviews| Index: runtime/vm/parser.cc |
| =================================================================== |
| --- runtime/vm/parser.cc (revision 4727) |
| +++ runtime/vm/parser.cc (working copy) |
| @@ -29,6 +29,7 @@ |
| // All references to Dart names are listed here. |
| static const char* kAssertionErrorName = "AssertionError"; |
| +static const char* kTypeErrorName = "TypeError"; |
| static const char* kFallThroughErrorName = "FallThroughError"; |
| static const char* kStaticResolutionExceptionName = "StaticResolutionException"; |
| static const char* kThrowNewName = "_throwNew"; |
| @@ -818,7 +819,8 @@ |
| // mode, because they are part of the function type of closurized |
| // functions appearing in type tests with typedefs. |
| parameter.type = &AbstractType::ZoneHandle( |
| - ParseType(is_top_level_ ? kCanResolve : kMustResolve)); |
| + ParseType(is_top_level_ ? ClassFinalizer::kTryResolve : |
| + ClassFinalizer::kFinalize)); |
| } else { |
| parameter.type = &Type::ZoneHandle(Type::DynamicType()); |
| } |
| @@ -880,8 +882,8 @@ |
| ASSERT(signature_function.signature_class() == signature_class.raw()); |
| Type& signature_type = Type::ZoneHandle(signature_class.SignatureType()); |
| if (!is_top_level_ && !signature_type.IsFinalized()) { |
| - signature_type ^= |
| - ClassFinalizer::FinalizeType(signature_class, signature_type); |
| + signature_type ^= ClassFinalizer::FinalizeType( |
| + signature_class, signature_type, ClassFinalizer::kFinalize); |
| } |
| // The type of the parameter is now the signature type. |
| parameter.type = &signature_type; |
| @@ -2345,7 +2347,8 @@ |
| // The declared type of fields is never ignored, even in unchecked mode, |
| // because getters and setters could be closurized at some time (not |
| // supported yet). |
| - member.type = &AbstractType::ZoneHandle(ParseType(kCanResolve)); |
| + member.type = &AbstractType::ZoneHandle( |
| + ParseType(ClassFinalizer::kTryResolve)); |
| } |
| } |
| } |
| @@ -2530,7 +2533,8 @@ |
| if (CurrentToken() == Token::kEXTENDS) { |
| ConsumeToken(); |
| const intptr_t type_pos = token_index_; |
| - const AbstractType& type = AbstractType::Handle(ParseType(kCanResolve)); |
| + const AbstractType& type = AbstractType::Handle( |
| + ParseType(ClassFinalizer::kTryResolve)); |
| if (type.IsTypeParameter()) { |
| ErrorMsg(type_pos, |
| "class '%s' may not extend type parameter '%s'", |
| @@ -2679,7 +2683,7 @@ |
| } else if (!IsFunctionTypeAliasName()) { |
| // Type annotations in typedef are never ignored, even in unchecked mode. |
| // Wait until we have an owner class before resolving the result type. |
| - result_type = ParseType(kDoNotResolve); |
| + result_type = ParseType(ClassFinalizer::kDoNotResolve); |
| } |
| const intptr_t alias_name_pos = token_index_; |
| @@ -2691,7 +2695,9 @@ |
| // At this point, the type parameters have been parsed, so we can resolve the |
| // result type. |
| if (!result_type.IsNull()) { |
| - ResolveTypeFromClass(alias_owner, kCanResolve, &result_type); |
| + ResolveTypeFromClass(alias_owner, |
| + ClassFinalizer::kTryResolve, |
| + &result_type); |
| } |
| // Parse the formal parameters of the function type. |
| if (CurrentToken() != Token::kLPAREN) { |
| @@ -2920,7 +2926,7 @@ |
| AbstractType& bound = Type::ZoneHandle(Type::DynamicType()); |
| if (CurrentToken() == Token::kEXTENDS) { |
| ConsumeToken(); |
| - bound = ParseType(kCanResolve); |
| + bound = ParseType(ClassFinalizer::kTryResolve); |
| } |
| type_parameters_array.Add(&type_parameter); |
| bounds_array.Add(&bound); |
| @@ -2944,7 +2950,7 @@ |
| const intptr_t num_types = bounds.Length(); |
| for (intptr_t i = 0; i < num_types; i++) { |
| bound = bounds.TypeAt(i); |
| - ResolveTypeFromClass(cls, kCanResolve, &bound); |
| + ResolveTypeFromClass(cls, ClassFinalizer::kTryResolve, &bound); |
| bounds.SetTypeAt(i, bound); |
| } |
| } |
| @@ -2952,14 +2958,19 @@ |
| RawAbstractTypeArguments* Parser::ParseTypeArguments( |
| - TypeResolution type_resolution) { |
| + Error* malformed_error, |
| + ClassFinalizer::TypeFinalization finalization) { |
| TRACE_PARSER("ParseTypeArguments"); |
| if (CurrentToken() == Token::kLT) { |
| GrowableArray<AbstractType*> types; |
| do { |
| ConsumeToken(); |
| - AbstractType& type = AbstractType::ZoneHandle(ParseType(type_resolution)); |
| + AbstractType& type = AbstractType::ZoneHandle(ParseType(finalization)); |
| types.Add(&type); |
| + // Only keep the error for the first malformed type argument. |
| + if (malformed_error->IsNull() && type.IsMalformed()) { |
| + *malformed_error = type.malformed_error(); |
| + } |
| } while (CurrentToken() == Token::kCOMMA); |
| Token::Kind token = CurrentToken(); |
| if ((token == Token::kGT) || (token == Token::kSHR)) { |
| @@ -2967,7 +2978,7 @@ |
| } else { |
| ErrorMsg("right angle bracket expected"); |
| } |
| - if (type_resolution != kIgnore) { |
| + if (finalization != ClassFinalizer::kIgnore) { |
| return NewTypeArguments(types); |
| } |
| } |
| @@ -2985,7 +2996,8 @@ |
| do { |
| ConsumeToken(); |
| intptr_t supertype_pos = token_index_; |
| - AbstractType& interface = AbstractType::ZoneHandle(ParseType(kCanResolve)); |
| + AbstractType& interface = AbstractType::ZoneHandle( |
| + ParseType(ClassFinalizer::kTryResolve)); |
| interface_name = interface.Name(); |
| for (int i = 0; i < interfaces.length(); i++) { |
| String& other_name = String::Handle(interfaces[i]->Name()); |
| @@ -3049,8 +3061,8 @@ |
| const bool is_final = (CurrentToken() == Token::kFINAL); |
| const bool is_static = true; |
| const AbstractType& type = AbstractType::ZoneHandle(ParseFinalVarOrType( |
| - FLAG_enable_type_checks ? kCanResolve : kIgnore)); |
| - |
| + FLAG_enable_type_checks ? ClassFinalizer::kTryResolve : |
| + ClassFinalizer::kIgnore)); |
| while (true) { |
| const intptr_t name_pos = token_index_; |
| String& var_name = *ExpectIdentifier("variable name expected"); |
| @@ -3113,7 +3125,7 @@ |
| // Parse optional type. |
| if ((CurrentToken() == Token::kIDENT) && |
| (LookaheadToken(1) != Token::kLPAREN)) { |
| - result_type = ParseType(kCanResolve); |
| + result_type = ParseType(ClassFinalizer::kTryResolve); |
| } |
| } |
| const intptr_t name_pos = token_index_; |
| @@ -3180,7 +3192,7 @@ |
| ConsumeToken(); |
| result_type = Type::VoidType(); |
| } else { |
| - result_type = ParseType(kCanResolve); |
| + result_type = ParseType(ClassFinalizer::kTryResolve); |
| } |
| is_getter = (CurrentToken() == Token::kGET); |
| if (CurrentToken() == Token::kGET || CurrentToken() == Token::kSET) { |
| @@ -3707,8 +3719,10 @@ |
| // Parses ('var' | 'final' [type] | type). |
| // The presence of 'final' must be detected and remembered before the call. |
| -// If a type is parsed, it is resolved (or not) according to type_resolution. |
| -RawAbstractType* Parser::ParseFinalVarOrType(TypeResolution type_resolution) { |
| +// If a type is parsed, it may be resolved and finalized according to the given |
| +// type finalization mode. |
| +RawAbstractType* Parser::ParseFinalVarOrType( |
| + ClassFinalizer::TypeFinalization finalization) { |
| TRACE_PARSER("ParseFinalVarOrType"); |
| if (CurrentToken() == Token::kVAR) { |
| ConsumeToken(); |
| @@ -3737,7 +3751,7 @@ |
| return Type::DynamicType(); |
| } |
| } |
| - return ParseType(type_resolution); |
| + return ParseType(finalization); |
| } |
| @@ -3748,7 +3762,8 @@ |
| TRACE_PARSER("ParseVariableDeclarationList"); |
| bool is_final = (CurrentToken() == Token::kFINAL); |
| const AbstractType& type = AbstractType::ZoneHandle(ParseFinalVarOrType( |
| - FLAG_enable_type_checks ? kMustResolve : kIgnore)); |
| + FLAG_enable_type_checks ? ClassFinalizer::kFinalize : |
| + ClassFinalizer::kIgnore)); |
| if (!IsIdentifier()) { |
| ErrorMsg("identifier expected"); |
| } |
| @@ -3784,7 +3799,7 @@ |
| result_type = Type::VoidType(); |
| } else if ((CurrentToken() == Token::kIDENT) && |
| (LookaheadToken(1) != Token::kLPAREN)) { |
| - result_type = ParseType(kMustResolve); |
| + result_type = ParseType(ClassFinalizer::kFinalize); |
| } |
| const intptr_t ident_pos = token_index_; |
| if (IsIdentifier()) { |
| @@ -3885,8 +3900,8 @@ |
| // Since the signature type is cached by the signature class, it may have |
| // been finalized already. |
| if (!signature_type.IsFinalized()) { |
| - signature_type ^= |
| - ClassFinalizer::FinalizeType(signature_class, signature_type); |
| + signature_type ^= ClassFinalizer::FinalizeType( |
| + signature_class, signature_type, ClassFinalizer::kFinalize); |
| // The call to ClassFinalizer::FinalizeType may have |
| // extended the vector of type arguments. |
| ASSERT(signature_type_arguments.IsNull() || |
| @@ -4431,7 +4446,8 @@ |
| } else { |
| // The case without a type is handled above, so require a type here. |
| const AbstractType& type = AbstractType::ZoneHandle(ParseFinalVarOrType( |
| - FLAG_enable_type_checks ? kMustResolve : kIgnore)); |
| + FLAG_enable_type_checks ? ClassFinalizer::kFinalize : |
| + ClassFinalizer::kIgnore)); |
| loop_var_pos = token_index_; |
| loop_var_name = ExpectIdentifier("variable name expected"); |
| loop_var = new LocalVariable(loop_var_pos, *loop_var_name, type); |
| @@ -4690,7 +4706,7 @@ |
| // The type of the catch parameter must always be resolved, even in unchecked |
| // mode. |
| catch_param->type = &AbstractType::ZoneHandle( |
| - ParseFinalVarOrType(kMustResolve)); |
| + ParseFinalVarOrType(ClassFinalizer::kFinalizeWellFormed)); |
| catch_param->token_index = token_index_; |
| catch_param->var = ExpectIdentifier("identifier expected"); |
| } |
| @@ -5222,7 +5238,6 @@ |
| } |
| -// Static |
| RawError* Parser::FormatError(const Script& script, |
| intptr_t token_index, |
| const char* message_header, |
| @@ -5238,7 +5253,6 @@ |
| } |
| -// Static. |
| void Parser::FormatMessage(const Script& script, |
| intptr_t token_index, |
| const char* message_header, |
| @@ -5462,13 +5476,34 @@ |
| } |
| const intptr_t type_pos = token_index_; |
| const AbstractType& type = |
| - AbstractType::ZoneHandle(ParseType(kMustResolve)); |
| + AbstractType::ZoneHandle(ParseType(ClassFinalizer::kFinalize)); |
| if (!type.IsInstantiated() && |
| (current_block_->scope->function_level() > 0)) { |
| // Make sure that the instantiator is captured. |
| CaptureReceiver(); |
| } |
| right_operand = new TypeNode(type_pos, type); |
| + if (type.IsMalformed()) { |
|
srdjan
2012/02/29 00:15:54
Could you factor this code out please.
regis
2012/02/29 02:10:01
Done.
|
| + // Throw a new TypeError. |
| + ArgumentListNode* arguments = new ArgumentListNode(op_pos); |
| + // Location argument. |
| + arguments->Add(new LiteralNode( |
| + type_pos, Integer::ZoneHandle(Integer::New(type_pos)))); |
| + // Src value argument. |
| + arguments->Add(new LiteralNode(type_pos, Instance::ZoneHandle())); |
| + // Dst type name argument. |
| + arguments->Add(new LiteralNode(type_pos, String::ZoneHandle( |
| + String::NewSymbol("malformed type")))); |
| + // Dst type name argument. |
| + arguments->Add(new LiteralNode(type_pos, String::ZoneHandle( |
| + String::NewSymbol("")))); |
| + // Malformed type error. |
| + const Error& error = Error::Handle(type.malformed_error()); |
| + arguments->Add(new LiteralNode(type_pos, String::ZoneHandle( |
| + String::NewSymbol(error.ToErrorCString())))); |
| + return MakeStaticCall(kTypeErrorName, kThrowNewName, arguments); |
| + break; |
| + } |
| } |
| if (Token::IsRelationalOperator(op_kind) |
| || Token::IsInstanceofOperator(op_kind) |
| @@ -6250,16 +6285,16 @@ |
| // Resolve the given type and its type arguments from the given scope class |
| -// according to the given type_resolution. |
| +// according to the given type finalization mode. |
| // If the given scope class is null, use the current library, but do not try to |
| // resolve type parameters. |
| // Not all involved type classes may get resolved yet, but at least the type |
| // parameters of the given class will get resolved, thereby relieving the class |
| // finalizer from resolving type parameters out of context. |
| void Parser::ResolveTypeFromClass(const Class& scope_class, |
| - TypeResolution type_resolution, |
| + ClassFinalizer::TypeFinalization finalization, |
| AbstractType* type) { |
| - ASSERT((type_resolution == kCanResolve) || (type_resolution == kMustResolve)); |
| + ASSERT(finalization >= ClassFinalizer::kTryResolve); |
| ASSERT(type != NULL); |
| if (type->IsResolved()) { |
| return; |
| @@ -6297,16 +6332,19 @@ |
| // Local lookup in library prefix scope. |
| resolved_type_class = lib_prefix.LookupLocalClass(unresolved_class_name); |
| } |
| + // At this point, we can only have a parameterized_type. |
| + Type& parameterized_type = Type::Handle(); |
| + parameterized_type ^= type->raw(); |
| if (!resolved_type_class.IsNull()) { |
| Object& type_class = Object::Handle(resolved_type_class.raw()); |
| - ASSERT(type->IsType()); |
| // Replace unresolved class with resolved type class. |
| - Type& parameterized_type = Type::Handle(); |
| - parameterized_type ^= type->raw(); |
| parameterized_type.set_type_class(type_class); |
| - } else if (type_resolution == kMustResolve) { |
| - ErrorMsg(type->token_index(), "type '%s' is not loaded", |
| - String::Handle(type->Name()).ToCString()); |
| + } else if (finalization >= ClassFinalizer::kFinalize) { |
| + // The type is malformed. |
| + ClassFinalizer::FinalizeMalformedType( |
| + current_class(), parameterized_type, finalization, |
| + "type '%s' is not loaded", |
| + String::Handle(parameterized_type.Name()).ToCString()); |
| } |
| } |
| // Resolve type arguments, if any. |
| @@ -6316,9 +6354,7 @@ |
| const intptr_t num_arguments = arguments.Length(); |
| for (intptr_t i = 0; i < num_arguments; i++) { |
| AbstractType& type_argument = AbstractType::Handle(arguments.TypeAt(i)); |
| - ResolveTypeFromClass(scope_class, |
| - type_resolution, |
| - &type_argument); |
| + ResolveTypeFromClass(scope_class, finalization, &type_argument); |
| arguments.SetTypeAt(i, type_argument); |
| } |
| } |
| @@ -6754,15 +6790,16 @@ |
| } |
| -// Parses type = [ident "."] ident ["<" type { "," type } ">"] and resolve it |
| -// according to the given type_resolution. |
| -RawAbstractType* Parser::ParseType(TypeResolution type_resolution) { |
| +// Parses type = [ident "."] ident ["<" type { "," type } ">"], then resolve and |
| +// finalize it according to the given type finalization mode. |
| +RawAbstractType* Parser::ParseType( |
| + ClassFinalizer::TypeFinalization finalization) { |
| TRACE_PARSER("ParseType"); |
| if (CurrentToken() != Token::kIDENT) { |
| ErrorMsg("type name expected"); |
| } |
| QualIdent type_name; |
| - if (type_resolution == kIgnore) { |
| + if (finalization == ClassFinalizer::kIgnore) { |
| SkipQualIdent(); |
| } else { |
| ParseQualIdent(&type_name); |
| @@ -6775,8 +6812,8 @@ |
| } |
| } |
| Object& type_class = Object::Handle(); |
| - // Leave type_class as null if type_resolution equals kIgnore. |
| - if (type_resolution != kIgnore) { |
| + // Leave type_class as null if type finalization mode is kIgnore. |
| + if (finalization != ClassFinalizer::kIgnore) { |
| LibraryPrefix& lib_prefix = LibraryPrefix::Handle(); |
| if (type_name.lib_prefix != NULL) { |
| lib_prefix = type_name.lib_prefix->raw(); |
| @@ -6785,18 +6822,27 @@ |
| *type_name.ident, |
| type_name.ident_pos); |
| } |
| + Error& malformed_error = Error::Handle(); |
| AbstractTypeArguments& type_arguments = |
| - AbstractTypeArguments::Handle(ParseTypeArguments(type_resolution)); |
| - if (type_resolution == kIgnore) { |
| + AbstractTypeArguments::Handle(ParseTypeArguments(&malformed_error, |
| + finalization)); |
| + if (finalization == ClassFinalizer::kIgnore) { |
| return Type::DynamicType(); |
| } |
| AbstractType& type = AbstractType::Handle( |
| Type::New(type_class, type_arguments, type_name.ident_pos)); |
| - if ((type_resolution == kCanResolve) || (type_resolution == kMustResolve)) { |
| + if (!malformed_error.IsNull()) { |
| + Type& parameterized_type = Type::Handle(); |
| + parameterized_type ^= type.raw(); |
| + parameterized_type.set_type_class(Class::Handle(Object::dynamic_class())); |
| + parameterized_type.set_arguments(AbstractTypeArguments::Handle()); |
| + parameterized_type.set_malformed_error(malformed_error); |
| + } |
| + if (finalization >= ClassFinalizer::kTryResolve) { |
| const Class& scope_class = Class::Handle(TypeParametersScopeClass()); |
| - ResolveTypeFromClass(scope_class, type_resolution, &type); |
| - if (type_resolution == kMustResolve) { |
| - type ^= ClassFinalizer::FinalizeType(current_class(), type); |
| + ResolveTypeFromClass(scope_class, finalization, &type); |
| + if (finalization >= ClassFinalizer::kFinalize) { |
| + type ^= ClassFinalizer::FinalizeType(current_class(), type, finalization); |
| } |
| } |
| return type.raw(); |
| @@ -7157,8 +7203,10 @@ |
| ConsumeToken(); |
| } |
| const intptr_t type_pos = token_index_; |
| - AbstractTypeArguments& type_arguments = |
| - AbstractTypeArguments::ZoneHandle(ParseTypeArguments(kMustResolve)); |
| + Error& malformed_error = Error::Handle(); |
| + AbstractTypeArguments& type_arguments = AbstractTypeArguments::ZoneHandle( |
| + ParseTypeArguments(&malformed_error, |
| + ClassFinalizer::kFinalizeWellFormed)); |
| AstNode* primary = NULL; |
| if ((CurrentToken() == Token::kLBRACK) || |
| (CurrentToken() == Token::kINDEX)) { |
| @@ -7199,7 +7247,8 @@ |
| } |
| intptr_t type_pos = token_index_; |
| - const AbstractType& type = AbstractType::Handle(ParseType(kMustResolve)); |
| + const AbstractType& type = AbstractType::Handle( |
| + ParseType(ClassFinalizer::kFinalizeWellFormed)); |
| if (type.IsTypeParameter()) { |
| ErrorMsg(type_pos, |
| "type parameter '%s' cannot be instantiated", |
| @@ -7345,7 +7394,8 @@ |
| // TODO(regis): Temporary type should be allocated in new gen heap. |
| Type& temp_type = Type::Handle( |
| Type::New(constructor_class, temp_type_arguments, type.token_index())); |
| - temp_type ^= ClassFinalizer::FinalizeType(current_class(), temp_type); |
| + temp_type ^= ClassFinalizer::FinalizeType( |
| + current_class(), temp_type, ClassFinalizer::kFinalize); |
| // The type argument vector may have been expanded with the type arguments |
| // of the super type when finalizing the temporary type. |
| type_arguments = temp_type.arguments(); |