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

Unified Diff: runtime/vm/parser.cc

Issue 11369219: Check result type of redirecting factory in checked mode. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 1 month 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
Index: runtime/vm/parser.cc
===================================================================
--- runtime/vm/parser.cc (revision 14858)
+++ runtime/vm/parser.cc (working copy)
@@ -9118,7 +9118,7 @@
ErrorMsg("type name expected");
}
intptr_t type_pos = TokenPos();
- AbstractType& type = AbstractType::Handle(
+ AbstractType& type = AbstractType::ZoneHandle(
ParseType(ClassFinalizer::kCanonicalizeForCreation));
// In case the type is malformed, throw a dynamic type error after finishing
// parsing the instance creation expression.
@@ -9250,6 +9250,10 @@
ASSERT(!constructor_class.is_interface());
}
+ // An additional type check of the result of a redirecting factory may be
+ // required.
+ bool check_result_type = false;
+
// Make sure that an appropriate constructor exists.
const String& constructor_name =
BuildConstructorName(constructor_class_name, named_constructor);
@@ -9276,18 +9280,26 @@
}
return ThrowNoSuchMethodError(call_pos, external_constructor_name);
} else if (constructor.IsRedirectingFactory()) {
- type = constructor.RedirectionType();
- if (type.IsMalformed()) {
+ Type& redirect_type = Type::Handle(constructor.RedirectionType());
+ if (!redirect_type.IsMalformed() && !redirect_type.IsInstantiated()) {
+ // The type arguments of the redirection type are instantiated from the
+ // type arguments of the parsed type of the 'new' or 'const' expression.
+ redirect_type ^= redirect_type.InstantiateFrom(type_arguments);
+ }
+ if (redirect_type.IsMalformed()) {
if (is_const) {
- const Error& error = Error::Handle(type.malformed_error());
+ const Error& error = Error::Handle(redirect_type.malformed_error());
ErrorMsg(error);
}
- return ThrowTypeError(type.token_pos(), type);
+ return ThrowTypeError(redirect_type.token_pos(), redirect_type);
}
+ check_result_type =
+ FLAG_enable_type_checks && !redirect_type.IsSubtypeOf(type, NULL);
+ type = redirect_type.raw();
+ type_class = type.type_class();
+ type_arguments = type.arguments();
constructor = constructor.RedirectionTarget();
ASSERT(!constructor.IsNull());
- type_class = type.type_class();
- type_arguments = type.arguments();
constructor_class = constructor.Owner();
ASSERT(type_class.raw() == constructor_class.raw());
}
@@ -9300,8 +9312,7 @@
// It is ok to call a factory method of an abstract class, but it is
// a dynamic error to instantiate an abstract class.
ASSERT(!constructor.IsNull());
- if (constructor_class.is_abstract() &&
- !constructor.IsFactory()) {
+ if (constructor_class.is_abstract() && !constructor.IsFactory()) {
ArgumentListNode* arguments = new ArgumentListNode(type_pos);
arguments->Add(new LiteralNode(
TokenPos(), Integer::ZoneHandle(Integer::New(type_pos))));
@@ -9399,6 +9410,23 @@
const Instance& const_instance = Instance::Cast(constructor_result);
new_object = new LiteralNode(new_pos,
Instance::ZoneHandle(const_instance.raw()));
+ if (check_result_type) {
+ ASSERT(!type.IsMalformed());
+ Error& malformed_error = Error::Handle();
+ if (!const_instance.IsInstanceOf(type,
+ TypeArguments::Handle(),
+ &malformed_error)) {
+ type = ClassFinalizer::NewFinalizedMalformedType(
+ malformed_error,
+ current_class(),
+ new_pos,
+ ClassFinalizer::kTryResolve, // No compile-time error.
+ "const factory result is not an instance of '%s'",
+ String::Handle(type.UserVisibleName()).ToCString());
+ new_object = ThrowTypeError(new_pos, type);
+ }
+ check_result_type = false;
+ }
}
} else {
CheckFunctionIsCallable(new_pos, constructor);
@@ -9414,6 +9442,10 @@
new_object = CreateConstructorCallNode(
new_pos, type_arguments, constructor, arguments);
}
+ if (check_result_type) {
+ const String& dst_name = String::ZoneHandle(Symbols::New("factory result"));
hausner 2012/11/13 19:06:37 Would it make sense to add this string to the symb
regis 2012/11/13 19:29:26 I'll do it in a following cl. Thanks.
+ new_object = new AssignableNode(new_pos, new_object, type, dst_name);
+ }
return new_object;
}

Powered by Google App Engine
This is Rietveld 408576698