From ed80cd2f15156841c39741d789c3ca185808e8df Mon Sep 17 00:00:00 2001 From: josh11b <15258583+josh11b@users.noreply.github.com> Date: Mon, 25 Nov 2024 17:12:46 -0800 Subject: [PATCH] Facet member access (#4371) Adds `FacetAccessWitness` instruction and uses it in `member_access.cpp` to support accessing members of facets. Still to do: interface witness access is producing runtime values when it should produce symbolic values. --------- Co-authored-by: Josh L --- toolchain/check/eval.cpp | 16 +- toolchain/check/member_access.cpp | 146 +++++++++++++----- .../impl/fail_todo_impl_assoc_const.carbon | 38 ++--- .../no_prelude/fail_member_lookup.carbon | 64 +++++++- .../no_prelude/fail_todo_facet_lookup.carbon | 28 ++-- .../testdata/where_expr/constraints.carbon | 119 +++++++------- .../testdata/where_expr/designator.carbon | 5 +- .../testdata/where_expr/non_generic.carbon | 11 +- toolchain/sem_ir/file.cpp | 1 + toolchain/sem_ir/inst_kind.def | 1 + toolchain/sem_ir/stringify_type.cpp | 6 + toolchain/sem_ir/typed_insts.h | 16 +- 12 files changed, 309 insertions(+), 142 deletions(-) diff --git a/toolchain/check/eval.cpp b/toolchain/check/eval.cpp index eedb0fa7c009..7fef1804defe 100644 --- a/toolchain/check/eval.cpp +++ b/toolchain/check/eval.cpp @@ -1627,7 +1627,21 @@ static auto TryEvalInstInContext(EvalContext& eval_context, return MakeNonConstantResult(phase); } } - + case CARBON_KIND(SemIR::FacetAccessWitness typed_inst): { + Phase phase = Phase::Template; + if (ReplaceFieldWithConstantValue( + eval_context, &typed_inst, + &SemIR::FacetAccessWitness::facet_value_inst_id, &phase)) { + if (auto facet_value = eval_context.insts().TryGetAs( + typed_inst.facet_value_inst_id)) { + return eval_context.constant_values().Get( + facet_value->witness_inst_id); + } + return MakeConstantResult(eval_context.context(), typed_inst, phase); + } else { + return MakeNonConstantResult(phase); + } + } case CARBON_KIND(SemIR::WhereExpr typed_inst): { Phase phase = Phase::Template; SemIR::TypeId base_facet_type_id = diff --git a/toolchain/check/member_access.cpp b/toolchain/check/member_access.cpp index cce4dd077265..007b7fc63e89 100644 --- a/toolchain/check/member_access.cpp +++ b/toolchain/check/member_access.cpp @@ -124,6 +124,46 @@ static auto ScopeNeedsImplLookup(Context& context, return true; } +static auto GetInterfaceFromFacetType(Context& context, SemIR::TypeId type_id) + -> std::optional { + auto facet_type = context.types().GetAs(type_id); + const auto& facet_type_info = + context.facet_types().Get(facet_type.facet_type_id); + return facet_type_info.TryAsSingleInterface(); +} + +static auto AccessMemberOfInterfaceWitness( + Context& context, SemIR::LocId loc_id, SemIR::InstId witness_id, + SemIR::SpecificId interface_specific_id, + SemIR::AssociatedEntityType assoc_type, SemIR::InstId member_id) + -> SemIR::InstId { + auto member_value_id = context.constant_values().GetConstantInstId(member_id); + if (!member_value_id.is_valid()) { + if (member_value_id != SemIR::InstId::BuiltinErrorInst) { + context.TODO(member_id, "non-constant associated entity"); + } + return SemIR::InstId::BuiltinErrorInst; + } + + auto assoc_entity = + context.insts().TryGetAs(member_value_id); + if (!assoc_entity) { + context.TODO(member_id, "unexpected value for associated entity"); + return SemIR::InstId::BuiltinErrorInst; + } + + // TODO: This produces the type of the associated entity with no value for + // `Self`. The type `Self` might appear in the type of an associated constant, + // and if so, we'll need to substitute it here somehow. + auto subst_type_id = SemIR::GetTypeInSpecific( + context.sem_ir(), interface_specific_id, assoc_type.entity_type_id); + + return context.GetOrAddInst( + loc_id, {.type_id = subst_type_id, + .witness_id = witness_id, + .index = assoc_entity->index}); +} + // Performs impl lookup for a member name expression. This finds the relevant // impl witness and extracts the corresponding impl member. static auto PerformImplLookup( @@ -131,11 +171,8 @@ static auto PerformImplLookup( SemIR::AssociatedEntityType assoc_type, SemIR::InstId member_id, Context::BuildDiagnosticFn missing_impl_diagnoser = nullptr) -> SemIR::InstId { - auto facet_type = - context.types().GetAs(assoc_type.interface_type_id); - const auto& facet_type_info = - context.facet_types().Get(facet_type.facet_type_id); - auto interface_type = facet_type_info.TryAsSingleInterface(); + auto interface_type = + GetInterfaceFromFacetType(context, assoc_type.interface_type_id); if (!interface_type) { context.TODO(loc_id, "Lookup of impl witness not yet supported except for a single " @@ -170,42 +207,20 @@ static auto PerformImplLookup( } return SemIR::InstId::BuiltinErrorInst; } - - auto member_value_id = context.constant_values().GetConstantInstId(member_id); - if (!member_value_id.is_valid()) { - if (member_value_id != SemIR::InstId::BuiltinErrorInst) { - context.TODO(member_id, "non-constant associated entity"); - } - return SemIR::InstId::BuiltinErrorInst; - } - - auto assoc_entity = - context.insts().TryGetAs(member_value_id); - if (!assoc_entity) { - context.TODO(member_id, "unexpected value for associated entity"); - return SemIR::InstId::BuiltinErrorInst; - } - - // TODO: This produces the type of the associated entity with no value for - // `Self`. The type `Self` might appear in the type of an associated constant, - // and if so, we'll need to substitute it here somehow. - auto subst_type_id = SemIR::GetTypeInSpecific( - context.sem_ir(), interface_type->specific_id, assoc_type.entity_type_id); - - return context.GetOrAddInst( - loc_id, {.type_id = subst_type_id, - .witness_id = witness_id, - .index = assoc_entity->index}); + return AccessMemberOfInterfaceWitness(context, loc_id, witness_id, + interface_type->specific_id, assoc_type, + member_id); } // Performs a member name lookup into the specified scope, including performing // impl lookup if necessary. If the scope is invalid, assume an error has // already been diagnosed, and return BuiltinErrorInst. static auto LookupMemberNameInScope(Context& context, SemIR::LocId loc_id, - SemIR::InstId /*base_id*/, + SemIR::InstId base_id, SemIR::NameId name_id, SemIR::ConstantId name_scope_const_id, - llvm::ArrayRef lookup_scopes) + llvm::ArrayRef lookup_scopes, + bool lookup_in_type_of_base) -> SemIR::InstId { AccessInfo access_info = { .constant_id = name_scope_const_id, @@ -250,7 +265,64 @@ static auto LookupMemberNameInScope(Context& context, SemIR::LocId loc_id, // impl member is not supposed to be treated as ambiguous. if (auto assoc_type = context.types().TryGetAs(type_id)) { - if (ScopeNeedsImplLookup(context, name_scope_const_id)) { + if (lookup_in_type_of_base) { + SemIR::TypeId base_type_id = context.insts().Get(base_id).type_id(); + if (base_type_id != SemIR::TypeId::TypeType && + context.IsFacetType(base_type_id)) { + // Handles `T.F` when `T` is a non-type facet. + + auto assoc_interface = + GetInterfaceFromFacetType(context, assoc_type->interface_type_id); + // An associated entity should always be associated with a single + // interface. + CARBON_CHECK(assoc_interface); + + // First look for `*assoc_interface` in the type of the base. If it is + // found, get the witness that the interface is implemented from + // `base_id`. + auto facet_type = context.types().GetAs(base_type_id); + const auto& facet_type_info = + context.facet_types().Get(facet_type.facet_type_id); + // Witness that `T` implements the `*assoc_interface`. + SemIR::InstId witness_inst_id = SemIR::InstId::Invalid; + for (auto base_interface : facet_type_info.impls_constraints) { + // Get the witness that `T` implements `base_type_id`. + if (base_interface == *assoc_interface) { + witness_inst_id = context.GetOrAddInst( + loc_id, {.type_id = context.GetBuiltinType( + SemIR::BuiltinInstKind::WitnessType), + .facet_value_inst_id = base_id}); + // TODO: Result will eventually be a facet type witness instead of + // an interface witness. Will need to use the index + // `*assoc_interface` was found in + // `facet_type_info.impls_constraints` to get the correct interface + // witness out. + break; + } + } + // TODO: If that fails, would need to do impl lookup to see if the facet + // value implements the interface of `*assoc_type`. + if (!witness_inst_id.is_valid()) { + context.TODO(member_id, + "associated entity not found in facet type, need to do " + "impl lookup"); + return SemIR::InstId::BuiltinErrorInst; + } + + member_id = AccessMemberOfInterfaceWitness( + context, loc_id, witness_inst_id, assoc_interface->specific_id, + *assoc_type, member_id); + } else { + // Handles `x.F` if `x` is of type `class C` that extends an interface + // containing `F`. + SemIR::ConstantId constant_id = + context.types().GetConstantId(base_type_id); + member_id = PerformImplLookup(context, loc_id, constant_id, *assoc_type, + member_id); + } + } else if (ScopeNeedsImplLookup(context, name_scope_const_id)) { + // Handles `T.F` where `T` is a type extending an interface containing + // `F`. member_id = PerformImplLookup(context, loc_id, name_scope_const_id, *assoc_type, member_id); } @@ -342,7 +414,8 @@ auto PerformMemberAccess(Context& context, SemIR::LocId loc_id, if (context.AppendLookupScopesForConstant(loc_id, base_const_id, &lookup_scopes)) { return LookupMemberNameInScope(context, loc_id, base_id, name_id, - base_const_id, lookup_scopes); + base_const_id, lookup_scopes, + /*lookup_in_type_of_base=*/false); } } @@ -401,7 +474,8 @@ auto PerformMemberAccess(Context& context, SemIR::LocId loc_id, // Perform lookup into the base type. auto member_id = LookupMemberNameInScope(context, loc_id, base_id, name_id, - base_type_const_id, lookup_scopes); + base_type_const_id, lookup_scopes, + /*lookup_in_type_of_base=*/true); // Perform instance binding if we found an instance member. member_id = PerformInstanceBinding(context, loc_id, base_id, member_id); diff --git a/toolchain/check/testdata/impl/fail_todo_impl_assoc_const.carbon b/toolchain/check/testdata/impl/fail_todo_impl_assoc_const.carbon index ccafb1ce761f..2cdaebdf22bf 100644 --- a/toolchain/check/testdata/impl/fail_todo_impl_assoc_const.carbon +++ b/toolchain/check/testdata/impl/fail_todo_impl_assoc_const.carbon @@ -10,35 +10,28 @@ interface I { let T:! type; } -// CHECK:STDERR: fail_todo_impl_assoc_const.carbon:[[@LINE+10]]:1: error: semantics TODO: `impl of interface with associated constant` [SemanticsTodo] +// CHECK:STDERR: fail_todo_impl_assoc_const.carbon:[[@LINE+3]]:1: error: semantics TODO: `impl of interface with associated constant` [SemanticsTodo] // CHECK:STDERR: impl bool as I where .T = bool {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: -// CHECK:STDERR: fail_todo_impl_assoc_const.carbon:[[@LINE+6]]:27: error: cannot implicitly convert from `type` to `` [ImplicitAsConversionFailure] -// CHECK:STDERR: impl bool as I where .T = bool {} -// CHECK:STDERR: ^~~~ -// CHECK:STDERR: fail_todo_impl_assoc_const.carbon:[[@LINE+3]]:27: note: type `type` does not implement interface `ImplicitAs()` [MissingImplInMemberAccessNote] -// CHECK:STDERR: impl bool as I where .T = bool {} -// CHECK:STDERR: ^~~~ impl bool as I where .T = bool {} // CHECK:STDOUT: --- fail_todo_impl_assoc_const.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %I.type.1: type = facet_type <@I> [template] -// CHECK:STDOUT: %Self.1: %I.type.1 = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %Self: %I.type.1 = bind_symbolic_name Self, 0 [symbolic] // CHECK:STDOUT: %.1: type = assoc_entity_type %I.type.1, type [template] // CHECK:STDOUT: %.2: %.1 = assoc_entity element0, @I.%T [template] // CHECK:STDOUT: %Bool.type: type = fn_type @Bool [template] // CHECK:STDOUT: %Bool: %Bool.type = struct_value () [template] // CHECK:STDOUT: %.Self: %I.type.1 = bind_symbolic_name .Self, 0 [symbolic] +// CHECK:STDOUT: %.3: = facet_access_witness %.Self [symbolic] // CHECK:STDOUT: %I.type.2: type = facet_type <@I where TODO> [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { -// CHECK:STDOUT: .Bool = %import_ref.1 -// CHECK:STDOUT: .ImplicitAs = %import_ref.2 +// CHECK:STDOUT: .Bool = %import_ref // CHECK:STDOUT: import Core//prelude // CHECK:STDOUT: import Core//prelude/... // CHECK:STDOUT: } @@ -51,24 +44,27 @@ impl bool as I where .T = bool {} // CHECK:STDOUT: } // CHECK:STDOUT: %Core.import = import Core // CHECK:STDOUT: %I.decl: type = interface_decl @I [template = constants.%I.type.1] {} {} -// CHECK:STDOUT: impl_decl @impl.9 [template] {} { -// CHECK:STDOUT: %bool.make_type.loc23_6: init type = call constants.%Bool() [template = bool] -// CHECK:STDOUT: %.loc23_6.1: type = value_of_initializer %bool.make_type.loc23_6 [template = bool] -// CHECK:STDOUT: %.loc23_6.2: type = converted %bool.make_type.loc23_6, %.loc23_6.1 [template = bool] +// CHECK:STDOUT: impl_decl @impl [template] {} { +// CHECK:STDOUT: %bool.make_type.loc16_6: init type = call constants.%Bool() [template = bool] +// CHECK:STDOUT: %.loc16_6.1: type = value_of_initializer %bool.make_type.loc16_6 [template = bool] +// CHECK:STDOUT: %.loc16_6.2: type = converted %bool.make_type.loc16_6, %.loc16_6.1 [template = bool] // CHECK:STDOUT: %I.ref: type = name_ref I, file.%I.decl [template = constants.%I.type.1] // CHECK:STDOUT: %.Self: %I.type.1 = bind_symbolic_name .Self, 0 [symbolic = constants.%.Self] // CHECK:STDOUT: %.Self.ref: %I.type.1 = name_ref .Self, %.Self [symbolic = constants.%.Self] // CHECK:STDOUT: %T.ref: %.1 = name_ref T, @I.%.loc11 [template = constants.%.2] -// CHECK:STDOUT: %bool.make_type.loc23_27: init type = call constants.%Bool() [template = bool] -// CHECK:STDOUT: %.loc23_27: %.1 = converted %bool.make_type.loc23_27, [template = ] -// CHECK:STDOUT: %.loc23_16: type = where_expr %.Self [template = constants.%I.type.2] { -// CHECK:STDOUT: requirement_rewrite %T.ref, +// CHECK:STDOUT: %.loc16_22.1: = facet_access_witness %.Self.ref [symbolic = constants.%.3] +// CHECK:STDOUT: %.loc16_22.2: type = interface_witness_access %.loc16_22.1, element0 +// CHECK:STDOUT: %bool.make_type.loc16_27: init type = call constants.%Bool() [template = bool] +// CHECK:STDOUT: %.loc16_27.1: type = value_of_initializer %bool.make_type.loc16_27 [template = bool] +// CHECK:STDOUT: %.loc16_27.2: type = converted %bool.make_type.loc16_27, %.loc16_27.1 [template = bool] +// CHECK:STDOUT: %.loc16_16: type = where_expr %.Self [template = constants.%I.type.2] { +// CHECK:STDOUT: requirement_rewrite %.loc16_22.2, %.loc16_27.2 // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: interface @I { -// CHECK:STDOUT: %Self: %I.type.1 = bind_symbolic_name Self, 0 [symbolic = constants.%Self.1] +// CHECK:STDOUT: %Self: %I.type.1 = bind_symbolic_name Self, 0 [symbolic = constants.%Self] // CHECK:STDOUT: %T: type = assoc_const_decl T [template] // CHECK:STDOUT: %.loc11: %.1 = assoc_entity element0, %T [template = constants.%.2] // CHECK:STDOUT: @@ -78,7 +74,7 @@ impl bool as I where .T = bool {} // CHECK:STDOUT: witness = (%T) // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: impl @impl.9: %.loc23_6.2 as %.loc23_16 { +// CHECK:STDOUT: impl @impl: %.loc16_6.2 as %.loc16_16 { // CHECK:STDOUT: !members: // CHECK:STDOUT: witness = // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/interface/no_prelude/fail_member_lookup.carbon b/toolchain/check/testdata/interface/no_prelude/fail_member_lookup.carbon index d3a581c4edc7..c63f847d0ea9 100644 --- a/toolchain/check/testdata/interface/no_prelude/fail_member_lookup.carbon +++ b/toolchain/check/testdata/interface/no_prelude/fail_member_lookup.carbon @@ -21,17 +21,25 @@ fn F() { // CHECK:STDERR: Interface.F(); - // CHECK:STDERR: fail_member_lookup.carbon:[[@LINE+3]]:10: error: `Core.ImplicitAs` implicitly referenced here, but package `Core` not found [CoreNotFound] + // CHECK:STDERR: fail_member_lookup.carbon:[[@LINE+4]]:10: error: `Core.ImplicitAs` implicitly referenced here, but package `Core` not found [CoreNotFound] // CHECK:STDERR: var v: Interface.T; // CHECK:STDERR: ^~~~~~~~~~~ + // CHECK:STDERR: var v: Interface.T; } +interface Different {} + +// CHECK:STDERR: fail_member_lookup.carbon:[[@LINE+3]]:24: error: cannot access member of interface `Interface` in type `Different` that does not implement that interface [MissingImplInMemberAccess] +// CHECK:STDERR: fn G(U:! Different) -> U.(Interface.T); +// CHECK:STDERR: ^~~~~~~~~~~~~~~ +fn G(U:! Different) -> U.(Interface.T); + // CHECK:STDOUT: --- fail_member_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: %Self.1: %Interface.type = bind_symbolic_name Self, 0 [symbolic] // CHECK:STDOUT: %F.type.1: type = fn_type @F.1 [template] // CHECK:STDOUT: %F.1: %F.type.1 = struct_value () [template] // CHECK:STDOUT: %.1: type = assoc_entity_type %Interface.type, %F.type.1 [template] @@ -40,19 +48,43 @@ fn F() { // CHECK:STDOUT: %.4: %.3 = assoc_entity element1, @Interface.%T [template] // CHECK:STDOUT: %F.type.2: type = fn_type @F.2 [template] // CHECK:STDOUT: %F.2: %F.type.2 = struct_value () [template] +// CHECK:STDOUT: %Different.type: type = facet_type <@Different> [template] +// CHECK:STDOUT: %Self.2: %Different.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %U: %Different.type = bind_symbolic_name U, 0 [symbolic] +// CHECK:STDOUT: %U.patt: %Different.type = symbolic_binding_pattern U, 0 [symbolic] +// CHECK:STDOUT: %G.type: type = fn_type @G [template] +// CHECK:STDOUT: %G: %G.type = struct_value () [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace [template] { // CHECK:STDOUT: .Interface = %Interface.decl // CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: .Different = %Different.decl +// CHECK:STDOUT: .G = %G.decl // CHECK:STDOUT: } // CHECK:STDOUT: %Interface.decl: type = interface_decl @Interface [template = constants.%Interface.type] {} {} // CHECK:STDOUT: %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {} {} +// CHECK:STDOUT: %Different.decl: type = interface_decl @Different [template = constants.%Different.type] {} {} +// CHECK:STDOUT: %G.decl: %G.type = fn_decl @G [template = constants.%G] { +// CHECK:STDOUT: %U.patt.loc36_6.1: %Different.type = symbolic_binding_pattern U, 0 [symbolic = %U.patt.loc36_6.2 (constants.%U.patt)] +// CHECK:STDOUT: %U.param_patt: %Different.type = value_param_pattern %U.patt.loc36_6.1, runtime_param [symbolic = %U.patt.loc36_6.2 (constants.%U.patt)] +// CHECK:STDOUT: %return.patt: = return_slot_pattern +// CHECK:STDOUT: %return.param_patt: = out_param_pattern %return.patt, runtime_param0 +// CHECK:STDOUT: } { +// CHECK:STDOUT: %Different.ref: type = name_ref Different, file.%Different.decl [template = constants.%Different.type] +// CHECK:STDOUT: %U.ref: %Different.type = name_ref U, %U.loc36_6.1 [symbolic = %U.loc36_6.2 (constants.%U)] +// CHECK:STDOUT: %Interface.ref: type = name_ref Interface, file.%Interface.decl [template = constants.%Interface.type] +// CHECK:STDOUT: %T.ref: %.3 = name_ref T, @Interface.%.loc14 [template = constants.%.4] +// CHECK:STDOUT: %U.param: %Different.type = value_param runtime_param +// CHECK:STDOUT: %U.loc36_6.1: %Different.type = bind_symbolic_name U, 0, %U.param [symbolic = %U.loc36_6.2 (constants.%U)] +// CHECK:STDOUT: %return.param: ref = out_param runtime_param0 +// CHECK:STDOUT: %return: ref = return_slot %return.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: %Self: %Interface.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self.1] // CHECK:STDOUT: %F.decl: %F.type.1 = fn_decl @F.1 [template = constants.%F.1] {} {} // CHECK:STDOUT: %.loc12: %.1 = assoc_entity element0, %F.decl [template = constants.%.2] // CHECK:STDOUT: %T: type = assoc_const_decl T [template] @@ -65,6 +97,14 @@ fn F() { // CHECK:STDOUT: witness = (%F.decl, %T) // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: interface @Different { +// CHECK:STDOUT: %Self: %Different.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: generic fn @F.1(@Interface.%Self: %Interface.type) { // CHECK:STDOUT: // CHECK:STDOUT: fn(); @@ -74,13 +114,25 @@ fn F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Interface.ref.loc22: type = name_ref Interface, file.%Interface.decl [template = constants.%Interface.type] // CHECK:STDOUT: %F.ref: %.1 = name_ref F, @Interface.%.loc12 [template = constants.%.2] -// CHECK:STDOUT: %Interface.ref.loc27: type = name_ref Interface, file.%Interface.decl [template = constants.%Interface.type] +// CHECK:STDOUT: %Interface.ref.loc28: type = name_ref Interface, file.%Interface.decl [template = constants.%Interface.type] // CHECK:STDOUT: %T.ref: %.3 = name_ref T, @Interface.%.loc14 [template = constants.%.4] -// CHECK:STDOUT: %.loc27: type = converted %T.ref, [template = ] +// CHECK:STDOUT: %.loc28: type = converted %T.ref, [template = ] // CHECK:STDOUT: %v.var: ref = var v // CHECK:STDOUT: %v: ref = bind_name v, %v.var // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @F.1(constants.%Self) {} +// CHECK:STDOUT: generic fn @G(%U.loc36_6.1: %Different.type) { +// CHECK:STDOUT: %U.loc36_6.2: %Different.type = bind_symbolic_name U, 0 [symbolic = %U.loc36_6.2 (constants.%U)] +// CHECK:STDOUT: %U.patt.loc36_6.2: %Different.type = symbolic_binding_pattern U, 0 [symbolic = %U.patt.loc36_6.2 (constants.%U.patt)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn(%U.param_patt: %Different.type) -> ; +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F.1(constants.%Self.1) {} +// CHECK:STDOUT: +// CHECK:STDOUT: specific @G(constants.%U) { +// CHECK:STDOUT: %U.loc36_6.2 => constants.%U +// CHECK:STDOUT: %U.patt.loc36_6.2 => constants.%U +// CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interface/no_prelude/fail_todo_facet_lookup.carbon b/toolchain/check/testdata/interface/no_prelude/fail_todo_facet_lookup.carbon index 78d7a7444d34..c2f3be18300c 100644 --- a/toolchain/check/testdata/interface/no_prelude/fail_todo_facet_lookup.carbon +++ b/toolchain/check/testdata/interface/no_prelude/fail_todo_facet_lookup.carbon @@ -11,7 +11,7 @@ interface Interface { fn F(); } fn CallStatic(T:! Interface) { - // CHECK:STDERR: fail_todo_facet_lookup.carbon:[[@LINE+4]]:3: error: value of type ` in Interface>` is not callable [CallToNonCallable] + // CHECK:STDERR: fail_todo_facet_lookup.carbon:[[@LINE+4]]:3: error: value of type `` is not callable [CallToNonCallable] // CHECK:STDERR: T.F(); // CHECK:STDERR: ^~~~ // CHECK:STDERR: @@ -38,7 +38,8 @@ fn CallFacet(T:! Interface, x: T) { // 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: %.3: type = facet_access_type %T [symbolic] +// CHECK:STDOUT: %.3: = facet_access_witness %T [symbolic] +// CHECK:STDOUT: %.4: type = facet_access_type %T [symbolic] // CHECK:STDOUT: %CallFacet.type: type = fn_type @CallFacet [template] // CHECK:STDOUT: %CallFacet: %CallFacet.type = struct_value () [template] // CHECK:STDOUT: } @@ -61,17 +62,17 @@ fn CallFacet(T:! Interface, x: T) { // 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 [symbolic = %T.patt.loc21_14.2 (constants.%T.patt)] -// CHECK:STDOUT: %x.patt: @CallFacet.%.loc21_32.3 (%.3) = binding_pattern x -// CHECK:STDOUT: %x.param_patt: @CallFacet.%.loc21_32.3 (%.3) = value_param_pattern %x.patt, runtime_param0 +// CHECK:STDOUT: %x.patt: @CallFacet.%.loc21_32.3 (%.4) = binding_pattern x +// CHECK:STDOUT: %x.param_patt: @CallFacet.%.loc21_32.3 (%.4) = value_param_pattern %x.patt, runtime_param0 // CHECK:STDOUT: } { // CHECK:STDOUT: %Interface.ref: type = name_ref Interface, file.%Interface.decl [template = constants.%Interface.type] // CHECK:STDOUT: %T.ref: %Interface.type = name_ref T, %T.loc21_14.1 [symbolic = %T.loc21_14.2 (constants.%T)] -// CHECK:STDOUT: %.loc21_32.1: type = facet_access_type %T.ref [symbolic = %.loc21_32.3 (constants.%.3)] -// CHECK:STDOUT: %.loc21_32.2: type = converted %T.ref, %.loc21_32.1 [symbolic = %.loc21_32.3 (constants.%.3)] +// CHECK:STDOUT: %.loc21_32.1: type = facet_access_type %T.ref [symbolic = %.loc21_32.3 (constants.%.4)] +// CHECK:STDOUT: %.loc21_32.2: type = converted %T.ref, %.loc21_32.1 [symbolic = %.loc21_32.3 (constants.%.4)] // CHECK:STDOUT: %T.param: %Interface.type = value_param runtime_param // 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.%.loc21_32.3 (%.3) = value_param runtime_param0 -// CHECK:STDOUT: %x: @CallFacet.%.loc21_32.3 (%.3) = bind_name x, %x.param +// CHECK:STDOUT: %x.param: @CallFacet.%.loc21_32.3 (%.4) = value_param runtime_param0 +// CHECK:STDOUT: %x: @CallFacet.%.loc21_32.3 (%.4) = bind_name x, %x.param // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: @@ -96,11 +97,14 @@ fn CallFacet(T:! Interface, x: 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: %.loc18_4.3: = facet_access_witness %T.loc13_15.2 [symbolic = %.loc18_4.3 (constants.%.3)] // 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: %.1 = name_ref F, @Interface.%.loc11 [template = constants.%.2] +// CHECK:STDOUT: %.loc18_4.1: = facet_access_witness %T.ref [symbolic = %.loc18_4.3 (constants.%.3)] +// CHECK:STDOUT: %.loc18_4.2: %F.type = interface_witness_access %.loc18_4.1, element0 // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: } @@ -108,13 +112,13 @@ fn CallFacet(T:! Interface, x: T) { // 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: %.loc21_32.3: type = facet_access_type %T.loc21_14.2 [symbolic = %.loc21_32.3 (constants.%.3)] +// CHECK:STDOUT: %.loc21_32.3: type = facet_access_type %T.loc21_14.2 [symbolic = %.loc21_32.3 (constants.%.4)] // CHECK:STDOUT: // CHECK:STDOUT: !definition: // CHECK:STDOUT: -// CHECK:STDOUT: fn(%T.param_patt: %Interface.type, %x.param_patt: @CallFacet.%.loc21_32.3 (%.3)) { +// CHECK:STDOUT: fn(%T.param_patt: %Interface.type, %x.param_patt: @CallFacet.%.loc21_32.3 (%.4)) { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %x.ref: @CallFacet.%.loc21_32.3 (%.3) = name_ref x, %x +// CHECK:STDOUT: %x.ref: @CallFacet.%.loc21_32.3 (%.4) = name_ref x, %x // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: } @@ -129,6 +133,6 @@ fn CallFacet(T:! Interface, x: T) { // 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: %.loc21_32.3 => constants.%.3 +// CHECK:STDOUT: %.loc21_32.3 => constants.%.4 // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/where_expr/constraints.carbon b/toolchain/check/testdata/where_expr/constraints.carbon index d2ae1c5db6be..d6f43c4f73d8 100644 --- a/toolchain/check/testdata/where_expr/constraints.carbon +++ b/toolchain/check/testdata/where_expr/constraints.carbon @@ -25,7 +25,7 @@ fn Impls(V:! J where .Self impls I); fn And(W:! I where .Self impls J and .Member == ()); -// --- fail_todo_equal_constraint.carbon +// --- equal_constraint.carbon library "[[@TEST_NAME]]"; @@ -33,13 +33,6 @@ interface N { let P:! type; } -// CHECK:STDERR: fail_todo_equal_constraint.carbon:[[@LINE+7]]:27: error: cannot implicitly convert from `{}` to `` [ImplicitAsConversionFailure] -// CHECK:STDERR: fn Equal(T:! N where .P = {}); -// CHECK:STDERR: ^~ -// CHECK:STDERR: fail_todo_equal_constraint.carbon:[[@LINE+4]]:27: note: type `{}` does not implement interface `ImplicitAs()` [MissingImplInMemberAccessNote] -// CHECK:STDERR: fn Equal(T:! N where .P = {}); -// CHECK:STDERR: ^~ -// CHECK:STDERR: fn Equal(T:! N where .P = {}); // --- fail_todo_associated_type_impls.carbon @@ -53,10 +46,7 @@ interface K { let Associated:! L; } -// CHECK:STDERR: fail_todo_associated_type_impls.carbon:[[@LINE+7]]:36: error: cannot implicitly convert from `` to `type` [ImplicitAsConversionFailure] -// CHECK:STDERR: fn AssociatedTypeImpls(W:! K where .Associated impls M); -// CHECK:STDERR: ^~~~~~~~~~~ -// CHECK:STDERR: fail_todo_associated_type_impls.carbon:[[@LINE+4]]:36: note: type `` does not implement interface `ImplicitAs(type)` [MissingImplInMemberAccessNote] +// CHECK:STDERR: fail_todo_associated_type_impls.carbon:[[@LINE+4]]:36: error: cannot evaluate type expression [TypeExprEvaluationFailure] // CHECK:STDERR: fn AssociatedTypeImpls(W:! K where .Associated impls M); // CHECK:STDERR: ^~~~~~~~~~~ // CHECK:STDERR: @@ -69,12 +59,10 @@ library "[[@TEST_NAME]]"; import library "state_constraints"; // `2` can't be converted to the type of `I.Member` -// TODO: The diagnostics are wrong since member access into facets isn't -// working properly yet. -// CHECK:STDERR: fail_check_rewrite_constraints.carbon:[[@LINE+7]]:46: error: cannot implicitly convert from `Core.IntLiteral` to `` [ImplicitAsConversionFailure] +// CHECK:STDERR: fail_check_rewrite_constraints.carbon:[[@LINE+7]]:46: error: cannot implicitly convert from `Core.IntLiteral` to `type` [ImplicitAsConversionFailure] // CHECK:STDERR: fn RewriteTypeMismatch(X:! I where .Member = 2); // CHECK:STDERR: ^ -// CHECK:STDERR: fail_check_rewrite_constraints.carbon:[[@LINE+4]]:46: note: type `Core.IntLiteral` does not implement interface `ImplicitAs()` [MissingImplInMemberAccessNote] +// CHECK:STDERR: fail_check_rewrite_constraints.carbon:[[@LINE+4]]:46: note: type `Core.IntLiteral` does not implement interface `ImplicitAs(type)` [MissingImplInMemberAccessNote] // CHECK:STDERR: fn RewriteTypeMismatch(X:! I where .Member = 2); // CHECK:STDERR: ^ // CHECK:STDERR: @@ -201,6 +189,7 @@ let B: type where .Self impls A = D; // CHECK:STDOUT: %Impls.type: type = fn_type @Impls [template] // CHECK:STDOUT: %Impls: %Impls.type = struct_value () [template] // CHECK:STDOUT: %.6: type = facet_access_type %.Self.1 [symbolic] +// CHECK:STDOUT: %.7: = facet_access_witness %.Self.1 [symbolic] // CHECK:STDOUT: %I.type.3: type = facet_type <@I where TODO> [template] // CHECK:STDOUT: %W: %I.type.3 = bind_symbolic_name W, 0 [symbolic] // CHECK:STDOUT: %W.patt: %I.type.3 = symbolic_binding_pattern W, 0 [symbolic] @@ -269,10 +258,12 @@ let B: type where .Self impls A = D; // CHECK:STDOUT: %.loc15_20.2: type = converted %.Self.ref.loc15_20, %.loc15_20.1 [symbolic = constants.%.6] // CHECK:STDOUT: %.Self.ref.loc15_38: %I.type.1 = name_ref .Self, %.Self [symbolic = constants.%.Self.1] // CHECK:STDOUT: %Member.ref: %.1 = name_ref Member, @I.%.loc7 [template = constants.%.2] +// CHECK:STDOUT: %.loc15_38.1: = facet_access_witness %.Self.ref.loc15_38 [symbolic = constants.%.7] +// CHECK:STDOUT: %.loc15_38.2: type = interface_witness_access %.loc15_38.1, element0 // CHECK:STDOUT: %.loc15_50: %empty_tuple.type = tuple_literal () // CHECK:STDOUT: %.loc15_14: type = where_expr %.Self [template = constants.%I.type.3] { // CHECK:STDOUT: requirement_impls %.loc15_20.2, %J.ref -// CHECK:STDOUT: requirement_equivalent %Member.ref, %.loc15_50 +// CHECK:STDOUT: requirement_equivalent %.loc15_38.2, %.loc15_50 // CHECK:STDOUT: } // CHECK:STDOUT: %W.param: %I.type.3 = value_param runtime_param // CHECK:STDOUT: %W.loc15_8.1: %I.type.3 = bind_symbolic_name W, 0, %W.param [symbolic = %W.loc15_8.2 (constants.%W)] @@ -338,15 +329,16 @@ let B: type where .Self impls A = D; // CHECK:STDOUT: %W.patt.loc15_8.2 => constants.%W // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_equal_constraint.carbon +// CHECK:STDOUT: --- equal_constraint.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %N.type.1: type = facet_type <@N> [template] -// CHECK:STDOUT: %Self.1: %N.type.1 = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %Self: %N.type.1 = bind_symbolic_name Self, 0 [symbolic] // CHECK:STDOUT: %.1: type = assoc_entity_type %N.type.1, type [template] // CHECK:STDOUT: %.2: %.1 = assoc_entity element0, @N.%P [template] // CHECK:STDOUT: %.Self: %N.type.1 = bind_symbolic_name .Self, 0 [symbolic] -// CHECK:STDOUT: %.3: type = struct_type {} [template] +// CHECK:STDOUT: %.3: = facet_access_witness %.Self [symbolic] +// CHECK:STDOUT: %.4: type = struct_type {} [template] // CHECK:STDOUT: %N.type.2: type = facet_type <@N where TODO> [template] // CHECK:STDOUT: %T: %N.type.2 = bind_symbolic_name T, 0 [symbolic] // CHECK:STDOUT: %T.patt: %N.type.2 = symbolic_binding_pattern T, 0 [symbolic] @@ -356,7 +348,6 @@ let B: type where .Self impls A = D; // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { -// CHECK:STDOUT: .ImplicitAs = %import_ref.1 // CHECK:STDOUT: import Core//prelude // CHECK:STDOUT: import Core//prelude/... // CHECK:STDOUT: } @@ -371,25 +362,27 @@ let B: type where .Self impls A = D; // CHECK:STDOUT: %Core.import = import Core // CHECK:STDOUT: %N.decl: type = interface_decl @N [template = constants.%N.type.1] {} {} // CHECK:STDOUT: %Equal.decl: %Equal.type = fn_decl @Equal [template = constants.%Equal] { -// CHECK:STDOUT: %T.patt.loc15_10.1: %N.type.2 = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc15_10.2 (constants.%T.patt)] -// CHECK:STDOUT: %T.param_patt: %N.type.2 = value_param_pattern %T.patt.loc15_10.1, runtime_param [symbolic = %T.patt.loc15_10.2 (constants.%T.patt)] +// CHECK:STDOUT: %T.patt.loc8_10.1: %N.type.2 = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc8_10.2 (constants.%T.patt)] +// CHECK:STDOUT: %T.param_patt: %N.type.2 = value_param_pattern %T.patt.loc8_10.1, runtime_param [symbolic = %T.patt.loc8_10.2 (constants.%T.patt)] // CHECK:STDOUT: } { // CHECK:STDOUT: %N.ref: type = name_ref N, file.%N.decl [template = constants.%N.type.1] // CHECK:STDOUT: %.Self: %N.type.1 = bind_symbolic_name .Self, 0 [symbolic = constants.%.Self] // CHECK:STDOUT: %.Self.ref: %N.type.1 = name_ref .Self, %.Self [symbolic = constants.%.Self] // CHECK:STDOUT: %P.ref: %.1 = name_ref P, @N.%.loc5 [template = constants.%.2] -// CHECK:STDOUT: %.loc15_28.1: %.3 = struct_literal () -// CHECK:STDOUT: %.loc15_28.2: %.1 = converted %.loc15_28.1, [template = ] -// CHECK:STDOUT: %.loc15_16: type = where_expr %.Self [template = constants.%N.type.2] { -// CHECK:STDOUT: requirement_rewrite %P.ref, +// CHECK:STDOUT: %.loc8_22.1: = facet_access_witness %.Self.ref [symbolic = constants.%.3] +// CHECK:STDOUT: %.loc8_22.2: type = interface_witness_access %.loc8_22.1, element0 +// CHECK:STDOUT: %.loc8_28.1: %.4 = struct_literal () +// CHECK:STDOUT: %.loc8_28.2: type = converted %.loc8_28.1, constants.%.4 [template = constants.%.4] +// CHECK:STDOUT: %.loc8_16: type = where_expr %.Self [template = constants.%N.type.2] { +// CHECK:STDOUT: requirement_rewrite %.loc8_22.2, %.loc8_28.2 // CHECK:STDOUT: } // CHECK:STDOUT: %T.param: %N.type.2 = value_param runtime_param -// CHECK:STDOUT: %T.loc15_10.1: %N.type.2 = bind_symbolic_name T, 0, %T.param [symbolic = %T.loc15_10.2 (constants.%T)] +// CHECK:STDOUT: %T.loc8_10.1: %N.type.2 = bind_symbolic_name T, 0, %T.param [symbolic = %T.loc8_10.2 (constants.%T)] // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: interface @N { -// CHECK:STDOUT: %Self: %N.type.1 = bind_symbolic_name Self, 0 [symbolic = constants.%Self.1] +// CHECK:STDOUT: %Self: %N.type.1 = bind_symbolic_name Self, 0 [symbolic = constants.%Self] // CHECK:STDOUT: %P: type = assoc_const_decl P [template] // CHECK:STDOUT: %.loc5: %.1 = assoc_entity element0, %P [template = constants.%.2] // CHECK:STDOUT: @@ -399,16 +392,16 @@ let B: type where .Self impls A = D; // CHECK:STDOUT: witness = (%P) // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: generic fn @Equal(%T.loc15_10.1: %N.type.2) { -// CHECK:STDOUT: %T.loc15_10.2: %N.type.2 = bind_symbolic_name T, 0 [symbolic = %T.loc15_10.2 (constants.%T)] -// CHECK:STDOUT: %T.patt.loc15_10.2: %N.type.2 = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc15_10.2 (constants.%T.patt)] +// CHECK:STDOUT: generic fn @Equal(%T.loc8_10.1: %N.type.2) { +// CHECK:STDOUT: %T.loc8_10.2: %N.type.2 = bind_symbolic_name T, 0 [symbolic = %T.loc8_10.2 (constants.%T)] +// CHECK:STDOUT: %T.patt.loc8_10.2: %N.type.2 = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc8_10.2 (constants.%T.patt)] // CHECK:STDOUT: // CHECK:STDOUT: fn(%T.param_patt: %N.type.2); // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Equal(constants.%T) { -// CHECK:STDOUT: %T.loc15_10.2 => constants.%T -// CHECK:STDOUT: %T.patt.loc15_10.2 => constants.%T +// CHECK:STDOUT: %T.loc8_10.2 => constants.%T +// CHECK:STDOUT: %T.patt.loc8_10.2 => constants.%T // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- fail_todo_associated_type_impls.carbon @@ -423,6 +416,7 @@ let B: type where .Self impls A = D; // CHECK:STDOUT: %.1: type = assoc_entity_type %K.type.1, %L.type [template] // CHECK:STDOUT: %.2: %.1 = assoc_entity element0, @K.%Associated [template] // CHECK:STDOUT: %.Self: %K.type.1 = bind_symbolic_name .Self, 0 [symbolic] +// CHECK:STDOUT: %.3: = facet_access_witness %.Self [symbolic] // CHECK:STDOUT: %K.type.2: type = facet_type <@K where TODO> [template] // CHECK:STDOUT: %W: %K.type.2 = bind_symbolic_name W, 0 [symbolic] // CHECK:STDOUT: %W.patt: %K.type.2 = symbolic_binding_pattern W, 0 [symbolic] @@ -432,7 +426,6 @@ let B: type where .Self impls A = D; // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { -// CHECK:STDOUT: .ImplicitAs = %import_ref.1 // CHECK:STDOUT: import Core//prelude // CHECK:STDOUT: import Core//prelude/... // CHECK:STDOUT: } @@ -451,20 +444,23 @@ let B: type where .Self impls A = D; // CHECK:STDOUT: %M.decl: type = interface_decl @M [template = constants.%M.type] {} {} // CHECK:STDOUT: %K.decl: type = interface_decl @K [template = constants.%K.type.1] {} {} // CHECK:STDOUT: %AssociatedTypeImpls.decl: %AssociatedTypeImpls.type = fn_decl @AssociatedTypeImpls [template = constants.%AssociatedTypeImpls] { -// CHECK:STDOUT: %W.patt.loc18_24.1: %K.type.2 = symbolic_binding_pattern W, 0 [symbolic = %W.patt.loc18_24.2 (constants.%W.patt)] -// CHECK:STDOUT: %W.param_patt: %K.type.2 = value_param_pattern %W.patt.loc18_24.1, runtime_param [symbolic = %W.patt.loc18_24.2 (constants.%W.patt)] +// CHECK:STDOUT: %W.patt.loc15_24.1: %K.type.2 = symbolic_binding_pattern W, 0 [symbolic = %W.patt.loc15_24.2 (constants.%W.patt)] +// CHECK:STDOUT: %W.param_patt: %K.type.2 = value_param_pattern %W.patt.loc15_24.1, runtime_param [symbolic = %W.patt.loc15_24.2 (constants.%W.patt)] // CHECK:STDOUT: } { // CHECK:STDOUT: %K.ref: type = name_ref K, file.%K.decl [template = constants.%K.type.1] // CHECK:STDOUT: %.Self: %K.type.1 = bind_symbolic_name .Self, 0 [symbolic = constants.%.Self] // CHECK:STDOUT: %.Self.ref: %K.type.1 = name_ref .Self, %.Self [symbolic = constants.%.Self] // CHECK:STDOUT: %Associated.ref: %.1 = name_ref Associated, @K.%.loc8 [template = constants.%.2] +// CHECK:STDOUT: %.loc15_36.1: = facet_access_witness %.Self.ref [symbolic = constants.%.3] +// CHECK:STDOUT: %.loc15_36.2: %L.type = interface_witness_access %.loc15_36.1, element0 // CHECK:STDOUT: %M.ref: type = name_ref M, file.%M.decl [template = constants.%M.type] -// CHECK:STDOUT: %.loc18_36: type = converted %Associated.ref, [template = ] -// CHECK:STDOUT: %.loc18_30: type = where_expr %.Self [template = constants.%K.type.2] { +// CHECK:STDOUT: %.loc15_36.3: type = facet_access_type %.loc15_36.2 +// CHECK:STDOUT: %.loc15_36.4: type = converted %.loc15_36.2, %.loc15_36.3 +// CHECK:STDOUT: %.loc15_30: type = where_expr %.Self [template = constants.%K.type.2] { // CHECK:STDOUT: requirement_impls , %M.ref // CHECK:STDOUT: } // CHECK:STDOUT: %W.param: %K.type.2 = value_param runtime_param -// CHECK:STDOUT: %W.loc18_24.1: %K.type.2 = bind_symbolic_name W, 0, %W.param [symbolic = %W.loc18_24.2 (constants.%W)] +// CHECK:STDOUT: %W.loc15_24.1: %K.type.2 = bind_symbolic_name W, 0, %W.param [symbolic = %W.loc15_24.2 (constants.%W)] // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: @@ -496,16 +492,16 @@ let B: type where .Self impls A = D; // CHECK:STDOUT: witness = (%Associated) // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: generic fn @AssociatedTypeImpls(%W.loc18_24.1: %K.type.2) { -// CHECK:STDOUT: %W.loc18_24.2: %K.type.2 = bind_symbolic_name W, 0 [symbolic = %W.loc18_24.2 (constants.%W)] -// CHECK:STDOUT: %W.patt.loc18_24.2: %K.type.2 = symbolic_binding_pattern W, 0 [symbolic = %W.patt.loc18_24.2 (constants.%W.patt)] +// CHECK:STDOUT: generic fn @AssociatedTypeImpls(%W.loc15_24.1: %K.type.2) { +// CHECK:STDOUT: %W.loc15_24.2: %K.type.2 = bind_symbolic_name W, 0 [symbolic = %W.loc15_24.2 (constants.%W)] +// CHECK:STDOUT: %W.patt.loc15_24.2: %K.type.2 = symbolic_binding_pattern W, 0 [symbolic = %W.patt.loc15_24.2 (constants.%W.patt)] // CHECK:STDOUT: // CHECK:STDOUT: fn(%W.param_patt: %K.type.2); // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @AssociatedTypeImpls(constants.%W) { -// CHECK:STDOUT: %W.loc18_24.2 => constants.%W -// CHECK:STDOUT: %W.patt.loc18_24.2 => constants.%W +// CHECK:STDOUT: %W.loc15_24.2 => constants.%W +// CHECK:STDOUT: %W.patt.loc15_24.2 => constants.%W // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- fail_check_rewrite_constraints.carbon @@ -515,7 +511,8 @@ let B: type where .Self impls A = D; // CHECK:STDOUT: %.Self: %I.type.1 = bind_symbolic_name .Self, 0 [symbolic] // CHECK:STDOUT: %.1: type = assoc_entity_type %I.type.1, type [template] // CHECK:STDOUT: %.2: %.1 = assoc_entity element0, imports.%import_ref.11 [template] -// CHECK:STDOUT: %.3: Core.IntLiteral = int_value 2 [template] +// CHECK:STDOUT: %.3: = facet_access_witness %.Self [symbolic] +// CHECK:STDOUT: %.4: Core.IntLiteral = int_value 2 [template] // CHECK:STDOUT: %I.type.2: type = facet_type <@I where TODO> [template] // CHECK:STDOUT: %X: %I.type.2 = bind_symbolic_name X, 0 [symbolic] // CHECK:STDOUT: %X.patt: %I.type.2 = symbolic_binding_pattern X, 0 [symbolic] @@ -528,7 +525,7 @@ let B: type where .Self impls A = D; // CHECK:STDOUT: %import_ref.2: type = import_ref Main//state_constraints, inst+7, loaded [template = constants.%I.type.1] // CHECK:STDOUT: %import_ref.3 = import_ref Main//state_constraints, inst+35, unloaded // CHECK:STDOUT: %import_ref.4 = import_ref Main//state_constraints, inst+57, unloaded -// CHECK:STDOUT: %import_ref.5 = import_ref Main//state_constraints, inst+82, unloaded +// CHECK:STDOUT: %import_ref.5 = import_ref Main//state_constraints, inst+85, unloaded // CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { // CHECK:STDOUT: .ImplicitAs = %import_ref.12 // CHECK:STDOUT: import Core//prelude @@ -554,20 +551,22 @@ let B: type where .Self impls A = D; // CHECK:STDOUT: %Core.import = import Core // CHECK:STDOUT: %default.import = import // CHECK:STDOUT: %RewriteTypeMismatch.decl: %RewriteTypeMismatch.type = fn_decl @RewriteTypeMismatch [template = constants.%RewriteTypeMismatch] { -// CHECK:STDOUT: %X.patt.loc16_24.1: %I.type.2 = symbolic_binding_pattern X, 0 [symbolic = %X.patt.loc16_24.2 (constants.%X.patt)] -// CHECK:STDOUT: %X.param_patt: %I.type.2 = value_param_pattern %X.patt.loc16_24.1, runtime_param [symbolic = %X.patt.loc16_24.2 (constants.%X.patt)] +// CHECK:STDOUT: %X.patt.loc14_24.1: %I.type.2 = symbolic_binding_pattern X, 0 [symbolic = %X.patt.loc14_24.2 (constants.%X.patt)] +// CHECK:STDOUT: %X.param_patt: %I.type.2 = value_param_pattern %X.patt.loc14_24.1, runtime_param [symbolic = %X.patt.loc14_24.2 (constants.%X.patt)] // CHECK:STDOUT: } { // CHECK:STDOUT: %I.ref: type = name_ref I, imports.%import_ref.2 [template = constants.%I.type.1] // CHECK:STDOUT: %.Self: %I.type.1 = bind_symbolic_name .Self, 0 [symbolic = constants.%.Self] // CHECK:STDOUT: %.Self.ref: %I.type.1 = name_ref .Self, %.Self [symbolic = constants.%.Self] // CHECK:STDOUT: %Member.ref: %.1 = name_ref Member, imports.%import_ref.7 [template = constants.%.2] -// CHECK:STDOUT: %.loc16_46.1: Core.IntLiteral = int_value 2 [template = constants.%.3] -// CHECK:STDOUT: %.loc16_46.2: %.1 = converted %.loc16_46.1, [template = ] -// CHECK:STDOUT: %.loc16_30: type = where_expr %.Self [template = constants.%I.type.2] { -// CHECK:STDOUT: requirement_rewrite %Member.ref, +// CHECK:STDOUT: %.loc14_36.1: = facet_access_witness %.Self.ref [symbolic = constants.%.3] +// CHECK:STDOUT: %.loc14_36.2: type = interface_witness_access %.loc14_36.1, element0 +// CHECK:STDOUT: %.loc14_46.1: Core.IntLiteral = int_value 2 [template = constants.%.4] +// CHECK:STDOUT: %.loc14_46.2: type = converted %.loc14_46.1, [template = ] +// CHECK:STDOUT: %.loc14_30: type = where_expr %.Self [template = constants.%I.type.2] { +// CHECK:STDOUT: requirement_rewrite %.loc14_36.2, // CHECK:STDOUT: } // CHECK:STDOUT: %X.param: %I.type.2 = value_param runtime_param -// CHECK:STDOUT: %X.loc16_24.1: %I.type.2 = bind_symbolic_name X, 0, %X.param [symbolic = %X.loc16_24.2 (constants.%X)] +// CHECK:STDOUT: %X.loc14_24.1: %I.type.2 = bind_symbolic_name X, 0, %X.param [symbolic = %X.loc14_24.2 (constants.%X)] // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: @@ -579,16 +578,16 @@ let B: type where .Self impls A = D; // CHECK:STDOUT: witness = (imports.%import_ref.9, imports.%import_ref.10) // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: generic fn @RewriteTypeMismatch(%X.loc16_24.1: %I.type.2) { -// CHECK:STDOUT: %X.loc16_24.2: %I.type.2 = bind_symbolic_name X, 0 [symbolic = %X.loc16_24.2 (constants.%X)] -// CHECK:STDOUT: %X.patt.loc16_24.2: %I.type.2 = symbolic_binding_pattern X, 0 [symbolic = %X.patt.loc16_24.2 (constants.%X.patt)] +// CHECK:STDOUT: generic fn @RewriteTypeMismatch(%X.loc14_24.1: %I.type.2) { +// CHECK:STDOUT: %X.loc14_24.2: %I.type.2 = bind_symbolic_name X, 0 [symbolic = %X.loc14_24.2 (constants.%X)] +// CHECK:STDOUT: %X.patt.loc14_24.2: %I.type.2 = symbolic_binding_pattern X, 0 [symbolic = %X.patt.loc14_24.2 (constants.%X.patt)] // CHECK:STDOUT: // CHECK:STDOUT: fn(%X.param_patt: %I.type.2); // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @RewriteTypeMismatch(constants.%X) { -// CHECK:STDOUT: %X.loc16_24.2 => constants.%X -// CHECK:STDOUT: %X.patt.loc16_24.2 => constants.%X +// CHECK:STDOUT: %X.loc14_24.2 => constants.%X +// CHECK:STDOUT: %X.patt.loc14_24.2 => constants.%X // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- fail_left_of_impls_non_type.carbon @@ -786,7 +785,7 @@ let B: type where .Self impls A = D; // CHECK:STDOUT: %import_ref.2 = import_ref Main//state_constraints, inst+7, unloaded // CHECK:STDOUT: %import_ref.3 = import_ref Main//state_constraints, inst+35, unloaded // CHECK:STDOUT: %import_ref.4: %Impls.type = import_ref Main//state_constraints, inst+57, loaded [template = constants.%Impls] -// CHECK:STDOUT: %import_ref.5 = import_ref Main//state_constraints, inst+82, unloaded +// CHECK:STDOUT: %import_ref.5 = import_ref Main//state_constraints, inst+85, unloaded // CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { // CHECK:STDOUT: .ImplicitAs = %import_ref.7 // CHECK:STDOUT: import Core//prelude diff --git a/toolchain/check/testdata/where_expr/designator.carbon b/toolchain/check/testdata/where_expr/designator.carbon index 71344665cb88..da3c7ea84c37 100644 --- a/toolchain/check/testdata/where_expr/designator.carbon +++ b/toolchain/check/testdata/where_expr/designator.carbon @@ -100,6 +100,7 @@ class D { // CHECK:STDOUT: %T.patt: %I.type.2 = symbolic_binding_pattern T, 0 [symbolic] // CHECK:STDOUT: %PeriodSelf.type: type = fn_type @PeriodSelf [template] // CHECK:STDOUT: %PeriodSelf: %PeriodSelf.type = struct_value () [template] +// CHECK:STDOUT: %.3: = facet_access_witness %.Self.1 [symbolic] // CHECK:STDOUT: %I.type.3: type = facet_type <@I where TODO> [template] // CHECK:STDOUT: %U: %I.type.3 = bind_symbolic_name U, 0 [symbolic] // CHECK:STDOUT: %U.patt: %I.type.3 = symbolic_binding_pattern U, 0 [symbolic] @@ -152,9 +153,11 @@ class D { // CHECK:STDOUT: %.Self: %I.type.1 = bind_symbolic_name .Self, 0 [symbolic = constants.%.Self.1] // CHECK:STDOUT: %.Self.ref: %I.type.1 = name_ref .Self, %.Self [symbolic = constants.%.Self.1] // CHECK:STDOUT: %Member.ref: %.1 = name_ref Member, @I.%.loc5 [template = constants.%.2] +// CHECK:STDOUT: %.loc10_29.1: = facet_access_witness %.Self.ref [symbolic = constants.%.3] +// CHECK:STDOUT: %.loc10_29.2: type = interface_witness_access %.loc10_29.1, element0 // CHECK:STDOUT: %.loc10_41: %empty_tuple.type = tuple_literal () // CHECK:STDOUT: %.loc10_23: type = where_expr %.Self [template = constants.%I.type.3] { -// CHECK:STDOUT: requirement_equivalent %Member.ref, %.loc10_41 +// CHECK:STDOUT: requirement_equivalent %.loc10_29.2, %.loc10_41 // CHECK:STDOUT: } // CHECK:STDOUT: %U.param: %I.type.3 = value_param runtime_param // CHECK:STDOUT: %U.loc10_17.1: %I.type.3 = bind_symbolic_name U, 0, %U.param [symbolic = %U.loc10_17.2 (constants.%U)] diff --git a/toolchain/check/testdata/where_expr/non_generic.carbon b/toolchain/check/testdata/where_expr/non_generic.carbon index c8d932e5375e..ffacf28ff334 100644 --- a/toolchain/check/testdata/where_expr/non_generic.carbon +++ b/toolchain/check/testdata/where_expr/non_generic.carbon @@ -21,10 +21,11 @@ fn NotGenericF(U: I where .T == i32) {} // CHECK:STDOUT: %.1: type = assoc_entity_type %I.type.1, type [template] // CHECK:STDOUT: %.2: %.1 = assoc_entity element0, @I.%T [template] // CHECK:STDOUT: %.Self: %I.type.1 = bind_symbolic_name .Self, 0 [symbolic] -// CHECK:STDOUT: %.3: Core.IntLiteral = int_value 32 [template] +// CHECK:STDOUT: %.3: = facet_access_witness %.Self [symbolic] +// CHECK:STDOUT: %.4: Core.IntLiteral = int_value 32 [template] // CHECK:STDOUT: %Int.type: type = fn_type @Int [template] // CHECK:STDOUT: %Int: %Int.type = struct_value () [template] -// CHECK:STDOUT: %i32: type = int_type signed, %.3 [template] +// CHECK:STDOUT: %i32: type = int_type signed, %.4 [template] // CHECK:STDOUT: %I.type.2: type = facet_type <@I where TODO> [template] // CHECK:STDOUT: %NotGenericF.type: type = fn_type @NotGenericF [template] // CHECK:STDOUT: %NotGenericF: %NotGenericF.type = struct_value () [template] @@ -54,10 +55,12 @@ fn NotGenericF(U: I where .T == i32) {} // CHECK:STDOUT: %.Self: %I.type.1 = bind_symbolic_name .Self, 0 [symbolic = constants.%.Self] // CHECK:STDOUT: %.Self.ref: %I.type.1 = name_ref .Self, %.Self [symbolic = constants.%.Self] // CHECK:STDOUT: %T.ref: %.1 = name_ref T, @I.%.loc11 [template = constants.%.2] -// CHECK:STDOUT: %.loc14_33: Core.IntLiteral = int_value 32 [template = constants.%.3] +// CHECK:STDOUT: %.loc14_27.1: = facet_access_witness %.Self.ref [symbolic = constants.%.3] +// CHECK:STDOUT: %.loc14_27.2: type = interface_witness_access %.loc14_27.1, element0 +// CHECK:STDOUT: %.loc14_33: Core.IntLiteral = int_value 32 [template = constants.%.4] // CHECK:STDOUT: %int.make_type_signed: init type = call constants.%Int(%.loc14_33) [template = constants.%i32] // CHECK:STDOUT: %.loc14_21: type = where_expr %.Self [template = constants.%I.type.2] { -// CHECK:STDOUT: requirement_equivalent %T.ref, %int.make_type_signed +// CHECK:STDOUT: requirement_equivalent %.loc14_27.2, %int.make_type_signed // CHECK:STDOUT: } // CHECK:STDOUT: %U.param: %I.type.2 = value_param runtime_param0 // CHECK:STDOUT: %U: %I.type.2 = bind_name U, %U.param diff --git a/toolchain/sem_ir/file.cpp b/toolchain/sem_ir/file.cpp index 772ccb7a6a52..0cb334482b26 100644 --- a/toolchain/sem_ir/file.cpp +++ b/toolchain/sem_ir/file.cpp @@ -264,6 +264,7 @@ auto GetExprCategory(const File& file, InstId inst_id) -> ExprCategory { case CompleteTypeWitness::Kind: case ConstType::Kind: case FacetAccessType::Kind: + case FacetAccessWitness::Kind: case FacetType::Kind: case FacetValue::Kind: case FloatLiteral::Kind: diff --git a/toolchain/sem_ir/inst_kind.def b/toolchain/sem_ir/inst_kind.def index 7043cc38d460..141f0b2ed698 100644 --- a/toolchain/sem_ir/inst_kind.def +++ b/toolchain/sem_ir/inst_kind.def @@ -85,6 +85,7 @@ CARBON_SEM_IR_INST_KIND(ConstType) CARBON_SEM_IR_INST_KIND(Converted) CARBON_SEM_IR_INST_KIND(Deref) CARBON_SEM_IR_INST_KIND(FacetAccessType) +CARBON_SEM_IR_INST_KIND(FacetAccessWitness) CARBON_SEM_IR_INST_KIND(FacetType) CARBON_SEM_IR_INST_KIND(FacetValue) CARBON_SEM_IR_INST_KIND(FieldDecl) diff --git a/toolchain/sem_ir/stringify_type.cpp b/toolchain/sem_ir/stringify_type.cpp index 995513125df3..04d33ab27ade 100644 --- a/toolchain/sem_ir/stringify_type.cpp +++ b/toolchain/sem_ir/stringify_type.cpp @@ -192,6 +192,12 @@ auto StringifyTypeExpr(const SemIR::File& outer_sem_ir, InstId outer_inst_id) push_inst_id(inst.facet_value_inst_id); break; } + case CARBON_KIND(FacetAccessWitness inst): { + out << ""); + push_inst_id(inst.facet_value_inst_id); + break; + } case CARBON_KIND(FacetType inst): { const FacetTypeInfo& facet_type_info = sem_ir.facet_types().Get(inst.facet_type_id); diff --git a/toolchain/sem_ir/typed_insts.h b/toolchain/sem_ir/typed_insts.h index c955e6f0aff8..c0816f771464 100644 --- a/toolchain/sem_ir/typed_insts.h +++ b/toolchain/sem_ir/typed_insts.h @@ -602,7 +602,21 @@ struct FacetAccessType { InstId facet_value_inst_id; }; -// TODO: `FacetAccessWitness` +// Represents accessing the `witness` field in a facet value, which is +// notionally a pair of a type and a witness. +struct FacetAccessWitness { + static constexpr auto Kind = + InstKind::FacetAccessWitness.Define( + {.ir_name = "facet_access_witness", + .is_type = InstIsType::Never, + .constant_kind = InstConstantKind::SymbolicOnly, + .is_lowered = false}); + + // Always the builtin witness type. + TypeId type_id; + // An instruction that evaluates to a `FacetValue`. + InstId facet_value_inst_id; +}; // A facet type value. struct FacetType {