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

Unified Diff: runtime/vm/parser.cc

Issue 19030004: Stop resolving classes prematurely in the vm (issue 11023). (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 5 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/object.cc ('k') | tests/language/language.status » ('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 24964)
+++ runtime/vm/parser.cc (working copy)
@@ -1281,7 +1281,7 @@
// 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_ ? ClassFinalizer::kTryResolve :
+ ParseType(is_top_level_ ? ClassFinalizer::kResolveTypeParameters :
ClassFinalizer::kCanonicalize));
} else {
parameter.type = &Type::ZoneHandle(Type::DynamicType());
@@ -2800,20 +2800,17 @@
ConsumeToken();
const intptr_t type_pos = TokenPos();
const AbstractType& type = AbstractType::Handle(
- ParseType(ClassFinalizer::kTryResolve));
- if (!type.IsMalformed() &&
- (type.IsTypeParameter() || type.IsDynamicType())) {
+ ParseType(ClassFinalizer::kResolveTypeParameters));
+ if (!type.IsMalformed() && type.IsTypeParameter()) {
// Replace the type with a malformed type and compile a throw when called.
redirection_type = ClassFinalizer::NewFinalizedMalformedType(
Error::Handle(), // No previous error.
current_class(),
type_pos,
- ClassFinalizer::kTryResolve, // No compile-time error.
- "factory '%s' may not redirect to %s'%s'",
+ ClassFinalizer::kResolveTypeParameters, // No compile-time error.
+ "factory '%s' may not redirect to type parameter '%s'",
method->name->ToCString(),
- type.IsTypeParameter() ? "type parameter " : "",
- type.IsTypeParameter() ?
- String::Handle(type.UserVisibleName()).ToCString() : "dynamic");
+ String::Handle(type.UserVisibleName()).ToCString());
} else {
redirection_type ^= type.raw();
}
@@ -3022,11 +3019,15 @@
// invocation/compilation.
// For instance fields, the expression is parsed when a constructor
// is compiled.
- // For static fields with very simple initializer expressions
+ // For static const fields with very simple initializer expressions
// (e.g. a literal number or string) we optimize away the
// kConstImplicitGetter and initialize the field here.
+ // We also do it for static final non-const fields, but only in production
+ // mode.
- if (field->has_static && (field->has_final || field->has_const) &&
+ if (field->has_static &&
+ (field->has_const ||
+ (!FLAG_enable_type_checks && field->has_final)) &&
(LookaheadToken(1) == Token::kSEMICOLON)) {
has_simple_literal = IsSimpleLiteral(*field->type, &init_value);
}
@@ -3215,7 +3216,7 @@
// because getters and setters could be closurized at some time (not
// supported yet).
member.type = &AbstractType::ZoneHandle(
- ParseType(ClassFinalizer::kTryResolve));
+ ParseType(ClassFinalizer::kResolveTypeParameters));
}
}
}
@@ -3464,18 +3465,13 @@
if (CurrentToken() == Token::kEXTENDS) {
ConsumeToken();
const intptr_t type_pos = TokenPos();
- super_type = ParseType(ClassFinalizer::kTryResolve);
+ super_type = ParseType(ClassFinalizer::kResolveTypeParameters);
if (super_type.IsTypeParameter()) {
ErrorMsg(type_pos,
"class '%s' may not extend type parameter '%s'",
class_name.ToCString(),
String::Handle(super_type.UserVisibleName()).ToCString());
}
- if (super_type.IsDynamicType()) {
- ErrorMsg(type_pos,
- "class '%s' may not extend 'dynamic'",
- class_name.ToCString());
- }
if (CurrentToken() == Token::kWITH) {
super_type = ParseMixins(super_type);
}
@@ -3671,7 +3667,7 @@
const intptr_t type_pos = TokenPos();
AbstractType& type =
- AbstractType::Handle(ParseType(ClassFinalizer::kTryResolve));
+ AbstractType::Handle(ParseType(ClassFinalizer::kResolveTypeParameters));
if (type.IsTypeParameter()) {
ErrorMsg(type_pos,
"class '%s' may not extend type parameter '%s'",
@@ -3787,7 +3783,7 @@
// result type.
if (!result_type.IsNull()) {
ResolveTypeFromClass(function_type_alias,
- ClassFinalizer::kTryResolve,
+ ClassFinalizer::kResolveTypeParameters,
&result_type);
}
// Parse the formal parameters of the function type.
@@ -3984,7 +3980,7 @@
type_parameter ^= type_parameters.TypeAt(i);
type_parameter_bound = type_parameter.bound();
ResolveTypeFromClass(cls,
- ClassFinalizer::kTryResolve,
+ ClassFinalizer::kResolveTypeParameters,
&type_parameter_bound);
type_parameter.set_bound(type_parameter_bound);
}
@@ -4046,15 +4042,12 @@
do {
ConsumeToken();
intptr_t interface_pos = TokenPos();
- interface = ParseType(ClassFinalizer::kTryResolve);
+ interface = ParseType(ClassFinalizer::kResolveTypeParameters);
if (interface.IsTypeParameter()) {
ErrorMsg(interface_pos,
"type parameter '%s' may not be used in interface list",
String::Handle(interface.UserVisibleName()).ToCString());
}
- if (interface.IsDynamicType()) {
- ErrorMsg(interface_pos, "'dynamic' may not be used in interface list");
- }
all_interfaces.Add(interface);
} while (CurrentToken() == Token::kCOMMA);
cls_interfaces = Array::MakeArray(all_interfaces);
@@ -4080,7 +4073,7 @@
do {
ConsumeToken();
const intptr_t mixin_pos = TokenPos();
- mixin_type = ParseType(ClassFinalizer::kTryResolve);
+ mixin_type = ParseType(ClassFinalizer::kResolveTypeParameters);
if (mixin_type.IsTypeParameter()) {
ErrorMsg(mixin_pos,
"mixin type '%s' may not be a type parameter",
@@ -4113,7 +4106,7 @@
// to get the copy is to rewind the parser, parse the mixin type
// again and steal its type arguments.
SetPosition(mixin_pos);
- mixin_type = ParseType(ClassFinalizer::kTryResolve);
+ mixin_type = ParseType(ClassFinalizer::kResolveTypeParameters);
mixin_type_arguments = mixin_type.arguments();
mixin_application_type = Type::New(mixin_application,
@@ -4136,7 +4129,7 @@
const bool is_static = true;
const AbstractType& type =
AbstractType::ZoneHandle(ParseConstFinalVarOrType(
- FLAG_enable_type_checks ? ClassFinalizer::kTryResolve :
+ FLAG_enable_type_checks ? ClassFinalizer::kResolveTypeParameters :
ClassFinalizer::kIgnore));
Field& field = Field::Handle();
Function& getter = Function::Handle();
@@ -4175,7 +4168,8 @@
ConsumeToken();
Instance& field_value = Instance::Handle(Object::sentinel().raw());
bool has_simple_literal = false;
- if (is_final && (LookaheadToken(1) == Token::kSEMICOLON)) {
+ if ((is_const || (!FLAG_enable_type_checks && is_final)) &&
+ (LookaheadToken(1) == Token::kSEMICOLON)) {
has_simple_literal = IsSimpleLiteral(type, &field_value);
}
SkipExpr();
@@ -4234,7 +4228,7 @@
// Parse optional type.
if ((CurrentToken() == Token::kIDENT) &&
(LookaheadToken(1) != Token::kLPAREN)) {
- result_type = ParseType(ClassFinalizer::kTryResolve);
+ result_type = ParseType(ClassFinalizer::kResolveTypeParameters);
}
}
const intptr_t name_pos = TokenPos();
@@ -4328,7 +4322,7 @@
ConsumeToken();
result_type = Type::VoidType();
} else {
- result_type = ParseType(ClassFinalizer::kTryResolve);
+ result_type = ParseType(ClassFinalizer::kResolveTypeParameters);
}
is_getter = (CurrentToken() == Token::kGET);
if (CurrentToken() == Token::kGET || CurrentToken() == Token::kSET) {
@@ -5324,30 +5318,41 @@
bool Parser::IsSimpleLiteral(const AbstractType& type, Instance* value) {
- bool no_check = type.IsDynamicType();
- if ((CurrentToken() == Token::kINTEGER) &&
- (no_check || type.IsIntType() || type.IsNumberType())) {
+ // Assigning null never causes a type error.
+ if (CurrentToken() == Token::kNULL) {
+ *value = Instance::null();
+ return true;
+ }
+ // If the type of the const field is guaranteed to be instantiated once
+ // resolved at class finalization time, and if the type of the literal is one
+ // of int, double, String, or bool, then preset the field with the value and
+ // perform the type check (in checked mode only) at finalization time.
+ if (type.IsTypeParameter() ||
+ (type.arguments() != AbstractTypeArguments::null())) {
+ // Type parameters are always resolved eagerly by the parser and never
+ // resolved later by the class finalizer. Therefore, we know here that if
+ // 'type' is not a type parameter (an unresolved type will not get resolved
+ // to a type parameter later) and if 'type' has no type arguments, then it
+ // will be instantiated at class finalization time. Otherwise, we return
+ // false, since the type test would not be possible at finalization time for
+ // an uninstantiated type.
+ return false;
+ }
+ if (CurrentToken() == Token::kINTEGER) {
*value = CurrentIntegerLiteral();
return true;
- } else if ((CurrentToken() == Token::kDOUBLE) &&
- (no_check || type.IsDoubleType() || type.IsNumberType())) {
+ } else if (CurrentToken() == Token::kDOUBLE) {
*value = CurrentDoubleLiteral();
return true;
- } else if ((CurrentToken() == Token::kSTRING) &&
- (no_check || type.IsStringType())) {
+ } else if (CurrentToken() == Token::kSTRING) {
*value = CurrentLiteral()->raw();
return true;
- } else if ((CurrentToken() == Token::kTRUE) &&
- (no_check || type.IsBoolType())) {
+ } else if (CurrentToken() == Token::kTRUE) {
*value = Bool::True().raw();
return true;
- } else if ((CurrentToken() == Token::kFALSE) &&
- (no_check || type.IsBoolType())) {
+ } else if (CurrentToken() == Token::kFALSE) {
*value = Bool::False().raw();
return true;
- } else if (CurrentToken() == Token::kNULL) {
- *value = Instance::null();
- return true;
}
return false;
}
@@ -8002,7 +8007,7 @@
void Parser::ResolveTypeFromClass(const Class& scope_class,
ClassFinalizer::FinalizationKind finalization,
AbstractType* type) {
- ASSERT(finalization >= ClassFinalizer::kTryResolve);
+ ASSERT(finalization >= ClassFinalizer::kResolveTypeParameters);
ASSERT(type != NULL);
if (type->IsResolved()) {
return;
@@ -8050,25 +8055,29 @@
return;
}
}
- // Resolve classname in the scope of the current library.
- Error& error = Error::Handle();
- // If we finalize a type expression, as opposed to a type annotation, we
- // tell the resolver (by passing NULL) to immediately report an ambiguous
- // type as a compile time error.
- resolved_type_class = ResolveClassInCurrentLibraryScope(
- unresolved_class.token_pos(),
- unresolved_class_name,
- finalization >= ClassFinalizer::kCanonicalizeExpression ?
- NULL : &error);
- if (!error.IsNull()) {
- *type = ClassFinalizer::NewFinalizedMalformedType(
- error,
- scope_class,
+ // The referenced class may not have been parsed yet. It would be wrong
+ // to resolve it too early to an imported class of the same name.
+ if (finalization > ClassFinalizer::kResolveTypeParameters) {
+ // Resolve classname in the scope of the current library.
+ Error& error = Error::Handle();
+ // If we finalize a type expression, as opposed to a type annotation,
+ // we tell the resolver (by passing NULL) to immediately report an
+ // ambiguous type as a compile time error.
+ resolved_type_class = ResolveClassInCurrentLibraryScope(
unresolved_class.token_pos(),
- finalization,
- "cannot resolve class '%s'",
- unresolved_class_name.ToCString());
- return;
+ unresolved_class_name,
+ finalization >= ClassFinalizer::kCanonicalizeExpression ?
+ NULL : &error);
+ if (!error.IsNull()) {
+ *type = ClassFinalizer::NewFinalizedMalformedType(
+ error,
+ scope_class,
+ unresolved_class.token_pos(),
+ finalization,
+ "cannot resolve class '%s'",
+ unresolved_class_name.ToCString());
+ return;
+ }
}
} else {
LibraryPrefix& lib_prefix =
@@ -8530,8 +8539,8 @@
if (first_lib_url.raw() == lib.url()) {
ambiguous_ref_error = FormatErrorMsg(
script_, ident_pos, "Error",
- "ambiguous reference: "
- "'%s' as library '%s' is imported multiple times",
+ "ambiguous reference to '%s', "
+ "as library '%s' is imported multiple times",
name.ToCString(),
first_lib_url.ToCString());
} else {
@@ -8850,7 +8859,7 @@
parameterized_type.set_arguments(Object::null_abstract_type_arguments());
parameterized_type.set_malformed_error(malformed_error);
}
- if (finalization >= ClassFinalizer::kTryResolve) {
+ if (finalization >= ClassFinalizer::kResolveTypeParameters) {
ResolveTypeFromClass(current_class(), finalization, &type);
if (finalization >= ClassFinalizer::kCanonicalize) {
type ^= ClassFinalizer::FinalizeType(current_class(), type, finalization);
@@ -8953,6 +8962,7 @@
AstNode* elem = element_list[i];
// Arguments have been evaluated to a literal value already.
ASSERT(elem->IsLiteralNode());
+ ASSERT(!is_top_level_); // We cannot check unresolved types.
if (FLAG_enable_type_checks &&
!element_type.IsDynamicType() &&
(!elem->AsLiteralNode()->literal().IsNull() &&
@@ -9149,6 +9159,7 @@
AstNode* arg = kv_pairs_list[i];
// Arguments have been evaluated to a literal value already.
ASSERT(arg->IsLiteralNode());
+ ASSERT(!is_top_level_); // We cannot check unresolved types.
if (FLAG_enable_type_checks &&
((i % 2) == 1) && // Check values only, not keys.
!value_type.IsDynamicType() &&
@@ -9305,7 +9316,7 @@
Error::Handle(), // No previous error.
current_class(),
type_pos,
- ClassFinalizer::kTryResolve, // No compile-time error.
+ ClassFinalizer::kResolveTypeParameters, // No compile-time error.
"%s'%s' cannot be instantiated",
type.IsTypeParameter() ? "type parameter " : "",
type.IsTypeParameter() ?
@@ -9371,7 +9382,7 @@
Error::Handle(), // No previous error.
current_class(),
call_pos,
- ClassFinalizer::kTryResolve, // No compile-time error.
+ ClassFinalizer::kResolveTypeParameters, // No compile-time error.
"class '%s' has no constructor or factory named '%s'",
String::Handle(type_class.Name()).ToCString(),
external_constructor_name.ToCString());
@@ -9482,6 +9493,7 @@
if (!type_bound.IsNull()) {
ASSERT(!type_bound.IsMalformed());
Error& malformed_error = Error::Handle();
+ ASSERT(!is_top_level_); // We cannot check unresolved types.
if (!const_instance.IsInstanceOf(type_bound,
TypeArguments::Handle(),
&malformed_error)) {
@@ -9489,7 +9501,7 @@
malformed_error,
current_class(),
new_pos,
- ClassFinalizer::kTryResolve, // No compile-time error.
+ ClassFinalizer::kResolveTypeParameters, // No compile-time error.
"const factory result is not an instance of '%s'",
String::Handle(type_bound.UserVisibleName()).ToCString());
new_object = ThrowTypeError(new_pos, type_bound);
« no previous file with comments | « runtime/vm/object.cc ('k') | tests/language/language.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698