mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 20:10:13 +01:00
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:
co-authored by
Jon Ross-Perkins
parent
2424ea16ea
commit
abf23ae7fe
@@ -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"],
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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:
|
||||
|
||||
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 =
|
||||
|
||||
Reference in New Issue
Block a user