From 8ca244ba27f85b9bc5b2b01daacf020f398ac58a Mon Sep 17 00:00:00 2001 From: Regis Crelier Date: Mon, 10 Apr 2017 11:06:10 -0700 Subject: [PATCH] Make finalization of recursive function types more robust, especially since the Kernel frontend may omit the information that a function type is a typedef. Re-enable several previously failing tests for dartk. R=asiva@google.com Review-Url: https://codereview.chromium.org/2806893002 . --- runtime/vm/class_finalizer.cc | 112 ++++++++++++-------------- runtime/vm/object.cc | 17 +++- tests/language/language_kernel.status | 7 -- 3 files changed, 66 insertions(+), 70 deletions(-) diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc index e100cc529ac..ab89f7fcdbd 100644 --- a/runtime/vm/class_finalizer.cc +++ b/runtime/vm/class_finalizer.cc @@ -815,19 +815,8 @@ intptr_t ClassFinalizer::ExpandAndFinalizeTypeArguments( } } - // Self referencing types may get finalized indirectly. - if (!type.IsFinalized()) { - ASSERT(full_arguments.IsNull() || - !full_arguments.IsRaw(0, num_type_arguments)); - if (FLAG_trace_type_finalization) { - THR_Print("Marking type '%s' as finalized for class '%s'\n", - String::Handle(zone, type.Name()).ToCString(), - String::Handle(zone, cls.Name()).ToCString()); - } - // Mark the type as finalized. - type.SetIsFinalized(); - // Do not yet remove the type from the pending_types array. - } + ASSERT(full_arguments.IsNull() || + !full_arguments.IsRaw(0, num_type_arguments)); return full_arguments.IsNull() ? 0 : full_arguments.Length(); } @@ -1225,6 +1214,57 @@ RawAbstractType* ClassFinalizer::FinalizeType(const Class& cls, const intptr_t num_expanded_type_arguments = ExpandAndFinalizeTypeArguments(cls, type, pending_types); + // Self referencing types may get finalized indirectly. + if (!type.IsFinalized()) { + // If the type is a function type, we also need to finalize the types in its + // signature, i.e. finalize the result type and parameter types of the + // signature function of this function type. + // We do this after marking this type as finalized in order to allow a + // typedef function type to refer to itself via its parameter types and + // result type. + if (type.IsFunctionType()) { + const Type& fun_type = Type::Cast(type); + const Class& scope_class = Class::Handle(zone, fun_type.type_class()); + if (scope_class.IsTypedefClass()) { + Function& signature = + Function::Handle(zone, scope_class.signature_function()); + if (!scope_class.is_type_finalized()) { + FinalizeSignature(scope_class, signature); + } + // If the function type is a generic typedef, instantiate its signature + // from its type arguments. + // Example: typedef T F(T x) has uninstantiated signature (T x) => T. + // The instantiated signature of F(int) becomes (int x) => int. + // Note that after this step, the signature of the function type is not + // identical to the canonical signature of the typedef class anymore. + if (scope_class.IsGeneric() && !signature.HasInstantiatedSignature()) { + const TypeArguments& type_args = + TypeArguments::Handle(zone, fun_type.arguments()); + if (FLAG_trace_type_finalization) { + THR_Print("Instantiating signature '%s' of typedef '%s'\n", + String::Handle(zone, signature.Signature()).ToCString(), + String::Handle(zone, fun_type.Name()).ToCString()); + } + signature = signature.InstantiateSignatureFrom(type_args, Heap::kOld); + // Note that if type_args contains type parameters, signature is still + // uninstantiated here (typedef type parameters were substituted in + // the signature with typedef type arguments). + } + fun_type.set_signature(signature); + } else { + FinalizeSignature(cls, Function::Handle(zone, fun_type.signature())); + } + } + + if (FLAG_trace_type_finalization) { + THR_Print("Marking type '%s' as finalized for class '%s'\n", + String::Handle(zone, type.Name()).ToCString(), + String::Handle(zone, cls.Name()).ToCString()); + } + // Mark the type as finalized. + type.SetIsFinalized(); + } + // If we are done finalizing a graph of mutually recursive types, check their // bounds. if (is_root_type) { @@ -1236,52 +1276,6 @@ RawAbstractType* ClassFinalizer::FinalizeType(const Class& cls, } } - // If the type is a function type, we also need to finalize the types in its - // signature, i.e. finalize the result type and parameter types of the - // signature function of this function type. - // We do this after marking this type as finalized in order to allow a - // typedef function type to refer to itself via its parameter types and - // result type. - if (type.IsFunctionType()) { - ASSERT(!type.IsBeingFinalized()); - const Type& fun_type = Type::Cast(type); - const Class& scope_class = Class::Handle(zone, fun_type.type_class()); - if (scope_class.IsTypedefClass()) { - Function& signature = - Function::Handle(zone, scope_class.signature_function()); - if (!scope_class.is_type_finalized()) { - FinalizeSignature(scope_class, signature); - } - // If the function type is a generic typedef, instantiate its signature - // from its type arguments. - // Example: typedef T F(T x) has uninstantiated signature (T x) => T. - // The instantiated signature of F(int) becomes (int x) => int. - // Note that after this step, the signature of the function type is not - // identical to the canonical signature of the typedef class anymore. - if (scope_class.IsGeneric() && !signature.HasInstantiatedSignature()) { - const TypeArguments& type_args = - TypeArguments::Handle(zone, fun_type.arguments()); - if (FLAG_trace_type_finalization) { - THR_Print("Instantiating signature '%s' of typedef '%s'\n", - String::Handle(zone, signature.Signature()).ToCString(), - String::Handle(zone, fun_type.Name()).ToCString()); - } - signature = signature.InstantiateSignatureFrom(type_args, Heap::kOld); - // Note that if type_args contains type parameters, signature is still - // uninstantiated here (typedef type parameters were substituted in the - // signature with typedef type arguments). - } - fun_type.set_signature(signature); - // The type was already marked as finalized and uninstantiated in - // ExpandAndFinalizeTypeArguments above when its signature was not - // instantiated yet. Check again by calling ResetIsFinalized(). - fun_type.ResetIsFinalized(); - } else { - const Function& signature = Function::Handle(zone, fun_type.signature()); - FinalizeSignature(cls, signature); - } - } - if (FLAG_trace_type_finalization) { THR_Print("Done finalizing type '%s' with %" Pd " type args: %s\n", String::Handle(zone, type.Name()).ToCString(), diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index c7472e4a7ee..66fc98ee3bf 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -16875,6 +16875,12 @@ bool Type::IsInstantiated(Genericity genericity, TrailPtr trail) const { if (HasResolvedTypeClass()) { const Class& cls = Class::Handle(type_class()); len = cls.NumTypeParameters(); // Check the type parameters only. + if (len > num_type_args) { + // This type has the wrong number of arguments and is not finalized yet. + // Type arguments are reset to null when finalizing such a type. + ASSERT(!IsFinalized()); + len = num_type_args; + } } return (len == 0) || args.IsSubvectorInstantiated(num_type_args - len, len, genericity, @@ -16921,10 +16927,12 @@ RawAbstractType* Type::InstantiateFrom( const LanguageError& bound_error = LanguageError::Handle(zone, error()); instantiated_type.set_error(bound_error); } - // If this type is a function type, instantiate its signature. + // For a function type, possibly instantiate and set its signature. if (!sig_fun.IsNull()) { - // If we are finalizing a typedef, do not yet instantiate its signature. - // Other function types should never be instantiated while unfinalized. + // If we are finalizing a typedef, do not yet instantiate its signature, + // since it gets instantiated just before the type is marked as finalized. + // Other function types should never get instantiated while unfinalized, + // even while checking bounds of recursive types. if (IsFinalized()) { // A generic typedef may actually declare an instantiated signature. if (!sig_fun.HasInstantiatedSignature()) { @@ -16932,7 +16940,8 @@ RawAbstractType* Type::InstantiateFrom( space); } } else { - ASSERT(cls.IsTypedefClass()); + // The Kernel frontend does not keep the information that a function type + // is a typedef, so we cannot assert that cls.IsTypedefClass(). } instantiated_type.set_signature(sig_fun); } diff --git a/tests/language/language_kernel.status b/tests/language/language_kernel.status index 2b0ffeb27fc..ea7eaaeb9ea 100644 --- a/tests/language/language_kernel.status +++ b/tests/language/language_kernel.status @@ -88,11 +88,6 @@ cyclic_constructor_test/01: MissingCompileTimeError cyclic_type_test/00: RuntimeError cyclic_type_test/01: RuntimeError cyclic_type_test/03: RuntimeError -cyclic_type_variable_test/01: Crash -cyclic_type_variable_test/02: Crash -cyclic_type_variable_test/03: Crash -cyclic_type_variable_test/04: Crash -cyclic_type_variable_test/none: Crash cyclic_typedef_test/01: MissingCompileTimeError cyclic_typedef_test/02: MissingCompileTimeError cyclic_typedef_test/03: MissingCompileTimeError @@ -406,7 +401,6 @@ vm/optimized_stacktrace_test: Skip # Issue 28788 [ $compiler == dartk && $mode == debug ] constructor_duplicate_initializers_test/03: Crash deopt_inlined_function_lazy_test: Skip -function_malformed_result_type_test: Crash hello_dart_test: Crash # error: expected: cls.is_type_finalized() not_enough_positional_arguments_test/02: Crash # Dartk Issue 28301 not_enough_positional_arguments_test/05: Crash # Dartk Issue 28301 @@ -419,7 +413,6 @@ ref_before_declaration_test/05: Crash ref_before_declaration_test/06: Crash ref_before_declaration_test/07: Crash ref_before_declaration_test/none: Crash -regress_29025_test: Crash try_catch_syntax_test/05: Crash vm/lazy_deopt_vm_test: Crash