ImplWitness (#4679)

* Change `InterfaceWitness` -> `ImplWitness`
* Include a `SpecificId` in the `ImplWitness`. This allows the
`InstBlock` it contains to have its own identity, allowing it to be
changed as the impl is processed. Evaluation only updates the specific.
* Create the `ImplWitness` at the start of the impl definition. In the
future, this will be populated with the values of non-function
associated constants. For now, it starts full of invalid instruction
ids.
* Implements the model suggested in #4672 .

Note that the non-SemIR testdata changes are to these file:
* `toolchain/check/testdata/impl/lookup/fail_todo_undefined_impl.carbon`
* `toolchain/check/testdata/struct/import.carbon`
* `toolchain/check/testdata/tuple/import.carbon`

The last two are due to an import of generics bug exposed by this PR,
which will be fixed in a follow-on.

---------

Co-authored-by: Josh L <josh11b@users.noreply.github.com>
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This commit is contained in:
josh11b
2025-01-02 23:03:11 +00:00
committed by GitHub
co-authored by Josh L Richard Smith
parent 4a7aefefaa
commit c5fd8f42b8
256 changed files with 3060 additions and 2616 deletions
+8 -8
View File
@@ -785,14 +785,14 @@ fn CallImplicitNotDeducible() {
// CHECK:STDOUT: %tuple.type.4: type = tuple_type (Core.IntLiteral, %i32) [template]
// CHECK:STDOUT: %TupleParam.specific_fn: <specific function> = specific_function %TupleParam, @TupleParam(Core.IntLiteral) [template]
// CHECK:STDOUT: %Convert.type.2: type = fn_type @Convert.1, @ImplicitAs(%i32) [template]
// CHECK:STDOUT: %impl_witness.19: <witness> = impl_witness (imports.%import_ref.14), @impl.1(%int_32) [template]
// CHECK:STDOUT: %Convert.type.10: type = fn_type @Convert.2, @impl.1(%int_32) [template]
// CHECK:STDOUT: %Convert.10: %Convert.type.10 = struct_value () [template]
// CHECK:STDOUT: %interface.19: <witness> = interface_witness (%Convert.10) [template]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %int_2.1, %Convert.10 [template]
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.2(%int_32) [template]
// CHECK:STDOUT: %int_2.2: %i32 = int_value 2 [template]
// CHECK:STDOUT: %tuple: %tuple.type.4 = tuple_value (%int_1, %int_2.2) [template]
// CHECK:STDOUT: %complete_type.3: <witness> = complete_type_witness %tuple.type.4 [template]
// CHECK:STDOUT: %complete_type.4: <witness> = complete_type_witness %tuple.type.4 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
@@ -853,7 +853,7 @@ fn CallImplicitNotDeducible() {
// CHECK:STDOUT: %int_2: Core.IntLiteral = int_value 2 [template = constants.%int_2.1]
// CHECK:STDOUT: %.loc7_19.1: %tuple.type.3 = tuple_literal (%int_1, %int_2)
// CHECK:STDOUT: %TupleParam.specific_fn: <specific function> = specific_function %TupleParam.ref, @TupleParam(Core.IntLiteral) [template = constants.%TupleParam.specific_fn]
// CHECK:STDOUT: %impl.elem0: %Convert.type.2 = interface_witness_access constants.%interface.19, element0 [template = constants.%Convert.10]
// CHECK:STDOUT: %impl.elem0: %Convert.type.2 = impl_witness_access constants.%impl_witness.19, element0 [template = constants.%Convert.10]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %int_2, %impl.elem0 [template = constants.%Convert.bound]
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.2(constants.%int_32) [template = constants.%Convert.specific_fn]
// CHECK:STDOUT: %int.convert_checked: init %i32 = call %Convert.specific_fn(%int_2) [template = constants.%int_2.2]
@@ -877,7 +877,7 @@ fn CallImplicitNotDeducible() {
// CHECK:STDOUT: %tuple.type => constants.%tuple.type.4
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT: %require_complete => constants.%complete_type.3
// CHECK:STDOUT: %require_complete => constants.%complete_type.4
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- deduce_nested_struct.carbon
@@ -900,14 +900,14 @@ fn CallImplicitNotDeducible() {
// CHECK:STDOUT: %struct_type.a.b.3: type = struct_type {.a: Core.IntLiteral, .b: %i32} [template]
// CHECK:STDOUT: %StructParam.specific_fn: <specific function> = specific_function %StructParam, @StructParam(Core.IntLiteral) [template]
// CHECK:STDOUT: %Convert.type.2: type = fn_type @Convert.1, @ImplicitAs(%i32) [template]
// CHECK:STDOUT: %impl_witness.19: <witness> = impl_witness (imports.%import_ref.14), @impl.1(%int_32) [template]
// CHECK:STDOUT: %Convert.type.10: type = fn_type @Convert.2, @impl.1(%int_32) [template]
// CHECK:STDOUT: %Convert.10: %Convert.type.10 = struct_value () [template]
// CHECK:STDOUT: %interface.19: <witness> = interface_witness (%Convert.10) [template]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %int_2.1, %Convert.10 [template]
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.2(%int_32) [template]
// CHECK:STDOUT: %int_2.2: %i32 = int_value 2 [template]
// CHECK:STDOUT: %struct: %struct_type.a.b.3 = struct_value (%int_1, %int_2.2) [template]
// CHECK:STDOUT: %complete_type.3: <witness> = complete_type_witness %struct_type.a.b.3 [template]
// CHECK:STDOUT: %complete_type.4: <witness> = complete_type_witness %struct_type.a.b.3 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
@@ -967,7 +967,7 @@ fn CallImplicitNotDeducible() {
// CHECK:STDOUT: %int_2: Core.IntLiteral = int_value 2 [template = constants.%int_2.1]
// CHECK:STDOUT: %.loc7_30.1: %struct_type.a.b.2 = struct_literal (%int_1, %int_2)
// CHECK:STDOUT: %StructParam.specific_fn: <specific function> = specific_function %StructParam.ref, @StructParam(Core.IntLiteral) [template = constants.%StructParam.specific_fn]
// CHECK:STDOUT: %impl.elem0: %Convert.type.2 = interface_witness_access constants.%interface.19, element0 [template = constants.%Convert.10]
// CHECK:STDOUT: %impl.elem0: %Convert.type.2 = impl_witness_access constants.%impl_witness.19, element0 [template = constants.%Convert.10]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %int_2, %impl.elem0 [template = constants.%Convert.bound]
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.2(constants.%int_32) [template = constants.%Convert.specific_fn]
// CHECK:STDOUT: %int.convert_checked: init %i32 = call %Convert.specific_fn(%int_2) [template = constants.%int_2.2]
@@ -991,7 +991,7 @@ fn CallImplicitNotDeducible() {
// CHECK:STDOUT: %struct_type.a.b.loc4_44.2 => constants.%struct_type.a.b.3
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT: %require_complete => constants.%complete_type.3
// CHECK:STDOUT: %require_complete => constants.%complete_type.4
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_deduce_bigger_struct.carbon
@@ -21,9 +21,9 @@ fn F(N:! i32, a: [i32; N]*);
// CHECK:STDOUT: %N.2: %i32 = bind_symbolic_name N, 0 [symbolic]
// CHECK:STDOUT: %N.patt.2: %i32 = symbolic_binding_pattern N, 0 [symbolic]
// CHECK:STDOUT: %Convert.type.2: type = fn_type @Convert.1, @ImplicitAs(Core.IntLiteral) [template]
// CHECK:STDOUT: %impl_witness.19: <witness> = impl_witness (imports.%import_ref.18), @impl.2(%int_32) [template]
// CHECK:STDOUT: %Convert.type.9: type = fn_type @Convert.3, @impl.2(%int_32) [template]
// CHECK:STDOUT: %Convert.9: %Convert.type.9 = struct_value () [template]
// CHECK:STDOUT: %interface.19: <witness> = interface_witness (%Convert.9) [template]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %N.2, %Convert.9 [symbolic]
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.3(%int_32) [symbolic]
// CHECK:STDOUT: %int.convert_checked: init Core.IntLiteral = call %Convert.specific_fn(%N.2) [symbolic]
@@ -63,7 +63,7 @@ fn F(N:! i32, a: [i32; N]*);
// CHECK:STDOUT: %int_32.loc14_19: Core.IntLiteral = int_value 32 [template = constants.%int_32]
// CHECK:STDOUT: %i32.loc14_19: type = class_type @Int, @Int(constants.%int_32) [template = constants.%i32]
// CHECK:STDOUT: %N.ref: %i32 = name_ref N, %N.loc14_6.1 [symbolic = %N.loc14_6.2 (constants.%N.2)]
// CHECK:STDOUT: %impl.elem0: %Convert.type.2 = interface_witness_access constants.%interface.19, element0 [template = constants.%Convert.9]
// CHECK:STDOUT: %impl.elem0: %Convert.type.2 = impl_witness_access constants.%impl_witness.19, element0 [template = constants.%Convert.9]
// CHECK:STDOUT: %Convert.bound.loc14_24.1: <bound method> = bound_method %N.ref, %impl.elem0 [symbolic = %Convert.bound.loc14_24.2 (constants.%Convert.bound)]
// CHECK:STDOUT: %Convert.specific_fn.loc14_24.1: <specific function> = specific_function %Convert.bound.loc14_24.1, @Convert.3(constants.%int_32) [symbolic = %Convert.specific_fn.loc14_24.2 (constants.%Convert.specific_fn)]
// CHECK:STDOUT: %int.convert_checked.loc14_24.1: init Core.IntLiteral = call %Convert.specific_fn.loc14_24.1(%N.ref) [symbolic = %int.convert_checked.loc14_24.2 (constants.%int.convert_checked)]
+8 -8
View File
@@ -66,9 +66,9 @@ fn CallUndefined() -> i32 {
// CHECK:STDOUT: %complete_type.2: <witness> = complete_type_witness %i32.builtin [template]
// CHECK:STDOUT: %int_0.1: Core.IntLiteral = int_value 0 [template]
// CHECK:STDOUT: %Convert.type.2: type = fn_type @Convert.1, @As(%i32) [template]
// CHECK:STDOUT: %impl_witness.19: <witness> = impl_witness (imports.%import_ref.27), @impl.3(%int_32) [template]
// CHECK:STDOUT: %Convert.type.10: type = fn_type @Convert.5, @impl.3(%int_32) [template]
// CHECK:STDOUT: %Convert.10: %Convert.type.10 = struct_value () [template]
// CHECK:STDOUT: %interface.19: <witness> = interface_witness (%Convert.10) [template]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %int_0.1, %Convert.10 [template]
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.5(%int_32) [template]
// CHECK:STDOUT: %int_0.2: %i32 = int_value 0 [template]
@@ -139,7 +139,7 @@ fn CallUndefined() -> i32 {
// CHECK:STDOUT: %int_0: Core.IntLiteral = int_value 0 [template = constants.%int_0.1]
// CHECK:STDOUT: %int_32.loc9: Core.IntLiteral = int_value 32 [template = constants.%int_32]
// CHECK:STDOUT: %i32.loc9: type = class_type @Int, @Int(constants.%int_32) [template = constants.%i32]
// CHECK:STDOUT: %impl.elem0: %Convert.type.2 = interface_witness_access constants.%interface.19, element0 [template = constants.%Convert.10]
// CHECK:STDOUT: %impl.elem0: %Convert.type.2 = impl_witness_access constants.%impl_witness.19, element0 [template = constants.%Convert.10]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %int_0, %impl.elem0 [template = constants.%Convert.bound]
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.5(constants.%int_32) [template = constants.%Convert.specific_fn]
// CHECK:STDOUT: %int.convert_checked: init %i32 = call %Convert.specific_fn(%int_0) [template = constants.%int_0.2]
@@ -180,14 +180,14 @@ fn CallUndefined() -> i32 {
// CHECK:STDOUT: %complete_type.2: <witness> = complete_type_witness %i32.builtin [template]
// CHECK:STDOUT: %int_0.1: Core.IntLiteral = int_value 0 [template]
// CHECK:STDOUT: %Convert.type.2: type = fn_type @Convert.1, @As(%i32) [template]
// CHECK:STDOUT: %impl_witness.19: <witness> = impl_witness (imports.%import_ref.27), @impl.3(%int_32) [template]
// CHECK:STDOUT: %Convert.type.10: type = fn_type @Convert.5, @impl.3(%int_32) [template]
// CHECK:STDOUT: %Convert.10: %Convert.type.10 = struct_value () [template]
// CHECK:STDOUT: %interface.19: <witness> = interface_witness (%Convert.10) [template]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %int_0.1, %Convert.10 [template]
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.5(%int_32) [template]
// CHECK:STDOUT: %int_0.2: %i32 = int_value 0 [template]
// CHECK:STDOUT: %Defined.specific_fn: <specific function> = specific_function %Defined, @Defined(%i32) [template]
// CHECK:STDOUT: %require_complete.3: <witness> = require_complete_type %T [symbolic]
// CHECK:STDOUT: %require_complete.5: <witness> = require_complete_type %T [symbolic]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
@@ -256,7 +256,7 @@ fn CallUndefined() -> i32 {
// CHECK:STDOUT: %T.patt.loc4: type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc4 (constants.%T.patt)]
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT: %require_complete: <witness> = require_complete_type @Defined.%T.loc4_12.2 (%T) [symbolic = %require_complete (constants.%require_complete.3)]
// CHECK:STDOUT: %require_complete: <witness> = require_complete_type @Defined.%T.loc4_12.2 (%T) [symbolic = %require_complete (constants.%require_complete.5)]
// CHECK:STDOUT:
// CHECK:STDOUT: fn[%T.param_patt: type](%x.param_patt: %T) -> %T {
// CHECK:STDOUT: !entry:
@@ -271,7 +271,7 @@ fn CallUndefined() -> i32 {
// CHECK:STDOUT: %int_0: Core.IntLiteral = int_value 0 [template = constants.%int_0.1]
// CHECK:STDOUT: %int_32.loc7: Core.IntLiteral = int_value 32 [template = constants.%int_32]
// CHECK:STDOUT: %i32.loc7: type = class_type @Int, @Int(constants.%int_32) [template = constants.%i32]
// CHECK:STDOUT: %impl.elem0: %Convert.type.2 = interface_witness_access constants.%interface.19, element0 [template = constants.%Convert.10]
// CHECK:STDOUT: %impl.elem0: %Convert.type.2 = impl_witness_access constants.%impl_witness.19, element0 [template = constants.%Convert.10]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %int_0, %impl.elem0 [template = constants.%Convert.bound]
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.5(constants.%int_32) [template = constants.%Convert.specific_fn]
// CHECK:STDOUT: %int.convert_checked: init %i32 = call %Convert.specific_fn(%int_0) [template = constants.%int_0.2]
@@ -310,9 +310,9 @@ fn CallUndefined() -> i32 {
// CHECK:STDOUT: %CallUndefined: %CallUndefined.type = struct_value () [template]
// CHECK:STDOUT: %int_0.1: Core.IntLiteral = int_value 0 [template]
// CHECK:STDOUT: %Convert.type.2: type = fn_type @Convert.1, @As(%i32) [template]
// CHECK:STDOUT: %impl_witness.19: <witness> = impl_witness (imports.%import_ref.27), @impl.3(%int_32) [template]
// CHECK:STDOUT: %Convert.type.10: type = fn_type @Convert.5, @impl.3(%int_32) [template]
// CHECK:STDOUT: %Convert.10: %Convert.type.10 = struct_value () [template]
// CHECK:STDOUT: %interface.19: <witness> = interface_witness (%Convert.10) [template]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %int_0.1, %Convert.10 [template]
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.5(%int_32) [template]
// CHECK:STDOUT: %int_0.2: %i32 = int_value 0 [template]
@@ -376,7 +376,7 @@ fn CallUndefined() -> i32 {
// CHECK:STDOUT: %int_0: Core.IntLiteral = int_value 0 [template = constants.%int_0.1]
// CHECK:STDOUT: %int_32.loc13: Core.IntLiteral = int_value 32 [template = constants.%int_32]
// CHECK:STDOUT: %i32.loc13: type = class_type @Int, @Int(constants.%int_32) [template = constants.%i32]
// CHECK:STDOUT: %impl.elem0: %Convert.type.2 = interface_witness_access constants.%interface.19, element0 [template = constants.%Convert.10]
// CHECK:STDOUT: %impl.elem0: %Convert.type.2 = impl_witness_access constants.%impl_witness.19, element0 [template = constants.%Convert.10]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %int_0, %impl.elem0 [template = constants.%Convert.bound]
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.5(constants.%int_32) [template = constants.%Convert.specific_fn]
// CHECK:STDOUT: %int.convert_checked: init %i32 = call %Convert.specific_fn(%int_0) [template = constants.%int_0.2]