mirror of
https://github.com/dart-lang/sdk
synced 2024-11-05 18:22:09 +00:00
Implement latest rules prohibiting some self referencing typedefs.
Update tests. Review URL: https://chromiumcodereview.appspot.com//10377095 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@7524 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
dec5e465f9
commit
5d9dab620c
9 changed files with 169 additions and 59 deletions
|
@ -563,9 +563,8 @@ void ClassFinalizer::FinalizeTypeArguments(
|
|||
FinalizationKind finalization) {
|
||||
ASSERT(arguments.Length() >= cls.NumTypeArguments());
|
||||
if (!cls.is_finalized()) {
|
||||
const GrowableObjectArray& visited =
|
||||
GrowableObjectArray::Handle(GrowableObjectArray::New());
|
||||
ResolveInterfaces(cls, visited);
|
||||
GrowableArray<intptr_t> visited_interfaces;
|
||||
ResolveInterfaces(cls, &visited_interfaces);
|
||||
FinalizeTypeParameters(cls);
|
||||
}
|
||||
Type& super_type = Type::Handle(cls.super_type());
|
||||
|
@ -669,9 +668,8 @@ RawAbstractType* ClassFinalizer::FinalizeType(const Class& cls,
|
|||
// parameters of the type class must be finalized.
|
||||
Class& type_class = Class::Handle(parameterized_type.type_class());
|
||||
if (!type_class.is_finalized()) {
|
||||
const GrowableObjectArray& visited =
|
||||
GrowableObjectArray::Handle(GrowableObjectArray::New());
|
||||
ResolveInterfaces(type_class, visited);
|
||||
GrowableArray<intptr_t> visited_interfaces;
|
||||
ResolveInterfaces(type_class, &visited_interfaces);
|
||||
FinalizeTypeParameters(type_class);
|
||||
}
|
||||
|
||||
|
@ -752,10 +750,8 @@ RawAbstractType* ClassFinalizer::FinalizeType(const Class& cls,
|
|||
}
|
||||
}
|
||||
|
||||
// Illegally self referencing types may get finalized indirectly.
|
||||
if (parameterized_type.IsFinalized()) {
|
||||
ASSERT(parameterized_type.IsMalformed());
|
||||
} else {
|
||||
// Self referencing types may get finalized indirectly.
|
||||
if (!parameterized_type.IsFinalized()) {
|
||||
// Mark the type as finalized.
|
||||
if (parameterized_type.IsInstantiated()) {
|
||||
parameterized_type.set_is_finalized_instantiated();
|
||||
|
@ -791,18 +787,30 @@ RawAbstractType* ClassFinalizer::FinalizeType(const Class& cls,
|
|||
}
|
||||
}
|
||||
|
||||
// If the type class is a signature class, we also finalize its signature
|
||||
// type, thereby finalizing the result type and parameter types of its
|
||||
// signature function.
|
||||
// If the type class is a signature class, we are currently finalizing a
|
||||
// signature type, i.e. finalizing the result type and parameter types of the
|
||||
// signature function of this signature type.
|
||||
// We do this after marking this type as finalized in order to allow a
|
||||
// function type to refer to itself via its parameter types and result type.
|
||||
if (type_class.IsSignatureClass()) {
|
||||
// Signature classes are finalized upon creation.
|
||||
ASSERT(type_class.is_finalized());
|
||||
// Resolve and finalize the result and parameter types of the signature
|
||||
// function of this signature class.
|
||||
ResolveAndFinalizeSignature(
|
||||
type_class, Function::Handle(type_class.signature_function()));
|
||||
// Signature classes are finalized upon creation, except function type
|
||||
// aliases.
|
||||
if (type_class.IsCanonicalSignatureClass()) {
|
||||
ASSERT(type_class.is_finalized());
|
||||
// Resolve and finalize the result and parameter types of the signature
|
||||
// function of this signature class.
|
||||
ASSERT(type_class.SignatureType() == type.raw());
|
||||
ResolveAndFinalizeSignature(
|
||||
type_class, Function::Handle(type_class.signature_function()));
|
||||
} else {
|
||||
// This type is a function type alias. Its class may need to be finalized
|
||||
// and checked for illegal self reference.
|
||||
FinalizeClass(type_class, false);
|
||||
// Finalizing the signature function here (as in the canonical case above)
|
||||
// would not mark the canonical signature type as finalized.
|
||||
const Type& signature_type = Type::Handle(type_class.SignatureType());
|
||||
FinalizeType(cls, signature_type, finalization);
|
||||
}
|
||||
}
|
||||
|
||||
return parameterized_type.Canonicalize();
|
||||
|
@ -1059,8 +1067,6 @@ void ClassFinalizer::FinalizeClass(const Class& cls, bool generating_snapshot) {
|
|||
if (FLAG_trace_class_finalization) {
|
||||
OS::Print("Finalize %s\n", cls.ToCString());
|
||||
}
|
||||
// Signature classes are finalized upon creation.
|
||||
ASSERT(!cls.IsSignatureClass());
|
||||
if (!IsSuperCycleFree(cls)) {
|
||||
const String& name = String::Handle(cls.Name());
|
||||
const Script& script = Script::Handle(cls.script());
|
||||
|
@ -1068,9 +1074,8 @@ void ClassFinalizer::FinalizeClass(const Class& cls, bool generating_snapshot) {
|
|||
"class '%s' has a cycle in its superclass relationship",
|
||||
name.ToCString());
|
||||
}
|
||||
const GrowableObjectArray& visited =
|
||||
GrowableObjectArray::Handle(GrowableObjectArray::New());
|
||||
ResolveInterfaces(cls, visited);
|
||||
GrowableArray<intptr_t> visited_interfaces;
|
||||
ResolveInterfaces(cls, &visited_interfaces);
|
||||
// Finalize super class.
|
||||
const Class& super_class = Class::Handle(cls.SuperClass());
|
||||
if (!super_class.IsNull()) {
|
||||
|
@ -1084,6 +1089,24 @@ void ClassFinalizer::FinalizeClass(const Class& cls, bool generating_snapshot) {
|
|||
super_type ^= FinalizeType(cls, super_type, kFinalizeWellFormed);
|
||||
cls.set_super_type(super_type);
|
||||
}
|
||||
// Signature classes are finalized upon creation, except function type
|
||||
// aliases.
|
||||
if (cls.IsSignatureClass()) {
|
||||
ASSERT(!cls.IsCanonicalSignatureClass());
|
||||
// Check for illegal self references.
|
||||
GrowableArray<intptr_t> visited_aliases;
|
||||
if (!IsAliasCycleFree(cls, &visited_aliases)) {
|
||||
const String& name = String::Handle(cls.Name());
|
||||
const Script& script = Script::Handle(cls.script());
|
||||
ReportError(script, cls.token_index(),
|
||||
"typedef '%s' illegally refers to itself",
|
||||
name.ToCString());
|
||||
}
|
||||
// TODO(regis): Also check this: "It is a compile-time error if any default
|
||||
// values are specified in the signature of a function type alias".
|
||||
cls.Finalize();
|
||||
return;
|
||||
}
|
||||
// Finalize factory class, if any.
|
||||
if (cls.is_interface()) {
|
||||
if (cls.HasFactoryClass()) {
|
||||
|
@ -1153,6 +1176,58 @@ bool ClassFinalizer::IsSuperCycleFree(const Class& cls) {
|
|||
}
|
||||
|
||||
|
||||
// Returns false if the function type alias illegally refers to itself.
|
||||
bool ClassFinalizer::IsAliasCycleFree(const Class& cls,
|
||||
GrowableArray<intptr_t>* visited) {
|
||||
ASSERT(cls.IsSignatureClass());
|
||||
ASSERT(!cls.IsCanonicalSignatureClass());
|
||||
ASSERT(!cls.is_finalized());
|
||||
ASSERT(visited != NULL);
|
||||
const intptr_t cls_index = cls.index();
|
||||
for (int i = 0; i < visited->length(); i++) {
|
||||
if ((*visited)[i] == cls_index) {
|
||||
// We have already visited alias 'cls'. We found a cycle.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Visit the result type and parameter types of this signature type.
|
||||
visited->Add(cls.index());
|
||||
const Function& function = Function::Handle(cls.signature_function());
|
||||
// Check class of result type.
|
||||
AbstractType& type = AbstractType::Handle(function.result_type());
|
||||
ResolveType(cls, type, kFinalize);
|
||||
if (type.IsType() && !type.IsMalformed()) {
|
||||
const Class& type_class = Class::Handle(type.type_class());
|
||||
if (!type_class.is_finalized() &&
|
||||
type_class.IsSignatureClass() &&
|
||||
!type_class.IsCanonicalSignatureClass()) {
|
||||
if (!IsAliasCycleFree(type_class, visited)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check classes of formal parameter types.
|
||||
const intptr_t num_parameters = function.NumberOfParameters();
|
||||
for (intptr_t i = 0; i < num_parameters; i++) {
|
||||
type = function.ParameterTypeAt(i);
|
||||
ResolveType(cls, type, kFinalize);
|
||||
if (type.IsType() && !type.IsMalformed()) {
|
||||
const Class& type_class = Class::Handle(type.type_class());
|
||||
if (!type_class.is_finalized() &&
|
||||
type_class.IsSignatureClass() &&
|
||||
!type_class.IsCanonicalSignatureClass()) {
|
||||
if (!IsAliasCycleFree(type_class, visited)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
visited->RemoveLast();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ClassFinalizer::AddInterfaceIfUnique(
|
||||
const GrowableObjectArray& interface_list,
|
||||
const AbstractType& interface,
|
||||
|
@ -1191,12 +1266,11 @@ bool ClassFinalizer::AddInterfaceIfUnique(
|
|||
// graph. If we visit an interface a second time on a given path,
|
||||
// we found a loop.
|
||||
void ClassFinalizer::ResolveInterfaces(const Class& cls,
|
||||
const GrowableObjectArray& visited) {
|
||||
ASSERT(!visited.IsNull());
|
||||
Class& visited_cls = Class::Handle();
|
||||
for (int i = 0; i < visited.Length(); i++) {
|
||||
visited_cls ^= visited.At(i);
|
||||
if (visited_cls.raw() == cls.raw()) {
|
||||
GrowableArray<intptr_t>* visited) {
|
||||
ASSERT(visited != NULL);
|
||||
const intptr_t cls_index = cls.index();
|
||||
for (int i = 0; i < visited->length(); i++) {
|
||||
if ((*visited)[i] == cls_index) {
|
||||
// We have already visited interface class 'cls'. We found a cycle.
|
||||
const String& interface_name = String::Handle(cls.Name());
|
||||
const Script& script = Script::Handle(cls.script());
|
||||
|
@ -1219,7 +1293,7 @@ void ClassFinalizer::ResolveInterfaces(const Class& cls,
|
|||
(cls.library() == Library::CoreImplLibrary());
|
||||
|
||||
// Resolve and check the interfaces of cls.
|
||||
visited.Add(cls);
|
||||
visited->Add(cls_index);
|
||||
AbstractType& interface = AbstractType::Handle();
|
||||
Class& interface_class = Class::Handle();
|
||||
for (intptr_t i = 0; i < super_interfaces.Length(); i++) {
|
||||
|
@ -1260,7 +1334,7 @@ void ClassFinalizer::ResolveInterfaces(const Class& cls,
|
|||
// Now resolve the super interfaces.
|
||||
ResolveInterfaces(interface_class, visited);
|
||||
}
|
||||
visited.RemoveLast();
|
||||
visited->RemoveLast();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -90,13 +90,15 @@ class ClassFinalizer : public AllStatic {
|
|||
static bool FinalizePendingClasses(bool generating_snapshot);
|
||||
static void FinalizeClass(const Class& cls, bool generating_snapshot);
|
||||
static bool IsSuperCycleFree(const Class& cls);
|
||||
static bool IsAliasCycleFree(const Class& cls,
|
||||
GrowableArray<intptr_t>* visited);
|
||||
static void CheckForLegalConstClass(const Class& cls);
|
||||
static RawClass* ResolveClass(const Class& cls,
|
||||
const UnresolvedClass& unresolved_class);
|
||||
static void ResolveSuperType(const Class& cls);
|
||||
static void ResolveFactoryClass(const Class& cls);
|
||||
static void ResolveInterfaces(const Class& cls,
|
||||
const GrowableObjectArray& visited);
|
||||
GrowableArray<intptr_t>* visited);
|
||||
static void FinalizeTypeParameters(const Class& cls);
|
||||
static void FinalizeTypeArguments(const Class& cls,
|
||||
const AbstractTypeArguments& arguments,
|
||||
|
|
|
@ -606,7 +606,7 @@ RawError* Object::Init(Isolate* isolate) {
|
|||
object_store->set_object_class(cls);
|
||||
cls.set_name(String::Handle(String::NewSymbol("Object")));
|
||||
cls.set_script(script);
|
||||
cls.set_class_state(RawClass::kPreFinalized);
|
||||
cls.set_is_prefinalized();
|
||||
core_lib.AddClass(cls);
|
||||
pending_classes.Add(cls, Heap::kOld);
|
||||
type = Type::NewNonParameterizedType(cls);
|
||||
|
@ -998,6 +998,14 @@ RawString* Class::Name() const {
|
|||
|
||||
|
||||
RawType* Class::SignatureType() const {
|
||||
ASSERT(IsSignatureClass());
|
||||
const Function& function = Function::Handle(signature_function());
|
||||
ASSERT(!function.IsNull());
|
||||
if (function.signature_class() != raw()) {
|
||||
// This class is a function type alias. Return the canonical signature type.
|
||||
const Class& canonical_class = Class::Handle(function.signature_class());
|
||||
return canonical_class.SignatureType();
|
||||
}
|
||||
// Return the first canonical signature type if already computed.
|
||||
const Array& signature_types = Array::Handle(canonical_types());
|
||||
if (signature_types.Length() > 0) {
|
||||
|
@ -1007,7 +1015,6 @@ RawType* Class::SignatureType() const {
|
|||
return signature_type.raw();
|
||||
}
|
||||
}
|
||||
ASSERT(IsSignatureClass());
|
||||
// A signature class extends class Instance and is parameterized in the same
|
||||
// way as the owner class of its non-static signature function.
|
||||
// It is not type parameterized if its signature function is static.
|
||||
|
@ -1463,8 +1470,14 @@ RawClass* Class::NewSignatureClass(const String& name,
|
|||
// the signature class.
|
||||
if (signature_function.signature_class() == Object::null()) {
|
||||
signature_function.set_signature_class(result);
|
||||
result.set_is_finalized();
|
||||
} else {
|
||||
// This new signature class is an alias.
|
||||
ASSERT(!result.IsCanonicalSignatureClass());
|
||||
// Do not yet mark it as finalized, so that the class finalizer can check it
|
||||
// for illegal self references.
|
||||
result.set_is_prefinalized();
|
||||
}
|
||||
result.set_is_finalized();
|
||||
// Instances of a signature class can only be closures.
|
||||
ASSERT(result.instance_size() == Closure::InstanceSize());
|
||||
// Cache the signature type as the first canonicalized type in result.
|
||||
|
@ -1657,6 +1670,12 @@ void Class::set_is_finalized() const {
|
|||
}
|
||||
|
||||
|
||||
void Class::set_is_prefinalized() const {
|
||||
ASSERT(!is_finalized());
|
||||
set_class_state(RawClass::kPreFinalized);
|
||||
}
|
||||
|
||||
|
||||
void Class::set_interfaces(const Array& value) const {
|
||||
// Verification and resolving of interfaces occurs in finalizer.
|
||||
ASSERT(!value.IsNull());
|
||||
|
|
|
@ -655,6 +655,8 @@ class Class : public Object {
|
|||
return raw_ptr()->class_state_ == RawClass::kPreFinalized;
|
||||
}
|
||||
|
||||
void set_is_prefinalized() const;
|
||||
|
||||
bool is_const() const {
|
||||
return raw_ptr()->is_const_;
|
||||
}
|
||||
|
|
|
@ -2962,6 +2962,10 @@ void Parser::ParseFunctionTypeAlias(
|
|||
Class::NewSignatureClass(*alias_name,
|
||||
signature_function,
|
||||
script_));
|
||||
// This alias should not be marked as finalized yet, since it needs to be
|
||||
// checked in the class finalizer for illegal self references.
|
||||
ASSERT(!function_type_alias.IsCanonicalSignatureClass());
|
||||
ASSERT(!function_type_alias.is_finalized());
|
||||
library_.AddClass(function_type_alias);
|
||||
ExpectSemicolon();
|
||||
pending_classes.Add(function_type_alias, Heap::kOld);
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
// Dart test for self referencing function type alias.
|
||||
// Dart test for illegally self referencing function type alias.
|
||||
|
||||
typedef Handle Handle(String command);
|
||||
typedef Handle Handle(String command); /// 00: compile-time error
|
||||
|
||||
typedef F(F x); /// 01: compile-time error
|
||||
|
||||
typedef A(B x); /// 02: compile-time error
|
||||
typedef B(A x); /// 02: continued
|
||||
|
||||
main() {
|
||||
Handle handle = null;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,23 @@
|
|||
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
// Dart test for self referencing function type alias.
|
||||
// Dart test for legally self referencing function type alias.
|
||||
|
||||
typedef F(F x);
|
||||
typedef F(List<F> x);
|
||||
|
||||
typedef D C();
|
||||
|
||||
class D {
|
||||
C foo() { }
|
||||
D bar() { }
|
||||
}
|
||||
|
||||
main() {
|
||||
var func = _(F x) { };
|
||||
Expect.isTrue(func is F);
|
||||
var f = _(List x) { };
|
||||
Expect.isTrue(f is F);
|
||||
var g = _(List<F> x) { };
|
||||
Expect.isTrue(g is F);
|
||||
var d = new D();
|
||||
Expect.isTrue(d.foo is !C);
|
||||
Expect.isTrue(d.bar is C);
|
||||
}
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
// Dart test for self referencing function type alias.
|
||||
|
||||
typedef A(B x);
|
||||
typedef B(A x);
|
||||
|
||||
main() {
|
||||
var aFunc = _(B x) { };
|
||||
var bFunc = _(A x) { };
|
||||
Expect.isTrue(aFunc is A);
|
||||
Expect.isTrue(bFunc is B);
|
||||
}
|
|
@ -89,6 +89,9 @@ duplicate_implements_test: Skip # Issue 976
|
|||
field3a_negative_test: Fail
|
||||
field_method4_negative_test: Fail
|
||||
final_syntax_test/*: Skip # can't handle base case
|
||||
function_type_alias5_test/00: Fail # Legally self referencing typedef
|
||||
function_type_alias5_test/01: Fail # Legally self referencing typedef
|
||||
function_type_alias5_test/02: Fail # Legally self referencing typedef
|
||||
function_type_alias_negative_test: Fail # Bug 5231617.
|
||||
generic_parameterized_extends_test: Skip # Bug 5392297
|
||||
getters_setters_type3_test: Fail # Issue 2351
|
||||
|
@ -275,8 +278,10 @@ function_type_alias_test: Fail
|
|||
function_type_alias2_test: Fail
|
||||
function_type_alias3_test: Fail
|
||||
function_type_alias4_test: Fail
|
||||
function_type_alias5_test/00: Fail
|
||||
function_type_alias5_test/01: Fail
|
||||
function_type_alias5_test/02: Fail
|
||||
function_type_alias6_test: Fail
|
||||
function_type_alias7_test: Fail
|
||||
function_type_parameter2_test: Fail
|
||||
function_type_parameter_test: Fail
|
||||
generic_deep_test: Fail
|
||||
|
@ -492,8 +497,10 @@ function_test: Fail # internal error: Closures inside initializers not implement
|
|||
function_type_alias2_test: Fail # cannot resolve type f1
|
||||
function_type_alias3_test: Fail # cannot resolve type F
|
||||
function_type_alias4_test: Fail # cannot resolve type F
|
||||
function_type_alias5_test/00: Fail # visitIs for typedefs not implemented
|
||||
function_type_alias5_test/01: Fail # visitIs for typedefs not implemented
|
||||
function_type_alias5_test/02: Fail # visitIs for typedefs not implemented
|
||||
function_type_alias6_test: Fail # visitIs for typedefs not implemented
|
||||
function_type_alias7_test: Fail # visitIs for typedefs not implemented
|
||||
function_type_alias_test: Fail # cannot resolve type Fun
|
||||
function_type_parameter2_test: Fail # Internal Error: expected optional parameters
|
||||
function_type_parameter_test: Fail # Internal Error: expected optional parameters
|
||||
|
|
Loading…
Reference in a new issue