Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(256)

Unified Diff: runtime/vm/parser.cc

Issue 9515011: Add support for malformed types and postpone some related errors from compile (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/parser.h ('k') | runtime/vm/raw_object.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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();
« no previous file with comments | « runtime/vm/parser.h ('k') | runtime/vm/raw_object.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698