diff --git a/proposals/p6395.md b/proposals/p6395.md new file mode 100644 index 0000000000000..03e02f18e3980 --- /dev/null +++ b/proposals/p6395.md @@ -0,0 +1,167 @@ +# Type completeness in extend + + + +[Pull request](https://github.com/carbon-language/carbon-lang/pull/6395) + + + +## Table of contents + +- [Abstract](#abstract) +- [Problem](#problem) +- [Background](#background) +- [Proposal](#proposal) +- [Details](#details) +- [Rationale](#rationale) +- [Alternatives considered](#alternatives-considered) + + + +## Abstract + +Require the facet type in `extend require impls` and `extend impl as` +declarations to be complete, since `extend` changes the scopes which are looked +in for name lookup. + +## Problem + +Proposal +[#5168](https://github.com/carbon-language/carbon-lang/blob/trunk/proposals/p5168.md) +laid out rules for when a facet type needs to be identified or complete. When +`require impls Z` is written, then `Z` must be identified. However it does not +specify any rule for `extend require impls Z`. or `extend impl as Z`. + +If an interface `Y` uses `extend` for another interface `Z`, then a facet type +for `Y` will also allow name lookup into `Z`. Similarly if a class `Y` uses +`extend` for an interface `Z`, then an object of type `Y` will also allow name +lookup into `Z`. In both cases, when the definition of `Y` is complete, we +should also require `Z` to be complete, as its name scope becomes conceptually a +part of `Y`. + +Additionally, after an `extend ... Z` declaration inside the definition of `Y`, +the names of `Z` should be immediately available inside the `Y` definition, +including inside the nested definition of `extend impl as Z { ... }`. + +## Background + +- Proposal + [#5168](https://github.com/carbon-language/carbon-lang/blob/trunk/proposals/p5168.md): + Forward impl declaration of an incomplete interface +- Proposal + [#2760](https://github.com/carbon-language/carbon-lang/blob/trunk/proposals/p2760.md): + Consistent class and interface syntax + +## Proposal + +Require that `extend require impls Z` requires `Z` to be complete where the +declaration is written. Similarly, require that `extend impl as Z` requires `Z` +to be complete where the declaration is written. In both cases, this ensures +that `Z` is complete by the time the definition of the enclosing class, +interface, or named constraint is complete. And it ensures that we can perform +name lookup into `Z` from within the enclosing scope of the `extend` declaration +thereafter. + +We call a `extend require` declaration _extend-reachable_ from a facet type if +it's enclosing interface or named constraint is part of that facet type, or if +its enclosing interface or named constraint is named by another +_extend-reachable_ declaration. That is, we can find a path from the facet type +to the `extend require` declaration through other `extend require` declarations. + +We say that a facet type is complete if: + +- All its _extend-reachable_ `extend require` declarations are complete. This + follows from the enclosing interface or named constraint being complete. +- We are able to form a specific for each interface and named constraint + extended by the facet type. +- We are able to form a specific for each _extend-reachable_ `extend require` + declaration in the context of the specific facet type being completed, + without monomorphization errors. + +## Details + +To `extend` an entity `Y` with another `Z` means that name lookups into `Y` will +also look into `Z`. At the end of the definition of `Y`, we expect to be able to +perform name lookup into `Y`, as it is complete. To maintain this property +through `extend`, we require that `extend require` declarations only name other +interfaces or named constraints that are themselves complete. + +This functions recursively: Since each interface or named constraint is +complete, we already know the `extend require` declarations inside are complete. +However it is possible to uncover monomorphization errors once a specific is +applied to the facet type in an `extend require` or `extend impls` declaration. +For example: + +```carbon +interface Z(T:! type) {} + +class C(N! i32) { + extend impls Z(array(i32, N)) {} +} +``` + +Here the facet type `Z(array(i32, N))` is complete at the point where it is +written, so `C(N)` is complete. However checking `C(-1)` for completeness must +form a specific for the `extend impls` declaration that will generate an error +(as -1 is not valid for an array size), failing type completeness. + +The same is true for any `extend require` declaration which is +_extend-reachable_ from the facet type in the `extend` declaration. So we +require type completeness to form a specific for each extended interface or +named constraint in the facet type, as well as for each extended interface or +named constraint in the facet type of a `extend require` declaration that is +_extend-reachable_ from them. This implies forming a specific for any interface +or named constraint along the path to an _extend-reachable_ `extend require` +declaration. + +These rules prohibit `extend require` to name its enclosing interface or named +constraint, since the enclosing definition is trivially not complete yet. This +seems reasonable as all names available inside the enclosing interface or named +constraint are already available or would conflict with the ones that are. + +## Rationale + +This is based on the principle of +[Code that is easy to read, understand, and write](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write). +For code to be easy to write, the rules need to be consistent. Once an `extend` +declaration has been written, the names inside should become available through +the enclosing scope immediately. If we allow an interface named in an +_extend-reachable_ `extend require` declaration to be incomplete, then name +lookup will fail ambiguously. Those same names may be valid later once the +interface is defined. + +## Alternatives considered + +We considered not requiring that the facet type in an `extend` be complete where +it is written, but only when the enclosing class, interface, or named constraint +is required to be complete. However this does not allow the use of names from +the facet type in the `extend` to be used within the enclosing definition scope. +They would not become available until the enclosing definition scope was closed +and complete. + +In particular, we want this to work: + +```carbon +interface Z { + let X:! type; + fn F() -> X; +} +class C { + extend impl as Z where .X = () { + // Names `X` directly. + fn F() -> X; + } + + // Names `X` and `F` directly. + fn G() -> X { return F(); } +} + +// Now `C` is complete, `C.X` and `C.F` are also available. +fn H() -> C.X { + return C.F(); +} +``` diff --git a/toolchain/check/testdata/impl/use_assoc_const.carbon b/toolchain/check/testdata/impl/use_assoc_const.carbon index d89e5a5f630b4..cdc07b3c9459c 100644 --- a/toolchain/check/testdata/impl/use_assoc_const.carbon +++ b/toolchain/check/testdata/impl/use_assoc_const.carbon @@ -141,6 +141,9 @@ interface J { class E { extend impl as J where .U = i32 { + // TODO: U should be in scope and usable as soon as we finish the + // declaration / enter the definition. + // // CHECK:STDERR: fail_todo_use_associated_constant_in_impl.carbon:[[@LINE+14]]:13: error: cannot implicitly convert non-type value of type `` to `type` [ConversionFailureNonTypeToFacet] // CHECK:STDERR: fn F(u: U) -> U { // CHECK:STDERR: ^ @@ -161,6 +164,67 @@ class E { } } +// --- fail_todo_call_extend_fn.carbon +library "[[@TEST_NAME]]"; + +interface J { + fn F() {} +} + +class E { + extend impl as J { + fn F() {} + } + + // TODO: `F` should be in scope and directly callable. + // CHECK:STDERR: fail_todo_call_extend_fn.carbon:[[@LINE+4]]:12: error: value of type `` is not callable [CallToNonCallable] + // CHECK:STDERR: fn G() { F(); } + // CHECK:STDERR: ^~~ + // CHECK:STDERR: + fn G() { F(); } +} + +// --- fail_todo_call_extend_method.carbon +library "[[@TEST_NAME]]"; + +interface J { + fn F[self: Self]() {} +} + +class E { + extend impl as J { + fn F[self: Self]() {} + } + + // TODO: `F` should be in scope and directly callable. + // CHECK:STDERR: fail_todo_call_extend_method.carbon:[[@LINE+4]]:12: error: value of type `` is not callable [CallToNonCallable] + // CHECK:STDERR: fn G() { F(); } + // CHECK:STDERR: ^~~ + // CHECK:STDERR: + fn G() { F(); } +} + +// --- fail_todo_use_extend_constant.carbon +library "[[@TEST_NAME]]"; + +interface J { + let X:! type; +} + +class E { + extend impl as J where .X = () {} + + // TODO: `X` should be in scope and directly usable. + // CHECK:STDERR: fail_todo_use_extend_constant.carbon:[[@LINE+7]]:13: error: cannot implicitly convert non-type value of type `` to `type` [ConversionFailureNonTypeToFacet] + // CHECK:STDERR: fn G() -> X { return (); } + // CHECK:STDERR: ^ + // CHECK:STDERR: fail_todo_use_extend_constant.carbon:[[@LINE+4]]:13: note: type `` does not implement interface `Core.ImplicitAs(type)` [MissingImplInMemberAccessNote] + // CHECK:STDERR: fn G() -> X { return (); } + // CHECK:STDERR: ^ + // CHECK:STDERR: + fn G() -> X { return (); } +} + // --- fail_todo_self_period_associated_type.carbon library "[[@TEST_NAME]]"; @@ -2309,11 +2373,11 @@ fn F() { // CHECK:STDOUT: %J.impl_witness: = impl_witness @E.%J.impl_witness_table [concrete] // CHECK:STDOUT: %ImplicitAs.type.cc7: type = generic_interface_type @ImplicitAs [concrete] // CHECK:STDOUT: %ImplicitAs.generic: %ImplicitAs.type.cc7 = struct_value () [concrete] -// CHECK:STDOUT: %E.as.J.impl.F.type.3487c0.1: type = fn_type @E.as.J.impl.F.loc24_21.1 [concrete] +// CHECK:STDOUT: %E.as.J.impl.F.type.3487c0.1: type = fn_type @E.as.J.impl.F.loc27_21.1 [concrete] // CHECK:STDOUT: %E.as.J.impl.F.1487eb.1: %E.as.J.impl.F.type.3487c0.1 = struct_value () [concrete] // CHECK:STDOUT: %J.facet: %J.type = facet_value %E, (%J.impl_witness) [concrete] // CHECK:STDOUT: %pattern_type.7ce: type = pattern_type %i32 [concrete] -// CHECK:STDOUT: %E.as.J.impl.F.type.3487c0.2: type = fn_type @E.as.J.impl.F.loc24_21.2 [concrete] +// CHECK:STDOUT: %E.as.J.impl.F.type.3487c0.2: type = fn_type @E.as.J.impl.F.loc27_21.2 [concrete] // CHECK:STDOUT: %E.as.J.impl.F.1487eb.2: %E.as.J.impl.F.type.3487c0.2 = struct_value () [concrete] // CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] // CHECK:STDOUT: %complete_type.357: = complete_type_witness %empty_struct_type [concrete] @@ -2379,24 +2443,24 @@ fn F() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: impl @E.as.J.impl: %Self.ref as %.loc9_20 { -// CHECK:STDOUT: %E.as.J.impl.F.decl.loc24_21.1: %E.as.J.impl.F.type.3487c0.1 = fn_decl @E.as.J.impl.F.loc24_21.1 [concrete = constants.%E.as.J.impl.F.1487eb.1] { +// CHECK:STDOUT: %E.as.J.impl.F.decl.loc27_21.1: %E.as.J.impl.F.type.3487c0.1 = fn_decl @E.as.J.impl.F.loc27_21.1 [concrete = constants.%E.as.J.impl.F.1487eb.1] { // CHECK:STDOUT: %u.patt: = value_binding_pattern u [concrete] // CHECK:STDOUT: %u.param_patt: = value_param_pattern %u.patt, call_param0 [concrete] // CHECK:STDOUT: %return.patt: = return_slot_pattern [concrete] // CHECK:STDOUT: %return.param_patt: = out_param_pattern %return.patt, call_param1 [concrete] // CHECK:STDOUT: } { -// CHECK:STDOUT: %U.ref.loc24_19: %J.assoc_type = name_ref U, @U.%assoc0 [concrete = constants.%assoc0.411] -// CHECK:STDOUT: %.loc24_19: type = converted %U.ref.loc24_19, [concrete = ] +// CHECK:STDOUT: %U.ref.loc27_19: %J.assoc_type = name_ref U, @U.%assoc0 [concrete = constants.%assoc0.411] +// CHECK:STDOUT: %.loc27_19: type = converted %U.ref.loc27_19, [concrete = ] // CHECK:STDOUT: %u.param: = value_param call_param0 // CHECK:STDOUT: %.1: = splice_block [concrete = ] { -// CHECK:STDOUT: %U.ref.loc24_13: %J.assoc_type = name_ref U, @U.%assoc0 [concrete = constants.%assoc0.411] -// CHECK:STDOUT: %.loc24_13: type = converted %U.ref.loc24_13, [concrete = ] +// CHECK:STDOUT: %U.ref.loc27_13: %J.assoc_type = name_ref U, @U.%assoc0 [concrete = constants.%assoc0.411] +// CHECK:STDOUT: %.loc27_13: type = converted %U.ref.loc27_13, [concrete = ] // CHECK:STDOUT: } // CHECK:STDOUT: %u: = value_binding u, %u.param // CHECK:STDOUT: %return.param: ref = out_param call_param1 // CHECK:STDOUT: %return: ref = return_slot %return.param // CHECK:STDOUT: } -// CHECK:STDOUT: %E.as.J.impl.F.decl.loc24_21.2: %E.as.J.impl.F.type.3487c0.2 = fn_decl @E.as.J.impl.F.loc24_21.2 [concrete = constants.%E.as.J.impl.F.1487eb.2] { +// CHECK:STDOUT: %E.as.J.impl.F.decl.loc27_21.2: %E.as.J.impl.F.type.3487c0.2 = fn_decl @E.as.J.impl.F.loc27_21.2 [concrete = constants.%E.as.J.impl.F.1487eb.2] { // CHECK:STDOUT: %u.patt: %pattern_type.7ce = value_binding_pattern u [concrete] // CHECK:STDOUT: %u.param_patt: %pattern_type.7ce = value_param_pattern %u.patt, call_param0 [concrete] // CHECK:STDOUT: %return.patt: %pattern_type.7ce = return_slot_pattern [concrete] @@ -2410,7 +2474,7 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .U = -// CHECK:STDOUT: .F = %E.as.J.impl.F.decl.loc24_21.1 +// CHECK:STDOUT: .F = %E.as.J.impl.F.decl.loc27_21.1 // CHECK:STDOUT: witness = @E.%J.impl_witness // CHECK:STDOUT: } // CHECK:STDOUT: @@ -2431,7 +2495,7 @@ fn F() { // CHECK:STDOUT: requirement_rewrite %impl.elem0, %i32 // CHECK:STDOUT: } // CHECK:STDOUT: } -// CHECK:STDOUT: %J.impl_witness_table = impl_witness_table (%impl_witness_assoc_constant, @E.as.J.impl.%E.as.J.impl.F.decl.loc24_21.2), @E.as.J.impl [concrete] +// CHECK:STDOUT: %J.impl_witness_table = impl_witness_table (%impl_witness_assoc_constant, @E.as.J.impl.%E.as.J.impl.F.decl.loc27_21.2), @E.as.J.impl [concrete] // CHECK:STDOUT: %J.impl_witness: = impl_witness %J.impl_witness_table [concrete = constants.%J.impl_witness] // CHECK:STDOUT: %impl_witness_assoc_constant: type = impl_witness_assoc_constant constants.%i32 [concrete = constants.%i32] // CHECK:STDOUT: %complete_type: = complete_type_witness constants.%empty_struct_type [concrete = constants.%complete_type.357] @@ -2453,15 +2517,15 @@ fn F() { // CHECK:STDOUT: fn(%u.param: @J.F.%impl.elem0.loc5_11.1 (%impl.elem0.fa9)) -> @J.F.%impl.elem0.loc5_11.1 (%impl.elem0.fa9); // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @E.as.J.impl.F.loc24_21.1(%u.param: ) -> { +// CHECK:STDOUT: fn @E.as.J.impl.F.loc27_21.1(%u.param: ) -> { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %u.ref: = name_ref u, %u // CHECK:STDOUT: return to %return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @E.as.J.impl.F.loc24_21.2(%u.param: %i32) -> %i32 [thunk @E.as.J.impl.%E.as.J.impl.F.decl.loc24_21.1] { +// CHECK:STDOUT: fn @E.as.J.impl.F.loc27_21.2(%u.param: %i32) -> %i32 [thunk @E.as.J.impl.%E.as.J.impl.F.decl.loc27_21.1] { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %F.ref: %E.as.J.impl.F.type.3487c0.1 = name_ref F, @E.as.J.impl.%E.as.J.impl.F.decl.loc24_21.1 [concrete = constants.%E.as.J.impl.F.1487eb.1] +// CHECK:STDOUT: %F.ref: %E.as.J.impl.F.type.3487c0.1 = name_ref F, @E.as.J.impl.%E.as.J.impl.F.decl.loc27_21.1 [concrete = constants.%E.as.J.impl.F.1487eb.1] // CHECK:STDOUT: %u.ref: %i32 = name_ref u, %u.param // CHECK:STDOUT: %return.ref: ref %i32 = name_ref , %return.param // CHECK:STDOUT: %E.as.J.impl.F.call: init = call %F.ref() @@ -2486,6 +2550,362 @@ fn F() { // CHECK:STDOUT: %pattern_type => constants.%pattern_type.7ce // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_call_extend_fn.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %J.type: type = facet_type <@J> [concrete] +// CHECK:STDOUT: %Self: %J.type = symbolic_binding Self, 0 [symbolic] +// CHECK:STDOUT: %J.F.type: type = fn_type @J.F [concrete] +// CHECK:STDOUT: %J.F: %J.F.type = struct_value () [concrete] +// CHECK:STDOUT: %J.assoc_type: type = assoc_entity_type @J [concrete] +// CHECK:STDOUT: %assoc0: %J.assoc_type = assoc_entity element0, @J.%J.F.decl [concrete] +// CHECK:STDOUT: %E: type = class_type @E [concrete] +// CHECK:STDOUT: %J.impl_witness: = impl_witness @E.%J.impl_witness_table [concrete] +// CHECK:STDOUT: %E.as.J.impl.F.type: type = fn_type @E.as.J.impl.F [concrete] +// CHECK:STDOUT: %E.as.J.impl.F: %E.as.J.impl.F.type = struct_value () [concrete] +// CHECK:STDOUT: %J.facet: %J.type = facet_value %E, (%J.impl_witness) [concrete] +// CHECK:STDOUT: %E.G.type: type = fn_type @E.G [concrete] +// CHECK:STDOUT: %E.G: %E.G.type = struct_value () [concrete] +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [concrete] { +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .J = %J.decl +// CHECK:STDOUT: .E = %E.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %J.decl: type = interface_decl @J [concrete = constants.%J.type] {} {} +// CHECK:STDOUT: %E.decl: type = class_decl @E [concrete = constants.%E] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @J { +// CHECK:STDOUT: %Self: %J.type = symbolic_binding Self, 0 [symbolic = constants.%Self] +// CHECK:STDOUT: %J.F.decl: %J.F.type = fn_decl @J.F [concrete = constants.%J.F] {} {} +// CHECK:STDOUT: %assoc0: %J.assoc_type = assoc_entity element0, %J.F.decl [concrete = constants.%assoc0] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .F = %assoc0 +// CHECK:STDOUT: witness = (%J.F.decl) +// CHECK:STDOUT: +// CHECK:STDOUT: !requires: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @E.as.J.impl: %Self.ref as %J.ref { +// CHECK:STDOUT: %E.as.J.impl.F.decl: %E.as.J.impl.F.type = fn_decl @E.as.J.impl.F [concrete = constants.%E.as.J.impl.F] {} {} +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .F = %E.as.J.impl.F.decl +// CHECK:STDOUT: witness = @E.%J.impl_witness +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @E { +// CHECK:STDOUT: impl_decl @E.as.J.impl [concrete] {} { +// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%E [concrete = constants.%E] +// CHECK:STDOUT: %J.ref: type = name_ref J, file.%J.decl [concrete = constants.%J.type] +// CHECK:STDOUT: } +// CHECK:STDOUT: %J.impl_witness_table = impl_witness_table (@E.as.J.impl.%E.as.J.impl.F.decl), @E.as.J.impl [concrete] +// CHECK:STDOUT: %J.impl_witness: = impl_witness %J.impl_witness_table [concrete = constants.%J.impl_witness] +// CHECK:STDOUT: %E.G.decl: %E.G.type = fn_decl @E.G [concrete = constants.%E.G] {} {} +// CHECK:STDOUT: %complete_type: = complete_type_witness constants.%empty_struct_type [concrete = constants.%complete_type] +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%E +// CHECK:STDOUT: .J = +// CHECK:STDOUT: .G = %E.G.decl +// CHECK:STDOUT: .F = +// CHECK:STDOUT: extend @E.as.J.impl.%J.ref +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @J.F(@J.%Self: %J.type) { +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: fn() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @E.as.J.impl.F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @E.G() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %F.ref: %J.assoc_type = name_ref F, @J.%assoc0 [concrete = constants.%assoc0] +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @J.F(constants.%Self) {} +// CHECK:STDOUT: +// CHECK:STDOUT: specific @J.F(constants.%J.facet) {} +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_call_extend_method.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %J.type: type = facet_type <@J> [concrete] +// CHECK:STDOUT: %Self: %J.type = symbolic_binding Self, 0 [symbolic] +// CHECK:STDOUT: %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self [symbolic] +// CHECK:STDOUT: %pattern_type.4c4: type = pattern_type %Self.binding.as_type [symbolic] +// CHECK:STDOUT: %J.F.type: type = fn_type @J.F [concrete] +// CHECK:STDOUT: %J.F: %J.F.type = struct_value () [concrete] +// CHECK:STDOUT: %J.assoc_type: type = assoc_entity_type @J [concrete] +// CHECK:STDOUT: %assoc0: %J.assoc_type = assoc_entity element0, @J.%J.F.decl [concrete] +// CHECK:STDOUT: %require_complete: = require_complete_type %Self.binding.as_type [symbolic] +// CHECK:STDOUT: %E: type = class_type @E [concrete] +// CHECK:STDOUT: %J.impl_witness: = impl_witness @E.%J.impl_witness_table [concrete] +// CHECK:STDOUT: %pattern_type.a4a: type = pattern_type %E [concrete] +// CHECK:STDOUT: %E.as.J.impl.F.type: type = fn_type @E.as.J.impl.F [concrete] +// CHECK:STDOUT: %E.as.J.impl.F: %E.as.J.impl.F.type = struct_value () [concrete] +// CHECK:STDOUT: %J.facet: %J.type = facet_value %E, (%J.impl_witness) [concrete] +// CHECK:STDOUT: %E.G.type: type = fn_type @E.G [concrete] +// CHECK:STDOUT: %E.G: %E.G.type = struct_value () [concrete] +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [concrete] { +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .J = %J.decl +// CHECK:STDOUT: .E = %E.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %J.decl: type = interface_decl @J [concrete = constants.%J.type] {} {} +// CHECK:STDOUT: %E.decl: type = class_decl @E [concrete = constants.%E] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @J { +// CHECK:STDOUT: %Self: %J.type = symbolic_binding Self, 0 [symbolic = constants.%Self] +// CHECK:STDOUT: %J.F.decl: %J.F.type = fn_decl @J.F [concrete = constants.%J.F] { +// CHECK:STDOUT: %self.patt: @J.F.%pattern_type (%pattern_type.4c4) = value_binding_pattern self [concrete] +// CHECK:STDOUT: %self.param_patt: @J.F.%pattern_type (%pattern_type.4c4) = value_param_pattern %self.patt, call_param0 [concrete] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %self.param: @J.F.%Self.binding.as_type (%Self.binding.as_type) = value_param call_param0 +// CHECK:STDOUT: %.loc4_14.1: type = splice_block %.loc4_14.2 [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)] { +// CHECK:STDOUT: %Self.ref: %J.type = name_ref Self, @J.%Self [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: %Self.as_type: type = facet_access_type %Self.ref [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)] +// CHECK:STDOUT: %.loc4_14.2: type = converted %Self.ref, %Self.as_type [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)] +// CHECK:STDOUT: } +// CHECK:STDOUT: %self: @J.F.%Self.binding.as_type (%Self.binding.as_type) = value_binding self, %self.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %assoc0: %J.assoc_type = assoc_entity element0, %J.F.decl [concrete = constants.%assoc0] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .F = %assoc0 +// CHECK:STDOUT: witness = (%J.F.decl) +// CHECK:STDOUT: +// CHECK:STDOUT: !requires: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @E.as.J.impl: %Self.ref as %J.ref { +// CHECK:STDOUT: %E.as.J.impl.F.decl: %E.as.J.impl.F.type = fn_decl @E.as.J.impl.F [concrete = constants.%E.as.J.impl.F] { +// CHECK:STDOUT: %self.patt: %pattern_type.a4a = value_binding_pattern self [concrete] +// CHECK:STDOUT: %self.param_patt: %pattern_type.a4a = value_param_pattern %self.patt, call_param0 [concrete] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %self.param: %E = value_param call_param0 +// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%E [concrete = constants.%E] +// CHECK:STDOUT: %self: %E = value_binding self, %self.param +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .F = %E.as.J.impl.F.decl +// CHECK:STDOUT: witness = @E.%J.impl_witness +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @E { +// CHECK:STDOUT: impl_decl @E.as.J.impl [concrete] {} { +// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%E [concrete = constants.%E] +// CHECK:STDOUT: %J.ref: type = name_ref J, file.%J.decl [concrete = constants.%J.type] +// CHECK:STDOUT: } +// CHECK:STDOUT: %J.impl_witness_table = impl_witness_table (@E.as.J.impl.%E.as.J.impl.F.decl), @E.as.J.impl [concrete] +// CHECK:STDOUT: %J.impl_witness: = impl_witness %J.impl_witness_table [concrete = constants.%J.impl_witness] +// CHECK:STDOUT: %E.G.decl: %E.G.type = fn_decl @E.G [concrete = constants.%E.G] {} {} +// CHECK:STDOUT: %complete_type: = complete_type_witness constants.%empty_struct_type [concrete = constants.%complete_type] +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%E +// CHECK:STDOUT: .J = +// CHECK:STDOUT: .G = %E.G.decl +// CHECK:STDOUT: .F = +// CHECK:STDOUT: extend @E.as.J.impl.%J.ref +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @J.F(@J.%Self: %J.type) { +// CHECK:STDOUT: %Self: %J.type = symbolic_binding Self, 0 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)] +// CHECK:STDOUT: %pattern_type: type = pattern_type %Self.binding.as_type [symbolic = %pattern_type (constants.%pattern_type.4c4)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete: = require_complete_type %Self.binding.as_type [symbolic = %require_complete (constants.%require_complete)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn(%self.param: @J.F.%Self.binding.as_type (%Self.binding.as_type)) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @E.as.J.impl.F(%self.param: %E) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @E.G() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %F.ref: %J.assoc_type = name_ref F, @J.%assoc0 [concrete = constants.%assoc0] +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @J.F(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: %Self.binding.as_type => constants.%Self.binding.as_type +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.4c4 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @J.F(constants.%J.facet) { +// CHECK:STDOUT: %Self => constants.%J.facet +// CHECK:STDOUT: %Self.binding.as_type => constants.%E +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.a4a +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_use_extend_constant.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %J.type: type = facet_type <@J> [concrete] +// CHECK:STDOUT: %Self.dc6: %J.type = symbolic_binding Self, 0 [symbolic] +// CHECK:STDOUT: %J.assoc_type: type = assoc_entity_type @J [concrete] +// CHECK:STDOUT: %assoc0.8fd: %J.assoc_type = assoc_entity element0, @J.%X [concrete] +// CHECK:STDOUT: %E: type = class_type @E [concrete] +// CHECK:STDOUT: %.Self: %J.type = symbolic_binding .Self [symbolic_self] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %.Self.binding.as_type: type = symbolic_binding_type .Self, %.Self [symbolic_self] +// CHECK:STDOUT: %J.lookup_impl_witness: = lookup_impl_witness %.Self, @J [symbolic_self] +// CHECK:STDOUT: %impl.elem0: type = impl_witness_access %J.lookup_impl_witness, element0 [symbolic_self] +// CHECK:STDOUT: %empty_tuple: %empty_tuple.type = tuple_value () [concrete] +// CHECK:STDOUT: %J_where.type: type = facet_type <@J where %impl.elem0 = %empty_tuple.type> [concrete] +// CHECK:STDOUT: %J.impl_witness: = impl_witness @E.%J.impl_witness_table [concrete] +// CHECK:STDOUT: %ImplicitAs.type.cc7: type = generic_interface_type @ImplicitAs [concrete] +// CHECK:STDOUT: %ImplicitAs.generic: %ImplicitAs.type.cc7 = struct_value () [concrete] +// CHECK:STDOUT: %E.G.type: type = fn_type @E.G [concrete] +// CHECK:STDOUT: %E.G: %E.G.type = struct_value () [concrete] +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [concrete] { +// CHECK:STDOUT: .ImplicitAs = %Core.ImplicitAs +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/... +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.ImplicitAs: %ImplicitAs.type.cc7 = import_ref Core//prelude/parts/as, ImplicitAs, loaded [concrete = constants.%ImplicitAs.generic] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .J = %J.decl +// CHECK:STDOUT: .E = %E.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %J.decl: type = interface_decl @J [concrete = constants.%J.type] {} {} +// CHECK:STDOUT: %E.decl: type = class_decl @E [concrete = constants.%E] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @J { +// CHECK:STDOUT: %Self: %J.type = symbolic_binding Self, 0 [symbolic = constants.%Self.dc6] +// CHECK:STDOUT: %X: type = assoc_const_decl @X [concrete] { +// CHECK:STDOUT: %assoc0: %J.assoc_type = assoc_entity element0, @J.%X [concrete = constants.%assoc0.8fd] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .X = @X.%assoc0 +// CHECK:STDOUT: witness = (%X) +// CHECK:STDOUT: +// CHECK:STDOUT: !requires: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic assoc_const @X(@J.%Self: %J.type) { +// CHECK:STDOUT: assoc_const X:! type; +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @E.as.J.impl: %Self.ref as %.loc8_20 { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: witness = @E.%J.impl_witness +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @E { +// CHECK:STDOUT: impl_decl @E.as.J.impl [concrete] {} { +// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%E [concrete = constants.%E] +// CHECK:STDOUT: %J.ref: type = name_ref J, file.%J.decl [concrete = constants.%J.type] +// CHECK:STDOUT: %.Self: %J.type = symbolic_binding .Self [symbolic_self = constants.%.Self] +// CHECK:STDOUT: %.Self.ref: %J.type = name_ref .Self, %.Self [symbolic_self = constants.%.Self] +// CHECK:STDOUT: %X.ref: %J.assoc_type = name_ref X, @X.%assoc0 [concrete = constants.%assoc0.8fd] +// CHECK:STDOUT: %.Self.as_type: type = facet_access_type %.Self.ref [symbolic_self = constants.%.Self.binding.as_type] +// CHECK:STDOUT: %.loc8_26: type = converted %.Self.ref, %.Self.as_type [symbolic_self = constants.%.Self.binding.as_type] +// CHECK:STDOUT: %impl.elem0: type = impl_witness_access constants.%J.lookup_impl_witness, element0 [symbolic_self = constants.%impl.elem0] +// CHECK:STDOUT: %.loc8_32.1: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %.loc8_32.2: type = converted %.loc8_32.1, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type] +// CHECK:STDOUT: %.loc8_20: type = where_expr %.Self [concrete = constants.%J_where.type] { +// CHECK:STDOUT: requirement_base_facet_type constants.%J.type +// CHECK:STDOUT: requirement_rewrite %impl.elem0, %.loc8_32.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: %J.impl_witness_table = impl_witness_table (%impl_witness_assoc_constant), @E.as.J.impl [concrete] +// CHECK:STDOUT: %J.impl_witness: = impl_witness %J.impl_witness_table [concrete = constants.%J.impl_witness] +// CHECK:STDOUT: %impl_witness_assoc_constant: type = impl_witness_assoc_constant constants.%empty_tuple.type [concrete = constants.%empty_tuple.type] +// CHECK:STDOUT: %E.G.decl: %E.G.type = fn_decl @E.G [concrete = constants.%E.G] { +// CHECK:STDOUT: %return.patt: = return_slot_pattern [concrete] +// CHECK:STDOUT: %return.param_patt: = out_param_pattern %return.patt, call_param0 [concrete] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %X.ref: %J.assoc_type = name_ref X, @X.%assoc0 [concrete = constants.%assoc0.8fd] +// CHECK:STDOUT: %.loc18_13: type = converted %X.ref, [concrete = ] +// CHECK:STDOUT: %return.param: ref = out_param call_param0 +// CHECK:STDOUT: %return: ref = return_slot %return.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %complete_type: = complete_type_witness constants.%empty_struct_type [concrete = constants.%complete_type] +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%E +// CHECK:STDOUT: .J = +// CHECK:STDOUT: .X = +// CHECK:STDOUT: .G = %E.G.decl +// CHECK:STDOUT: extend @E.as.J.impl.%.loc8_20 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @E.G() -> { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc18_25: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple] +// CHECK:STDOUT: return to %return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @X(constants.%Self.dc6) {} +// CHECK:STDOUT: +// CHECK:STDOUT: specific @X(constants.%.Self) {} +// CHECK:STDOUT: // CHECK:STDOUT: --- fail_todo_self_period_associated_type.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { diff --git a/toolchain/check/testdata/interface/incomplete.carbon b/toolchain/check/testdata/interface/incomplete.carbon index 2436d928bf701..8f74a9454efd3 100644 --- a/toolchain/check/testdata/interface/incomplete.carbon +++ b/toolchain/check/testdata/interface/incomplete.carbon @@ -69,6 +69,22 @@ interface B { require impls A where .X = {}; } +// --- todo_fail_extend_require_enclosing.carbon +library "[[@TEST_NAME]]"; + +interface A { + // TODO: Should be an error. + extend require impls A; +} + +// --- todo_fail_extend_require_enclosing_generic.carbon +library "[[@TEST_NAME]]"; + +interface A(T:! type) { + // TODO: Should be an error. + extend require impls A({}); +} + // CHECK:STDOUT: --- fail_incomplete_type.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -221,3 +237,130 @@ interface B { // CHECK:STDOUT: !requires: // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: --- todo_fail_extend_require_enclosing.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %A.type: type = facet_type <@A> [concrete] +// CHECK:STDOUT: %Self: %A.type = symbolic_binding Self, 0 [symbolic] +// CHECK:STDOUT: %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self [symbolic] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .A = %A.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %A.decl: type = interface_decl @A [concrete = constants.%A.type] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @A { +// CHECK:STDOUT: %Self: %A.type = symbolic_binding Self, 0 [symbolic = constants.%Self] +// CHECK:STDOUT: %A.require0.decl = require_decl @A.require0 [concrete] { +// CHECK:STDOUT: require %Self.as_type impls <@A> +// CHECK:STDOUT: } { +// CHECK:STDOUT: %Self.as_type: type = facet_access_type @A.%Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)] +// CHECK:STDOUT: %A.ref: type = name_ref A, file.%A.decl [concrete = constants.%A.type] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .A = +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: +// CHECK:STDOUT: !requires: +// CHECK:STDOUT: @A.require0 { +// CHECK:STDOUT: require @A.require0.%Self.as_type impls <@A> +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic require @A.require0(@A.%Self: %A.type) { +// CHECK:STDOUT: %Self: %A.type = symbolic_binding Self, 0 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @A.require0(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: %Self.binding.as_type => constants.%Self.binding.as_type +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- todo_fail_extend_require_enclosing_generic.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %type: type = facet_type [concrete] +// CHECK:STDOUT: %.Self: %type = symbolic_binding .Self [symbolic_self] +// CHECK:STDOUT: %T: type = symbolic_binding T, 0 [symbolic] +// CHECK:STDOUT: %pattern_type: type = pattern_type type [concrete] +// CHECK:STDOUT: %A.type.495: type = generic_interface_type @A [concrete] +// CHECK:STDOUT: %A.generic: %A.type.495 = struct_value () [concrete] +// CHECK:STDOUT: %A.type.c1c: type = facet_type <@A, @A(%T)> [symbolic] +// CHECK:STDOUT: %Self: %A.type.c1c = symbolic_binding Self, 1 [symbolic] +// CHECK:STDOUT: %Self.binding.as_type: type = symbolic_binding_type Self, 1, %Self [symbolic] +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %empty_struct: %empty_struct_type = struct_value () [concrete] +// CHECK:STDOUT: %A.type.23f: type = facet_type <@A, @A(%empty_struct_type)> [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .A = %A.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %A.decl: %A.type.495 = interface_decl @A [concrete = constants.%A.generic] { +// CHECK:STDOUT: %T.patt: %pattern_type = symbolic_binding_pattern T, 0 [concrete] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %.Self: %type = symbolic_binding .Self [symbolic_self = constants.%.Self] +// CHECK:STDOUT: %T.loc3_13.2: type = symbolic_binding T, 0 [symbolic = %T.loc3_13.1 (constants.%T)] +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic interface @A(%T.loc3_13.2: type) { +// CHECK:STDOUT: %T.loc3_13.1: type = symbolic_binding T, 0 [symbolic = %T.loc3_13.1 (constants.%T)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %A.type: type = facet_type <@A, @A(%T.loc3_13.1)> [symbolic = %A.type (constants.%A.type.c1c)] +// CHECK:STDOUT: %Self.loc3_23.2: @A.%A.type (%A.type.c1c) = symbolic_binding Self, 1 [symbolic = %Self.loc3_23.2 (constants.%Self)] +// CHECK:STDOUT: +// CHECK:STDOUT: interface { +// CHECK:STDOUT: %Self.loc3_23.1: @A.%A.type (%A.type.c1c) = symbolic_binding Self, 1 [symbolic = %Self.loc3_23.2 (constants.%Self)] +// CHECK:STDOUT: %A.require0.decl = require_decl @A.require0 [concrete] { +// CHECK:STDOUT: require %Self.as_type impls <@A, @A(constants.%empty_struct_type)> +// CHECK:STDOUT: } { +// CHECK:STDOUT: %Self.as_type: type = facet_access_type @A.%Self.loc3_23.1 [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)] +// CHECK:STDOUT: %A.ref: %A.type.495 = name_ref A, file.%A.decl [concrete = constants.%A.generic] +// CHECK:STDOUT: %.loc5_27: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct] +// CHECK:STDOUT: %.loc5_28: type = converted %.loc5_27, constants.%empty_struct_type [concrete = constants.%empty_struct_type] +// CHECK:STDOUT: %A.type.loc5_28: type = facet_type <@A, @A(constants.%empty_struct_type)> [concrete = constants.%A.type.23f] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self.loc3_23.1 +// CHECK:STDOUT: .A = +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: +// CHECK:STDOUT: !requires: +// CHECK:STDOUT: @A.require0 { +// CHECK:STDOUT: require @A.require0.%Self.as_type impls <@A, @A(constants.%empty_struct_type)> +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic require @A.require0(@A.%T.loc3_13.2: type, @A.%Self.loc3_23.1: @A.%A.type (%A.type.c1c)) { +// CHECK:STDOUT: %T: type = symbolic_binding T, 0 [symbolic = %T (constants.%T)] +// CHECK:STDOUT: %A.type.loc5_18: type = facet_type <@A, @A(%T)> [symbolic = %A.type.loc5_18 (constants.%A.type.c1c)] +// CHECK:STDOUT: %Self: @A.require0.%A.type.loc5_18 (%A.type.c1c) = symbolic_binding Self, 1 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: %Self.binding.as_type: type = symbolic_binding_type Self, 1, %Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @A(constants.%T) { +// CHECK:STDOUT: %T.loc3_13.1 => constants.%T +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @A(constants.%empty_struct_type) { +// CHECK:STDOUT: %T.loc3_13.1 => constants.%empty_struct_type +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @A.require0(constants.%T, constants.%Self) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: %A.type.loc5_18 => constants.%A.type.c1c +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: %Self.binding.as_type => constants.%Self.binding.as_type +// CHECK:STDOUT: } +// CHECK:STDOUT: