Support accessing associated functions by member access into facets (#4872)

For an expression such as `(Type as Interface).AssocFn()`, track the
`Self` type `Type` in the result of the member access so that it's
available when checking the function call.

This introduces a new kind of type, `ImplFunctionType`, that represents
the type of a function that is expected within an impl, modeled as the
type of the function within the interface plus a value to use as `Self`.
Calls to values of this type behave like calls to the underlying
function except that the `Self` parameter is pre-bound to the self type
from the facet.

In order to support this, fix an issue where the imported list of
generic bindings lost their association with their enclosing generic.
This adds a little complexity to `import_ref`, including a new recursive
cycle that I intend to address in a follow-up PR.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
This commit is contained in:
Richard Smith
2025-02-04 22:38:38 +00:00
committed by GitHub
co-authored by Jon Ross-Perkins
parent dcfccd3187
commit fcfb1345d5
234 changed files with 4213 additions and 2531 deletions
@@ -34,10 +34,13 @@ interface I {
// CHECK:STDOUT: %tuple.type.d07: type = tuple_type (%i32, %i32) [template]
// CHECK:STDOUT: %assoc1: %I.assoc_type = assoc_entity element1, @I.%N [template]
// CHECK:STDOUT: %int_42.20e: Core.IntLiteral = int_value 42 [template]
// CHECK:STDOUT: %ImplicitAs.type.205: type = facet_type <@ImplicitAs, @ImplicitAs(%i32)> [template]
// CHECK:STDOUT: %Convert.type.1b6: type = fn_type @Convert.1, @ImplicitAs(%i32) [template]
// CHECK:STDOUT: %impl_witness.d39: <witness> = impl_witness (imports.%Core.import_ref.a5b), @impl.1(%int_32) [template]
// CHECK:STDOUT: %Convert.type.035: type = fn_type @Convert.2, @impl.1(%int_32) [template]
// CHECK:STDOUT: %Convert.956: %Convert.type.035 = struct_value () [template]
// CHECK:STDOUT: %ImplicitAs.facet: %ImplicitAs.type.205 = facet_value Core.IntLiteral, %impl_witness.d39 [template]
// CHECK:STDOUT: %.a0b: type = fn_type_with_self_type %Convert.type.1b6, %ImplicitAs.facet [template]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %int_42.20e, %Convert.956 [template]
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.2(%int_32) [template]
// CHECK:STDOUT: %int_42.c68: %i32 = int_value 42 [template]
@@ -75,10 +78,10 @@ interface I {
// CHECK:STDOUT: %N: %i32 = assoc_const_decl @N [template] {
// CHECK:STDOUT: %assoc1: %I.assoc_type = assoc_entity element1, @I.%N [template = constants.%assoc1]
// CHECK:STDOUT: %int_42: Core.IntLiteral = int_value 42 [template = constants.%int_42.20e]
// CHECK:STDOUT: %impl.elem0: %Convert.type.1b6 = impl_witness_access constants.%impl_witness.d39, element0 [template = constants.%Convert.956]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %int_42, %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_42) [template = constants.%int_42.c68]
// CHECK:STDOUT: %impl.elem0: %.a0b = impl_witness_access constants.%impl_witness.d39, element0 [template = constants.%Convert.956]
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %int_42, %impl.elem0 [template = constants.%Convert.bound]
// CHECK:STDOUT: %specific_fn: <specific function> = specific_function %bound_method, @Convert.2(constants.%int_32) [template = constants.%Convert.specific_fn]
// CHECK:STDOUT: %int.convert_checked: init %i32 = call %specific_fn(%int_42) [template = constants.%int_42.c68]
// CHECK:STDOUT: %.loc21_27.1: %i32 = value_of_initializer %int.convert_checked [template = constants.%int_42.c68]
// CHECK:STDOUT: %.loc21_27.2: %i32 = converted %int_42, %.loc21_27.1 [template = constants.%int_42.c68]
// CHECK:STDOUT: }
+2 -2
View File
@@ -82,7 +82,7 @@ fn AccessMissingConcrete(I:! Interface(i32)) -> i32 {
// CHECK:STDOUT: %assoc0.4ff: %Interface.assoc_type.44d = assoc_entity element0, @Interface.%X [template]
// CHECK:STDOUT: %I.as_type.ee6: type = facet_access_type %I.d08 [symbolic]
// CHECK:STDOUT: %I.as_wit.156: <witness> = facet_access_witness %I.d08 [symbolic]
// CHECK:STDOUT: %Interface.facet.a3f: %Interface.type.d32 = facet_value %I.as_type.ee6, %I.as_wit.156 [symbolic]
// CHECK:STDOUT: %Interface.facet.d35: %Interface.type.981 = facet_value %I.as_type.ee6, %I.as_wit.156 [symbolic]
// CHECK:STDOUT: %impl.elem0.b00: %i32 = impl_witness_access %I.as_wit.156, element0 [symbolic]
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -281,7 +281,7 @@ fn AccessMissingConcrete(I:! Interface(i32)) -> i32 {
// CHECK:STDOUT: %I.patt.loc12_19.2 => constants.%I.d08
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @X(constants.%i32, constants.%Interface.facet.a3f) {
// CHECK:STDOUT: specific @X(constants.%i32, constants.%Interface.facet.d35) {
// CHECK:STDOUT: %T => constants.%i32
// CHECK:STDOUT: %require_complete => constants.%complete_type.f8a
// CHECK:STDOUT: }
@@ -41,6 +41,7 @@ class C {
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [template]
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %empty_struct_type [template]
// CHECK:STDOUT: %C.val: %C = struct_value () [template]
// CHECK:STDOUT: %.eab: type = fn_type_with_self_type %F.type.0b5, %I.facet [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -103,7 +104,7 @@ class C {
// CHECK:STDOUT: %c.ref: ref %C = name_ref c, %c
// CHECK:STDOUT: %I.ref: type = name_ref I, @C.%I.decl [template = constants.%I.type]
// CHECK:STDOUT: %F.ref: %I.assoc_type = name_ref F, @I.%assoc0 [template = constants.%assoc0]
// CHECK:STDOUT: %impl.elem0: %F.type.0b5 = impl_witness_access constants.%impl_witness, element0 [template = constants.%F.eb2]
// CHECK:STDOUT: %impl.elem0: %.eab = impl_witness_access constants.%impl_witness, element0 [template = constants.%F.eb2]
// CHECK:STDOUT: %F.call: init %empty_tuple.type = call %impl.elem0()
// CHECK:STDOUT: return
// CHECK:STDOUT: }
@@ -0,0 +1,127 @@
// 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
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interface/no_prelude/fail_assoc_fn_invalid_use.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interface/no_prelude/fail_assoc_fn_invalid_use.carbon
// --- fail_member_access.carbon
library "[[@TEST_NAME]]";
interface I {
fn F[self: Self]();
}
fn Use(T:! I) {
// CHECK:STDERR: fail_member_access.carbon:[[@LINE+4]]:3: error: type `<type of F in T as I>` does not support qualified expressions [QualifiedExprUnsupported]
// CHECK:STDERR: T.F.member;
// CHECK:STDERR: ^~~~~~~~~~
// CHECK:STDERR:
T.F.member;
}
// CHECK:STDOUT: --- fail_member_access.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %I.type: type = facet_type <@I> [template]
// CHECK:STDOUT: %Self: %I.type = bind_symbolic_name Self, 0 [symbolic]
// CHECK:STDOUT: %Self.as_type: type = facet_access_type %Self [symbolic]
// CHECK:STDOUT: %F.type: type = fn_type @F [template]
// CHECK:STDOUT: %F: %F.type = struct_value () [template]
// CHECK:STDOUT: %I.assoc_type: type = assoc_entity_type %I.type [template]
// CHECK:STDOUT: %assoc0: %I.assoc_type = assoc_entity element0, @I.%F.decl [template]
// CHECK:STDOUT: %T: %I.type = bind_symbolic_name T, 0 [symbolic]
// CHECK:STDOUT: %T.patt: %I.type = symbolic_binding_pattern T, 0 [symbolic]
// CHECK:STDOUT: %Use.type: type = fn_type @Use [template]
// CHECK:STDOUT: %Use: %Use.type = struct_value () [template]
// CHECK:STDOUT: %T.as_type: type = facet_access_type %T [symbolic]
// CHECK:STDOUT: %T.as_wit: <witness> = facet_access_witness %T [symbolic]
// CHECK:STDOUT: %I.facet: %I.type = facet_value %T.as_type, %T.as_wit [symbolic]
// CHECK:STDOUT: %.de3: type = fn_type_with_self_type %F.type, %I.facet [symbolic]
// CHECK:STDOUT: %impl.elem0: %.de3 = impl_witness_access %T.as_wit, element0 [symbolic]
// CHECK:STDOUT: %require_complete: <witness> = require_complete_type %.de3 [symbolic]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .I = %I.decl
// CHECK:STDOUT: .Use = %Use.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %I.decl: type = interface_decl @I [template = constants.%I.type] {} {}
// CHECK:STDOUT: %Use.decl: %Use.type = fn_decl @Use [template = constants.%Use] {
// CHECK:STDOUT: %T.patt.loc8_8.1: %I.type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc8_8.2 (constants.%T.patt)]
// CHECK:STDOUT: %T.param_patt: %I.type = value_param_pattern %T.patt.loc8_8.1, runtime_param<none> [symbolic = %T.patt.loc8_8.2 (constants.%T.patt)]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %T.param: %I.type = value_param runtime_param<none>
// CHECK:STDOUT: %I.ref: type = name_ref I, file.%I.decl [template = constants.%I.type]
// CHECK:STDOUT: %T.loc8_8.1: %I.type = bind_symbolic_name T, 0, %T.param [symbolic = %T.loc8_8.2 (constants.%T)]
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: interface @I {
// CHECK:STDOUT: %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self]
// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] {
// CHECK:STDOUT: %self.patt: @F.%Self.as_type.loc5_14.1 (%Self.as_type) = binding_pattern self
// CHECK:STDOUT: %self.param_patt: @F.%Self.as_type.loc5_14.1 (%Self.as_type) = value_param_pattern %self.patt, runtime_param0
// CHECK:STDOUT: } {
// CHECK:STDOUT: %self.param: @F.%Self.as_type.loc5_14.1 (%Self.as_type) = value_param runtime_param0
// CHECK:STDOUT: %.loc5_14.1: type = splice_block %.loc5_14.2 [symbolic = %Self.as_type.loc5_14.1 (constants.%Self.as_type)] {
// CHECK:STDOUT: %Self.ref: %I.type = name_ref Self, @I.%Self [symbolic = %Self (constants.%Self)]
// CHECK:STDOUT: %Self.as_type.loc5_14.2: type = facet_access_type %Self.ref [symbolic = %Self.as_type.loc5_14.1 (constants.%Self.as_type)]
// CHECK:STDOUT: %.loc5_14.2: type = converted %Self.ref, %Self.as_type.loc5_14.2 [symbolic = %Self.as_type.loc5_14.1 (constants.%Self.as_type)]
// CHECK:STDOUT: }
// CHECK:STDOUT: %self: @F.%Self.as_type.loc5_14.1 (%Self.as_type) = bind_name self, %self.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %assoc0: %I.assoc_type = assoc_entity element0, %F.decl [template = constants.%assoc0]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = %Self
// CHECK:STDOUT: .F = %assoc0
// CHECK:STDOUT: witness = (%F.decl)
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic fn @F(@I.%Self: %I.type) {
// CHECK:STDOUT: %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = %Self (constants.%Self)]
// CHECK:STDOUT: %Self.as_type.loc5_14.1: type = facet_access_type %Self [symbolic = %Self.as_type.loc5_14.1 (constants.%Self.as_type)]
// CHECK:STDOUT:
// CHECK:STDOUT: fn[%self.param_patt: @F.%Self.as_type.loc5_14.1 (%Self.as_type)]();
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic fn @Use(%T.loc8_8.1: %I.type) {
// CHECK:STDOUT: %T.loc8_8.2: %I.type = bind_symbolic_name T, 0 [symbolic = %T.loc8_8.2 (constants.%T)]
// CHECK:STDOUT: %T.patt.loc8_8.2: %I.type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc8_8.2 (constants.%T.patt)]
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT: %T.as_type.loc13_4.2: type = facet_access_type %T.loc8_8.2 [symbolic = %T.as_type.loc13_4.2 (constants.%T.as_type)]
// CHECK:STDOUT: %T.as_wit.loc13_4.2: <witness> = facet_access_witness %T.loc8_8.2 [symbolic = %T.as_wit.loc13_4.2 (constants.%T.as_wit)]
// CHECK:STDOUT: %I.facet: %I.type = facet_value %T.as_type.loc13_4.2, %T.as_wit.loc13_4.2 [symbolic = %I.facet (constants.%I.facet)]
// CHECK:STDOUT: %.loc13_4.2: type = fn_type_with_self_type constants.%F.type, %I.facet [symbolic = %.loc13_4.2 (constants.%.de3)]
// CHECK:STDOUT: %impl.elem0.loc13_4.2: @Use.%.loc13_4.2 (%.de3) = impl_witness_access %T.as_wit.loc13_4.2, element0 [symbolic = %impl.elem0.loc13_4.2 (constants.%impl.elem0)]
// CHECK:STDOUT: %require_complete: <witness> = require_complete_type @Use.%.loc13_4.2 (%.de3) [symbolic = %require_complete (constants.%require_complete)]
// CHECK:STDOUT:
// CHECK:STDOUT: fn(%T.param_patt: %I.type) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %T.ref: %I.type = name_ref T, %T.loc8_8.1 [symbolic = %T.loc8_8.2 (constants.%T)]
// CHECK:STDOUT: %F.ref: %I.assoc_type = name_ref F, @I.%assoc0 [template = constants.%assoc0]
// CHECK:STDOUT: %T.as_type.loc13_4.1: type = facet_access_type %T.ref [symbolic = %T.as_type.loc13_4.2 (constants.%T.as_type)]
// CHECK:STDOUT: %.loc13_4.1: type = converted %T.ref, %T.as_type.loc13_4.1 [symbolic = %T.as_type.loc13_4.2 (constants.%T.as_type)]
// CHECK:STDOUT: %T.as_wit.loc13_4.1: <witness> = facet_access_witness %T.ref [symbolic = %T.as_wit.loc13_4.2 (constants.%T.as_wit)]
// CHECK:STDOUT: %impl.elem0.loc13_4.1: @Use.%.loc13_4.2 (%.de3) = impl_witness_access %T.as_wit.loc13_4.1, element0 [symbolic = %impl.elem0.loc13_4.2 (constants.%impl.elem0)]
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @F(constants.%Self) {
// CHECK:STDOUT: %Self => constants.%Self
// CHECK:STDOUT: %Self.as_type.loc5_14.1 => constants.%Self.as_type
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @Use(constants.%T) {
// CHECK:STDOUT: %T.loc8_8.2 => constants.%T
// CHECK:STDOUT: %T.patt.loc8_8.2 => constants.%T
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -1,147 +0,0 @@
// 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
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interface/no_prelude/fail_todo_facet_lookup.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interface/no_prelude/fail_todo_facet_lookup.carbon
interface Interface { fn F(); }
fn CallStatic(T:! Interface) {
// CHECK:STDERR: fail_todo_facet_lookup.carbon:[[@LINE+4]]:3: error: value of type `<type of F>` is not callable [CallToNonCallable]
// CHECK:STDERR: T.F();
// CHECK:STDERR: ^~~~~
// CHECK:STDERR:
T.F();
}
fn CallFacet(T:! Interface, x: T) {
// CHECK:STDERR: fail_todo_facet_lookup.carbon:[[@LINE+4]]:3: error: type `T` does not support qualified expressions [QualifiedExprUnsupported]
// CHECK:STDERR: x.F();
// CHECK:STDERR: ^~~
// CHECK:STDERR:
x.F();
}
// CHECK:STDOUT: --- fail_todo_facet_lookup.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %Interface.type: type = facet_type <@Interface> [template]
// CHECK:STDOUT: %Self: %Interface.type = bind_symbolic_name Self, 0 [symbolic]
// CHECK:STDOUT: %F.type: type = fn_type @F [template]
// CHECK:STDOUT: %F: %F.type = struct_value () [template]
// CHECK:STDOUT: %Interface.assoc_type: type = assoc_entity_type %Interface.type [template]
// CHECK:STDOUT: %assoc0: %Interface.assoc_type = assoc_entity element0, @Interface.%F.decl [template]
// CHECK:STDOUT: %T: %Interface.type = bind_symbolic_name T, 0 [symbolic]
// CHECK:STDOUT: %T.patt: %Interface.type = symbolic_binding_pattern T, 0 [symbolic]
// CHECK:STDOUT: %CallStatic.type: type = fn_type @CallStatic [template]
// CHECK:STDOUT: %CallStatic: %CallStatic.type = struct_value () [template]
// CHECK:STDOUT: %T.as_type: type = facet_access_type %T [symbolic]
// CHECK:STDOUT: %T.as_wit: <witness> = facet_access_witness %T [symbolic]
// CHECK:STDOUT: %impl.elem0: %F.type = impl_witness_access %T.as_wit, element0 [symbolic]
// CHECK:STDOUT: %CallFacet.type: type = fn_type @CallFacet [template]
// CHECK:STDOUT: %CallFacet: %CallFacet.type = struct_value () [template]
// CHECK:STDOUT: %require_complete: <witness> = require_complete_type %T.as_type [symbolic]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Interface = %Interface.decl
// CHECK:STDOUT: .CallStatic = %CallStatic.decl
// CHECK:STDOUT: .CallFacet = %CallFacet.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %Interface.decl: type = interface_decl @Interface [template = constants.%Interface.type] {} {}
// CHECK:STDOUT: %CallStatic.decl: %CallStatic.type = fn_decl @CallStatic [template = constants.%CallStatic] {
// CHECK:STDOUT: %T.patt.loc13_15.1: %Interface.type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc13_15.2 (constants.%T.patt)]
// CHECK:STDOUT: %T.param_patt: %Interface.type = value_param_pattern %T.patt.loc13_15.1, runtime_param<none> [symbolic = %T.patt.loc13_15.2 (constants.%T.patt)]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %T.param: %Interface.type = value_param runtime_param<none>
// CHECK:STDOUT: %Interface.ref: type = name_ref Interface, file.%Interface.decl [template = constants.%Interface.type]
// CHECK:STDOUT: %T.loc13_15.1: %Interface.type = bind_symbolic_name T, 0, %T.param [symbolic = %T.loc13_15.2 (constants.%T)]
// CHECK:STDOUT: }
// CHECK:STDOUT: %CallFacet.decl: %CallFacet.type = fn_decl @CallFacet [template = constants.%CallFacet] {
// CHECK:STDOUT: %T.patt.loc21_14.1: %Interface.type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc21_14.2 (constants.%T.patt)]
// CHECK:STDOUT: %T.param_patt: %Interface.type = value_param_pattern %T.patt.loc21_14.1, runtime_param<none> [symbolic = %T.patt.loc21_14.2 (constants.%T.patt)]
// CHECK:STDOUT: %x.patt: @CallFacet.%T.as_type.loc21_32.2 (%T.as_type) = binding_pattern x
// CHECK:STDOUT: %x.param_patt: @CallFacet.%T.as_type.loc21_32.2 (%T.as_type) = value_param_pattern %x.patt, runtime_param0
// CHECK:STDOUT: } {
// CHECK:STDOUT: %T.param: %Interface.type = value_param runtime_param<none>
// CHECK:STDOUT: %Interface.ref: type = name_ref Interface, file.%Interface.decl [template = constants.%Interface.type]
// CHECK:STDOUT: %T.loc21_14.1: %Interface.type = bind_symbolic_name T, 0, %T.param [symbolic = %T.loc21_14.2 (constants.%T)]
// CHECK:STDOUT: %x.param: @CallFacet.%T.as_type.loc21_32.2 (%T.as_type) = value_param runtime_param0
// CHECK:STDOUT: %.loc21_32.1: type = splice_block %.loc21_32.2 [symbolic = %T.as_type.loc21_32.2 (constants.%T.as_type)] {
// CHECK:STDOUT: %T.ref: %Interface.type = name_ref T, %T.loc21_14.1 [symbolic = %T.loc21_14.2 (constants.%T)]
// CHECK:STDOUT: %T.as_type.loc21_32.1: type = facet_access_type %T.ref [symbolic = %T.as_type.loc21_32.2 (constants.%T.as_type)]
// CHECK:STDOUT: %.loc21_32.2: type = converted %T.ref, %T.as_type.loc21_32.1 [symbolic = %T.as_type.loc21_32.2 (constants.%T.as_type)]
// CHECK:STDOUT: }
// CHECK:STDOUT: %x: @CallFacet.%T.as_type.loc21_32.2 (%T.as_type) = bind_name x, %x.param
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: interface @Interface {
// CHECK:STDOUT: %Self: %Interface.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self]
// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] {} {}
// CHECK:STDOUT: %assoc0: %Interface.assoc_type = assoc_entity element0, %F.decl [template = constants.%assoc0]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = %Self
// CHECK:STDOUT: .F = %assoc0
// CHECK:STDOUT: witness = (%F.decl)
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic fn @F(@Interface.%Self: %Interface.type) {
// CHECK:STDOUT: fn();
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic fn @CallStatic(%T.loc13_15.1: %Interface.type) {
// CHECK:STDOUT: %T.loc13_15.2: %Interface.type = bind_symbolic_name T, 0 [symbolic = %T.loc13_15.2 (constants.%T)]
// CHECK:STDOUT: %T.patt.loc13_15.2: %Interface.type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc13_15.2 (constants.%T.patt)]
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT: %T.as_type.loc18_4.2: type = facet_access_type %T.loc13_15.2 [symbolic = %T.as_type.loc18_4.2 (constants.%T.as_type)]
// CHECK:STDOUT: %T.as_wit.loc18_4.2: <witness> = facet_access_witness %T.loc13_15.2 [symbolic = %T.as_wit.loc18_4.2 (constants.%T.as_wit)]
// CHECK:STDOUT: %impl.elem0.loc18_4.2: %F.type = impl_witness_access %T.as_wit.loc18_4.2, element0 [symbolic = %impl.elem0.loc18_4.2 (constants.%impl.elem0)]
// CHECK:STDOUT:
// CHECK:STDOUT: fn(%T.param_patt: %Interface.type) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %T.ref: %Interface.type = name_ref T, %T.loc13_15.1 [symbolic = %T.loc13_15.2 (constants.%T)]
// CHECK:STDOUT: %F.ref: %Interface.assoc_type = name_ref F, @Interface.%assoc0 [template = constants.%assoc0]
// CHECK:STDOUT: %T.as_type.loc18_4.1: type = facet_access_type %T.ref [symbolic = %T.as_type.loc18_4.2 (constants.%T.as_type)]
// CHECK:STDOUT: %.loc18: type = converted %T.ref, %T.as_type.loc18_4.1 [symbolic = %T.as_type.loc18_4.2 (constants.%T.as_type)]
// CHECK:STDOUT: %T.as_wit.loc18_4.1: <witness> = facet_access_witness %T.ref [symbolic = %T.as_wit.loc18_4.2 (constants.%T.as_wit)]
// CHECK:STDOUT: %impl.elem0.loc18_4.1: %F.type = impl_witness_access %T.as_wit.loc18_4.1, element0 [symbolic = %impl.elem0.loc18_4.2 (constants.%impl.elem0)]
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic fn @CallFacet(%T.loc21_14.1: %Interface.type) {
// CHECK:STDOUT: %T.loc21_14.2: %Interface.type = bind_symbolic_name T, 0 [symbolic = %T.loc21_14.2 (constants.%T)]
// CHECK:STDOUT: %T.patt.loc21_14.2: %Interface.type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc21_14.2 (constants.%T.patt)]
// CHECK:STDOUT: %T.as_type.loc21_32.2: type = facet_access_type %T.loc21_14.2 [symbolic = %T.as_type.loc21_32.2 (constants.%T.as_type)]
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT: %require_complete: <witness> = require_complete_type @CallFacet.%T.as_type.loc21_32.2 (%T.as_type) [symbolic = %require_complete (constants.%require_complete)]
// CHECK:STDOUT:
// CHECK:STDOUT: fn(%T.param_patt: %Interface.type, %x.param_patt: @CallFacet.%T.as_type.loc21_32.2 (%T.as_type)) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %x.ref: @CallFacet.%T.as_type.loc21_32.2 (%T.as_type) = name_ref x, %x
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @F(constants.%Self) {}
// CHECK:STDOUT:
// CHECK:STDOUT: specific @CallStatic(constants.%T) {
// CHECK:STDOUT: %T.loc13_15.2 => constants.%T
// CHECK:STDOUT: %T.patt.loc13_15.2 => constants.%T
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @CallFacet(constants.%T) {
// CHECK:STDOUT: %T.loc21_14.2 => constants.%T
// CHECK:STDOUT: %T.patt.loc21_14.2 => constants.%T
// CHECK:STDOUT: %T.as_type.loc21_32.2 => constants.%T.as_type
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -91,7 +91,7 @@ fn G(T:! Generic(B)) {
// CHECK:STDOUT: %impl_witness.49b: <witness> = impl_witness (@impl.2.%F.decl) [template]
// CHECK:STDOUT: %F.type.005: type = fn_type @F.2 [template]
// CHECK:STDOUT: %F.317: %F.type.005 = struct_value () [template]
// CHECK:STDOUT: %WithAssocFn.facet: %WithAssocFn.type.ce6 = facet_value %C, %impl_witness.49b [symbolic]
// CHECK:STDOUT: %WithAssocFn.facet: %WithAssocFn.type.683 = facet_value %C, %impl_witness.49b [template]
// CHECK:STDOUT: %X.val: %X = struct_value () [template]
// CHECK:STDOUT: %N: %T.8b3 = bind_symbolic_name N, 1 [symbolic]
// CHECK:STDOUT: %N.patt: %T.8b3 = symbolic_binding_pattern N, 1 [symbolic]
@@ -116,14 +116,17 @@ impl C as AddWith(C) {
// CHECK:STDOUT: %impl_witness: <witness> = impl_witness (@impl.%F.decl) [template]
// CHECK:STDOUT: %F.type.c09: type = fn_type @F.2 [template]
// CHECK:STDOUT: %F.e62: %F.type.c09 = struct_value () [template]
// CHECK:STDOUT: %AddWith.facet: %AddWith.type.bc7 = facet_value %C, %impl_witness [symbolic]
// CHECK:STDOUT: %AddWith.facet: %AddWith.type.e8e = facet_value %C, %impl_witness [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Main.AddWith: %AddWith.type.b35 = import_ref Main//a, AddWith, loaded [template = constants.%AddWith.generic]
// CHECK:STDOUT: %Main.import_ref.f6b058.1: type = import_ref Main//a, loc4_19, loaded [symbolic = @AddWith.%T (constants.%T)]
// CHECK:STDOUT: %Main.import_ref.476 = import_ref Main//a, inst26 [no loc], unloaded
// CHECK:STDOUT: %Main.import_ref.550 = import_ref Main//a, loc5_9, unloaded
// CHECK:STDOUT: %Main.F: @AddWith.%F.type (%F.type.fbc) = import_ref Main//a, F, loaded [symbolic = @AddWith.%F (constants.%F.be3)]
// CHECK:STDOUT: %Main.import_ref.f6b058.2: type = import_ref Main//a, loc4_19, loaded [symbolic = @AddWith.%T (constants.%T)]
// CHECK:STDOUT: %Main.import_ref.5a4: @AddWith.%AddWith.type (%AddWith.type.bc7) = import_ref Main//a, inst26 [no loc], loaded [symbolic = @AddWith.%Self (constants.%Self)]
// CHECK:STDOUT: %Main.import_ref.0c5 = import_ref Main//a, loc5_9, unloaded
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -143,7 +146,7 @@ impl C as AddWith(C) {
// CHECK:STDOUT: %impl_witness: <witness> = impl_witness (@impl.%F.decl) [template = constants.%impl_witness]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic interface @AddWith(constants.%T: type) [from "a.carbon"] {
// CHECK:STDOUT: generic interface @AddWith(imports.%Main.import_ref.f6b058.1: type) [from "a.carbon"] {
// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T)]
// CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 [symbolic = %T.patt (constants.%T.patt)]
// CHECK:STDOUT:
@@ -179,7 +182,7 @@ impl C as AddWith(C) {
// CHECK:STDOUT: .Self = constants.%C
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic fn @F.1(constants.%T: type, constants.%Self: %AddWith.type.bc7) [from "a.carbon"] {
// CHECK:STDOUT: generic fn @F.1(imports.%Main.import_ref.f6b058.2: type, imports.%Main.import_ref.5a4: @AddWith.%AddWith.type (%AddWith.type.bc7)) [from "a.carbon"] {
// CHECK:STDOUT: fn();
// CHECK:STDOUT: }
// CHECK:STDOUT:
+2 -1
View File
@@ -34,6 +34,7 @@ fn F() {
// CHECK:STDOUT: %G.type.c84: type = fn_type @G.2 [template]
// CHECK:STDOUT: %G.5a2: %G.type.c84 = struct_value () [template]
// CHECK:STDOUT: %I.facet: %I.type = facet_value %empty_tuple.type, %impl_witness [template]
// CHECK:STDOUT: %.fbf: type = fn_type_with_self_type %G.type.bff, %I.facet [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -74,7 +75,7 @@ fn F() {
// CHECK:STDOUT: %.loc18: %empty_tuple.type = tuple_literal ()
// CHECK:STDOUT: %I.ref: type = name_ref I, %I.decl [template = constants.%I.type]
// CHECK:STDOUT: %G.ref: %I.assoc_type = name_ref G, @I.%assoc0 [template = constants.%assoc0]
// CHECK:STDOUT: %impl.elem0: %G.type.bff = impl_witness_access constants.%impl_witness, element0 [template = constants.%G.5a2]
// CHECK:STDOUT: %impl.elem0: %.fbf = impl_witness_access constants.%impl_witness, element0 [template = constants.%G.5a2]
// CHECK:STDOUT: %G.call: init %empty_tuple.type = call %impl.elem0()
// CHECK:STDOUT: return
// CHECK:STDOUT: }
@@ -631,6 +631,8 @@ interface Foo(a:! const (const C)) {}
// CHECK:STDOUT: %Main.Bar: %Bar.type = import_ref Main//two_file, Bar, loaded [template = constants.%Bar.generic]
// CHECK:STDOUT: %Main.import_ref.8f2: <witness> = import_ref Main//two_file, loc4_10, loaded [template = constants.%complete_type]
// CHECK:STDOUT: %Main.import_ref.2c4 = import_ref Main//two_file, inst14 [no loc], unloaded
// CHECK:STDOUT: %Main.import_ref.11fba2.1: %C = import_ref Main//two_file, loc7_15, loaded [symbolic = @Foo.%a (constants.%a)]
// CHECK:STDOUT: %Main.import_ref.11fba2.2: %C = import_ref Main//two_file, loc8_15, loaded [symbolic = @Bar.%a (constants.%a)]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -660,7 +662,7 @@ interface Foo(a:! const (const C)) {}
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic interface @Foo(constants.%a: %C) [from "two_file.carbon"] {
// CHECK:STDOUT: generic interface @Foo(imports.%Main.import_ref.11fba2.1: %C) [from "two_file.carbon"] {
// CHECK:STDOUT: %a: %C = bind_symbolic_name a, 0 [symbolic = %a (constants.%a)]
// CHECK:STDOUT: %a.patt: %C = symbolic_binding_pattern a, 0 [symbolic = %a.patt (constants.%a.patt)]
// CHECK:STDOUT:
@@ -684,7 +686,7 @@ interface Foo(a:! const (const C)) {}
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic interface @Bar(constants.%a: %C) [from "two_file.carbon"] {
// CHECK:STDOUT: generic interface @Bar(imports.%Main.import_ref.11fba2.2: %C) [from "two_file.carbon"] {
// CHECK:STDOUT: %a: %C = bind_symbolic_name a, 0 [symbolic = %a (constants.%a)]
// CHECK:STDOUT: %a.patt: %C = symbolic_binding_pattern a, 0 [symbolic = %a.patt (constants.%a.patt)]
// CHECK:STDOUT:
@@ -1071,6 +1073,7 @@ interface Foo(a:! const (const C)) {}
// CHECK:STDOUT: %Main.Foo: %Foo.type = import_ref Main//alias_two_file, Foo, loaded [template = constants.%Foo.generic]
// CHECK:STDOUT: %Main.import_ref.8f2: <witness> = import_ref Main//alias_two_file, loc4_10, loaded [template = constants.%complete_type]
// CHECK:STDOUT: %Main.import_ref.2c4 = import_ref Main//alias_two_file, inst14 [no loc], unloaded
// CHECK:STDOUT: %Main.import_ref.11f: %C = import_ref Main//alias_two_file, loc6_15, loaded [symbolic = @Foo.%a (constants.%a)]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -1093,7 +1096,7 @@ interface Foo(a:! const (const C)) {}
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic interface @Foo(constants.%a: %C) [from "alias_two_file.carbon"] {
// CHECK:STDOUT: generic interface @Foo(imports.%Main.import_ref.11f: %C) [from "alias_two_file.carbon"] {
// CHECK:STDOUT: %a: %C = bind_symbolic_name a, 0 [symbolic = %a (constants.%a)]
// CHECK:STDOUT: %a.patt: %C = symbolic_binding_pattern a, 0 [symbolic = %a.patt (constants.%a.patt)]
// CHECK:STDOUT:
@@ -38,10 +38,13 @@ interface I {
// CHECK:STDOUT: %tuple.type.d07: type = tuple_type (%i32, %i32) [template]
// CHECK:STDOUT: %assoc3: %I.assoc_type = assoc_entity element3, @I.%N [template]
// CHECK:STDOUT: %int_42.20e: Core.IntLiteral = int_value 42 [template]
// CHECK:STDOUT: %ImplicitAs.type.205: type = facet_type <@ImplicitAs, @ImplicitAs(%i32)> [template]
// CHECK:STDOUT: %Convert.type.1b6: type = fn_type @Convert.1, @ImplicitAs(%i32) [template]
// CHECK:STDOUT: %impl_witness.d39: <witness> = impl_witness (imports.%Core.import_ref.a5b), @impl.1(%int_32) [template]
// CHECK:STDOUT: %Convert.type.035: type = fn_type @Convert.2, @impl.1(%int_32) [template]
// CHECK:STDOUT: %Convert.956: %Convert.type.035 = struct_value () [template]
// CHECK:STDOUT: %ImplicitAs.facet: %ImplicitAs.type.205 = facet_value Core.IntLiteral, %impl_witness.d39 [template]
// CHECK:STDOUT: %.a0b: type = fn_type_with_self_type %Convert.type.1b6, %ImplicitAs.facet [template]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %int_42.20e, %Convert.956 [template]
// CHECK:STDOUT: %Convert.specific_fn: <specific function> = specific_function %Convert.bound, @Convert.2(%int_32) [template]
// CHECK:STDOUT: %int_42.c68: %i32 = int_value 42 [template]
@@ -107,10 +110,10 @@ interface I {
// CHECK:STDOUT: %N: %i32 = assoc_const_decl @N [template] {
// CHECK:STDOUT: %assoc3: %I.assoc_type = assoc_entity element3, @I.%N [template = constants.%assoc3]
// CHECK:STDOUT: %int_42: Core.IntLiteral = int_value 42 [template = constants.%int_42.20e]
// CHECK:STDOUT: %impl.elem0: %Convert.type.1b6 = impl_witness_access constants.%impl_witness.d39, element0 [template = constants.%Convert.956]
// CHECK:STDOUT: %Convert.bound: <bound method> = bound_method %int_42, %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_42) [template = constants.%int_42.c68]
// CHECK:STDOUT: %impl.elem0: %.a0b = impl_witness_access constants.%impl_witness.d39, element0 [template = constants.%Convert.956]
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %int_42, %impl.elem0 [template = constants.%Convert.bound]
// CHECK:STDOUT: %specific_fn: <specific function> = specific_function %bound_method, @Convert.2(constants.%int_32) [template = constants.%Convert.specific_fn]
// CHECK:STDOUT: %int.convert_checked: init %i32 = call %specific_fn(%int_42) [template = constants.%int_42.c68]
// CHECK:STDOUT: %.loc19_19.1: %i32 = value_of_initializer %int.convert_checked [template = constants.%int_42.c68]
// CHECK:STDOUT: %.loc19_19.2: %i32 = converted %int_42, %.loc19_19.1 [template = constants.%int_42.c68]
// CHECK:STDOUT: }