Initial scaffolding for building a witness table for an impl. (#3743)

Add an instruction to hold the witness table, along with a corresponding
type to keep things simpler. Add `check/impl.{h,cpp}` to house the new
logic. No checking of impls against interfaces is performed yet.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
This commit is contained in:
Richard Smith
2024-03-07 23:10:14 +00:00
committed by GitHub
co-authored by Jon Ross-Perkins
parent 2424ea16ea
commit abf23ae7fe
27 changed files with 216 additions and 29 deletions
+15
View File
@@ -102,6 +102,7 @@ cc_library(
deps = [
":context",
":function",
":impl",
":import",
":interface",
"//common:check",
@@ -145,6 +146,20 @@ cc_library(
],
)
cc_library(
name = "impl",
srcs = ["impl.cpp"],
hdrs = ["impl.h"],
deps = [
":context",
"//common:check",
"//toolchain/sem_ir:file",
"//toolchain/sem_ir:ids",
"//toolchain/sem_ir:inst",
"//toolchain/sem_ir:inst_kind",
],
)
cc_library(
name = "import",
srcs = ["import.cpp"],
+3 -1
View File
@@ -699,6 +699,7 @@ class TypeCompleter {
case SemIR::BuiltinKind::NamespaceType:
case SemIR::BuiltinKind::FunctionType:
case SemIR::BuiltinKind::BoundMethodType:
case SemIR::BuiltinKind::WitnessType:
return MakeCopyValueRepr(type_id);
case SemIR::BuiltinKind::StringType:
@@ -842,10 +843,11 @@ class TypeCompleter {
case SemIR::FunctionDecl::Kind:
case SemIR::ImplDecl::Kind:
case SemIR::Import::Kind:
case SemIR::ImportRefUnused::Kind:
case SemIR::InitializeFrom::Kind:
case SemIR::InterfaceDecl::Kind:
case SemIR::InterfaceWitness::Kind:
case SemIR::IntLiteral::Kind:
case SemIR::ImportRefUnused::Kind:
case SemIR::NameRef::Kind:
case SemIR::Namespace::Kind:
case SemIR::Param::Kind:
+3
View File
@@ -329,6 +329,9 @@ auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst)
return RebuildIfFieldsAreConstant(context, inst,
&SemIR::BoundMethod::object_id,
&SemIR::BoundMethod::function_id);
case SemIR::InterfaceWitness::Kind:
return RebuildIfFieldsAreConstant(context, inst,
&SemIR::InterfaceWitness::table_id);
case SemIR::PointerType::Kind:
return RebuildIfFieldsAreConstant(context, inst,
&SemIR::PointerType::pointee_id);
+7 -3
View File
@@ -5,6 +5,7 @@
#include "toolchain/check/context.h"
#include "toolchain/check/convert.h"
#include "toolchain/check/decl_name_stack.h"
#include "toolchain/check/impl.h"
#include "toolchain/check/modifiers.h"
#include "toolchain/parse/typed_nodes.h"
#include "toolchain/sem_ir/ids.h"
@@ -270,11 +271,14 @@ auto HandleImplDefinition(Context& context,
Parse::ImplDefinitionId /*parse_node*/) -> bool {
auto impl_id =
context.node_stack().Pop<Parse::NodeKind::ImplDefinitionStart>();
if (!context.impls().Get(impl_id).is_defined()) {
context.impls().Get(impl_id).witness_id =
BuildImplWitness(context, impl_id);
}
context.inst_block_stack().Pop();
context.decl_name_stack().PopScope();
// The impl is now fully defined.
context.impls().Get(impl_id).defined = true;
return true;
}
+37
View File
@@ -0,0 +1,37 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "toolchain/check/impl.h"
#include "toolchain/check/context.h"
#include "toolchain/sem_ir/ids.h"
#include "toolchain/sem_ir/impl.h"
namespace Carbon::Check {
auto BuildImplWitness(Context& context, SemIR::ImplId impl_id)
-> SemIR::InstId {
auto& impl = context.impls().Get(impl_id);
CARBON_CHECK(impl.is_being_defined());
// TODO: Handle non-interface constraints.
auto interface_type =
context.types().TryGetAs<SemIR::InterfaceType>(impl.constraint_id);
if (!interface_type) {
context.TODO(context.insts().GetParseNode(impl.definition_id),
"impl as non-interface");
return SemIR::InstId::BuiltinError;
}
auto interface_id = interface_type->interface_id;
// TODO: Form the witness table.
auto table_id = context.inst_blocks().Add({});
return context.AddInst(SemIR::InterfaceWitness{
context.GetBuiltinType(SemIR::BuiltinKind::WitnessType), interface_id,
table_id});
}
} // namespace Carbon::Check
+18
View File
@@ -0,0 +1,18 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef CARBON_TOOLCHAIN_CHECK_IMPL_H_
#define CARBON_TOOLCHAIN_CHECK_IMPL_H_
#include "toolchain/check/context.h"
#include "toolchain/sem_ir/ids.h"
namespace Carbon::Check {
// Builds and returns a witness for the impl `impl_id`.
auto BuildImplWitness(Context& context, SemIR::ImplId impl_id) -> SemIR::InstId;
} // namespace Carbon::Check
#endif // CARBON_TOOLCHAIN_CHECK_IMPL_H_
+2
View File
@@ -28,6 +28,7 @@
// CHECK:STDOUT: instFunctionType: {kind: ImportRefUsed, arg0: ir0, arg1: instFunctionType, type: typeTypeType}
// CHECK:STDOUT: instBoundMethodType: {kind: ImportRefUsed, arg0: ir0, arg1: instBoundMethodType, type: typeTypeType}
// CHECK:STDOUT: instNamespaceType: {kind: ImportRefUsed, arg0: ir0, arg1: instNamespaceType, type: typeTypeType}
// CHECK:STDOUT: instWitnessType: {kind: ImportRefUsed, arg0: ir0, arg1: instWitnessType, type: typeTypeType}
// CHECK:STDOUT: inst+0: {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type0}
// CHECK:STDOUT: constant_values:
// CHECK:STDOUT: instTypeType: template instTypeType
@@ -39,6 +40,7 @@
// CHECK:STDOUT: instFunctionType: template instFunctionType
// CHECK:STDOUT: instBoundMethodType: template instBoundMethodType
// CHECK:STDOUT: instNamespaceType: template instNamespaceType
// CHECK:STDOUT: instWitnessType: template instWitnessType
// CHECK:STDOUT: inst+0: template inst+0
// CHECK:STDOUT: inst_blocks:
// CHECK:STDOUT: empty: {}
+3
View File
@@ -18,6 +18,7 @@ impl i32 as Simple {
// CHECK:STDOUT: %.1: type = interface_type @Simple [template]
// CHECK:STDOUT: %.2: type = assoc_entity_type @Simple, <function> [template]
// CHECK:STDOUT: %.3: <associated <function> in Simple> = assoc_entity element0, @Simple.%F [template]
// CHECK:STDOUT: %.4: <witness> = interface_witness @Simple, () [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -43,9 +44,11 @@ impl i32 as Simple {
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl: i32 as Simple {
// CHECK:STDOUT: %F: <function> = fn_decl @F.2 [template] {}
// CHECK:STDOUT: %.1: <witness> = interface_witness @Simple, () [template = constants.%.4]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .F = %F
// CHECK:STDOUT: witness = %.1
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F.1();
+7 -1
View File
@@ -14,6 +14,7 @@ impl i32 as Empty {
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.1: type = interface_type @Empty [template]
// CHECK:STDOUT: %.2: <witness> = interface_witness @Empty, () [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -34,5 +35,10 @@ impl i32 as Empty {
// CHECK:STDOUT: witness = ()
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl: i32 as Empty {}
// CHECK:STDOUT: impl @impl: i32 as Empty {
// CHECK:STDOUT: %.1: <witness> = interface_witness @Empty, () [template = constants.%.2]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: witness = %.1
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -12,9 +12,12 @@ interface GenericInterface(T:! type) {
}
class C {
// CHECK:STDERR: fail_extend_impl_forall.carbon:[[@LINE+6]]:3: ERROR: Cannot `extend` a parameterized `impl`.
// CHECK:STDERR: fail_extend_impl_forall.carbon:[[@LINE+9]]:3: ERROR: Cannot `extend` a parameterized `impl`.
// CHECK:STDERR: extend impl forall [T:! type] as GenericInterface(T) {
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: fail_extend_impl_forall.carbon:[[@LINE+6]]:3: ERROR: Semantics TODO: `impl as non-interface`.
// CHECK:STDERR: extend impl forall [T:! type] as GenericInterface(T) {
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR: fail_extend_impl_forall.carbon:[[@LINE+3]]:36: ERROR: Value of type `type` is not callable.
// CHECK:STDERR: extend impl forall [T:! type] as GenericInterface(T) {
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~
@@ -62,21 +65,22 @@ class C {
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl: C as <error> {
// CHECK:STDOUT: %F: <function> = fn_decl @F.2 [template] {
// CHECK:STDOUT: %T.ref: type = name_ref T, @C.%T.loc21_23.2 [symbolic = @C.%T.loc21_23.2]
// CHECK:STDOUT: %x.loc22_10.1: T = param x
// CHECK:STDOUT: %x.loc22_10.2: T = bind_name x, %x.loc22_10.1
// CHECK:STDOUT: %T.ref: type = name_ref T, @C.%T.loc24_23.2 [symbolic = @C.%T.loc24_23.2]
// CHECK:STDOUT: %x.loc25_10.1: T = param x
// CHECK:STDOUT: %x.loc25_10.2: T = bind_name x, %x.loc25_10.1
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .F = %F
// CHECK:STDOUT: witness = <error>
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: impl_decl @impl {
// CHECK:STDOUT: %T.loc21_23.1: type = param T
// CHECK:STDOUT: %T.loc21_23.2: type = bind_symbolic_name T, %T.loc21_23.1 [symbolic]
// CHECK:STDOUT: %T.loc24_23.1: type = param T
// CHECK:STDOUT: %T.loc24_23.2: type = bind_symbolic_name T, %T.loc24_23.1 [symbolic]
// CHECK:STDOUT: %GenericInterface.ref: type = name_ref GenericInterface, file.%GenericInterface.decl [template = constants.%.1]
// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc21_23.2 [symbolic = %T.loc21_23.2]
// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc24_23.2 [symbolic = %T.loc24_23.2]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
@@ -86,7 +90,7 @@ class C {
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F.1(@GenericInterface.%x.loc11_8.2: T);
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F.2(@impl.%x.loc22_10.2: T) {
// CHECK:STDOUT: fn @F.2(@impl.%x.loc25_10.2: T) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: return
// CHECK:STDOUT: }
@@ -15,6 +15,7 @@ extend impl i32 as I {}
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.1: type = interface_type @I [template]
// CHECK:STDOUT: %.2: <witness> = interface_witness @I, () [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -35,5 +36,10 @@ extend impl i32 as I {}
// CHECK:STDOUT: witness = ()
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl: i32 as I {}
// CHECK:STDOUT: impl @impl: i32 as I {
// CHECK:STDOUT: %.1: <witness> = interface_witness @I, () [template = constants.%.2]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: witness = %.1
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -38,7 +38,8 @@ class E {
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.1: type = interface_type @I [template]
// CHECK:STDOUT: %C: type = class_type @C [template]
// CHECK:STDOUT: %.2: type = struct_type {} [template]
// CHECK:STDOUT: %.2: <witness> = interface_witness @I, () [template]
// CHECK:STDOUT: %.3: type = struct_type {} [template]
// CHECK:STDOUT: %D: type = class_type @D [template]
// CHECK:STDOUT: %E: type = class_type @E [template]
// CHECK:STDOUT: }
@@ -64,11 +65,21 @@ class E {
// CHECK:STDOUT: witness = ()
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl.1: i32 as I {}
// CHECK:STDOUT: impl @impl.1: i32 as I {
// CHECK:STDOUT: %.1: <witness> = interface_witness @I, () [template = constants.%.2]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: witness = %.1
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl.2: D as I;
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl.3: E as I {}
// CHECK:STDOUT: impl @impl.3: E as I {
// CHECK:STDOUT: %.1: <witness> = interface_witness @I, () [template = constants.%.2]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: witness = %.1
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
// CHECK:STDOUT: impl_decl @impl.1 {
@@ -21,6 +21,7 @@ impl as Simple {
// CHECK:STDOUT: %.1: type = interface_type @Simple [template]
// CHECK:STDOUT: %.2: type = assoc_entity_type @Simple, <function> [template]
// CHECK:STDOUT: %.3: <associated <function> in Simple> = assoc_entity element0, @Simple.%F [template]
// CHECK:STDOUT: %.4: <witness> = interface_witness @Simple, () [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -46,9 +47,11 @@ impl as Simple {
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl: <error> as Simple {
// CHECK:STDOUT: %F: <function> = fn_decl @F.2 [template] {}
// CHECK:STDOUT: %.1: <witness> = interface_witness @Simple, () [template = constants.%.4]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .F = %F
// CHECK:STDOUT: witness = %.1
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F.1();
@@ -4,6 +4,9 @@
//
// AUTOUPDATE
// CHECK:STDERR: fail_impl_bad_interface.carbon:[[@LINE+6]]:1: ERROR: Semantics TODO: `impl as non-interface`.
// CHECK:STDERR: impl i32 as false {}
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~
// CHECK:STDERR: fail_impl_bad_interface.carbon:[[@LINE+3]]:13: ERROR: Cannot implicitly convert from `bool` to `type`.
// CHECK:STDERR: impl i32 as false {}
// CHECK:STDERR: ^~~~~
@@ -18,9 +21,12 @@ impl i32 as false {}
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {}
// CHECK:STDOUT: impl_decl @impl {
// CHECK:STDOUT: %.loc10: bool = bool_literal false [template = constants.%.1]
// CHECK:STDOUT: %.loc13: bool = bool_literal false [template = constants.%.1]
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl: i32 as <error> {}
// CHECK:STDOUT: impl @impl: i32 as <error> {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: witness = <error>
// CHECK:STDOUT: }
// CHECK:STDOUT:
+7 -1
View File
@@ -16,6 +16,7 @@ impl true as I {}
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.1: type = interface_type @I [template]
// CHECK:STDOUT: %.2: bool = bool_literal true [template]
// CHECK:STDOUT: %.3: <witness> = interface_witness @I, () [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -37,5 +38,10 @@ impl true as I {}
// CHECK:STDOUT: witness = ()
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl: <error> as I {}
// CHECK:STDOUT: impl @impl: <error> as I {
// CHECK:STDOUT: %.1: <witness> = interface_witness @I, () [template = constants.%.3]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: witness = %.1
// CHECK:STDOUT: }
// CHECK:STDOUT:
+5 -1
View File
@@ -20,6 +20,7 @@ impl i32 as I {}
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %.1: type = interface_type @I [template]
// CHECK:STDOUT: %.2: <witness> = interface_witness @I, () [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -43,5 +44,8 @@ impl i32 as I {}
// CHECK:STDOUT: witness = ()
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl: i32 as I {}
// CHECK:STDOUT: impl @impl: i32 as I {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: witness = <unexpected instref inst+6>
// CHECK:STDOUT: }
// CHECK:STDOUT:
+6 -3
View File
@@ -34,9 +34,10 @@ fn G(c: C) {
// CHECK:STDOUT: %.2: type = assoc_entity_type @HasF, <function> [template]
// CHECK:STDOUT: %.3: <associated <function> in HasF> = assoc_entity element0, @HasF.%F [template]
// CHECK:STDOUT: %C: type = class_type @C [template]
// CHECK:STDOUT: %.4: type = struct_type {} [template]
// CHECK:STDOUT: %.5: type = tuple_type () [template]
// CHECK:STDOUT: %.6: type = ptr_type {} [template]
// CHECK:STDOUT: %.4: <witness> = interface_witness @HasF, () [template]
// CHECK:STDOUT: %.5: type = struct_type {} [template]
// CHECK:STDOUT: %.6: type = tuple_type () [template]
// CHECK:STDOUT: %.7: type = ptr_type {} [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -67,9 +68,11 @@ fn G(c: C) {
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl: C as HasF {
// CHECK:STDOUT: %F: <function> = fn_decl @F.2 [template] {}
// CHECK:STDOUT: %.1: <witness> = interface_witness @HasF, () [template = constants.%.4]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .F = %F
// CHECK:STDOUT: witness = %.1
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
+4 -1
View File
@@ -21,7 +21,8 @@ class C {
// CHECK:STDOUT: %.2: type = assoc_entity_type @Simple, <function> [template]
// CHECK:STDOUT: %.3: <associated <function> in Simple> = assoc_entity element0, @Simple.%F [template]
// CHECK:STDOUT: %C: type = class_type @C [template]
// CHECK:STDOUT: %.4: type = struct_type {} [template]
// CHECK:STDOUT: %.4: <witness> = interface_witness @Simple, () [template]
// CHECK:STDOUT: %.5: type = struct_type {} [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -46,9 +47,11 @@ class C {
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl: C as Simple {
// CHECK:STDOUT: %F: <function> = fn_decl @F.2 [template] {}
// CHECK:STDOUT: %.1: <witness> = interface_witness @Simple, () [template = constants.%.4]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .F = %F
// CHECK:STDOUT: witness = %.1
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
+3
View File
@@ -18,6 +18,7 @@ impl forall [T:! type] T as Simple {
// CHECK:STDOUT: %.1: type = interface_type @Simple [template]
// CHECK:STDOUT: %.2: type = assoc_entity_type @Simple, <function> [template]
// CHECK:STDOUT: %.3: <associated <function> in Simple> = assoc_entity element0, @Simple.%F [template]
// CHECK:STDOUT: %.4: <witness> = interface_witness @Simple, () [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -46,9 +47,11 @@ impl forall [T:! type] T as Simple {
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl: T as Simple {
// CHECK:STDOUT: %F: <function> = fn_decl @F.2 [template] {}
// CHECK:STDOUT: %.1: <witness> = interface_witness @Simple, () [template = constants.%.4]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .F = %F
// CHECK:STDOUT: witness = %.1
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F.1();
+7 -1
View File
@@ -20,6 +20,7 @@ impl i32 as I {}
// CHECK:STDOUT: %.1: type = interface_type @I [template]
// CHECK:STDOUT: %X: type = class_type @X [template]
// CHECK:STDOUT: %.2: type = struct_type {} [template]
// CHECK:STDOUT: %.3: <witness> = interface_witness @I, () [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -45,7 +46,12 @@ impl i32 as I {}
// CHECK:STDOUT: witness = ()
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: impl @impl: i32 as I {}
// CHECK:STDOUT: impl @impl: i32 as I {
// CHECK:STDOUT: %.1: <witness> = interface_witness @I, () [template = constants.%.3]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: witness = %.1
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @X {
// CHECK:STDOUT: impl_decl @impl {
+6
View File
@@ -246,6 +246,12 @@ auto HandleInterfaceDecl(FunctionContext& /*context*/,
FatalErrorIfEncountered(inst);
}
auto HandleInterfaceWitness(FunctionContext& /*context*/,
SemIR::InstId /*inst_id*/,
SemIR::InterfaceWitness inst) -> void {
FatalErrorIfEncountered(inst);
}
auto HandleIntLiteral(FunctionContext& context, SemIR::InstId inst_id,
SemIR::IntLiteral inst) -> void {
const llvm::APInt& i = context.sem_ir().ints().Get(inst.int_id);
+3
View File
@@ -73,6 +73,9 @@ CARBON_SEM_IR_BUILTIN_KIND(BoundMethodType, "<bound method>")
// The type of namespace and imported package names.
CARBON_SEM_IR_BUILTIN_KIND(NamespaceType, "<namespace>")
// The type of witnesses.
CARBON_SEM_IR_BUILTIN_KIND(WitnessType, "<witness>")
// Keep invalid last, so that we can use values as array indices without needing
// an invalid entry.
CARBON_SEM_IR_BUILTIN_KIND_NAME(Invalid)
+3
View File
@@ -238,6 +238,7 @@ static auto GetTypePrecedence(InstKind kind) -> int {
case ImportRefUnused::Kind:
case InitializeFrom::Kind:
case InterfaceDecl::Kind:
case InterfaceWitness::Kind:
case IntLiteral::Kind:
case Namespace::Kind:
case Param::Kind:
@@ -485,6 +486,7 @@ static auto StringifyTypeExprImpl(const SemIR::File& outer_sem_ir,
case ImportRefUnused::Kind:
case InitializeFrom::Kind:
case InterfaceDecl::Kind:
case InterfaceWitness::Kind:
case IntLiteral::Kind:
case Namespace::Kind:
case Param::Kind:
@@ -591,6 +593,7 @@ auto GetExprCategory(const File& file, InstId inst_id) -> ExprCategory {
case FacetTypeAccess::Kind:
case InterfaceDecl::Kind:
case InterfaceType::Kind:
case InterfaceWitness::Kind:
case IntLiteral::Kind:
case Param::Kind:
case PointerType::Kind:
+12 -1
View File
@@ -747,7 +747,18 @@ class Formatter {
out_ << ' ';
OpenBrace();
FormatCodeBlock(impl_info.body_block_id);
FormatNameScope(impl_info.scope_id, "!members:\n");
// Print the !members label even if the name scope is empty because we
// always list the witness in this section.
IndentLabel();
out_ << "!members:\n";
FormatNameScope(impl_info.scope_id);
Indent();
out_ << "witness = ";
FormatArg(impl_info.witness_id);
out_ << "\n";
CloseBrace();
out_ << '\n';
} else {
+9 -2
View File
@@ -18,7 +18,12 @@ struct Impl : public Printable<Impl> {
// Determines whether this impl has been fully defined. This is false until we
// reach the `}` of the impl definition.
auto is_defined() const -> bool { return defined; }
auto is_defined() const -> bool { return witness_id.is_valid(); }
// Determines whether this impl's definition has begun but not yet ended.
auto is_being_defined() const -> bool {
return definition_id.is_valid() && !is_defined();
}
// The following members always have values, and do not change throughout the
// lifetime of the interface.
@@ -40,7 +45,9 @@ struct Impl : public Printable<Impl> {
InstBlockId body_block_id = InstBlockId::Invalid;
// The following members are set at the `}` of the impl definition.
bool defined = false;
// The witness for the impl. This can be `BuiltinError`.
InstId witness_id = InstId::Invalid;
};
// A collection of `Impl`s, which can be accessed by the self type and
+1
View File
@@ -56,6 +56,7 @@ CARBON_SEM_IR_INST_KIND(ImportRefUsed)
CARBON_SEM_IR_INST_KIND(InitializeFrom)
CARBON_SEM_IR_INST_KIND(InterfaceDecl)
CARBON_SEM_IR_INST_KIND(InterfaceType)
CARBON_SEM_IR_INST_KIND(InterfaceWitness)
CARBON_SEM_IR_INST_KIND(IntLiteral)
CARBON_SEM_IR_INST_KIND(NameRef)
CARBON_SEM_IR_INST_KIND(Namespace)
+11
View File
@@ -540,6 +540,17 @@ struct InterfaceType {
// here.
};
// A witness that a type implements an interface.
struct InterfaceWitness {
static constexpr auto Kind =
InstKind::InterfaceWitness.Define<Parse::InvalidNodeId>(
"interface_witness");
TypeId type_id;
InterfaceId interface_id;
InstBlockId table_id;
};
struct IntLiteral {
// TODO: Make Parse::NodeId more specific.
static constexpr auto Kind =