| Index: runtime/vm/parser.cc
|
| ===================================================================
|
| --- runtime/vm/parser.cc (revision 4731)
|
| +++ 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::FinalizationKind 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::FinalizationKind 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,
|
| @@ -5438,6 +5452,28 @@
|
| }
|
|
|
|
|
| +AstNode* Parser::ThrowTypeError(intptr_t type_pos, const AbstractType& type) {
|
| + ASSERT(type.IsMalformed());
|
| + ArgumentListNode* arguments = new ArgumentListNode(type_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);
|
| +}
|
| +
|
| +
|
| AstNode* Parser::ParseBinaryExpr(int min_preced) {
|
| TRACE_PARSER("ParseBinaryExpr");
|
| ASSERT(min_preced >= 4);
|
| @@ -5462,13 +5498,16 @@
|
| }
|
| 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()) {
|
| + return ThrowTypeError(type_pos, type);
|
| + }
|
| }
|
| if (Token::IsRelationalOperator(op_kind)
|
| || Token::IsInstanceofOperator(op_kind)
|
| @@ -6250,16 +6289,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::FinalizationKind finalization,
|
| AbstractType* type) {
|
| - ASSERT((type_resolution == kCanResolve) || (type_resolution == kMustResolve));
|
| + ASSERT(finalization >= ClassFinalizer::kTryResolve);
|
| ASSERT(type != NULL);
|
| if (type->IsResolved()) {
|
| return;
|
| @@ -6297,16 +6336,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 +6358,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 +6794,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::FinalizationKind 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 +6816,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 +6826,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 +7207,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 +7251,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 +7398,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();
|
|
|