diff --git a/toolchain/check/convert.cpp b/toolchain/check/convert.cpp index e825e574da3f..4c6c264f1549 100644 --- a/toolchain/check/convert.cpp +++ b/toolchain/check/convert.cpp @@ -868,8 +868,12 @@ static auto ConvertStructToClass(Context& context, SemIR::StructType src_type, target.storage_id.has_value()); PendingBlock target_block(&context); auto& dest_class_info = context.classes().Get(dest_type.class_id); - CARBON_CHECK(is_partial || - dest_class_info.inheritance_kind != SemIR::Class::Abstract); + if (!is_partial && + dest_class_info.inheritance_kind == SemIR::Class::Abstract) { + CARBON_DIAGNOSTIC(AbstractTypeInInit, Error, + "initialization of abstract class {0}", SemIR::TypeId); + context.emitter().Emit(value_id, AbstractTypeInInit, target.type_id); + } auto object_repr_id = dest_class_info.GetObjectRepr(context.sem_ir(), dest_type.specific_id); if (object_repr_id == SemIR::ErrorInst::TypeId) { @@ -1957,58 +1961,33 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id, } auto original_inner_expr_id = expr_id; - auto incomplete_diagnostic = [&](auto& builder) { - CARBON_CHECK(!target.is_initializer(), - "Initialization of incomplete types is expected to be " - "caught elsewhere."); - CARBON_DIAGNOSTIC(IncompleteTypeInValueConversion, Context, - "forming value of incomplete type {0}", SemIR::TypeId); - CARBON_DIAGNOSTIC(IncompleteTypeInConversion, Context, - "invalid use of incomplete type {0}", SemIR::TypeId); - builder.Context(loc_id, - target.kind == ConversionTarget::Value - ? IncompleteTypeInValueConversion - : IncompleteTypeInConversion, - target.type_id); - }; - - // Allow forming a value or reference of abstract class type, but not - // an initializer. - bool require_concrete = - target.is_initializer() || - // TODO: relax this restriction. - !context.insts().Is(expr_id); - // TODO: Push this check down to the points where we perform operations that // need the type to be complete. if (ConversionNeedsCompleteTarget(context, expr_id, target)) { - if (require_concrete) { - if (target.diagnose) { - if (!RequireConcreteType( - context, target.type_id, loc_id, incomplete_diagnostic, - [&](auto& builder) { - CARBON_DIAGNOSTIC(AbstractTypeInInit, Context, - "initialization of abstract type {0}", - SemIR::TypeId); - builder.Context(loc_id, AbstractTypeInInit, target.type_id); - })) { - return SemIR::ErrorInst::InstId; - } - } else { - if (!TryIsConcreteType(context, target.type_id, loc_id)) { - return SemIR::ErrorInst::InstId; - } + if (target.diagnose) { + if (!RequireCompleteType( + context, target.type_id, loc_id, [&](auto& builder) { + CARBON_CHECK( + !target.is_initializer(), + "Initialization of incomplete types is expected to be " + "caught elsewhere."); + CARBON_DIAGNOSTIC(IncompleteTypeInValueConversion, Context, + "forming value of incomplete type {0}", + SemIR::TypeId); + CARBON_DIAGNOSTIC(IncompleteTypeInConversion, Context, + "invalid use of incomplete type {0}", + SemIR::TypeId); + builder.Context(loc_id, + target.kind == ConversionTarget::Value + ? IncompleteTypeInValueConversion + : IncompleteTypeInConversion, + target.type_id); + })) { + return SemIR::ErrorInst::InstId; } } else { - if (target.diagnose) { - if (!RequireCompleteType(context, target.type_id, loc_id, - incomplete_diagnostic)) { - return SemIR::ErrorInst::InstId; - } - } else { - if (!TryToCompleteType(context, target.type_id, loc_id)) { - return SemIR::ErrorInst::InstId; - } + if (!TryToCompleteType(context, target.type_id, loc_id)) { + return SemIR::ErrorInst::InstId; } } } diff --git a/toolchain/check/testdata/class/abstract/abstract.carbon b/toolchain/check/testdata/class/abstract/abstract.carbon index a9761dcab9b3..e7a532e42337 100644 --- a/toolchain/check/testdata/class/abstract/abstract.carbon +++ b/toolchain/check/testdata/class/abstract/abstract.carbon @@ -2,7 +2,7 @@ // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/destroy.carbon +// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/full.carbon // TODO: Add ranges and switch to "--dump-sem-ir-ranges=only". // EXTRA-ARGS: --dump-sem-ir-ranges=if-present // @@ -154,29 +154,11 @@ class Derived { var d: {}; } -fn Access(d: Derived) -> {} { +fn AccessViaBase(d: Derived) -> {} { return d.base.a; } -// --- fail_todo_access_abstract_subobject_derived_to_base_conversion.carbon -library "[[@TEST_NAME]]"; - -abstract class Abstract { - var a: {}; -} - -class Derived { - extend base: Abstract; -} - fn Access(d: Derived) -> {} { - // CHECK:STDERR: fail_todo_access_abstract_subobject_derived_to_base_conversion.carbon:[[@LINE+7]]:10: error: initialization of abstract type `Abstract` [AbstractTypeInInit] - // CHECK:STDERR: return d.a; - // CHECK:STDERR: ^~~ - // CHECK:STDERR: fail_todo_access_abstract_subobject_derived_to_base_conversion.carbon:[[@LINE-12]]:1: note: class was declared abstract here [ClassAbstractHere] - // CHECK:STDERR: abstract class Abstract { - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: return d.a; } @@ -187,12 +169,13 @@ abstract class Abstract { } fn F() { - // CHECK:STDERR: fail_abstract_let_temporary_struct_literal.carbon:[[@LINE+7]]:28: error: initialization of abstract type `Abstract` [AbstractTypeInInit] + // CHECK:STDERR: fail_abstract_let_temporary_struct_literal.carbon:[[@LINE+8]]:28: error: initialization of abstract class `Abstract` [AbstractTypeInInit] + // CHECK:STDERR: let unused l: Abstract = {}; + // CHECK:STDERR: ^~ + // CHECK:STDERR: + // CHECK:STDERR: fail_abstract_let_temporary_struct_literal.carbon:[[@LINE+4]]:28: error: cannot access member of interface `Core.Destroy` in type `Abstract` that does not implement that interface [MissingImplInMemberAccess] // CHECK:STDERR: let unused l: Abstract = {}; // CHECK:STDERR: ^~ - // CHECK:STDERR: fail_abstract_let_temporary_struct_literal.carbon:[[@LINE-7]]:1: note: class was declared abstract here [ClassAbstractHere] - // CHECK:STDERR: abstract class Abstract { - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: let unused l: Abstract = {}; } @@ -208,16 +191,11 @@ class Derived { } fn F() { - // TODO: We should be able to construct a temporary `Derived`, and assign it - // to the `Abstract` value since `Abstract` and `Derived` have pointer value - // representations. + // TODO: support destroying classes that derive from abstract types. // - // CHECK:STDERR: fail_todo_abstract_let_temporary.carbon:[[@LINE+7]]:28: error: initialization of abstract type `Abstract` [AbstractTypeInInit] + // CHECK:STDERR: fail_todo_abstract_let_temporary.carbon:[[@LINE+4]]:28: error: cannot access member of interface `Core.Destroy` in type `Derived` that does not implement that interface [MissingImplInMemberAccess] // CHECK:STDERR: let unused l: Abstract = {.base = {}} as Derived; // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: fail_todo_abstract_let_temporary.carbon:[[@LINE-15]]:1: note: class was declared abstract here [ClassAbstractHere] - // CHECK:STDERR: abstract class Abstract { - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: let unused l: Abstract = {.base = {}} as Derived; } @@ -244,6 +222,23 @@ fn CallReturnAbstract() { ReturnAbstract(); } +// --- fail_assign_to_abstract_ref.carbon +library "[[@TEST_NAME]]"; + +abstract class Abstract { +} + +fn Assign(ref a: Abstract) { + // CHECK:STDERR: fail_assign_to_abstract_ref.carbon:[[@LINE+7]]:7: error: cannot copy value of type `Abstract` [CopyOfUncopyableType] + // CHECK:STDERR: a = a; + // CHECK:STDERR: ^ + // CHECK:STDERR: fail_assign_to_abstract_ref.carbon:[[@LINE+4]]:7: note: type `Abstract` does not implement interface `Core.Copy` [MissingImplInMemberAccessInContext] + // CHECK:STDERR: a = a; + // CHECK:STDERR: ^ + // CHECK:STDERR: + a = a; +} + // CHECK:STDOUT: --- fail_abstract_field.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -307,7 +302,7 @@ fn CallReturnAbstract() { // CHECK:STDOUT: import Core//prelude // CHECK:STDOUT: import Core//prelude/... // CHECK:STDOUT: } -// CHECK:STDOUT: %Core.Destroy: type = import_ref Core//prelude/parts/destroy, Destroy, loaded [concrete = constants.%Destroy.type] +// CHECK:STDOUT: %Core.Destroy: type = import_ref Core//prelude/destroy, Destroy, loaded [concrete = constants.%Destroy.type] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -763,6 +758,8 @@ fn CallReturnAbstract() { // CHECK:STDOUT: %.469: Core.Form = init_form %empty_struct_type [concrete] // CHECK:STDOUT: %return.param_patt: %pattern_type.a96 = out_param_pattern [concrete] // CHECK:STDOUT: %return.patt: %pattern_type.a96 = return_slot_pattern %return.param_patt, %empty_struct_type [concrete] +// CHECK:STDOUT: %AccessViaBase.type: type = fn_type @AccessViaBase [concrete] +// CHECK:STDOUT: %AccessViaBase: %AccessViaBase.type = struct_value () [concrete] // CHECK:STDOUT: %Access.type: type = fn_type @Access [concrete] // CHECK:STDOUT: %Access: %Access.type = struct_value () [concrete] // CHECK:STDOUT: } @@ -779,20 +776,36 @@ fn CallReturnAbstract() { // CHECK:STDOUT: .Core = imports.%Core // CHECK:STDOUT: .Abstract = %Abstract.decl // CHECK:STDOUT: .Derived = %Derived.decl +// CHECK:STDOUT: .AccessViaBase = %AccessViaBase.decl // CHECK:STDOUT: .Access = %Access.decl // CHECK:STDOUT: } // CHECK:STDOUT: %Core.import = import Core // CHECK:STDOUT: %Abstract.decl: type = class_decl @Abstract [concrete = constants.%Abstract] {} {} // CHECK:STDOUT: %Derived.decl: type = class_decl @Derived [concrete = constants.%Derived] {} {} +// CHECK:STDOUT: %AccessViaBase.decl: %AccessViaBase.type = fn_decl @AccessViaBase [concrete = constants.%AccessViaBase] { +// CHECK:STDOUT: %d.param_patt: %pattern_type.746 = value_param_pattern [concrete = constants.%d.param_patt] +// CHECK:STDOUT: %d.patt: %pattern_type.746 = at_binding_pattern d, %d.param_patt [concrete = constants.%d.patt.fac] +// CHECK:STDOUT: %return.param_patt: %pattern_type.a96 = out_param_pattern [concrete = constants.%return.param_patt] +// CHECK:STDOUT: %return.patt: %pattern_type.a96 = return_slot_pattern %return.param_patt, %.loc13_34.2 [concrete = constants.%return.patt] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %.loc13_34.1: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct] +// CHECK:STDOUT: %.loc13_34.2: type = converted %.loc13_34.1, constants.%empty_struct_type [concrete = constants.%empty_struct_type] +// CHECK:STDOUT: %.loc13_34.3: Core.Form = init_form %.loc13_34.2 [concrete = constants.%.469] +// CHECK:STDOUT: %d.param: %Derived = value_param call_param0 +// CHECK:STDOUT: %Derived.ref: type = name_ref Derived, file.%Derived.decl [concrete = constants.%Derived] +// CHECK:STDOUT: %d: %Derived = value_binding d, %d.param +// CHECK:STDOUT: %return.param: ref %empty_struct_type = out_param call_param1 +// CHECK:STDOUT: %return: ref %empty_struct_type = return_slot %return.param +// CHECK:STDOUT: } // CHECK:STDOUT: %Access.decl: %Access.type = fn_decl @Access [concrete = constants.%Access] { // CHECK:STDOUT: %d.param_patt: %pattern_type.746 = value_param_pattern [concrete = constants.%d.param_patt] // CHECK:STDOUT: %d.patt: %pattern_type.746 = at_binding_pattern d, %d.param_patt [concrete = constants.%d.patt.fac] // CHECK:STDOUT: %return.param_patt: %pattern_type.a96 = out_param_pattern [concrete = constants.%return.param_patt] -// CHECK:STDOUT: %return.patt: %pattern_type.a96 = return_slot_pattern %return.param_patt, %.loc13_27.2 [concrete = constants.%return.patt] +// CHECK:STDOUT: %return.patt: %pattern_type.a96 = return_slot_pattern %return.param_patt, %.loc17_27.2 [concrete = constants.%return.patt] // CHECK:STDOUT: } { -// CHECK:STDOUT: %.loc13_27.1: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct] -// CHECK:STDOUT: %.loc13_27.2: type = converted %.loc13_27.1, constants.%empty_struct_type [concrete = constants.%empty_struct_type] -// CHECK:STDOUT: %.loc13_27.3: Core.Form = init_form %.loc13_27.2 [concrete = constants.%.469] +// CHECK:STDOUT: %.loc17_27.1: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct] +// CHECK:STDOUT: %.loc17_27.2: type = converted %.loc17_27.1, constants.%empty_struct_type [concrete = constants.%empty_struct_type] +// CHECK:STDOUT: %.loc17_27.3: Core.Form = init_form %.loc17_27.2 [concrete = constants.%.469] // CHECK:STDOUT: %d.param: %Derived = value_param call_param0 // CHECK:STDOUT: %Derived.ref: type = name_ref Derived, file.%Derived.decl [concrete = constants.%Derived] // CHECK:STDOUT: %d: %Derived = value_binding d, %d.param @@ -823,10 +836,11 @@ fn CallReturnAbstract() { // CHECK:STDOUT: .Abstract = // CHECK:STDOUT: .base = %.loc8 // CHECK:STDOUT: .d = %.loc10 +// CHECK:STDOUT: .a = // CHECK:STDOUT: extend %Abstract.ref // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Access(%d.param: %Derived) -> out %return.param: %empty_struct_type { +// CHECK:STDOUT: fn @AccessViaBase(%d.param: %Derived) -> out %return.param: %empty_struct_type { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %d.ref: %Derived = name_ref d, %d // CHECK:STDOUT: %base.ref: %Derived.elem.ce6 = name_ref base, @Derived.%.loc8 [concrete = @Derived.%.loc8] @@ -841,96 +855,16 @@ fn CallReturnAbstract() { // CHECK:STDOUT: return %.loc14_18 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_access_abstract_subobject_derived_to_base_conversion.carbon -// CHECK:STDOUT: -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %Abstract: type = class_type @Abstract [concrete] -// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] -// CHECK:STDOUT: %empty_struct: %empty_struct_type = struct_value () [concrete] -// CHECK:STDOUT: %pattern_type.a96: type = pattern_type %empty_struct_type [concrete] -// CHECK:STDOUT: %Abstract.elem: type = unbound_element_type %Abstract, %empty_struct_type [concrete] -// CHECK:STDOUT: %struct_type.a.225: type = struct_type {.a: %empty_struct_type} [concrete] -// CHECK:STDOUT: %complete_type.8c6: = complete_type_witness %struct_type.a.225 [concrete] -// CHECK:STDOUT: %Derived: type = class_type @Derived [concrete] -// CHECK:STDOUT: %Derived.elem: type = unbound_element_type %Derived, %Abstract [concrete] -// CHECK:STDOUT: %struct_type.base.285: type = struct_type {.base: %Abstract} [concrete] -// CHECK:STDOUT: %complete_type.7ce: = complete_type_witness %struct_type.base.285 [concrete] -// CHECK:STDOUT: %pattern_type.746: type = pattern_type %Derived [concrete] -// CHECK:STDOUT: %d.param_patt: %pattern_type.746 = value_param_pattern [concrete] -// CHECK:STDOUT: %d.patt: %pattern_type.746 = at_binding_pattern d, %d.param_patt [concrete] -// CHECK:STDOUT: %.469: Core.Form = init_form %empty_struct_type [concrete] -// CHECK:STDOUT: %return.param_patt: %pattern_type.a96 = out_param_pattern [concrete] -// CHECK:STDOUT: %return.patt: %pattern_type.a96 = return_slot_pattern %return.param_patt, %empty_struct_type [concrete] -// CHECK:STDOUT: %Access.type: type = fn_type @Access [concrete] -// CHECK:STDOUT: %Access: %Access.type = struct_value () [concrete] -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: imports { -// CHECK:STDOUT: %Core: = namespace file.%Core.import, [concrete] { -// CHECK:STDOUT: import Core//prelude -// CHECK:STDOUT: import Core//prelude/... -// CHECK:STDOUT: } -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: file { -// CHECK:STDOUT: package: = namespace [concrete] { -// CHECK:STDOUT: .Core = imports.%Core -// CHECK:STDOUT: .Abstract = %Abstract.decl -// CHECK:STDOUT: .Derived = %Derived.decl -// CHECK:STDOUT: .Access = %Access.decl -// CHECK:STDOUT: } -// CHECK:STDOUT: %Core.import = import Core -// CHECK:STDOUT: %Abstract.decl: type = class_decl @Abstract [concrete = constants.%Abstract] {} {} -// CHECK:STDOUT: %Derived.decl: type = class_decl @Derived [concrete = constants.%Derived] {} {} -// CHECK:STDOUT: %Access.decl: %Access.type = fn_decl @Access [concrete = constants.%Access] { -// CHECK:STDOUT: %d.param_patt: %pattern_type.746 = value_param_pattern [concrete = constants.%d.param_patt] -// CHECK:STDOUT: %d.patt: %pattern_type.746 = at_binding_pattern d, %d.param_patt [concrete = constants.%d.patt] -// CHECK:STDOUT: %return.param_patt: %pattern_type.a96 = out_param_pattern [concrete = constants.%return.param_patt] -// CHECK:STDOUT: %return.patt: %pattern_type.a96 = return_slot_pattern %return.param_patt, %.loc11_27.2 [concrete = constants.%return.patt] -// CHECK:STDOUT: } { -// CHECK:STDOUT: %.loc11_27.1: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct] -// CHECK:STDOUT: %.loc11_27.2: type = converted %.loc11_27.1, constants.%empty_struct_type [concrete = constants.%empty_struct_type] -// CHECK:STDOUT: %.loc11_27.3: Core.Form = init_form %.loc11_27.2 [concrete = constants.%.469] -// CHECK:STDOUT: %d.param: %Derived = value_param call_param0 -// CHECK:STDOUT: %Derived.ref: type = name_ref Derived, file.%Derived.decl [concrete = constants.%Derived] -// CHECK:STDOUT: %d: %Derived = value_binding d, %d.param -// CHECK:STDOUT: %return.param: ref %empty_struct_type = out_param call_param1 -// CHECK:STDOUT: %return: ref %empty_struct_type = return_slot %return.param -// CHECK:STDOUT: } -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: class @Abstract { -// CHECK:STDOUT: %.loc4: %Abstract.elem = field_decl a, element0 [concrete] -// CHECK:STDOUT: %complete_type: = complete_type_witness constants.%struct_type.a.225 [concrete = constants.%complete_type.8c6] -// CHECK:STDOUT: complete_type_witness = %complete_type -// CHECK:STDOUT: -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = constants.%Abstract -// CHECK:STDOUT: .a = %.loc4 -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: class @Derived { -// CHECK:STDOUT: %Abstract.ref: type = name_ref Abstract, file.%Abstract.decl [concrete = constants.%Abstract] -// CHECK:STDOUT: %.loc8: %Derived.elem = base_decl %Abstract.ref, element0 [concrete] -// CHECK:STDOUT: %complete_type: = complete_type_witness constants.%struct_type.base.285 [concrete = constants.%complete_type.7ce] -// CHECK:STDOUT: complete_type_witness = %complete_type -// CHECK:STDOUT: -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = constants.%Derived -// CHECK:STDOUT: .Abstract = -// CHECK:STDOUT: .base = %.loc8 -// CHECK:STDOUT: .a = -// CHECK:STDOUT: extend %Abstract.ref -// CHECK:STDOUT: } -// CHECK:STDOUT: // CHECK:STDOUT: fn @Access(%d.param: %Derived) -> out %return.param: %empty_struct_type { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %d.ref: %Derived = name_ref d, %d // CHECK:STDOUT: %a.ref: %Abstract.elem = name_ref a, @Abstract.%.loc4 [concrete = @Abstract.%.loc4] -// CHECK:STDOUT: %.loc19_11.1: %empty_struct_type = class_element_access , element0 [concrete = ] -// CHECK:STDOUT: %.loc19_11.2: init %empty_struct_type = struct_init () [concrete = constants.%empty_struct] -// CHECK:STDOUT: %.loc19_13: init %empty_struct_type = converted %.loc19_11.1, %.loc19_11.2 [concrete = constants.%empty_struct] -// CHECK:STDOUT: return %.loc19_13 +// CHECK:STDOUT: %.loc18_11.1: ref %Abstract = class_element_access %d.ref, element0 +// CHECK:STDOUT: %.loc18_11.2: ref %Abstract = converted %d.ref, %.loc18_11.1 +// CHECK:STDOUT: %.loc18_11.3: ref %empty_struct_type = class_element_access %.loc18_11.2, element0 +// CHECK:STDOUT: %.loc18_11.4: init %empty_struct_type = struct_init () [concrete = constants.%empty_struct] +// CHECK:STDOUT: %.loc18_13: init %empty_struct_type = converted %.loc18_11.3, %.loc18_11.4 [concrete = constants.%empty_struct] +// CHECK:STDOUT: return %.loc18_13 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- fail_abstract_let_temporary_struct_literal.carbon @@ -941,16 +875,21 @@ fn CallReturnAbstract() { // CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete] // CHECK:STDOUT: %F.type: type = fn_type @F [concrete] // CHECK:STDOUT: %F: %F.type = struct_value () [concrete] -// CHECK:STDOUT: %pattern_type: type = pattern_type %Abstract [concrete] -// CHECK:STDOUT: %l.patt: %pattern_type = value_binding_pattern l [concrete] +// CHECK:STDOUT: %pattern_type.169: type = pattern_type %Abstract [concrete] +// CHECK:STDOUT: %l.patt: %pattern_type.169 = value_binding_pattern l [concrete] // CHECK:STDOUT: %empty_struct: %empty_struct_type = struct_value () [concrete] +// CHECK:STDOUT: %Abstract.val: %Abstract = struct_value () [concrete] +// CHECK:STDOUT: %.69a: ref %Abstract = temporary invalid, %Abstract.val [concrete] +// CHECK:STDOUT: %Destroy.type: type = facet_type <@Destroy> [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Core: = namespace file.%Core.import, [concrete] { +// CHECK:STDOUT: .Destroy = %Core.Destroy // CHECK:STDOUT: import Core//prelude // CHECK:STDOUT: import Core//prelude/... // CHECK:STDOUT: } +// CHECK:STDOUT: %Core.Destroy: type = import_ref Core//prelude/destroy, Destroy, loaded [concrete = constants.%Destroy.type] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -975,11 +914,16 @@ fn CallReturnAbstract() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: name_binding_decl { -// CHECK:STDOUT: %l.patt: %pattern_type = value_binding_pattern l [concrete = constants.%l.patt] +// CHECK:STDOUT: %l.patt: %pattern_type.169 = value_binding_pattern l [concrete = constants.%l.patt] // CHECK:STDOUT: } -// CHECK:STDOUT: %.loc14: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct] +// CHECK:STDOUT: %.loc15_29.1: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct] +// CHECK:STDOUT: %.loc15_29.2: ref %Abstract = temporary_storage +// CHECK:STDOUT: %.loc15_29.3: init %Abstract to %.loc15_29.2 = class_init () [concrete = constants.%Abstract.val] +// CHECK:STDOUT: %.loc15_29.4: init %Abstract = converted %.loc15_29.1, %.loc15_29.3 [concrete = constants.%Abstract.val] +// CHECK:STDOUT: %.loc15_29.5: ref %Abstract = temporary %.loc15_29.2, %.loc15_29.4 [concrete = constants.%.69a] +// CHECK:STDOUT: %.loc15_29.6: %Abstract = acquire_value %.loc15_29.5 [concrete = constants.%Abstract.val] // CHECK:STDOUT: %Abstract.ref: type = name_ref Abstract, file.%Abstract.decl [concrete = constants.%Abstract] -// CHECK:STDOUT: %l: %Abstract = value_binding l, [concrete = ] +// CHECK:STDOUT: %l: %Abstract = value_binding l, %.loc15_29.6 // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: @@ -995,8 +939,8 @@ fn CallReturnAbstract() { // CHECK:STDOUT: %complete_type.7ce: = complete_type_witness %struct_type.base.285 [concrete] // CHECK:STDOUT: %F.type: type = fn_type @F [concrete] // CHECK:STDOUT: %F: %F.type = struct_value () [concrete] -// CHECK:STDOUT: %pattern_type: type = pattern_type %Abstract [concrete] -// CHECK:STDOUT: %l.patt: %pattern_type = value_binding_pattern l [concrete] +// CHECK:STDOUT: %pattern_type.169: type = pattern_type %Abstract [concrete] +// CHECK:STDOUT: %l.patt: %pattern_type.169 = value_binding_pattern l [concrete] // CHECK:STDOUT: %empty_struct.a40: %empty_struct_type = struct_value () [concrete] // CHECK:STDOUT: %struct_type.base.f5e: type = struct_type {.base: %empty_struct_type} [concrete] // CHECK:STDOUT: %struct: %struct_type.base.f5e = struct_value (%empty_struct.a40) [concrete] @@ -1004,13 +948,18 @@ fn CallReturnAbstract() { // CHECK:STDOUT: %empty_struct.5e0: %.79f = struct_value () [concrete] // CHECK:STDOUT: %Abstract.val: %Abstract = struct_value () [concrete] // CHECK:STDOUT: %Derived.val: %Derived = struct_value (%Abstract.val) [concrete] +// CHECK:STDOUT: %.521: ref %Derived = temporary invalid, %Derived.val [concrete] +// CHECK:STDOUT: %.5d3: ref %Abstract = class_element_access %.521, element0 [concrete] +// CHECK:STDOUT: %Destroy.type: type = facet_type <@Destroy> [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Core: = namespace file.%Core.import, [concrete] { +// CHECK:STDOUT: .Destroy = %Core.Destroy // CHECK:STDOUT: import Core//prelude // CHECK:STDOUT: import Core//prelude/... // CHECK:STDOUT: } +// CHECK:STDOUT: %Core.Destroy: type = import_ref Core//prelude/destroy, Destroy, loaded [concrete = constants.%Destroy.type] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -1050,20 +999,24 @@ fn CallReturnAbstract() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: name_binding_decl { -// CHECK:STDOUT: %l.patt: %pattern_type = value_binding_pattern l [concrete = constants.%l.patt] +// CHECK:STDOUT: %l.patt: %pattern_type.169 = value_binding_pattern l [concrete = constants.%l.patt] // CHECK:STDOUT: } -// CHECK:STDOUT: %.loc22_38.1: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct.a40] -// CHECK:STDOUT: %.loc22_39.1: %struct_type.base.f5e = struct_literal (%.loc22_38.1) [concrete = constants.%struct] +// CHECK:STDOUT: %.loc17_38.1: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct.a40] +// CHECK:STDOUT: %.loc17_39.1: %struct_type.base.f5e = struct_literal (%.loc17_38.1) [concrete = constants.%struct] // CHECK:STDOUT: %Derived.ref: type = name_ref Derived, file.%Derived.decl [concrete = constants.%Derived] -// CHECK:STDOUT: %.loc22_39.2: ref %Derived = temporary_storage -// CHECK:STDOUT: %.loc22_39.3: ref %.79f = class_element_access %.loc22_39.2, element0 -// CHECK:STDOUT: %.loc22_38.2: init %.79f to %.loc22_39.3 = class_init () [concrete = constants.%empty_struct.5e0] -// CHECK:STDOUT: %.loc22_39.4: init %.79f = converted %.loc22_38.1, %.loc22_38.2 [concrete = constants.%empty_struct.5e0] -// CHECK:STDOUT: %.loc22_39.5: init %Abstract = as_compatible %.loc22_39.4 [concrete = constants.%Abstract.val] -// CHECK:STDOUT: %.loc22_39.6: init %Derived to %.loc22_39.2 = class_init (%.loc22_39.5) [concrete = constants.%Derived.val] -// CHECK:STDOUT: %.loc22_41: init %Derived = converted %.loc22_39.1, %.loc22_39.6 [concrete = constants.%Derived.val] +// CHECK:STDOUT: %.loc17_39.2: ref %Derived = temporary_storage +// CHECK:STDOUT: %.loc17_39.3: ref %.79f = class_element_access %.loc17_39.2, element0 +// CHECK:STDOUT: %.loc17_38.2: init %.79f to %.loc17_39.3 = class_init () [concrete = constants.%empty_struct.5e0] +// CHECK:STDOUT: %.loc17_39.4: init %.79f = converted %.loc17_38.1, %.loc17_38.2 [concrete = constants.%empty_struct.5e0] +// CHECK:STDOUT: %.loc17_39.5: init %Abstract = as_compatible %.loc17_39.4 [concrete = constants.%Abstract.val] +// CHECK:STDOUT: %.loc17_39.6: init %Derived to %.loc17_39.2 = class_init (%.loc17_39.5) [concrete = constants.%Derived.val] +// CHECK:STDOUT: %.loc17_41.1: init %Derived = converted %.loc17_39.1, %.loc17_39.6 [concrete = constants.%Derived.val] +// CHECK:STDOUT: %.loc17_41.2: ref %Derived = temporary %.loc17_39.2, %.loc17_41.1 [concrete = constants.%.521] +// CHECK:STDOUT: %.loc17_41.3: ref %Abstract = class_element_access %.loc17_41.2, element0 [concrete = constants.%.5d3] +// CHECK:STDOUT: %.loc17_41.4: ref %Abstract = converted %.loc17_41.1, %.loc17_41.3 [concrete = constants.%.5d3] +// CHECK:STDOUT: %.loc17_41.5: %Abstract = acquire_value %.loc17_41.4 // CHECK:STDOUT: %Abstract.ref: type = name_ref Abstract, file.%Abstract.decl [concrete = constants.%Abstract] -// CHECK:STDOUT: %l: %Abstract = value_binding l, [concrete = ] +// CHECK:STDOUT: %l: %Abstract = value_binding l, %.loc17_41.5 // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: @@ -1128,3 +1081,61 @@ fn CallReturnAbstract() { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: --- fail_assign_to_abstract_ref.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %Abstract: type = class_type @Abstract [concrete] +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete] +// CHECK:STDOUT: %pattern_type.169: type = pattern_type %Abstract [concrete] +// CHECK:STDOUT: %a.param_patt: %pattern_type.169 = ref_param_pattern [concrete] +// CHECK:STDOUT: %a.patt: %pattern_type.169 = at_binding_pattern a, %a.param_patt [concrete] +// CHECK:STDOUT: %Assign.type: type = fn_type @Assign [concrete] +// CHECK:STDOUT: %Assign: %Assign.type = struct_value () [concrete] +// CHECK:STDOUT: %Copy.type: type = facet_type <@Copy> [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [concrete] { +// CHECK:STDOUT: .Copy = %Core.Copy +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/... +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.Copy: type = import_ref Core//prelude/copy, Copy, loaded [concrete = constants.%Copy.type] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .Abstract = %Abstract.decl +// CHECK:STDOUT: .Assign = %Assign.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %Abstract.decl: type = class_decl @Abstract [concrete = constants.%Abstract] {} {} +// CHECK:STDOUT: %Assign.decl: %Assign.type = fn_decl @Assign [concrete = constants.%Assign] { +// CHECK:STDOUT: %a.param_patt: %pattern_type.169 = ref_param_pattern [concrete = constants.%a.param_patt] +// CHECK:STDOUT: %a.patt: %pattern_type.169 = at_binding_pattern a, %a.param_patt [concrete = constants.%a.patt] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %a.param: ref %Abstract = ref_param call_param0 +// CHECK:STDOUT: %Abstract.ref: type = name_ref Abstract, file.%Abstract.decl [concrete = constants.%Abstract] +// CHECK:STDOUT: %a: ref %Abstract = ref_binding a, %a.param +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Abstract { +// CHECK:STDOUT: %complete_type: = complete_type_witness constants.%empty_struct_type [concrete = constants.%complete_type] +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Abstract +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Assign(%a.param: ref %Abstract) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref.loc14_3: ref %Abstract = name_ref a, %a +// CHECK:STDOUT: %a.ref.loc14_7: ref %Abstract = name_ref a, %a +// CHECK:STDOUT: %.loc14: %Abstract = acquire_value %a.ref.loc14_7 +// CHECK:STDOUT: assign %a.ref.loc14_3, +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/class/abstract/fail_abstract_in_struct.carbon b/toolchain/check/testdata/class/abstract/fail_abstract_in_struct.carbon index 53995e885d18..1650d09ba7f1 100644 --- a/toolchain/check/testdata/class/abstract/fail_abstract_in_struct.carbon +++ b/toolchain/check/testdata/class/abstract/fail_abstract_in_struct.carbon @@ -42,20 +42,13 @@ abstract class Abstract2 {} // CHECK:STDERR: var v: {.m2: Abstract2}; -// --- fail_todo_abstract_let.carbon +// --- abstract_let.carbon library "[[@TEST_NAME]]"; abstract class Abstract3 { } fn F(a: Abstract3) { - // CHECK:STDERR: fail_todo_abstract_let.carbon:[[@LINE+7]]:36: error: initialization of abstract type `{.m3: Abstract3}` [AbstractTypeInInit] - // CHECK:STDERR: let unused l: {.m3: Abstract3} = {.m3 = a}; - // CHECK:STDERR: ^~~~~~~~~ - // CHECK:STDERR: fail_todo_abstract_let.carbon:[[@LINE-7]]:1: note: uses class that was declared abstract here [ClassAbstractHere] - // CHECK:STDERR: abstract class Abstract3 { - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: let unused l: {.m3: Abstract3} = {.m3 = a}; } @@ -200,7 +193,7 @@ var v5: {.m: Abstract}; // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_abstract_let.carbon +// CHECK:STDOUT: --- abstract_let.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %Abstract3: type = class_type @Abstract3 [concrete] @@ -246,12 +239,14 @@ var v5: {.m: Abstract}; // CHECK:STDOUT: %l.patt: %pattern_type.2be = value_binding_pattern l [concrete = constants.%l.patt] // CHECK:STDOUT: } // CHECK:STDOUT: %a.ref: %Abstract3 = name_ref a, %a -// CHECK:STDOUT: %.loc14_44: %struct_type.m3.937 = struct_literal (%a.ref) -// CHECK:STDOUT: %.loc14_32: type = splice_block %struct_type.m3 [concrete = constants.%struct_type.m3.937] { -// CHECK:STDOUT: %Abstract3.ref.loc14: type = name_ref Abstract3, file.%Abstract3.decl [concrete = constants.%Abstract3] +// CHECK:STDOUT: %.loc7_44.1: %struct_type.m3.937 = struct_literal (%a.ref) +// CHECK:STDOUT: %struct: %struct_type.m3.937 = struct_value (%a.ref) +// CHECK:STDOUT: %.loc7_44.2: %struct_type.m3.937 = converted %.loc7_44.1, %struct +// CHECK:STDOUT: %.loc7_32: type = splice_block %struct_type.m3 [concrete = constants.%struct_type.m3.937] { +// CHECK:STDOUT: %Abstract3.ref.loc7: type = name_ref Abstract3, file.%Abstract3.decl [concrete = constants.%Abstract3] // CHECK:STDOUT: %struct_type.m3: type = struct_type {.m3: %Abstract3} [concrete = constants.%struct_type.m3.937] // CHECK:STDOUT: } -// CHECK:STDOUT: %l: %struct_type.m3.937 = value_binding l, [concrete = ] +// CHECK:STDOUT: %l: %struct_type.m3.937 = value_binding l, %.loc7_44.2 // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/class/abstract/fail_abstract_in_tuple.carbon b/toolchain/check/testdata/class/abstract/fail_abstract_in_tuple.carbon index 305f6618f61f..5955a8de3314 100644 --- a/toolchain/check/testdata/class/abstract/fail_abstract_in_tuple.carbon +++ b/toolchain/check/testdata/class/abstract/fail_abstract_in_tuple.carbon @@ -44,20 +44,13 @@ fn Var() { var unused v: (Abstract2,); } -// --- fail_todo_abstract_let.carbon +// --- abstract_let.carbon library "[[@TEST_NAME]]"; abstract class Abstract3 { } fn F(a: Abstract3) { - // CHECK:STDERR: fail_todo_abstract_let.carbon:[[@LINE+7]]:32: error: initialization of abstract type `(Abstract3,)` [AbstractTypeInInit] - // CHECK:STDERR: let unused l: (Abstract3,) = (a,); - // CHECK:STDERR: ^~~~ - // CHECK:STDERR: fail_todo_abstract_let.carbon:[[@LINE-7]]:1: note: uses class that was declared abstract here [ClassAbstractHere] - // CHECK:STDERR: abstract class Abstract3 { - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: let unused l: (Abstract3,) = (a,); } @@ -237,7 +230,7 @@ fn Var5() { // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_abstract_let.carbon +// CHECK:STDOUT: --- abstract_let.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %Abstract3: type = class_type @Abstract3 [concrete] @@ -294,13 +287,15 @@ fn Var5() { // CHECK:STDOUT: %l.patt: %pattern_type.ac0 = value_binding_pattern l [concrete = constants.%l.patt] // CHECK:STDOUT: } // CHECK:STDOUT: %a.ref: %Abstract3 = name_ref a, %a -// CHECK:STDOUT: %.loc14_35: %tuple.type.4cc = tuple_literal (%a.ref) -// CHECK:STDOUT: %.loc14_28.1: type = splice_block %.loc14_28.3 [concrete = constants.%tuple.type.4cc] { -// CHECK:STDOUT: %Abstract3.ref.loc14: type = name_ref Abstract3, file.%Abstract3.decl [concrete = constants.%Abstract3] -// CHECK:STDOUT: %.loc14_28.2: %tuple.type.85c = tuple_literal (%Abstract3.ref.loc14) [concrete = constants.%tuple] -// CHECK:STDOUT: %.loc14_28.3: type = converted %.loc14_28.2, constants.%tuple.type.4cc [concrete = constants.%tuple.type.4cc] +// CHECK:STDOUT: %.loc7_35.1: %tuple.type.4cc = tuple_literal (%a.ref) +// CHECK:STDOUT: %tuple: %tuple.type.4cc = tuple_value (%a.ref) +// CHECK:STDOUT: %.loc7_35.2: %tuple.type.4cc = converted %.loc7_35.1, %tuple +// CHECK:STDOUT: %.loc7_28.1: type = splice_block %.loc7_28.3 [concrete = constants.%tuple.type.4cc] { +// CHECK:STDOUT: %Abstract3.ref.loc7: type = name_ref Abstract3, file.%Abstract3.decl [concrete = constants.%Abstract3] +// CHECK:STDOUT: %.loc7_28.2: %tuple.type.85c = tuple_literal (%Abstract3.ref.loc7) [concrete = constants.%tuple] +// CHECK:STDOUT: %.loc7_28.3: type = converted %.loc7_28.2, constants.%tuple.type.4cc [concrete = constants.%tuple.type.4cc] // CHECK:STDOUT: } -// CHECK:STDOUT: %l: %tuple.type.4cc = value_binding l, [concrete = ] +// CHECK:STDOUT: %l: %tuple.type.4cc = value_binding l, %.loc7_35.2 // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interop/cpp/class/export/base.carbon b/toolchain/check/testdata/interop/cpp/class/export/base.carbon index 75e0cabd238a..921f15a9ad48 100644 --- a/toolchain/check/testdata/interop/cpp/class/export/base.carbon +++ b/toolchain/check/testdata/interop/cpp/class/export/base.carbon @@ -133,16 +133,6 @@ import Cpp; // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: abstract class Abstract { - // CHECK:STDERR: fail_todo_abstract_nonvirtual_dtor_but_virtual_fns.carbon:[[@LINE+10]]:3: error: initialization of abstract type `Abstract` [AbstractTypeInInit] - // CHECK:STDERR: abstract fn F(self); - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: fail_todo_abstract_nonvirtual_dtor_but_virtual_fns.carbon:[[@LINE-4]]:1: note: class was declared abstract here [ClassAbstractHere] - // CHECK:STDERR: abstract class Abstract { - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: fail_todo_abstract_nonvirtual_dtor_but_virtual_fns.carbon:[[@LINE+4]]:17: note: initializing function parameter [InCallToFunctionParam] - // CHECK:STDERR: abstract fn F(self); - // CHECK:STDERR: ^~~~ - // CHECK:STDERR: abstract fn F(self); }