From d491387a98907c3e1a9bfb1e96116dd97380758b Mon Sep 17 00:00:00 2001 From: David Blaikie Date: Sat, 12 Oct 2024 08:17:42 -0700 Subject: [PATCH] Disallow creating instances of abstract classes (#4381) A good first-pass, at least. (abstract adapters are rejected with this change, though pending further language design discussion) --------- Co-authored-by: Richard Smith --- toolchain/check/context.cpp | 40 +- toolchain/check/context.h | 17 +- toolchain/check/convert.cpp | 59 +- toolchain/check/function.cpp | 9 +- toolchain/check/handle_binding_pattern.cpp | 32 +- toolchain/check/handle_class.cpp | 26 +- .../array/fail_incomplete_element.carbon | 2 +- .../class/cross_package_import.carbon | 2 +- .../check/testdata/class/fail_abstract.carbon | 787 ++++++++++++++++-- .../testdata/class/fail_import_misuses.carbon | 2 +- .../testdata/class/fail_incomplete.carbon | 2 +- .../no_prelude/fail_nested_incomplete.carbon | 2 +- .../tuple/fail_nested_incomplete.carbon | 2 +- toolchain/diagnostics/diagnostic_emitter.h | 27 +- toolchain/diagnostics/diagnostic_kind.def | 6 +- 15 files changed, 870 insertions(+), 145 deletions(-) diff --git a/toolchain/check/context.cpp b/toolchain/check/context.cpp index a92d4275aba6..ca2ce6a93c3e 100644 --- a/toolchain/check/context.cpp +++ b/toolchain/check/context.cpp @@ -195,6 +195,17 @@ auto Context::DiagnoseNameNotFound(SemIRLoc loc, SemIR::NameId name_id) emitter_->Emit(loc, NameNotFound, name_id); } +auto Context::NoteAbstractClass(SemIR::ClassId class_id, + DiagnosticBuilder& builder) -> void { + const auto& class_info = classes().Get(class_id); + CARBON_CHECK( + class_info.inheritance_kind == SemIR::Class::InheritanceKind::Abstract, + "Class is not abstract"); + CARBON_DIAGNOSTIC(ClassAbstractHere, Note, + "class was declared abstract here"); + builder.Note(class_info.definition_id, ClassAbstractHere); +} + auto Context::NoteIncompleteClass(SemIR::ClassId class_id, DiagnosticBuilder& builder) -> void { const auto& class_info = classes().Get(class_id); @@ -1128,8 +1139,33 @@ class TypeCompleter { } // namespace auto Context::TryToCompleteType(SemIR::TypeId type_id, - BuildDiagnosticFn diagnoser) -> bool { - return TypeCompleter(*this, diagnoser).Complete(type_id); + BuildDiagnosticFn diagnoser, + BuildDiagnosticFn abstract_diagnoser) -> bool { + if (!TypeCompleter(*this, diagnoser).Complete(type_id)) { + return false; + } + + if (!abstract_diagnoser) { + return true; + } + + if (auto class_type = types().TryGetAs(type_id)) { + auto& class_info = classes().Get(class_type->class_id); + if (class_info.inheritance_kind != + SemIR::Class::InheritanceKind::Abstract) { + return true; + } + + auto builder = abstract_diagnoser(); + if (!builder) { + return false; + } + NoteAbstractClass(class_type->class_id, builder); + builder.Emit(); + return false; + } + + return true; } auto Context::TryToDefineType(SemIR::TypeId type_id, diff --git a/toolchain/check/context.h b/toolchain/check/context.h index ae97e88a1a2b..82f57fb0ec79 100644 --- a/toolchain/check/context.h +++ b/toolchain/check/context.h @@ -235,6 +235,10 @@ class Context { auto NoteIncompleteClass(SemIR::ClassId class_id, DiagnosticBuilder& builder) -> void; + // Adds a note to a diagnostic explaining that a class is abstract. + auto NoteAbstractClass(SemIR::ClassId class_id, DiagnosticBuilder& builder) + -> void; + // Adds a note to a diagnostic explaining that an interface is not defined. auto NoteUndefinedInterface(SemIR::InterfaceId interface_id, DiagnosticBuilder& builder) -> void; @@ -319,7 +323,9 @@ class Context { // if a `diagnoser` is provided. The builder it returns will be annotated to // describe the reason why the type is not complete. auto TryToCompleteType(SemIR::TypeId type_id, - BuildDiagnosticFn diagnoser = nullptr) -> bool; + BuildDiagnosticFn diagnoser = nullptr, + BuildDiagnosticFn abstract_diagnoser = nullptr) + -> bool; // Attempts to complete and define the type `type_id`. Returns `true` if the // type is defined, or `false` if no definition is available. A defined type @@ -333,11 +339,12 @@ class Context { // Returns the type `type_id` as a complete type, or produces an incomplete // type error and returns an error type. This is a convenience wrapper around // TryToCompleteType. `diagnoser` must not be null. - auto AsCompleteType(SemIR::TypeId type_id, BuildDiagnosticFn diagnoser) + auto AsCompleteType(SemIR::TypeId type_id, BuildDiagnosticFn diagnoser, + BuildDiagnosticFn abstract_diagnoser = nullptr) -> SemIR::TypeId { - CARBON_CHECK(diagnoser); - return TryToCompleteType(type_id, diagnoser) ? type_id - : SemIR::TypeId::Error; + return TryToCompleteType(type_id, diagnoser, abstract_diagnoser) + ? type_id + : SemIR::TypeId::Error; } // Returns whether `type_id` represents a facet type. diff --git a/toolchain/check/convert.cpp b/toolchain/check/convert.cpp index 928a36bf4dd3..5e90ef7da750 100644 --- a/toolchain/check/convert.cpp +++ b/toolchain/check/convert.cpp @@ -533,15 +533,7 @@ static auto ConvertStructToClass(Context& context, SemIR::StructType src_type, ConversionTarget target) -> SemIR::InstId { PendingBlock target_block(context); auto& dest_class_info = context.classes().Get(dest_type.class_id); - if (dest_class_info.inheritance_kind == SemIR::Class::Abstract) { - CARBON_DIAGNOSTIC(ConstructionOfAbstractClass, Error, - "cannot construct instance of abstract class; " - "consider using `partial {0}` instead", - TypeIdAsRawType); - context.emitter().Emit(value_id, ConstructionOfAbstractClass, - target.type_id); - return SemIR::InstId::BuiltinError; - } + CARBON_CHECK(dest_class_info.inheritance_kind != SemIR::Class::Abstract); auto object_repr_id = dest_class_info.GetObjectRepr(context.sem_ir(), dest_type.specific_id); if (object_repr_id == SemIR::TypeId::Error) { @@ -937,23 +929,38 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id, } // We can only perform initialization for complete types. - if (!context.TryToCompleteType(target.type_id, [&] { - CARBON_DIAGNOSTIC(IncompleteTypeInInit, Error, - "initialization of incomplete type {0}", - SemIR::TypeId); - CARBON_DIAGNOSTIC(IncompleteTypeInValueConversion, Error, - "forming value of incomplete type {0}", - SemIR::TypeId); - CARBON_DIAGNOSTIC(IncompleteTypeInConversion, Error, - "invalid use of incomplete type {0}", SemIR::TypeId); - return context.emitter().Build(loc_id, - target.is_initializer() - ? IncompleteTypeInInit - : target.kind == ConversionTarget::Value - ? IncompleteTypeInValueConversion - : IncompleteTypeInConversion, - target.type_id); - })) { + if (!context.TryToCompleteType( + target.type_id, + [&] { + CARBON_DIAGNOSTIC(IncompleteTypeInInit, Error, + "initialization of incomplete type {0}", + SemIR::TypeId); + CARBON_DIAGNOSTIC(IncompleteTypeInValueConversion, Error, + "forming value of incomplete type {0}", + SemIR::TypeId); + CARBON_DIAGNOSTIC(IncompleteTypeInConversion, Error, + "invalid use of incomplete type {0}", + SemIR::TypeId); + assert(!target.is_initializer()); + assert(target.kind == ConversionTarget::Value); + return context.emitter().Build( + loc_id, + target.is_initializer() ? IncompleteTypeInInit + : target.kind == ConversionTarget::Value + ? IncompleteTypeInValueConversion + : IncompleteTypeInConversion, + target.type_id); + }, + [&] { + CARBON_DIAGNOSTIC(AbstractTypeInInit, Error, + "initialization of abstract type {0}", + SemIR::TypeId); + if (!target.is_initializer()) { + return context.emitter().BuildSuppressed(); + } + return context.emitter().Build(loc_id, AbstractTypeInInit, + target.type_id); + })) { return SemIR::InstId::BuiltinError; } diff --git a/toolchain/check/function.cpp b/toolchain/check/function.cpp index ec6a31f5349a..c92c9b6df6f8 100644 --- a/toolchain/check/function.cpp +++ b/toolchain/check/function.cpp @@ -81,11 +81,18 @@ auto CheckFunctionReturnType(Context& context, SemIRLoc loc, return context.emitter().Build(loc, IncompleteTypeInFunctionReturnType, return_info.type_id); }; + auto diagnose_abstract_return_type = [&] { + CARBON_DIAGNOSTIC(AbstractTypeInFunctionReturnType, Error, + "function returns abstract type {0}", SemIR::TypeId); + return context.emitter().Build(loc, AbstractTypeInFunctionReturnType, + return_info.type_id); + }; // TODO: Consider suppressing the diagnostic if we've already diagnosed a // definition or call to this function. if (context.TryToCompleteType(return_info.type_id, - diagnose_incomplete_return_type)) { + diagnose_incomplete_return_type, + diagnose_abstract_return_type)) { return_info = SemIR::ReturnTypeInfo::ForFunction(context.sem_ir(), function, specific_id); } diff --git a/toolchain/check/handle_binding_pattern.cpp b/toolchain/check/handle_binding_pattern.cpp index 7e2343cab2dc..9c25bf4fd797 100644 --- a/toolchain/check/handle_binding_pattern.cpp +++ b/toolchain/check/handle_binding_pattern.cpp @@ -100,16 +100,28 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id, // A `var` declaration at class scope introduces a field. auto parent_class_decl = context.GetCurrentScopeAs(); - cast_type_id = context.AsCompleteType(cast_type_id, [&] { - CARBON_DIAGNOSTIC(IncompleteTypeInVarDecl, Error, - "{0} has incomplete type {1}", llvm::StringLiteral, - InstIdAsType); - return context.emitter().Build(type_node, IncompleteTypeInVarDecl, - parent_class_decl - ? llvm::StringLiteral("Field") - : llvm::StringLiteral("Variable"), - cast_type_inst_id); - }); + cast_type_id = context.AsCompleteType( + cast_type_id, + [&] { + CARBON_DIAGNOSTIC(IncompleteTypeInVarDecl, Error, + "{0} has incomplete type {1}", + llvm::StringLiteral, SemIR::TypeId); + return context.emitter().Build( + type_node, IncompleteTypeInVarDecl, + parent_class_decl ? llvm::StringLiteral("field") + : llvm::StringLiteral("variable"), + cast_type_id); + }, + [&] { + CARBON_DIAGNOSTIC(AbstractTypeInVarDecl, Error, + "{0} has abstract type {1}", llvm::StringLiteral, + SemIR::TypeId); + return context.emitter().Build( + type_node, AbstractTypeInVarDecl, + parent_class_decl ? llvm::StringLiteral("field") + : llvm::StringLiteral("variable"), + cast_type_id); + }); if (parent_class_decl) { CARBON_CHECK(context_node_kind == Parse::NodeKind::VariableIntroducer, "`returned var` at class scope"); diff --git a/toolchain/check/handle_class.cpp b/toolchain/check/handle_class.cpp index 1e6e044f107a..5defa16b87a4 100644 --- a/toolchain/check/handle_class.cpp +++ b/toolchain/check/handle_class.cpp @@ -383,14 +383,24 @@ auto HandleParseNode(Context& context, Parse::AdaptDeclId node_id) -> bool { return true; } - auto [adapted_type_inst_id, adapted_type_id] = - ExprAsType(context, node_id, adapted_type_expr_id); - adapted_type_id = context.AsCompleteType(adapted_type_id, [&] { - CARBON_DIAGNOSTIC(IncompleteTypeInAdaptDecl, Error, - "adapted type {0} is an incomplete type", InstIdAsType); - return context.emitter().Build(node_id, IncompleteTypeInAdaptDecl, - adapted_type_inst_id); - }); + auto adapted_type_id = + ExprAsType(context, node_id, adapted_type_expr_id).type_id; + adapted_type_id = context.AsCompleteType( + adapted_type_id, + [&] { + CARBON_DIAGNOSTIC(IncompleteTypeInAdaptDecl, Error, + "adapted type {0} is an incomplete type", + SemIR::TypeId); + return context.emitter().Build(node_id, IncompleteTypeInAdaptDecl, + adapted_type_id); + }, + [&] { + CARBON_DIAGNOSTIC(AbstractTypeInAdaptDecl, Error, + "adapted type {0} is an abstract type", + SemIR::TypeId); + return context.emitter().Build(node_id, AbstractTypeInAdaptDecl, + adapted_type_id); + }); // Build a SemIR representation for the declaration. class_info.adapt_id = context.AddInst( diff --git a/toolchain/check/testdata/array/fail_incomplete_element.carbon b/toolchain/check/testdata/array/fail_incomplete_element.carbon index bb2821ecbe3d..cf5ed6ea984c 100644 --- a/toolchain/check/testdata/array/fail_incomplete_element.carbon +++ b/toolchain/check/testdata/array/fail_incomplete_element.carbon @@ -10,7 +10,7 @@ class Incomplete; -// CHECK:STDERR: fail_incomplete_element.carbon:[[@LINE+6]]:8: error: Variable has incomplete type `[Incomplete; 1]` +// CHECK:STDERR: fail_incomplete_element.carbon:[[@LINE+6]]:8: error: variable has incomplete type `[Incomplete; 1]` // CHECK:STDERR: var a: [Incomplete; 1]; // CHECK:STDERR: ^~~~~~~~~~~~~~~ // CHECK:STDERR: fail_incomplete_element.carbon:[[@LINE-5]]:1: note: class was forward declared here diff --git a/toolchain/check/testdata/class/cross_package_import.carbon b/toolchain/check/testdata/class/cross_package_import.carbon index a76979ad86a9..23f0f62dbf17 100644 --- a/toolchain/check/testdata/class/cross_package_import.carbon +++ b/toolchain/check/testdata/class/cross_package_import.carbon @@ -48,7 +48,7 @@ library "[[@TEST_NAME]]"; import Other library "other_extern"; -// CHECK:STDERR: fail_extern.carbon:[[@LINE+8]]:8: error: Variable has incomplete type `C` +// CHECK:STDERR: fail_extern.carbon:[[@LINE+8]]:8: error: variable has incomplete type `C` // CHECK:STDERR: var c: Other.C = {}; // CHECK:STDERR: ^~~~~~~ // CHECK:STDERR: fail_extern.carbon:[[@LINE-5]]:1: in import diff --git a/toolchain/check/testdata/class/fail_abstract.carbon b/toolchain/check/testdata/class/fail_abstract.carbon index 676de7cd67f3..e2424d6aec44 100644 --- a/toolchain/check/testdata/class/fail_abstract.carbon +++ b/toolchain/check/testdata/class/fail_abstract.carbon @@ -8,10 +8,90 @@ // TIP: To dump output, run: // TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/fail_abstract.carbon +// --- fail_abstract_field.carbon + +library "[[@TEST_NAME]]"; + +abstract class Abstract { +} + +class Contains { + // CHECK:STDERR: fail_abstract_field.carbon:[[@LINE+7]]:10: error: field has abstract type `Abstract` + // CHECK:STDERR: var a: Abstract; + // CHECK:STDERR: ^~~~~~~~ + // CHECK:STDERR: fail_abstract_field.carbon:[[@LINE-7]]:1: note: class was declared abstract here + // CHECK:STDERR: abstract class Abstract { + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + var a: Abstract; +} + +// --- fail_abstract_var.carbon + +library "[[@TEST_NAME]]"; + +abstract class Abstract { +} + +fn Var() { + // CHECK:STDERR: fail_abstract_var.carbon:[[@LINE+7]]:10: error: variable has abstract type `Abstract` + // CHECK:STDERR: var v: Abstract; + // CHECK:STDERR: ^~~~~~~~ + // CHECK:STDERR: fail_abstract_var.carbon:[[@LINE-7]]:1: note: class was declared abstract here + // CHECK:STDERR: abstract class Abstract { + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + var v: Abstract; +} + +// --- abstract_let.carbon + +library "[[@TEST_NAME]]"; + +abstract class Abstract { +} + +fn F(a: Abstract) { + let l: Abstract = a; +} + +// --- fail_abstract_adapter.carbon + +library "[[@TEST_NAME]]"; + +abstract class Abstract { +} + +class Adapter { + // TODO(#4387): This should probably be valid + // CHECK:STDERR: fail_abstract_adapter.carbon:[[@LINE+7]]:3: error: adapted type `Abstract` is an abstract type + // CHECK:STDERR: adapt Abstract; + // CHECK:STDERR: ^~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_abstract_adapter.carbon:[[@LINE-8]]:1: note: class was declared abstract here + // CHECK:STDERR: abstract class Abstract { + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + adapt Abstract; +} + +// --- define_and_call_abstract_param.carbon + +library "[[@TEST_NAME]]"; + +abstract class Abstract { +} + +fn Param(a: Abstract); + +fn Call(p: Abstract) { + Param(p); +} + +// --- fail_todo_return_nonabstract_derived.carbon + +library "[[@TEST_NAME]]"; -// --- fail_todo_rejects_valid_abstract_subobject_construction.carbon abstract class Abstract { - var a: i32; } class Derived { @@ -22,57 +102,396 @@ class Derived { fn Make() -> Derived { // TODO: This should be valid, and should construct an instance of `partial Abstract` as the base. - // CHECK:STDERR: fail_todo_rejects_valid_abstract_subobject_construction.carbon:[[@LINE+6]]:19: error: cannot construct instance of abstract class; consider using `partial Abstract` instead + // CHECK:STDERR: fail_todo_return_nonabstract_derived.carbon:[[@LINE+7]]:10: error: initialization of abstract type `Abstract` // CHECK:STDERR: return {.base = {.a = 1}, .d = 7}; - // CHECK:STDERR: ^~~~~~~~ - // CHECK:STDERR: - // CHECK:STDERR: fail_todo_rejects_valid_abstract_subobject_access.carbon: error: `Main//default` previously provided by `fail_todo_rejects_valid_abstract_subobject_construction.carbon` + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_todo_return_nonabstract_derived.carbon:[[@LINE-14]]:1: note: class was declared abstract here + // CHECK:STDERR: abstract class Abstract { + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: return {.base = {.a = 1}, .d = 7}; } -// --- fail_todo_rejects_valid_abstract_subobject_access.carbon +// --- fail_return_abstract.carbon -// CHECK:STDERR: fail_todo_rejects_valid_abstract_subobject_access.carbon:[[@LINE+6]]:14: error: name `Derived` not found -// CHECK:STDERR: fn Access(d: Derived) -> (i32, i32) { -// CHECK:STDERR: ^~~~~~~ -// CHECK:STDERR: -// CHECK:STDERR: fail_abstract_decl.carbon: error: `Main//default` previously provided by `fail_todo_rejects_valid_abstract_subobject_construction.carbon` -// CHECK:STDERR: -fn Access(d: Derived) -> (i32, i32) { - return (d.d, d.base.a); +library "[[@TEST_NAME]]"; + +abstract class Abstract { } -// --- fail_abstract_decl.carbon -// CHECK:STDERR: fail_abstract_decl.carbon:[[@LINE+3]]:1: error: `abstract` not allowed on `class` declaration, only definition -// CHECK:STDERR: abstract class AbstractDecl; -// CHECK:STDERR: ^~~~~~~~ -abstract class AbstractDecl; +class Derived { + extend base: Abstract; -// CHECK:STDOUT: --- fail_todo_rejects_valid_abstract_subobject_construction.carbon + var d: i32; +} + +fn Return(a: Abstract) -> Abstract { + // FIXME: Seems like this would be better off failing with "function returns abstract type" here instead of this \/ + // CHECK:STDERR: fail_return_abstract.carbon:[[@LINE+7]]:3: error: initialization of abstract type `Abstract` + // CHECK:STDERR: return a; + // CHECK:STDERR: ^~~~~~~~~ + // CHECK:STDERR: fail_return_abstract.carbon:[[@LINE-14]]:1: note: class was declared abstract here + // CHECK:STDERR: abstract class Abstract { + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + return a; +} + +// --- access_abstract_subobject.carbon + +library "[[@TEST_NAME]]"; + +abstract class Abstract { + var a: i32; +} + +class Derived { + extend base: Abstract; + + var d: i32; +} + +fn Access(d: Derived) -> i32 { + return d.base.a; +} + +// --- abstract_let_temporary.carbon + +library "[[@TEST_NAME]]"; + +abstract class Abstract { +} + +fn F() { + let l: Abstract = {}; +} + +// --- fail_call_abstract_return.carbon + +library "[[@TEST_NAME]]"; + +abstract class Abstract { +} + +fn ReturnAbstract() -> Abstract; + +fn CallReturnAbstract() { + // CHECK:STDERR: fail_call_abstract_return.carbon:[[@LINE+9]]:3: error: function returns abstract type `Abstract` + // CHECK:STDERR: ReturnAbstract(); + // CHECK:STDERR: ^~~~~~~~~~~~~~ + // CHECK:STDERR: fail_call_abstract_return.carbon:[[@LINE-9]]:1: note: class was declared abstract here + // CHECK:STDERR: abstract class Abstract { + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_call_abstract_return.carbon:[[@LINE-9]]:21: note: return type declared here + // CHECK:STDERR: fn ReturnAbstract() -> Abstract; + // CHECK:STDERR: ^~~~~~~~~~~ + ReturnAbstract(); +} + +// CHECK:STDOUT: --- fail_abstract_field.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %Abstract: type = class_type @Abstract [template] -// CHECK:STDOUT: %Int32.type: type = fn_type @Int32 [template] -// CHECK:STDOUT: %.1: type = tuple_type () [template] -// CHECK:STDOUT: %Int32: %Int32.type = struct_value () [template] -// CHECK:STDOUT: %.2: type = unbound_element_type %Abstract, i32 [template] -// CHECK:STDOUT: %.3: type = struct_type {.a: i32} [template] -// CHECK:STDOUT: %.4: = complete_type_witness %.3 [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: = complete_type_witness %.1 [template] +// CHECK:STDOUT: %Contains: type = class_type @Contains [template] +// CHECK:STDOUT: %.3: type = tuple_type () [template] +// CHECK:STDOUT: %.4: type = ptr_type %.1 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/operators +// CHECK:STDOUT: import Core//prelude/types +// CHECK:STDOUT: import Core//prelude/operators/arithmetic +// CHECK:STDOUT: import Core//prelude/operators/as +// CHECK:STDOUT: import Core//prelude/operators/bitwise +// CHECK:STDOUT: import Core//prelude/operators/comparison +// CHECK:STDOUT: import Core//prelude/types/bool +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .Abstract = %Abstract.decl +// CHECK:STDOUT: .Contains = %Contains.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %Abstract.decl: type = class_decl @Abstract [template = constants.%Abstract] {} {} +// CHECK:STDOUT: %Contains.decl: type = class_decl @Contains [template = constants.%Contains] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Abstract { +// CHECK:STDOUT: %.loc5: = complete_type_witness %.1 [template = constants.%.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Abstract +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Contains { +// CHECK:STDOUT: %Abstract.ref: type = name_ref Abstract, file.%Abstract.decl [template = constants.%Abstract] +// CHECK:STDOUT: %.loc15: = field_decl a, element0 [template] +// CHECK:STDOUT: %.loc16: = complete_type_witness [template = ] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Contains +// CHECK:STDOUT: .a = %.loc15 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_abstract_var.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %Abstract: type = class_type @Abstract [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: = complete_type_witness %.1 [template] +// CHECK:STDOUT: %Var.type: type = fn_type @Var [template] +// CHECK:STDOUT: %.3: type = tuple_type () [template] +// CHECK:STDOUT: %Var: %Var.type = struct_value () [template] +// CHECK:STDOUT: %.4: type = ptr_type %.1 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/operators +// CHECK:STDOUT: import Core//prelude/types +// CHECK:STDOUT: import Core//prelude/operators/arithmetic +// CHECK:STDOUT: import Core//prelude/operators/as +// CHECK:STDOUT: import Core//prelude/operators/bitwise +// CHECK:STDOUT: import Core//prelude/operators/comparison +// CHECK:STDOUT: import Core//prelude/types/bool +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .Abstract = %Abstract.decl +// CHECK:STDOUT: .Var = %Var.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %Abstract.decl: type = class_decl @Abstract [template = constants.%Abstract] {} {} +// CHECK:STDOUT: %Var.decl: %Var.type = fn_decl @Var [template = constants.%Var] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Abstract { +// CHECK:STDOUT: %.loc5: = complete_type_witness %.1 [template = constants.%.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Abstract +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Var() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Abstract.ref: type = name_ref Abstract, file.%Abstract.decl [template = constants.%Abstract] +// CHECK:STDOUT: %v.var: ref = var v +// CHECK:STDOUT: %v: ref = bind_name v, %v.var +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- abstract_let.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %Abstract: type = class_type @Abstract [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: = complete_type_witness %.1 [template] +// CHECK:STDOUT: %F.type: type = fn_type @F [template] +// CHECK:STDOUT: %.3: type = tuple_type () [template] +// CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: %.4: type = ptr_type %.1 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/operators +// CHECK:STDOUT: import Core//prelude/types +// CHECK:STDOUT: import Core//prelude/operators/arithmetic +// CHECK:STDOUT: import Core//prelude/operators/as +// CHECK:STDOUT: import Core//prelude/operators/bitwise +// CHECK:STDOUT: import Core//prelude/operators/comparison +// CHECK:STDOUT: import Core//prelude/types/bool +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .Abstract = %Abstract.decl +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %Abstract.decl: type = class_decl @Abstract [template = constants.%Abstract] {} {} +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] { +// CHECK:STDOUT: %a.patt: %Abstract = binding_pattern a +// CHECK:STDOUT: } { +// CHECK:STDOUT: %Abstract.ref.loc7: type = name_ref Abstract, file.%Abstract.decl [template = constants.%Abstract] +// CHECK:STDOUT: %a.param: %Abstract = param a, runtime_param0 +// CHECK:STDOUT: %a: %Abstract = bind_name a, %a.param +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Abstract { +// CHECK:STDOUT: %.loc5: = complete_type_witness %.1 [template = constants.%.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Abstract +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F(%a: %Abstract) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Abstract.ref.loc8: type = name_ref Abstract, file.%Abstract.decl [template = constants.%Abstract] +// CHECK:STDOUT: %a.ref: %Abstract = name_ref a, %a +// CHECK:STDOUT: %l: %Abstract = bind_name l, +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_abstract_adapter.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %Abstract: type = class_type @Abstract [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: = complete_type_witness %.1 [template] +// CHECK:STDOUT: %Adapter: type = class_type @Adapter [template] +// CHECK:STDOUT: %.3: type = tuple_type () [template] +// CHECK:STDOUT: %.4: type = ptr_type %.1 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/operators +// CHECK:STDOUT: import Core//prelude/types +// CHECK:STDOUT: import Core//prelude/operators/arithmetic +// CHECK:STDOUT: import Core//prelude/operators/as +// CHECK:STDOUT: import Core//prelude/operators/bitwise +// CHECK:STDOUT: import Core//prelude/operators/comparison +// CHECK:STDOUT: import Core//prelude/types/bool +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .Abstract = %Abstract.decl +// CHECK:STDOUT: .Adapter = %Adapter.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %Abstract.decl: type = class_decl @Abstract [template = constants.%Abstract] {} {} +// CHECK:STDOUT: %Adapter.decl: type = class_decl @Adapter [template = constants.%Adapter] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Abstract { +// CHECK:STDOUT: %.loc5: = complete_type_witness %.1 [template = constants.%.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Abstract +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Adapter { +// CHECK:STDOUT: %Abstract.ref: type = name_ref Abstract, file.%Abstract.decl [template = constants.%Abstract] +// CHECK:STDOUT: adapt_decl +// CHECK:STDOUT: %.loc17: = complete_type_witness [template = ] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Adapter +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- define_and_call_abstract_param.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %Abstract: type = class_type @Abstract [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: = complete_type_witness %.1 [template] +// CHECK:STDOUT: %Param.type: type = fn_type @Param [template] +// CHECK:STDOUT: %.3: type = tuple_type () [template] +// CHECK:STDOUT: %Param: %Param.type = struct_value () [template] +// CHECK:STDOUT: %Call.type: type = fn_type @Call [template] +// CHECK:STDOUT: %Call: %Call.type = struct_value () [template] +// CHECK:STDOUT: %.4: type = ptr_type %.1 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/operators +// CHECK:STDOUT: import Core//prelude/types +// CHECK:STDOUT: import Core//prelude/operators/arithmetic +// CHECK:STDOUT: import Core//prelude/operators/as +// CHECK:STDOUT: import Core//prelude/operators/bitwise +// CHECK:STDOUT: import Core//prelude/operators/comparison +// CHECK:STDOUT: import Core//prelude/types/bool +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .Abstract = %Abstract.decl +// CHECK:STDOUT: .Param = %Param.decl +// CHECK:STDOUT: .Call = %Call.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %Abstract.decl: type = class_decl @Abstract [template = constants.%Abstract] {} {} +// CHECK:STDOUT: %Param.decl: %Param.type = fn_decl @Param [template = constants.%Param] { +// CHECK:STDOUT: %a.patt: %Abstract = binding_pattern a +// CHECK:STDOUT: } { +// CHECK:STDOUT: %Abstract.ref: type = name_ref Abstract, file.%Abstract.decl [template = constants.%Abstract] +// CHECK:STDOUT: %a.param: %Abstract = param a, runtime_param0 +// CHECK:STDOUT: %a: %Abstract = bind_name a, %a.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %Call.decl: %Call.type = fn_decl @Call [template = constants.%Call] { +// CHECK:STDOUT: %p.patt: %Abstract = binding_pattern p +// CHECK:STDOUT: } { +// CHECK:STDOUT: %Abstract.ref: type = name_ref Abstract, file.%Abstract.decl [template = constants.%Abstract] +// CHECK:STDOUT: %p.param: %Abstract = param p, runtime_param0 +// CHECK:STDOUT: %p: %Abstract = bind_name p, %p.param +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Abstract { +// CHECK:STDOUT: %.loc5: = complete_type_witness %.1 [template = constants.%.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Abstract +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Param(%a: %Abstract); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Call(%p: %Abstract) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Param.ref: %Param.type = name_ref Param, file.%Param.decl [template = constants.%Param] +// CHECK:STDOUT: %p.ref: %Abstract = name_ref p, %p +// CHECK:STDOUT: %Param.call: init %.3 = call %Param.ref() [template = ] +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_return_nonabstract_derived.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %Abstract: type = class_type @Abstract [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: = complete_type_witness %.1 [template] // CHECK:STDOUT: %Derived: type = class_type @Derived [template] -// CHECK:STDOUT: %.5: type = ptr_type %.3 [template] -// CHECK:STDOUT: %.6: type = unbound_element_type %Derived, %Abstract [template] -// CHECK:STDOUT: %.7: type = unbound_element_type %Derived, i32 [template] -// CHECK:STDOUT: %.8: type = struct_type {.base: %Abstract, .d: i32} [template] -// CHECK:STDOUT: %.9: = complete_type_witness %.8 [template] +// CHECK:STDOUT: %.3: type = tuple_type () [template] +// CHECK:STDOUT: %.4: type = ptr_type %.1 [template] +// CHECK:STDOUT: %.5: type = unbound_element_type %Derived, %Abstract [template] +// CHECK:STDOUT: %Int32.type: type = fn_type @Int32 [template] +// CHECK:STDOUT: %Int32: %Int32.type = struct_value () [template] +// CHECK:STDOUT: %.6: type = unbound_element_type %Derived, i32 [template] +// CHECK:STDOUT: %.7: type = struct_type {.base: %Abstract, .d: i32} [template] +// CHECK:STDOUT: %.8: = complete_type_witness %.7 [template] // CHECK:STDOUT: %Make.type: type = fn_type @Make [template] // CHECK:STDOUT: %Make: %Make.type = struct_value () [template] -// CHECK:STDOUT: %.10: type = struct_type {.base: %.5, .d: i32} [template] -// CHECK:STDOUT: %.11: type = ptr_type %.10 [template] -// CHECK:STDOUT: %.12: type = ptr_type %.8 [template] -// CHECK:STDOUT: %.13: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.9: type = struct_type {.base: %.4, .d: i32} [template] +// CHECK:STDOUT: %.10: type = ptr_type %.9 [template] +// CHECK:STDOUT: %.11: type = ptr_type %.7 [template] +// CHECK:STDOUT: %.12: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.13: type = struct_type {.a: i32} [template] // CHECK:STDOUT: %.14: i32 = int_literal 7 [template] -// CHECK:STDOUT: %.15: type = struct_type {.base: %.3, .d: i32} [template] +// CHECK:STDOUT: %.15: type = struct_type {.base: %.13, .d: i32} [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -107,30 +526,25 @@ abstract class AbstractDecl; // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: class @Abstract { -// CHECK:STDOUT: %int.make_type_32: init type = call constants.%Int32() [template = i32] -// CHECK:STDOUT: %.loc2_10.1: type = value_of_initializer %int.make_type_32 [template = i32] -// CHECK:STDOUT: %.loc2_10.2: type = converted %int.make_type_32, %.loc2_10.1 [template = i32] -// CHECK:STDOUT: %.loc2_8: %.2 = field_decl a, element0 [template] -// CHECK:STDOUT: %.loc3: = complete_type_witness %.3 [template = constants.%.4] +// CHECK:STDOUT: %.loc5: = complete_type_witness %.1 [template = constants.%.2] // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = constants.%Abstract -// CHECK:STDOUT: .a = %.loc2_8 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: class @Derived { // CHECK:STDOUT: %Abstract.ref: type = name_ref Abstract, file.%Abstract.decl [template = constants.%Abstract] -// CHECK:STDOUT: %.loc6: %.6 = base_decl %Abstract, element0 [template] +// CHECK:STDOUT: %.loc8: %.5 = base_decl %Abstract, element0 [template] // CHECK:STDOUT: %int.make_type_32: init type = call constants.%Int32() [template = i32] -// CHECK:STDOUT: %.loc8_10.1: type = value_of_initializer %int.make_type_32 [template = i32] -// CHECK:STDOUT: %.loc8_10.2: type = converted %int.make_type_32, %.loc8_10.1 [template = i32] -// CHECK:STDOUT: %.loc8_8: %.7 = field_decl d, element1 [template] -// CHECK:STDOUT: %.loc9: = complete_type_witness %.8 [template = constants.%.9] +// CHECK:STDOUT: %.loc10_10.1: type = value_of_initializer %int.make_type_32 [template = i32] +// CHECK:STDOUT: %.loc10_10.2: type = converted %int.make_type_32, %.loc10_10.1 [template = i32] +// CHECK:STDOUT: %.loc10_8: %.6 = field_decl d, element1 [template] +// CHECK:STDOUT: %.loc11: = complete_type_witness %.7 [template = constants.%.8] // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = constants.%Derived -// CHECK:STDOUT: .base = %.loc6 -// CHECK:STDOUT: .d = %.loc8_8 +// CHECK:STDOUT: .base = %.loc8 +// CHECK:STDOUT: .d = %.loc10_8 // CHECK:STDOUT: extend name_scope2 // CHECK:STDOUT: } // CHECK:STDOUT: @@ -138,24 +552,30 @@ abstract class AbstractDecl; // CHECK:STDOUT: // CHECK:STDOUT: fn @Make() -> %return: %Derived { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %.loc19_25: i32 = int_literal 1 [template = constants.%.13] -// CHECK:STDOUT: %.loc19_26: %.3 = struct_literal (%.loc19_25) -// CHECK:STDOUT: %.loc19_34: i32 = int_literal 7 [template = constants.%.14] -// CHECK:STDOUT: %.loc19_35: %.15 = struct_literal (%.loc19_26, %.loc19_34) +// CHECK:STDOUT: %.loc22_25: i32 = int_literal 1 [template = constants.%.12] +// CHECK:STDOUT: %.loc22_26: %.13 = struct_literal (%.loc22_25) +// CHECK:STDOUT: %.loc22_34: i32 = int_literal 7 [template = constants.%.14] +// CHECK:STDOUT: %.loc22_35: %.15 = struct_literal (%.loc22_26, %.loc22_34) // CHECK:STDOUT: return to %return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_rejects_valid_abstract_subobject_access.carbon +// CHECK:STDOUT: --- fail_return_abstract.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { +// CHECK:STDOUT: %Abstract: type = class_type @Abstract [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: = complete_type_witness %.1 [template] +// CHECK:STDOUT: %Derived: type = class_type @Derived [template] +// CHECK:STDOUT: %.3: type = tuple_type () [template] +// CHECK:STDOUT: %.4: type = ptr_type %.1 [template] +// CHECK:STDOUT: %.5: type = unbound_element_type %Derived, %Abstract [template] // CHECK:STDOUT: %Int32.type: type = fn_type @Int32 [template] -// CHECK:STDOUT: %.1: type = tuple_type () [template] // CHECK:STDOUT: %Int32: %Int32.type = struct_value () [template] -// CHECK:STDOUT: %.2: type = tuple_type (type, type) [template] -// CHECK:STDOUT: %.3: type = tuple_type (i32, i32) [template] -// CHECK:STDOUT: %Access.type: type = fn_type @Access [template] -// CHECK:STDOUT: %Access: %Access.type = struct_value () [template] -// CHECK:STDOUT: %.4: type = ptr_type %.3 [template] +// CHECK:STDOUT: %.6: type = unbound_element_type %Derived, i32 [template] +// CHECK:STDOUT: %.7: type = struct_type {.base: %Abstract, .d: i32} [template] +// CHECK:STDOUT: %.8: = complete_type_witness %.7 [template] +// CHECK:STDOUT: %Return.type: type = fn_type @Return [template] +// CHECK:STDOUT: %Return: %Return.type = struct_value () [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -176,41 +596,164 @@ abstract class AbstractDecl; // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace [template] { // CHECK:STDOUT: .Core = imports.%Core -// CHECK:STDOUT: .Access = %Access.decl +// CHECK:STDOUT: .Abstract = %Abstract.decl +// CHECK:STDOUT: .Derived = %Derived.decl +// CHECK:STDOUT: .Return = %Return.decl // CHECK:STDOUT: } // CHECK:STDOUT: %Core.import = import Core -// CHECK:STDOUT: %Access.decl: %Access.type = fn_decl @Access [template = constants.%Access] { -// CHECK:STDOUT: %d.patt: = binding_pattern d +// CHECK:STDOUT: %Abstract.decl: type = class_decl @Abstract [template = constants.%Abstract] {} {} +// CHECK:STDOUT: %Derived.decl: type = class_decl @Derived [template = constants.%Derived] {} {} +// CHECK:STDOUT: %Return.decl: %Return.type = fn_decl @Return [template = constants.%Return] { +// CHECK:STDOUT: %a.patt: %Abstract = binding_pattern a // CHECK:STDOUT: } { -// CHECK:STDOUT: %Derived.ref: = name_ref Derived, [template = ] -// CHECK:STDOUT: %d.param: = param d, runtime_param0 -// CHECK:STDOUT: %d: = bind_name d, %d.param -// CHECK:STDOUT: %int.make_type_32.loc8_27: init type = call constants.%Int32() [template = i32] -// CHECK:STDOUT: %int.make_type_32.loc8_32: init type = call constants.%Int32() [template = i32] -// CHECK:STDOUT: %.loc8_35.1: %.2 = tuple_literal (%int.make_type_32.loc8_27, %int.make_type_32.loc8_32) -// CHECK:STDOUT: %.loc8_35.2: type = value_of_initializer %int.make_type_32.loc8_27 [template = i32] -// CHECK:STDOUT: %.loc8_35.3: type = converted %int.make_type_32.loc8_27, %.loc8_35.2 [template = i32] -// CHECK:STDOUT: %.loc8_35.4: type = value_of_initializer %int.make_type_32.loc8_32 [template = i32] -// CHECK:STDOUT: %.loc8_35.5: type = converted %int.make_type_32.loc8_32, %.loc8_35.4 [template = i32] -// CHECK:STDOUT: %.loc8_35.6: type = converted %.loc8_35.1, constants.%.3 [template = constants.%.3] -// CHECK:STDOUT: %return: ref %.3 = var +// CHECK:STDOUT: %Abstract.ref.loc13_14: type = name_ref Abstract, file.%Abstract.decl [template = constants.%Abstract] +// CHECK:STDOUT: %a.param: %Abstract = param a, runtime_param0 +// CHECK:STDOUT: %a: %Abstract = bind_name a, %a.param +// CHECK:STDOUT: %Abstract.ref.loc13_27: type = name_ref Abstract, file.%Abstract.decl [template = constants.%Abstract] +// CHECK:STDOUT: %return: ref %Abstract = var // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: class @Abstract { +// CHECK:STDOUT: %.loc5: = complete_type_witness %.1 [template = constants.%.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Abstract +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Derived { +// CHECK:STDOUT: %Abstract.ref: type = name_ref Abstract, file.%Abstract.decl [template = constants.%Abstract] +// CHECK:STDOUT: %.loc8: %.5 = base_decl %Abstract, element0 [template] +// CHECK:STDOUT: %int.make_type_32: init type = call constants.%Int32() [template = i32] +// CHECK:STDOUT: %.loc10_10.1: type = value_of_initializer %int.make_type_32 [template = i32] +// CHECK:STDOUT: %.loc10_10.2: type = converted %int.make_type_32, %.loc10_10.1 [template = i32] +// CHECK:STDOUT: %.loc10_8: %.6 = field_decl d, element1 [template] +// CHECK:STDOUT: %.loc11: = complete_type_witness %.7 [template = constants.%.8] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Derived +// CHECK:STDOUT: .base = %.loc8 +// CHECK:STDOUT: .d = %.loc10_8 +// CHECK:STDOUT: extend name_scope2 +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @Access(%d: ) -> %return: %.3 { +// CHECK:STDOUT: fn @Return(%a: %Abstract) -> %return: %Abstract { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %d.ref.loc9_11: = name_ref d, %d -// CHECK:STDOUT: %d.ref.loc9_16: = name_ref d, %d -// CHECK:STDOUT: %.loc9: = tuple_literal (, ) +// CHECK:STDOUT: %a.ref: %Abstract = name_ref a, %a // CHECK:STDOUT: return to %return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_abstract_decl.carbon +// CHECK:STDOUT: --- access_abstract_subobject.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { -// CHECK:STDOUT: %AbstractDecl: type = class_type @AbstractDecl [template] +// CHECK:STDOUT: %Abstract: type = class_type @Abstract [template] +// CHECK:STDOUT: %Int32.type: type = fn_type @Int32 [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %Int32: %Int32.type = struct_value () [template] +// CHECK:STDOUT: %.2: type = unbound_element_type %Abstract, i32 [template] +// CHECK:STDOUT: %.3: type = struct_type {.a: i32} [template] +// CHECK:STDOUT: %.4: = complete_type_witness %.3 [template] +// CHECK:STDOUT: %Derived: type = class_type @Derived [template] +// CHECK:STDOUT: %.5: type = ptr_type %.3 [template] +// CHECK:STDOUT: %.6: type = unbound_element_type %Derived, %Abstract [template] +// CHECK:STDOUT: %.7: type = unbound_element_type %Derived, i32 [template] +// CHECK:STDOUT: %.8: type = struct_type {.base: %Abstract, .d: i32} [template] +// CHECK:STDOUT: %.9: = complete_type_witness %.8 [template] +// CHECK:STDOUT: %Access.type: type = fn_type @Access [template] +// CHECK:STDOUT: %Access: %Access.type = struct_value () [template] +// CHECK:STDOUT: %.10: type = struct_type {.base: %.5, .d: i32} [template] +// CHECK:STDOUT: %.11: type = ptr_type %.10 [template] +// CHECK:STDOUT: %.12: type = ptr_type %.8 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { +// CHECK:STDOUT: .Int32 = %import_ref +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/operators +// CHECK:STDOUT: import Core//prelude/types +// CHECK:STDOUT: import Core//prelude/operators/arithmetic +// CHECK:STDOUT: import Core//prelude/operators/as +// CHECK:STDOUT: import Core//prelude/operators/bitwise +// CHECK:STDOUT: import Core//prelude/operators/comparison +// CHECK:STDOUT: import Core//prelude/types/bool +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref: %Int32.type = import_ref Core//prelude/types, inst+4, loaded [template = constants.%Int32] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// 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 [template = constants.%Abstract] {} {} +// CHECK:STDOUT: %Derived.decl: type = class_decl @Derived [template = constants.%Derived] {} {} +// CHECK:STDOUT: %Access.decl: %Access.type = fn_decl @Access [template = constants.%Access] { +// CHECK:STDOUT: %d.patt: %Derived = binding_pattern d +// CHECK:STDOUT: } { +// CHECK:STDOUT: %Derived.ref: type = name_ref Derived, file.%Derived.decl [template = constants.%Derived] +// CHECK:STDOUT: %d.param: %Derived = param d, runtime_param0 +// CHECK:STDOUT: %d: %Derived = bind_name d, %d.param +// CHECK:STDOUT: %int.make_type_32: init type = call constants.%Int32() [template = i32] +// CHECK:STDOUT: %.loc14_26.1: type = value_of_initializer %int.make_type_32 [template = i32] +// CHECK:STDOUT: %.loc14_26.2: type = converted %int.make_type_32, %.loc14_26.1 [template = i32] +// CHECK:STDOUT: %return: ref i32 = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Abstract { +// CHECK:STDOUT: %int.make_type_32: init type = call constants.%Int32() [template = i32] +// CHECK:STDOUT: %.loc5_10.1: type = value_of_initializer %int.make_type_32 [template = i32] +// CHECK:STDOUT: %.loc5_10.2: type = converted %int.make_type_32, %.loc5_10.1 [template = i32] +// CHECK:STDOUT: %.loc5_8: %.2 = field_decl a, element0 [template] +// CHECK:STDOUT: %.loc6: = complete_type_witness %.3 [template = constants.%.4] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Abstract +// CHECK:STDOUT: .a = %.loc5_8 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Derived { +// CHECK:STDOUT: %Abstract.ref: type = name_ref Abstract, file.%Abstract.decl [template = constants.%Abstract] +// CHECK:STDOUT: %.loc9: %.6 = base_decl %Abstract, element0 [template] +// CHECK:STDOUT: %int.make_type_32: init type = call constants.%Int32() [template = i32] +// CHECK:STDOUT: %.loc11_10.1: type = value_of_initializer %int.make_type_32 [template = i32] +// CHECK:STDOUT: %.loc11_10.2: type = converted %int.make_type_32, %.loc11_10.1 [template = i32] +// CHECK:STDOUT: %.loc11_8: %.7 = field_decl d, element1 [template] +// CHECK:STDOUT: %.loc12: = complete_type_witness %.8 [template = constants.%.9] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Derived +// CHECK:STDOUT: .base = %.loc9 +// CHECK:STDOUT: .d = %.loc11_8 +// CHECK:STDOUT: extend name_scope2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Access(%d: %Derived) -> i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %d.ref: %Derived = name_ref d, %d +// CHECK:STDOUT: %base.ref: %.6 = name_ref base, @Derived.%.loc9 [template = @Derived.%.loc9] +// CHECK:STDOUT: %.loc15: ref %Abstract = class_element_access %d.ref, element0 +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- abstract_let_temporary.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %Abstract: type = class_type @Abstract [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: = complete_type_witness %.1 [template] +// CHECK:STDOUT: %F.type: type = fn_type @F [template] +// CHECK:STDOUT: %.3: type = tuple_type () [template] +// CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: %.4: type = ptr_type %.1 [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -229,11 +772,85 @@ abstract class AbstractDecl; // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace [template] { // CHECK:STDOUT: .Core = imports.%Core -// CHECK:STDOUT: .AbstractDecl = %AbstractDecl.decl +// CHECK:STDOUT: .Abstract = %Abstract.decl +// CHECK:STDOUT: .F = %F.decl // CHECK:STDOUT: } // CHECK:STDOUT: %Core.import = import Core -// CHECK:STDOUT: %AbstractDecl.decl: type = class_decl @AbstractDecl [template = constants.%AbstractDecl] {} {} +// CHECK:STDOUT: %Abstract.decl: type = class_decl @Abstract [template = constants.%Abstract] {} {} +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] {} {} // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: class @AbstractDecl; +// CHECK:STDOUT: class @Abstract { +// CHECK:STDOUT: %.loc5: = complete_type_witness %.1 [template = constants.%.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Abstract +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Abstract.ref: type = name_ref Abstract, file.%Abstract.decl [template = constants.%Abstract] +// CHECK:STDOUT: %.loc8: %.1 = struct_literal () +// CHECK:STDOUT: %l: %Abstract = bind_name l, +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_call_abstract_return.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %Abstract: type = class_type @Abstract [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: = complete_type_witness %.1 [template] +// CHECK:STDOUT: %ReturnAbstract.type: type = fn_type @ReturnAbstract [template] +// CHECK:STDOUT: %.3: type = tuple_type () [template] +// CHECK:STDOUT: %ReturnAbstract: %ReturnAbstract.type = struct_value () [template] +// CHECK:STDOUT: %CallReturnAbstract.type: type = fn_type @CallReturnAbstract [template] +// CHECK:STDOUT: %CallReturnAbstract: %CallReturnAbstract.type = struct_value () [template] +// CHECK:STDOUT: %.4: type = ptr_type %.1 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/operators +// CHECK:STDOUT: import Core//prelude/types +// CHECK:STDOUT: import Core//prelude/operators/arithmetic +// CHECK:STDOUT: import Core//prelude/operators/as +// CHECK:STDOUT: import Core//prelude/operators/bitwise +// CHECK:STDOUT: import Core//prelude/operators/comparison +// CHECK:STDOUT: import Core//prelude/types/bool +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .Abstract = %Abstract.decl +// CHECK:STDOUT: .ReturnAbstract = %ReturnAbstract.decl +// CHECK:STDOUT: .CallReturnAbstract = %CallReturnAbstract.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %Abstract.decl: type = class_decl @Abstract [template = constants.%Abstract] {} {} +// CHECK:STDOUT: %ReturnAbstract.decl: %ReturnAbstract.type = fn_decl @ReturnAbstract [template = constants.%ReturnAbstract] {} { +// CHECK:STDOUT: %Abstract.ref: type = name_ref Abstract, file.%Abstract.decl [template = constants.%Abstract] +// CHECK:STDOUT: %return: ref %Abstract = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %CallReturnAbstract.decl: %CallReturnAbstract.type = fn_decl @CallReturnAbstract [template = constants.%CallReturnAbstract] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Abstract { +// CHECK:STDOUT: %.loc5: = complete_type_witness %.1 [template = constants.%.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Abstract +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @ReturnAbstract() -> %Abstract; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @CallReturnAbstract() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %ReturnAbstract.ref: %ReturnAbstract.type = name_ref ReturnAbstract, file.%ReturnAbstract.decl [template = constants.%ReturnAbstract] +// CHECK:STDOUT: %ReturnAbstract.call: init = call %ReturnAbstract.ref() +// CHECK:STDOUT: return +// CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/class/fail_import_misuses.carbon b/toolchain/check/testdata/class/fail_import_misuses.carbon index 46b2a9885d22..9f24c12c7425 100644 --- a/toolchain/check/testdata/class/fail_import_misuses.carbon +++ b/toolchain/check/testdata/class/fail_import_misuses.carbon @@ -34,7 +34,7 @@ import library "a"; class Empty { } -// CHECK:STDERR: fail_b.carbon:[[@LINE+7]]:8: error: Variable has incomplete type `Incomplete` +// CHECK:STDERR: fail_b.carbon:[[@LINE+7]]:8: error: variable has incomplete type `Incomplete` // CHECK:STDERR: var a: Incomplete; // CHECK:STDERR: ^~~~~~~~~~ // CHECK:STDERR: fail_b.carbon:[[@LINE-16]]:1: in import diff --git a/toolchain/check/testdata/class/fail_incomplete.carbon b/toolchain/check/testdata/class/fail_incomplete.carbon index 04f1e1dc59b0..8fd8b1141edb 100644 --- a/toolchain/check/testdata/class/fail_incomplete.carbon +++ b/toolchain/check/testdata/class/fail_incomplete.carbon @@ -30,7 +30,7 @@ fn CallClassFunction() { Class.Function(); } -// CHECK:STDERR: fail_incomplete.carbon:[[@LINE+7]]:17: error: Variable has incomplete type `Class` +// CHECK:STDERR: fail_incomplete.carbon:[[@LINE+7]]:17: error: variable has incomplete type `Class` // CHECK:STDERR: var global_var: Class; // CHECK:STDERR: ^~~~~ // CHECK:STDERR: fail_incomplete.carbon:[[@LINE-25]]:1: note: class was forward declared here diff --git a/toolchain/check/testdata/struct/no_prelude/fail_nested_incomplete.carbon b/toolchain/check/testdata/struct/no_prelude/fail_nested_incomplete.carbon index d31b0b8bfe8e..2a2937fde0e6 100644 --- a/toolchain/check/testdata/struct/no_prelude/fail_nested_incomplete.carbon +++ b/toolchain/check/testdata/struct/no_prelude/fail_nested_incomplete.carbon @@ -10,7 +10,7 @@ class Incomplete; -// CHECK:STDERR: fail_nested_incomplete.carbon:[[@LINE+6]]:8: error: Variable has incomplete type `{.a: Incomplete}` +// CHECK:STDERR: fail_nested_incomplete.carbon:[[@LINE+6]]:8: error: variable has incomplete type `{.a: Incomplete}` // CHECK:STDERR: var s: {.a: Incomplete}; // CHECK:STDERR: ^~~~~~~~~~~~~~~~ // CHECK:STDERR: fail_nested_incomplete.carbon:[[@LINE-5]]:1: note: class was forward declared here diff --git a/toolchain/check/testdata/tuple/fail_nested_incomplete.carbon b/toolchain/check/testdata/tuple/fail_nested_incomplete.carbon index 21d7182529a2..4d08476530bb 100644 --- a/toolchain/check/testdata/tuple/fail_nested_incomplete.carbon +++ b/toolchain/check/testdata/tuple/fail_nested_incomplete.carbon @@ -10,7 +10,7 @@ class Incomplete; -// CHECK:STDERR: fail_nested_incomplete.carbon:[[@LINE+6]]:8: error: Variable has incomplete type `(i32, Incomplete)` +// CHECK:STDERR: fail_nested_incomplete.carbon:[[@LINE+6]]:8: error: variable has incomplete type `(i32, Incomplete)` // CHECK:STDERR: var t: (i32, Incomplete); // CHECK:STDERR: ^~~~~~~~~~~~~~~~~ // CHECK:STDERR: fail_nested_incomplete.carbon:[[@LINE-5]]:1: note: class was forward declared here diff --git a/toolchain/diagnostics/diagnostic_emitter.h b/toolchain/diagnostics/diagnostic_emitter.h index 05e0dc9ed1f2..95e6fd69f0df 100644 --- a/toolchain/diagnostics/diagnostic_emitter.h +++ b/toolchain/diagnostics/diagnostic_emitter.h @@ -63,6 +63,9 @@ class DiagnosticEmitter { auto Note(LocT loc, const Internal::DiagnosticBase& diagnostic_base, Internal::NoTypeDeduction... args) -> DiagnosticBuilder& { + if (!emitter_) { + return *this; + } CARBON_CHECK(diagnostic_base.Level == DiagnosticLevel::Note || diagnostic_base.Level == DiagnosticLevel::LocationInfo, "{0}", static_cast(diagnostic_base.Level)); @@ -74,12 +77,20 @@ class DiagnosticEmitter { // For the expected usage see the builder API: `DiagnosticEmitter::Build`. template auto Emit() -> void { + if (!emitter_) { + return; + } for (auto annotate_fn : emitter_->annotate_fns_) { annotate_fn(*this); } emitter_->consumer_->HandleDiagnostic(std::move(diagnostic_)); } + // Returns true if this DiagnosticBuilder may emit a diagnostic. Can be used + // to avoid excess work computing notes, etc, if no diagnostic is going to + // be emitted anyway. + explicit operator bool() { return emitter_; } + private: friend class DiagnosticEmitter; @@ -93,12 +104,19 @@ class DiagnosticEmitter { CARBON_CHECK(diagnostic_base.Level != DiagnosticLevel::Note); } + // Create a null `DiagnosticBuilder` that will not emit anything. Notes will + // be silently ignored. + DiagnosticBuilder() : emitter_(nullptr) {} + // Adds a message to the diagnostic, handling conversion of the location and // arguments. template auto AddMessage(LocT loc, const Internal::DiagnosticBase& diagnostic_base, llvm::SmallVector args) -> void { + if (!emitter_) { + return; + } AddMessageWithDiagnosticLoc( emitter_->converter_->ConvertLoc( loc, @@ -117,7 +135,10 @@ class DiagnosticEmitter { auto AddMessageWithDiagnosticLoc( DiagnosticLoc loc, const Internal::DiagnosticBase& diagnostic_base, - llvm::SmallVector args) { + llvm::SmallVector args) -> void { + if (!emitter_) { + return; + } diagnostic_.messages.emplace_back(DiagnosticMessage{ .kind = diagnostic_base.Kind, .level = diagnostic_base.Level, @@ -183,6 +204,10 @@ class DiagnosticEmitter { {MakeAny(args)...}); } + // Create a null `DiagnosticBuilder` that will not emit anything. Notes will + // be silently ignored. + auto BuildSuppressed() -> DiagnosticBuilder { return DiagnosticBuilder(); } + private: // Converts an argument to llvm::Any for storage, handling input to storage // type conversion when needed. diff --git a/toolchain/diagnostics/diagnostic_kind.def b/toolchain/diagnostics/diagnostic_kind.def index 47ed671815a5..5542d306c3fd 100644 --- a/toolchain/diagnostics/diagnostic_kind.def +++ b/toolchain/diagnostics/diagnostic_kind.def @@ -217,11 +217,11 @@ CARBON_DIAGNOSTIC_KIND(AdaptWithVirtualHere) CARBON_DIAGNOSTIC_KIND(BaseDeclRepeated) CARBON_DIAGNOSTIC_KIND(BaseIsFinal) CARBON_DIAGNOSTIC_KIND(BaseMissingExtend) +CARBON_DIAGNOSTIC_KIND(ClassAbstractHere) CARBON_DIAGNOSTIC_KIND(ClassForwardDeclaredHere) CARBON_DIAGNOSTIC_KIND(ClassSpecificDeclOutsideClass) CARBON_DIAGNOSTIC_KIND(ClassSpecificDeclPrevious) CARBON_DIAGNOSTIC_KIND(ClassIncompleteWithinDefinition) -CARBON_DIAGNOSTIC_KIND(ConstructionOfAbstractClass) // Deduction. CARBON_DIAGNOSTIC_KIND(DeductionIncomplete) @@ -274,6 +274,10 @@ CARBON_DIAGNOSTIC_KIND(NameAmbiguousDueToExtend) CARBON_DIAGNOSTIC_KIND(NameNotFound) CARBON_DIAGNOSTIC_KIND(NoPeriodSelfForDesignator) +CARBON_DIAGNOSTIC_KIND(AbstractTypeInAdaptDecl) +CARBON_DIAGNOSTIC_KIND(AbstractTypeInFunctionReturnType) +CARBON_DIAGNOSTIC_KIND(AbstractTypeInInit) +CARBON_DIAGNOSTIC_KIND(AbstractTypeInVarDecl) CARBON_DIAGNOSTIC_KIND(AddrOfEphemeralRef) CARBON_DIAGNOSTIC_KIND(AddrOfNonRef) CARBON_DIAGNOSTIC_KIND(AddrOnNonSelfParam)