| Index: runtime/vm/object.cc
|
| diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
|
| index 6e3b4e9aa88b65a67e5db69527538e832836a4cf..0214fd9b87a2217fc8b7c5746a6189a67a4df9cc 100644
|
| --- a/runtime/vm/object.cc
|
| +++ b/runtime/vm/object.cc
|
| @@ -1996,8 +1996,7 @@ bool Class::IsInFullSnapshot() const {
|
| RawAbstractType* Class::RareType() const {
|
| const Type& type = Type::Handle(Type::New(
|
| *this, Object::null_type_arguments(), TokenPosition::kNoSource));
|
| - return ClassFinalizer::FinalizeType(*this, type,
|
| - ClassFinalizer::kCanonicalize);
|
| + return ClassFinalizer::FinalizeType(*this, type);
|
| }
|
|
|
|
|
| @@ -2005,8 +2004,7 @@ RawAbstractType* Class::DeclarationType() const {
|
| const TypeArguments& args = TypeArguments::Handle(type_parameters());
|
| const Type& type =
|
| Type::Handle(Type::New(*this, args, TokenPosition::kNoSource));
|
| - return ClassFinalizer::FinalizeType(*this, type,
|
| - ClassFinalizer::kCanonicalize);
|
| + return ClassFinalizer::FinalizeType(*this, type);
|
| }
|
|
|
|
|
| @@ -3834,17 +3832,9 @@ bool Class::TypeTestNonRecursive(const Class& cls,
|
| }
|
| if (other.IsDartFunctionClass()) {
|
| // Check if type S has a call() method.
|
| - Function& function = Function::Handle(
|
| - zone, thsi.LookupDynamicFunctionAllowAbstract(Symbols::Call()));
|
| - if (function.IsNull()) {
|
| - // Walk up the super_class chain.
|
| - Class& cls = Class::Handle(zone, thsi.SuperClass());
|
| - while (!cls.IsNull() && function.IsNull()) {
|
| - function = cls.LookupDynamicFunctionAllowAbstract(Symbols::Call());
|
| - cls = cls.SuperClass();
|
| - }
|
| - }
|
| - if (!function.IsNull()) {
|
| + const Function& call_function =
|
| + Function::Handle(zone, thsi.LookupCallFunctionForTypeTest());
|
| + if (!call_function.IsNull()) {
|
| return true;
|
| }
|
| }
|
| @@ -3866,8 +3856,7 @@ bool Class::TypeTestNonRecursive(const Class& cls,
|
| // runtime if this type test returns false at compile time.
|
| continue;
|
| }
|
| - ClassFinalizer::FinalizeType(thsi, interface,
|
| - ClassFinalizer::kCanonicalize);
|
| + ClassFinalizer::FinalizeType(thsi, interface);
|
| interfaces.SetAt(i, interface);
|
| }
|
| if (interface.IsMalbounded()) {
|
| @@ -4002,6 +3991,32 @@ RawFunction* Class::LookupFunctionAllowPrivate(const String& name) const {
|
| }
|
|
|
|
|
| +RawFunction* Class::LookupCallFunctionForTypeTest() const {
|
| + // If this class is not compiled yet, it is too early to lookup a call
|
| + // function. This case should only occur during bounds checking at compile
|
| + // time. Return null as if the call method did not exist, so the type test
|
| + // may return false, but without a bound error, and the bound check will get
|
| + // postponed to runtime.
|
| + if (!is_finalized()) {
|
| + return Function::null();
|
| + }
|
| + Zone* zone = Thread::Current()->zone();
|
| + Class& cls = Class::Handle(zone, raw());
|
| + Function& call_function = Function::Handle(zone);
|
| + do {
|
| + ASSERT(cls.is_finalized());
|
| + call_function = cls.LookupDynamicFunctionAllowAbstract(Symbols::Call());
|
| + cls = cls.SuperClass();
|
| + } while (call_function.IsNull() && !cls.IsNull());
|
| + if (!call_function.IsNull()) {
|
| + // Make sure the signature is finalized before using it in a type test.
|
| + ClassFinalizer::FinalizeSignature(
|
| + cls, call_function, ClassFinalizer::kFinalize); // No bounds checking.
|
| + }
|
| + return call_function.raw();
|
| +}
|
| +
|
| +
|
| // Returns true if 'prefix' and 'accessor_name' match 'name'.
|
| static bool MatchesAccessorName(const String& name,
|
| const char* prefix,
|
| @@ -6797,8 +6812,7 @@ RawFunction* Function::ImplicitClosureFunction() const {
|
|
|
| const Type& signature_type = Type::Handle(closure_function.SignatureType());
|
| if (!signature_type.IsFinalized()) {
|
| - ClassFinalizer::FinalizeType(Class::Handle(Owner()), signature_type,
|
| - ClassFinalizer::kCanonicalize);
|
| + ClassFinalizer::FinalizeType(Class::Handle(Owner()), signature_type);
|
| }
|
| set_implicit_closure_function(closure_function);
|
| ASSERT(closure_function.IsImplicitClosureFunction());
|
| @@ -15762,24 +15776,17 @@ bool Instance::IsInstanceOf(const AbstractType& other,
|
| const bool other_is_dart_function = instantiated_other.IsDartFunctionType();
|
| if (other_is_dart_function || instantiated_other.IsFunctionType()) {
|
| // Check if this instance understands a call() method of a compatible type.
|
| - Function& call = Function::Handle(
|
| - zone, cls.LookupDynamicFunctionAllowAbstract(Symbols::Call()));
|
| - if (call.IsNull()) {
|
| - // Walk up the super_class chain.
|
| - Class& super_cls = Class::Handle(zone, cls.SuperClass());
|
| - while (!super_cls.IsNull() && call.IsNull()) {
|
| - call = super_cls.LookupDynamicFunctionAllowAbstract(Symbols::Call());
|
| - super_cls = super_cls.SuperClass();
|
| - }
|
| - }
|
| - if (!call.IsNull()) {
|
| + const Function& call_function =
|
| + Function::Handle(zone, cls.LookupCallFunctionForTypeTest());
|
| + if (!call_function.IsNull()) {
|
| if (other_is_dart_function) {
|
| return true;
|
| }
|
| const Function& other_signature =
|
| Function::Handle(zone, Type::Cast(instantiated_other).signature());
|
| - if (call.IsSubtypeOf(type_arguments, other_signature,
|
| - other_type_arguments, bound_error, Heap::kOld)) {
|
| + if (call_function.IsSubtypeOf(type_arguments, other_signature,
|
| + other_type_arguments, bound_error,
|
| + Heap::kOld)) {
|
| return true;
|
| }
|
| }
|
| @@ -16581,19 +16588,11 @@ bool AbstractType::TypeTest(TypeTestKind test_kind,
|
| TypeArguments::Handle(zone, other.arguments()), bound_error, space);
|
| }
|
| // Check if type S has a call() method of function type T.
|
| - Function& function = Function::Handle(
|
| - zone, type_cls.LookupDynamicFunctionAllowAbstract(Symbols::Call()));
|
| - if (function.IsNull()) {
|
| - // Walk up the super_class chain.
|
| - Class& cls = Class::Handle(zone, type_cls.SuperClass());
|
| - while (!cls.IsNull() && function.IsNull()) {
|
| - function = cls.LookupDynamicFunctionAllowAbstract(Symbols::Call());
|
| - cls = cls.SuperClass();
|
| - }
|
| - }
|
| - if (!function.IsNull()) {
|
| + const Function& call_function =
|
| + Function::Handle(zone, type_cls.LookupCallFunctionForTypeTest());
|
| + if (!call_function.IsNull()) {
|
| if (other_is_dart_function_type ||
|
| - function.TypeTest(
|
| + call_function.TypeTest(
|
| test_kind, TypeArguments::Handle(zone, arguments()),
|
| Function::Handle(zone, Type::Cast(other).signature()),
|
| TypeArguments::Handle(zone, other.arguments()), bound_error,
|
| @@ -16884,7 +16883,8 @@ bool Type::IsInstantiated(TrailPtr trail) const {
|
| const Class& cls = Class::Handle(type_class());
|
| len = cls.NumTypeParameters(); // Check the type parameters only.
|
| }
|
| - return (len == 0) || args.IsSubvectorInstantiated(num_type_args - len, len);
|
| + return (len == 0) ||
|
| + args.IsSubvectorInstantiated(num_type_args - len, len, trail);
|
| }
|
|
|
|
|
| @@ -17864,6 +17864,15 @@ bool TypeParameter::CheckBound(const AbstractType& bounded_type,
|
| // Report the bound error only if both the bounded type and the upper bound
|
| // are instantiated. Otherwise, we cannot tell yet it is a bound error.
|
| if (bounded_type.IsInstantiated() && upper_bound.IsInstantiated()) {
|
| + // There is another special case where we do not want to report a bound
|
| + // error yet: if the upper bound is a function type, but the bounded type
|
| + // is not and its class is not compiled yet, i.e. we cannot look for
|
| + // a call method yet.
|
| + if (!bounded_type.IsFunctionType() && upper_bound.IsFunctionType() &&
|
| + bounded_type.HasResolvedTypeClass() &&
|
| + !Class::Handle(bounded_type.type_class()).is_finalized()) {
|
| + return false; // Not a subtype yet, but no bound error yet.
|
| + }
|
| const String& bounded_type_name =
|
| String::Handle(bounded_type.UserVisibleName());
|
| const String& upper_bound_name =
|
|
|