diff --git a/toolchain/check/eval.cpp b/toolchain/check/eval.cpp index c2024b42097e..238cd4eec2d7 100644 --- a/toolchain/check/eval.cpp +++ b/toolchain/check/eval.cpp @@ -20,6 +20,7 @@ #include "toolchain/check/facet_type.h" #include "toolchain/check/generic.h" #include "toolchain/check/import_ref.h" +#include "toolchain/check/inst.h" #include "toolchain/check/name_lookup.h" #include "toolchain/check/type.h" #include "toolchain/check/type_completion.h" @@ -2621,7 +2622,8 @@ static auto AddRequirementRewrite(Context& context, {.lhs_id = rewrite.lhs_id, .rhs_id = rewrite.rhs_id}); } -static auto AddRequirementImpls(Context& context, SemIR::RequirementImpls impls, +static auto AddRequirementImpls(Context& context, SemIR::LocId loc_id, + SemIR::RequirementImpls impls, SemIR::InstId period_self_id, SemIR::FacetTypeInfo* info, Phase* phase) -> void { @@ -2657,40 +2659,15 @@ static auto AddRequirementImpls(Context& context, SemIR::RequirementImpls impls, llvm::append_range(info->type_impls_interfaces, rhs.type_impls_interfaces); llvm::append_range(info->type_impls_named_constraints, rhs.type_impls_named_constraints); + llvm::append_range(info->rewrite_constraints, rhs.rewrite_constraints); } else { - // Consider `I where C(.Self) impls (J(.Self) where .Self impls K(.Self))`, - // when we are evaluating the `C(.Self) impls ()` requirement. - // The is our `rhs` here, and it will contain: - // * extend constraint: J(.Self) - // * self impls constraint: K(.Self) - // - // The value of `.Self` changes where we cross a `where` operator. This - // means extend constraints retain their original `.Self`, but self impls - // constraints should have their `.Self` replaced by the LHS of the impls - // requirement. - // - // However that is not quite enough. The view of the LHS of the impls - // requirement should be a facet with a facet type of the RHS extend - // constraints. In this case the LHS is C(.Self) and the RHS facet type is - // `J(.Self) where .Self impls K(.Self)`. The RHS facet type has impls - // constraints (which are on the RHS of a `where` operator), in which their - // `.Self` should be replaced by `C(.Self)` converted to the RHS facet - // type's extend constraints (which are on the LHS of a `where` operator), - // which is `C(.Self) as J(.Self)`. It should be enough to convert the LHS - // type to the type of the `.Self` that it is replacing, as that contains - // the extend constraints. - // - // So the final RHS facet type to be merged into `info` is: - // - // `J(.Self) where (C(.Self) as J(.Self)) impls K(C(.Self) as J(.Self))`. - auto lhs_facet_or_type = GetCanonicalFacetOrTypeValue(context, lhs_id); - auto impls_interface = [&](SemIR::SpecificInterface si) + auto extends_interface = [=](SemIR::SpecificInterface si) -> SemIR::FacetTypeInfo::TypeImplsInterface { return {lhs_facet_or_type, si}; }; - auto impls_constraint = [&](SemIR::SpecificNamedConstraint sc) + auto extends_constraint = [=](SemIR::SpecificNamedConstraint sc) -> SemIR::FacetTypeInfo::TypeImplsNamedConstraint { return {lhs_facet_or_type, sc}; }; @@ -2699,47 +2676,145 @@ static auto AddRequirementImpls(Context& context, SemIR::RequirementImpls impls, // converted to type impls constraints so they apply to the LHS type. llvm::append_range( info->type_impls_interfaces, - llvm::map_range(rhs.extend_constraints, impls_interface)); + llvm::map_range(rhs.extend_constraints, extends_interface)); llvm::append_range( info->type_impls_named_constraints, - llvm::map_range(rhs.extend_named_constraints, impls_constraint)); + llvm::map_range(rhs.extend_named_constraints, extends_constraint)); - // To replace the `.Self` in `.Self impls X` we convert from a self impls - // constraint to a type impls constraint where the type is the impls LHS - // type. We must also replace any `.Self` references in the constraint in - // the same way. The LHS type needs to be converted to a facet with its type - // containing the RHS facet type's extend constraints so that the extend - // constraints can be referenced in impls constraints. + // Impls constraints are written as `T impls X` where `T` is a facet and `X` + // is a facet type. The `T` can be `.Self`. // - // TODO: Convert the LHS used in the TypeImplsNamedConstraint to a facet - // with the RHS extend constraints (interfaces and named constraints). + // What's important here is that since `X` is a facet type, it can contain a + // `where` expression, and the value of `.Self` changes across a `where` + // expression. This can create ambiguous `.Self` references where on the RHS + // they refer to a different facet (`T`) than on the LHS, which is diagnosed + // as an error. // - // TODO: Replace `.Self` with the LHS type as a facet with the RHS extend - // constraints. + // TODO: For now we do this diagnosis here, but we should diagnose this + // during name lookup of `.Self` instead, in order to properly allow only + // implicit `.Self` references when it would be ambiguous. Then use + // `should_replace_implicit_only` in all cases. + // + // Implicit `.Self` references can't be avoided when referencing members of + // the facet's type such as with `.Member`. As such, we replace implicit + // `.Self` references on the RHS of a nested `where` with the inner-most + // facet that it could possibly refer to, the `T as X` from the `impls` + // constraint, which eliminates any ambiguity in the resulting facet type. + + class SubstPeriodSelfDiagnoseExplicitCallbacks + : public SubstPeriodSelfCallbacks { + public: + explicit SubstPeriodSelfDiagnoseExplicitCallbacks( + Context* context, SemIR::LocId loc_id, + SemIR::ConstantId period_self_replacement_id, Phase* phase) + : SubstPeriodSelfCallbacks(context, loc_id, + period_self_replacement_id), + phase_(phase) {} + + auto ShouldReplace(bool implicit) -> bool override { + if (!implicit && *phase_ != Phase::UnknownDueToError) { + CARBON_DIAGNOSTIC( + AmbiguousPeriodSelf, Error, + "`.Self` is ambiguous after nested `where` in ` " + "impls ...` clause."); + context().emitter().Emit(loc_id(), AmbiguousPeriodSelf); + *phase_ = Phase::UnknownDueToError; + } + return implicit; + } + + Phase* phase_; + }; + SubstPeriodSelfDiagnoseExplicitCallbacks + callbacks_should_replace_explicit_is_error( + &context, loc_id, context.constant_values().Get(lhs_facet_or_type), + phase); + + class SubstPeriodSelfImplicitOnlyCallbacks + : public SubstPeriodSelfCallbacks { + public: + explicit SubstPeriodSelfImplicitOnlyCallbacks( + Context* context, SemIR::LocId loc_id, + SemIR::ConstantId period_self_replacement_id) + : SubstPeriodSelfCallbacks(context, loc_id, + period_self_replacement_id) {} + + // TODO: Replace this callback with a SubstPeriodSelf parameter saying + // what to replace (as a bool or an enum). Then this subclass can go away. + auto ShouldReplace(bool implicit) -> bool override { return implicit; } + }; + SubstPeriodSelfImplicitOnlyCallbacks callbacks_should_replace_implicit_only( + &context, loc_id, context.constant_values().Get(lhs_facet_or_type)); + + auto self_impls_interface = [&](SemIR::SpecificInterface si) { + return SubstPeriodSelf(context, + callbacks_should_replace_explicit_is_error, si); + }; + auto self_impls_constraint = [&](SemIR::SpecificNamedConstraint sc) { + return SubstPeriodSelf(context, + callbacks_should_replace_explicit_is_error, sc); + }; + auto type_impls_interface = + [&](SemIR::FacetTypeInfo::TypeImplsInterface impls) + -> SemIR::FacetTypeInfo::TypeImplsInterface { + auto self = + SubstPeriodSelf(context, callbacks_should_replace_explicit_is_error, + context.constant_values().Get(impls.self_type)); + auto interface = + SubstPeriodSelf(context, callbacks_should_replace_explicit_is_error, + impls.specific_interface); + return {context.constant_values().GetInstId(self), interface}; + }; + auto type_impls_constraint = + [&](SemIR::FacetTypeInfo::TypeImplsNamedConstraint impls) + -> SemIR::FacetTypeInfo::TypeImplsNamedConstraint { + auto self = + SubstPeriodSelf(context, callbacks_should_replace_explicit_is_error, + context.constant_values().Get(impls.self_type)); + auto constraint = + SubstPeriodSelf(context, callbacks_should_replace_explicit_is_error, + impls.specific_named_constraint); + return {context.constant_values().GetInstId(self), constraint}; + }; + + llvm::append_range( + info->self_impls_constraints, + llvm::map_range(rhs.self_impls_constraints, self_impls_interface)); + llvm::append_range(info->self_impls_named_constraints, + llvm::map_range(rhs.self_impls_named_constraints, + self_impls_constraint)); llvm::append_range( info->type_impls_interfaces, - llvm::map_range(rhs.self_impls_constraints, impls_interface)); - llvm::append_range( - info->type_impls_named_constraints, - llvm::map_range(rhs.self_impls_named_constraints, impls_constraint)); - - // Type impls constraints are copied in, but need to have their `.Self` - // references replaced by the impls LHS type. Like above, the LHS type - // should be converted to a facet type containing the RHS facet type's - // extend constraints. - // - // TODO: Convert the LHS used in the TypeImplsNamedConstraint to a facet - // with the RHS extend constraints (interfaces and named constraints). - // - // TODO: Replace `.Self` with the LHS type as a facet with the RHS extend - // constraints. - llvm::append_range(info->type_impls_interfaces, rhs.type_impls_interfaces); + llvm::map_range(rhs.type_impls_interfaces, type_impls_interface)); llvm::append_range(info->type_impls_named_constraints, - rhs.type_impls_named_constraints); + llvm::map_range(rhs.type_impls_named_constraints, + type_impls_constraint)); + + // TODO: We have to pass explicit `.Self` along unchanged in rewrites. A + // rewrite of the form `M(.Self) where .M0 = {}` is an access into `.Self as + // M(.Self)`. The first `.Self` is implicit and should be replaced. The + // second is explicit but refers to the outer-most facet and should not be + // replaced. In the future when we diagnose ambiguous `.Self` in name + // lookup, we will replace all implicit `.Self` and leave all explicit + // `.Self` alone since they won't be ambiguous. + auto rewrite_constraint = + [&](SemIR::FacetTypeInfo::RewriteConstraint rewrite) + -> SemIR::FacetTypeInfo::RewriteConstraint { + auto lhs_id = + SubstPeriodSelf(context, callbacks_should_replace_implicit_only, + context.constant_values().Get(rewrite.lhs_id)); + auto rhs_id = + SubstPeriodSelf(context, callbacks_should_replace_implicit_only, + context.constant_values().Get(rewrite.rhs_id)); + return {context.constant_values().GetInstId(lhs_id), + context.constant_values().GetInstId(rhs_id)}; + }; + + llvm::append_range( + info->rewrite_constraints, + llvm::map_range(rhs.rewrite_constraints, rewrite_constraint)); } - // Other requirements are copied in. - llvm::append_range(info->rewrite_constraints, rhs.rewrite_constraints); info->other_requirements |= rhs.other_requirements; } @@ -2782,8 +2857,8 @@ auto TryEvalTypedInst(EvalContext& eval_context, break; } case CARBON_KIND(SemIR::RequirementImpls impls): { - AddRequirementImpls(eval_context.context(), impls, - typed_inst.period_self_id, &info, &phase); + AddRequirementImpls(eval_context.context(), SemIR::LocId(inst_id), + impls, typed_inst.period_self_id, &info, &phase); break; } case CARBON_KIND(SemIR::RequirementEquivalent _): { diff --git a/toolchain/check/eval_inst.cpp b/toolchain/check/eval_inst.cpp index 5443b1ba19b3..80970d76434c 100644 --- a/toolchain/check/eval_inst.cpp +++ b/toolchain/check/eval_inst.cpp @@ -284,24 +284,13 @@ auto EvalConstantInst(Context& /*context*/, SemIR::FunctionDecl inst) auto EvalConstantInst(Context& context, SemIR::InstId inst_id, SemIR::LookupImplWitness inst) -> ConstantEvalResult { - // If the monomorphized query self is a FacetValue, we may get a witness from - // it under limited circumstances. If no final witness is found though, we - // don't need to preserve it for future evaluations, so we strip it from the - // LookupImplWitness instruction to reduce the number of distinct constant - // values. + // Canonicalize the query self to reduce the number of unique witness + // instructions and enable constant value comparisons. auto self_facet_value_inst_id = SemIR::InstId::None; - if (auto facet_value = context.insts().TryGetAs( - inst.query_self_inst_id)) { - self_facet_value_inst_id = - std::exchange(inst.query_self_inst_id, facet_value->type_inst_id); - } - - // The self value is canonicalized in order to produce a canonical - // LookupImplWitness instruction, avoiding multiple constant values for - // `` and `` as type, which always have the same - // lookup result. - inst.query_self_inst_id = - GetCanonicalFacetOrTypeValue(context, inst.query_self_inst_id); + inst.query_self_inst_id = context.constant_values().GetInstId( + GetCanonicalQuerySelfForLookupImplWitness( + context, context.constant_values().Get(inst.query_self_inst_id), + &self_facet_value_inst_id)); auto witness_id = EvalLookupSingleFinalWitness(context, SemIR::LocId(inst_id), inst, self_facet_value_inst_id, @@ -361,22 +350,27 @@ auto EvalConstantInst(Context& context, SemIR::InstId inst_id, } case CARBON_KIND(SemIR::LookupImplWitness witness): { // If the witness is symbolic but has a self type that is a FacetType, it - // can pull rewrite values from the self type. If the access is for one of - // those rewrites, evaluate to the RHS of the rewrite. + // can pull rewrite values from the self's facet type. If the access is + // for one of those rewrites, evaluate to the RHS of the rewrite. - auto witness_self_type_id = + // The type of the query self type (a FacetType or TypeType). + auto access_self_type_id = context.insts().Get(witness.query_self_inst_id).type_id(); - if (!context.types().Is(witness_self_type_id)) { + if (context.types().Is(access_self_type_id)) { + // A self facet of type `type` has no rewrite constraints to look in. return ConstantEvalResult::NewSamePhase(inst); } // The `ImplWitnessAccess` is accessing a value, by index, for this - // interface. - auto access_interface_id = witness.query_specific_interface_id; + // `self impls interface` combination. + auto access_self = + context.constant_values().Get(witness.query_self_inst_id); + auto access_interface = context.specific_interfaces().Get( + witness.query_specific_interface_id); - auto witness_self_facet_type_id = + auto access_self_facet_type_id = context.types() - .GetAs(witness_self_type_id) + .GetAs(access_self_type_id) .facet_type_id; // TODO: We could consider something better than linear search here, such // as a map. However that would probably require heap allocations which @@ -385,35 +379,67 @@ auto EvalConstantInst(Context& context, SemIR::InstId inst_id, // associated constants are grouped together, as in // ResolveFacetTypeRewriteConstraints(), and limited to just the // `ImplWitnessAccess` entries, then a binary search may work here. - for (auto witness_rewrite : context.facet_types() - .Get(witness_self_facet_type_id) - .rewrite_constraints) { - // Look at each rewrite constraint in the self facet value's type. If - // the LHS is an `ImplWitnessAccess` into the same interface that `inst` - // is indexing into, then we can use its RHS as the value. - auto witness_rewrite_lhs_access = - context.insts().TryGetAs( - witness_rewrite.lhs_id); - if (!witness_rewrite_lhs_access) { + for (const auto& rewrite : context.facet_types() + .Get(access_self_facet_type_id) + .rewrite_constraints) { + // Look at each rewrite constraint in the self facet's type. If the LHS + // is an `ImplWitnessAccess` into the same interface that `inst` is + // indexing into, then we can use its RHS as the value. + auto rewrite_lhs_access = + context.insts().TryGetAs(rewrite.lhs_id); + if (!rewrite_lhs_access) { continue; } - if (witness_rewrite_lhs_access->index != inst.index) { + if (rewrite_lhs_access->index != inst.index) { continue; } - auto witness_rewrite_lhs_interface_id = - context.insts() - .GetAs( - witness_rewrite_lhs_access->witness_id) - .query_specific_interface_id; - if (witness_rewrite_lhs_interface_id != access_interface_id) { + // Witnesses come from impl lookup, and the operands are from + // IdentifiedFacetTypes, so `.Self` is replaced. However rewrite + // constraints are not part of an IdentifiedFacetType, so they are not + // replaced. We have to do the same replacement in the rewrite's LHS + // witness in order to compare it with the access witness. + // + // However we don't substitute the witness directly as that would + // re-evaluate it and cause us to do an impl lookup. Instead we + // substitute and compare its operands. + auto rewrite_lhs_witness = + context.insts().GetAs( + rewrite_lhs_access->witness_id); + + SubstPeriodSelfCallbacks callbacks(&context, SemIR::LocId(inst_id), + access_self); + + auto rewrite_lhs_self = context.constant_values().Get( + rewrite_lhs_witness.query_self_inst_id); + rewrite_lhs_self = + SubstPeriodSelf(context, callbacks, rewrite_lhs_self); + // Witnesses have a canonicalized self value. Perform the same + // canonicalization here so that we can compare them. + rewrite_lhs_self = GetCanonicalQuerySelfForLookupImplWitness( + context, rewrite_lhs_self); + + if (rewrite_lhs_self != access_self) { + // This rewrite is into a different self type than the access query. + continue; + } + + auto rewrite_lhs_interface = SubstPeriodSelf( + context, callbacks, + context.specific_interfaces().Get( + rewrite_lhs_witness.query_specific_interface_id)); + + if (rewrite_lhs_interface != access_interface) { + // This rewrite is into a different interface than the access query. continue; } // The `ImplWitnessAccess` evaluates to the RHS from the witness self - // facet value's type. - return ConstantEvalResult::Existing( - context.constant_values().Get(witness_rewrite.rhs_id)); + // facet value's type. Any `.Self` references in the RHS are also + // replaced with the self type of the access. + auto rewrite_rhs = SubstPeriodSelf( + context, callbacks, context.constant_values().Get(rewrite.rhs_id)); + return ConstantEvalResult::Existing(rewrite_rhs); } break; } diff --git a/toolchain/check/facet_type.cpp b/toolchain/check/facet_type.cpp index d321af6dc43d..1860c79ef16e 100644 --- a/toolchain/check/facet_type.cpp +++ b/toolchain/check/facet_type.cpp @@ -7,6 +7,7 @@ #include "toolchain/base/kind_switch.h" #include "toolchain/check/context.h" #include "toolchain/check/control_flow.h" +#include "toolchain/check/convert.h" #include "toolchain/check/generic.h" #include "toolchain/check/import_ref.h" #include "toolchain/check/inst.h" @@ -467,4 +468,258 @@ auto GetConstantFacetValueForTypeAndInterface( return self_value_const_id; } +SubstPeriodSelfCallbacks::SubstPeriodSelfCallbacks( + Context* context, SemIR::LocId loc_id, + SemIR::ConstantId period_self_replacement_id) + : SubstInstCallbacks(context), + loc_id_(loc_id), + period_self_replacement_id_(period_self_replacement_id) {} + +auto SubstPeriodSelfCallbacks::Subst(SemIR::InstId& inst_id) -> SubstResult { + // FacetTypes are concrete even if they have `.Self` inside them, but we + // don't recurse into FacetTypes, so we can use this as a base case. This + // avoids infinite recursion on TypeType and ErrorInst. + if (context().constant_values().Get(inst_id).is_concrete()) { + return FullySubstituted; + } + // Don't recurse into nested facet types, even if they are symbolic. Leave + // their `.Self` as is. + if (context().insts().Is(inst_id)) { + return FullySubstituted; + } + + // For `.X` (which is `.Self.X`) replace the `.Self` in the query self + // position, and report it as `implicit`. Any `.Self` references in the + // specific interface would be replaced later and not treated as `implicit`. + // + // TODO: This all goes away when eval doesn't need to know about implicit + // .Self for diagnostics, once we diagnose invalid `.Self` in name lookup. + if (auto access = + context().insts().TryGetAs(inst_id)) { + if (auto witness = context().insts().TryGetAs( + access->witness_id)) { + if (auto bind = context().insts().TryGetAs( + witness->query_self_inst_id)) { + const auto& entity_name = + context().entity_names().Get(bind->entity_name_id); + if (entity_name.name_id == SemIR::NameId::PeriodSelf) { + auto replacement_id = + GetReplacement(witness->query_self_inst_id, true); + auto new_witness = + Rebuild(access->witness_id, + SemIR::LookupImplWitness{ + .type_id = witness->type_id, + .query_self_inst_id = replacement_id, + // Don't replace `.Self` in the interface specific + // here. That is an explicit `.Self` use. We'll + // revisit the instruction for that. + .query_specific_interface_id = + witness->query_specific_interface_id, + }); + auto new_access = Rebuild(inst_id, SemIR::ImplWitnessAccess{ + .type_id = access->type_id, + .witness_id = new_witness, + .index = access->index, + }); + inst_id = new_access; + return SubstAgain; + } + } + } + } + + if (auto bind_type = + context().insts().TryGetAs(inst_id)) { + auto bind = context().insts().GetAs( + bind_type->facet_value_inst_id); + const auto& entity_name = context().entity_names().Get(bind.entity_name_id); + if (entity_name.name_id == SemIR::NameId::PeriodSelf) { + // We need to re-construct SymbolicBindingType, not just replace its + // facet instruction. If the new operand is a SymbolicBinding, we need + // to use its entity name. + inst_id = Rebuild( + inst_id, + SemIR::FacetAccessType{.type_id = SemIR::TypeType::TypeId, + .facet_value_inst_id = GetReplacement( + bind_type->facet_value_inst_id, false)}); + return FullySubstituted; + } + } + + if (auto bind = context().insts().TryGetAs(inst_id)) { + const auto& entity_name = + context().entity_names().Get(bind->entity_name_id); + if (entity_name.name_id == SemIR::NameId::PeriodSelf) { + inst_id = GetReplacement(inst_id, false); + return FullySubstituted; + } + } + + return SubstOperands; +} + +auto SubstPeriodSelfCallbacks::Rebuild(SemIR::InstId orig_inst_id, + SemIR::Inst new_inst) -> SemIR::InstId { + return RebuildNewInst(SemIR::LocId(orig_inst_id), new_inst); +} + +auto SubstPeriodSelfCallbacks::GetReplacement(SemIR::InstId period_self, + bool implicit) -> SemIR::InstId { + if (!ShouldReplace(implicit)) { + return period_self; + } + + auto period_self_type_id = context().insts().Get(period_self).type_id(); + CARBON_CHECK(context().types().Is(period_self_type_id)); + + auto replacement_self_inst_id = + context().constant_values().GetInstId(period_self_replacement_id_); + auto replacement_type_id = + context().insts().Get(replacement_self_inst_id).type_id(); + CARBON_CHECK(context().types().IsFacetType(replacement_type_id)); + + // If the replacement has the same type as `.Self`, use it directly. + if (replacement_type_id == period_self_type_id) { + return replacement_self_inst_id; + } + + // If we have already converted the replacement to the type of `.Self`, use + // our previous conversion. + if (period_self_type_id == cached_replacement_type_id_) { + return cached_replacement_id_; + } + + // Convert the replacement facet to the type of `.Self`. + cached_replacement_id_ = ConvertReplacement( + replacement_self_inst_id, replacement_type_id, period_self_type_id); + cached_replacement_type_id_ = period_self_type_id; + return cached_replacement_id_; +} + +auto SubstPeriodSelfCallbacks::ConvertReplacement( + SemIR::InstId replacement_self_inst_id, SemIR::TypeId replacement_type_id, + SemIR::TypeId period_self_type_id) -> SemIR::InstId { + // TODO: Replace all empty facet types with TypeType. + if (period_self_type_id == GetEmptyFacetType(context())) { + // Convert to an empty facet type (representing TypeType); we don't need + // any witnesses. + return ConvertToValueOfType(context(), loc_id_, replacement_self_inst_id, + period_self_type_id); + } + + // We have a facet or a type, but we need more interfaces in the facet type. + // We will have to synthesize a symbolic witness for each interface. + // + // Why is this okay? The type of `.Self` comes from interfaces that are + // before it (to the left of it) in the facet type. The replacement for + // `.Self` will have to impl those interfaces in order to match the facet + // type, so we know that it is valid to construct these witnesses. + + // Make the replacement into a type, which we will need for the FacetValue. + if (context().types().Is(replacement_type_id)) { + replacement_self_inst_id = context().constant_values().GetInstId( + EvalOrAddInst( + context(), loc_id_, + {.type_id = SemIR::TypeType::TypeId, + .facet_value_inst_id = replacement_self_inst_id})); + } + + auto period_self_facet_type = + context().types().GetAs(period_self_type_id); + auto identified_period_self_type_id = RequireIdentifiedFacetType( + context(), loc_id_, + context().constant_values().Get(replacement_self_inst_id), + period_self_facet_type, [&](auto& /*builder*/) { + // The facet type containing this `.Self` should have already been + // identified, which would ensure that the type of `.Self` can be + // identified since it can only depend on things to the left of it + // inside the same facet type. + CARBON_FATAL("could not identify type of `.Self`"); + }); + const auto& identified_period_self_type = + context().identified_facet_types().Get(identified_period_self_type_id); + auto required_impls = identified_period_self_type.required_impls(); + llvm::SmallVector witnesses; + witnesses.reserve(required_impls.size()); + for (const auto& req : required_impls) { + witnesses.push_back(context().constant_values().GetInstId( + EvalOrAddInst( + context(), loc_id_, + {.type_id = + GetSingletonType(context(), SemIR::WitnessType::TypeInstId), + .query_self_inst_id = + context().constant_values().GetInstId(req.self_facet_value), + .query_specific_interface_id = context().specific_interfaces().Add( + req.specific_interface)}))); + } + return context().constant_values().GetInstId(EvalOrAddInst( + context(), loc_id_, + { + .type_id = period_self_type_id, + .type_inst_id = + context().types().GetAsTypeInstId(replacement_self_inst_id), + .witnesses_block_id = context().inst_blocks().Add(witnesses), + })); +} + +auto SubstPeriodSelf(Context& context, SubstPeriodSelfCallbacks& callbacks, + SemIR::ConstantId const_id) -> SemIR::ConstantId { + // Don't replace `.Self` with itself; that is cyclical. + // + // If the types differ, we would try to convert the replacement to a `.Self` + // of the desired type in `const_id`, which is what we already have, so + // there's nothing we need to do. But trying to do that conversion recurses + // when the type of the `.Self` contains a `.Self`. + if (auto bind_type = + context.constant_values().TryGetInstAs( + GetCanonicalFacetOrTypeValue( + context, callbacks.period_self_replacement_id()))) { + if (context.entity_names().Get(bind_type->entity_name_id).name_id == + SemIR::NameId::PeriodSelf) { + return const_id; + } + } + + auto subst_id = SubstInst( + context, context.constant_values().GetInstId(const_id), callbacks); + return context.constant_values().Get(subst_id); +} + +static auto SubstPeriodSelfInSpecific(Context& context, + SubstPeriodSelfCallbacks& callbacks, + SemIR::SpecificId specific_id) + -> SemIR::SpecificId { + if (!specific_id.has_value()) { + return specific_id; + } + + const auto& specific = context.specifics().Get(specific_id); + + // Substitute into the specific without having to construct a FacetType + // instruction just to hold the specific interface inside a constant id. + llvm::SmallVector args( + context.inst_blocks().Get(specific.args_id)); + for (auto& arg_id : args) { + auto const_id = context.constant_values().Get(arg_id); + const_id = SubstPeriodSelf(context, callbacks, const_id); + arg_id = context.constant_values().GetInstId(const_id); + } + return MakeSpecific(context, callbacks.loc_id(), specific.generic_id, args); +} + +auto SubstPeriodSelf(Context& context, SubstPeriodSelfCallbacks& callbacks, + SemIR::SpecificInterface interface) + -> SemIR::SpecificInterface { + interface.specific_id = + SubstPeriodSelfInSpecific(context, callbacks, interface.specific_id); + return interface; +} +auto SubstPeriodSelf(Context& context, SubstPeriodSelfCallbacks& callbacks, + SemIR::SpecificNamedConstraint constraint) + -> SemIR::SpecificNamedConstraint { + constraint.specific_id = + SubstPeriodSelfInSpecific(context, callbacks, constraint.specific_id); + return constraint; +} + } // namespace Carbon::Check diff --git a/toolchain/check/facet_type.h b/toolchain/check/facet_type.h index 842c9ec85134..0760c3f19c14 100644 --- a/toolchain/check/facet_type.h +++ b/toolchain/check/facet_type.h @@ -8,6 +8,7 @@ #include #include "toolchain/check/context.h" +#include "toolchain/check/subst.h" #include "toolchain/sem_ir/entity_with_params_base.h" #include "toolchain/sem_ir/ids.h" @@ -89,6 +90,53 @@ auto GetConstantFacetValueForTypeAndInterface( SemIR::SpecificInterface specific_interface, SemIR::InstId witness_id) -> SemIR::ConstantId; +class SubstPeriodSelfCallbacks : public SubstInstCallbacks { + public: + explicit SubstPeriodSelfCallbacks( + Context* context, SemIR::LocId loc_id, + SemIR::ConstantId period_self_replacement_id); + auto Subst(SemIR::InstId& inst_id) -> SubstResult override; + auto Rebuild(SemIR::InstId orig_inst_id, SemIR::Inst new_inst) + -> SemIR::InstId override; + + virtual auto ShouldReplace(bool /*implicit*/) -> bool { return true; } + + auto loc_id() const -> SemIR::LocId { return loc_id_; } + auto period_self_replacement_id() const -> SemIR::ConstantId { + return period_self_replacement_id_; + } + + private: + auto GetReplacement(SemIR::InstId period_self, bool implicit) + -> SemIR::InstId; + auto ConvertReplacement(SemIR::InstId replacement_self_inst_id, + SemIR::TypeId replacement_type_id, + SemIR::TypeId period_self_type_id) -> SemIR::InstId; + + SemIR::LocId loc_id_; + SemIR::ConstantId period_self_replacement_id_; + + // The last output of GetReplacement(). + SemIR::InstId cached_replacement_id_ = SemIR::InstId::None; + // The type of the last output of GetReplacement(). If the type of `.Self` + // matches, we can reuse the `cached_replacement_id_`. + SemIR::TypeId cached_replacement_type_id_ = SemIR::TypeId::None; +}; + +// Replace all `.Self` references in `const_id`. The `callbacks` specifies the +// facet to replace them with. +auto SubstPeriodSelf(Context& context, SubstPeriodSelfCallbacks& callbacks, + SemIR::ConstantId const_id) -> SemIR::ConstantId; + +// Replace all `.Self` references in the specific of the interface or named +// constraint. The `callbacks` specifies the facet to replace them with. +auto SubstPeriodSelf(Context& context, SubstPeriodSelfCallbacks& callbacks, + SemIR::SpecificInterface interface) + -> SemIR::SpecificInterface; +auto SubstPeriodSelf(Context& context, SubstPeriodSelfCallbacks& callbacks, + SemIR::SpecificNamedConstraint constraint) + -> SemIR::SpecificNamedConstraint; + } // namespace Carbon::Check #endif // CARBON_TOOLCHAIN_CHECK_FACET_TYPE_H_ diff --git a/toolchain/check/handle_require.cpp b/toolchain/check/handle_require.cpp index 3393071964ca..ff1650d9d0d4 100644 --- a/toolchain/check/handle_require.cpp +++ b/toolchain/check/handle_require.cpp @@ -5,6 +5,7 @@ #include "toolchain/base/kind_switch.h" #include "toolchain/check/context.h" #include "toolchain/check/convert.h" +#include "toolchain/check/facet_type.h" #include "toolchain/check/generic.h" #include "toolchain/check/handle.h" #include "toolchain/check/inst.h" @@ -267,14 +268,91 @@ static auto ValidateRequire(Context& context, SemIR::LocId full_require_loc_id, return ValidateRequireResult{.identified_facet_type = &identified}; } +// Replace all `.Self` references with the self-type. +static auto SubstPeriodSelfInConstraint(Context& context, SemIR::LocId loc_id, + SemIR::TypeInstId self_type_inst_id, + SemIR::TypeInstId constraint_inst_id) + -> SemIR::TypeInstId { + auto orig_facet_type = context.insts().GetAs( + context.constant_values().GetConstantInstId(constraint_inst_id)); + const auto& orig_info = + context.facet_types().Get(orig_facet_type.facet_type_id); + + SubstPeriodSelfCallbacks callbacks( + &context, loc_id, context.constant_values().Get(self_type_inst_id)); + + auto replace_interface = [&](SemIR::SpecificInterface si) { + return SubstPeriodSelf(context, callbacks, si); + }; + auto replace_constraint = [&](SemIR::SpecificNamedConstraint sc) { + return SubstPeriodSelf(context, callbacks, sc); + }; + auto replace_type_impls_interface = + [&](SemIR::FacetTypeInfo::TypeImplsInterface impls) + -> SemIR::FacetTypeInfo::TypeImplsInterface { + auto self = SubstPeriodSelf(context, callbacks, + context.constant_values().Get(impls.self_type)); + auto interface = + SubstPeriodSelf(context, callbacks, impls.specific_interface); + return {context.constant_values().GetInstId(self), interface}; + }; + auto replace_type_impls_constraint = + [&](SemIR::FacetTypeInfo::TypeImplsNamedConstraint impls) + -> SemIR::FacetTypeInfo::TypeImplsNamedConstraint { + auto self = SubstPeriodSelf(context, callbacks, + context.constant_values().Get(impls.self_type)); + auto constraint = + SubstPeriodSelf(context, callbacks, impls.specific_named_constraint); + return {context.constant_values().GetInstId(self), constraint}; + }; + + SemIR::FacetTypeInfo info; + llvm::append_range( + info.extend_constraints, + llvm::map_range(orig_info.extend_constraints, replace_interface)); + llvm::append_range( + info.extend_named_constraints, + llvm::map_range(orig_info.extend_named_constraints, replace_constraint)); + llvm::append_range( + info.self_impls_constraints, + llvm::map_range(orig_info.self_impls_constraints, replace_interface)); + llvm::append_range(info.self_impls_named_constraints, + llvm::map_range(orig_info.self_impls_named_constraints, + replace_constraint)); + llvm::append_range(info.type_impls_interfaces, + llvm::map_range(orig_info.type_impls_interfaces, + replace_type_impls_interface)); + llvm::append_range(info.type_impls_named_constraints, + llvm::map_range(orig_info.type_impls_named_constraints, + replace_type_impls_constraint)); + // TODO: Replace .Self in rewrites too. We need to actually validate rewrite + // constraints from named constraints in impl lookup (see + // todo_fail_require_with_mismatching_rewrite_constraint.carbon). + llvm::append_range(info.rewrite_constraints, orig_info.rewrite_constraints); + + info.Canonicalize(); + if (info == orig_info) { + // Nothing was substituted, keep the original instruction. + // + // It is noteworthy that we keep the non-canonical instruction here, since + // it may have a symbolic value (which is attached to a generic, and can be + // updated by specifics). Returning the canonical constraint instruction + // would lose the attachment to the generic which would be incorrect. + return constraint_inst_id; + } + + return AddTypeInst( + context, loc_id, + {.type_id = SemIR::TypeType::TypeId, + .facet_type_id = context.facet_types().Add(info)}); +} + auto HandleParseNode(Context& context, Parse::RequireDeclId node_id) -> bool { auto [constraint_node_id, constraint_inst_id] = context.node_stack().PopExprWithNodeId(); auto [self_node_id, self_inst_id] = context.node_stack().PopWithNodeId(); - auto decl_block_id = context.inst_block_stack().Pop(); - // Process modifiers. auto introducer = context.decl_introducer_state_stack().Pop(); @@ -294,6 +372,7 @@ auto HandleParseNode(Context& context, Parse::RequireDeclId node_id) -> bool { auto scope_id = context.scope_stack().PeekNameScopeId(); context.name_scopes().Get(scope_id).set_has_error(); } + context.inst_block_stack().Pop(); DiscardGenericDecl(context); return true; } @@ -302,19 +381,32 @@ auto HandleParseNode(Context& context, Parse::RequireDeclId node_id) -> bool { if (identified_facet_type->required_impls().empty()) { // A `require T impls type` adds no actual constraints, so nothing to do. // This is not an error though. + context.inst_block_stack().Pop(); DiscardGenericDecl(context); return true; } - // TODO: Substitute .Self here. - auto constraint_type_inst_id = - context.types().GetAsTypeInstId(constraint_inst_id); + // The identified facet type also replaced `.Self` references, but we want to + // store the full facet type not just the identified one. So we have to + // replace `.Self` references explicitly here in the canonical constraint. We + // do this after `ValidateRequire()` which has ensured the constraint is in + // fact a FacetType. + auto constraint_type_inst_id = SubstPeriodSelfInConstraint( + context, constraint_node_id, self_inst_id, + context.types().GetAsTypeInstId(constraint_inst_id)); + // The replacement of `.Self` can create a new FacetType instruction which we + // want to be part of the require decl's inst block, so we defer the Pop until + // after the subst. + auto decl_block_id = context.inst_block_stack().Pop(); auto require_impls_decl = SemIR::RequireImplsDecl{// To be filled in after. .require_impls_id = SemIR::RequireImplsId::None, .decl_block_id = decl_block_id}; auto decl_id = AddPlaceholderInst(context, node_id, require_impls_decl); + // TODO: We don't need to store the `self_inst_id` anymore, since we've + // encoded it into the constraints of the facet type which was converted to + // the form ` where .Self impls `. auto require_impls_id = context.require_impls().Add( {.self_id = self_inst_id, .facet_type_inst_id = constraint_type_inst_id, diff --git a/toolchain/check/impl_lookup.cpp b/toolchain/check/impl_lookup.cpp index c3f47df17413..1cbc463bc940 100644 --- a/toolchain/check/impl_lookup.cpp +++ b/toolchain/check/impl_lookup.cpp @@ -28,6 +28,7 @@ #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/impl.h" #include "toolchain/sem_ir/inst.h" +#include "toolchain/sem_ir/type_iterator.h" #include "toolchain/sem_ir/typed_insts.h" namespace Carbon::Check { @@ -357,138 +358,71 @@ static auto IdentifyQuerySelfFacetType(Context& context, SemIR::LocId loc_id, /*allow_partially_identified=*/true); } -// Substitutes witnesess in place of `LookupImplWitness` queries into `.Self`, -// when the witness is for the same interface as the one `.Self` is referring -// to. -// -// This allows access to the `FacetType` and its constraints from the witness, -// and allows `ImplWitnessAccess` instructions to be immediately resolved to a -// more specific value when possible. -class SubstWitnessesCallbacks : public SubstInstCallbacks { +// Given a query `orig_inst_self` and `orig_interface`, try find a matching +// witness from impl lookup to use for the query. +static auto TryFindMatchingWitnessFromImplLookup( + Context& context, SemIR::LocId loc_id, + SemIR::ConstantId canonical_query_self_const_id, + llvm::ArrayRef req_impls, + llvm::ArrayRef found_witness_inst_ids, + SemIR::ConstantId orig_const_self, SemIR::SpecificInterface orig_interface) + -> SemIR::InstId { + // The `req_impls` come from an IdentifiedFacetType so they have `.Self` + // replaced. We need to do the same for the self and interface in the + // `orig_witness` for comparing with them. + SubstPeriodSelfCallbacks callbacks(&context, loc_id, + canonical_query_self_const_id); + orig_const_self = SubstPeriodSelf(context, callbacks, orig_const_self); + orig_interface = SubstPeriodSelf(context, callbacks, orig_interface); + + // Witnesses have a canonicalized self value. Perform the same + // canonicalization here so that we can compare them. + orig_const_self = + GetCanonicalQuerySelfForLookupImplWitness(context, orig_const_self); + + for (auto [req_impl, found_witness_inst_id] : + llvm::zip_equal(req_impls, found_witness_inst_ids)) { + auto [req_const_self, req_interface] = req_impl; + if (req_const_self == orig_const_self && req_interface == orig_interface) { + return found_witness_inst_id; + } + } + return SemIR::InstId::None; +} + +class SubstPeriodSelfInRewriteCallbacks : public SubstPeriodSelfCallbacks { public: - // `context` must not be null. - explicit SubstWitnessesCallbacks( + explicit SubstPeriodSelfInRewriteCallbacks( Context* context, SemIR::LocId loc_id, - SemIR::ConstantId query_self_const_id, + SemIR::ConstantId period_self_replacement_id, llvm::ArrayRef req_impls, llvm::ArrayRef witness_inst_ids) - : SubstInstCallbacks(context), - loc_id_(loc_id), - canonical_query_self_const_id_( - GetCanonicalFacetOrTypeValue(*context, query_self_const_id)), + : SubstPeriodSelfCallbacks(context, loc_id, period_self_replacement_id), req_impls_(req_impls), witness_inst_ids_(witness_inst_ids) {} - auto Subst(SemIR::InstId& inst_id) -> SubstResult override { - // `FacetType` can be concrete even when it has rewrite constraints that - // have a symbolic dependency on `.Self`. See use of - // `GetConstantValueIgnoringPeriodSelf` in eval. So in order to recurse into - // `FacetType` we must check for it before the `is_concrete` early return. - if (context().insts().Is(inst_id)) { - ++facet_type_depth_; - return SubstOperands; - } - - if (context().constant_values().Get(inst_id).is_concrete()) { - return FullySubstituted; - } - - auto access = context().insts().TryGetAs(inst_id); - if (!access) { - return SubstOperands; - } - - auto lookup = - context().insts().GetAs(access->witness_id); - auto bind_name = context().insts().TryGetAs( - lookup.query_self_inst_id); - if (!bind_name) { - return SubstOperands; - } - - const auto& self_entity_name = - context().entity_names().Get(bind_name->entity_name_id); - if (self_entity_name.name_id != SemIR::NameId::PeriodSelf) { - return SubstOperands; - } - - // TODO: Once we are numbering `EntityName`, (see the third model in - // https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.0#heading=h.7urbxcq23olv) - // then verify that the index here is equal to the `facet_type_depth_`, - // which would mean that it is a reference to the top-level `Self`, which is - // being replaced with the impl lookup query self facet value (and then we - // use the witness derived from it). - // - // For now, we only substitute if depth == 0, which is incorrect inside - // nested facet types, as it can miss references in specifics up to the top - // level facet value. - if (facet_type_depth_ > 0) { - return SubstOperands; - } - - auto witness_id = - FindWitnessForInterface(lookup.query_specific_interface_id); - if (!witness_id.has_value()) { - return SubstOperands; - } - - inst_id = RebuildNewInst( - context().insts().GetLocIdForDesugaring(loc_id_), - SemIR::ImplWitnessAccess{.type_id = GetSingletonType( - context(), SemIR::WitnessType::TypeInstId), - .witness_id = witness_id, - .index = access->index}); - // Once we replace a witness, we either have a concrete value or some - // reference to an associated constant that came from the witness's facet - // type. We don't want to substitute into the witness's facet type, so we - // don't recurse on whatever came from the witness. - return FullySubstituted; - } - auto Rebuild(SemIR::InstId orig_inst_id, SemIR::Inst new_inst) -> SemIR::InstId override { - if (context().insts().Is(orig_inst_id)) { - --facet_type_depth_; + // When rebuilding a witness where `.Self` was replaced, use a witness we + // found in impl lookup instead of performing impl lookup again. + if (auto lookup = new_inst.TryAs()) { + auto witness = TryFindMatchingWitnessFromImplLookup( + context(), loc_id(), period_self_replacement_id(), req_impls_, + witness_inst_ids_, + context().constant_values().Get(lookup->query_self_inst_id), + context().specific_interfaces().Get( + lookup->query_specific_interface_id)); + if (witness.has_value()) { + return witness; + } } - return RebuildNewInst(loc_id_, new_inst); - } - auto ReuseUnchanged(SemIR::InstId orig_inst_id) -> SemIR::InstId override { - if (context().insts().Is(orig_inst_id)) { - --facet_type_depth_; - } - return orig_inst_id; + return SubstPeriodSelfCallbacks::Rebuild(orig_inst_id, new_inst); } private: - auto FindWitnessForInterface(SemIR::SpecificInterfaceId specific_interface_id) - -> SemIR::InstId { - auto lookup_query_interface = - context().specific_interfaces().Get(specific_interface_id); - for (auto [req_impl, witness_inst_id] : - llvm::zip_equal(req_impls_, witness_inst_ids_)) { - auto [req_self, req_interface] = req_impl; - // The `LookupImplWitness` is for `.Self`, so if the witness is for some - // type other than the query self, we can't use it for `.Self`. - if (req_self != canonical_query_self_const_id_) { - continue; - } - // If the `LookupImplWitness` for `.Self` is not looking for the same - // interface as we have a witness for, this is not the right witness to - // use to replace the lookup for `.Self`. - if (req_interface.interface_id != lookup_query_interface.interface_id) { - continue; - } - return witness_inst_id; - } - return SemIR::InstId::None; - } - - SemIR::LocId loc_id_; - SemIR::ConstantId canonical_query_self_const_id_; llvm::ArrayRef req_impls_; llvm::ArrayRef witness_inst_ids_; - int facet_type_depth_ = 0; }; static auto VerifyQueryFacetTypeConstraints( @@ -503,17 +437,30 @@ static auto VerifyQueryFacetTypeConstraints( .facet_type_id); if (!facet_type_info.rewrite_constraints.empty()) { - auto callbacks = SubstWitnessesCallbacks( + SubstPeriodSelfInRewriteCallbacks callbacks( &context, loc_id, query_self_const_id, req_impls, witness_inst_ids); for (const auto& rewrite : facet_type_info.rewrite_constraints) { - auto lhs_id = SubstInst(context, rewrite.lhs_id, callbacks); - auto rhs_id = SubstInst(context, rewrite.rhs_id, callbacks); + // Replace `.Self` in rewrite constraints with the query self in order to + // find the provided values of rewrite constraints from the query. This + // includes replacing `.Self` in LookupImplWitness instructions. + // + // When we have found a witness in impl lookup for the query in a + // LookupImplWitness insts, we need to use that witness directly instead + // of rebuilding (and reevaluating) the LookupImplWitness which will + // execute another impl lookup. + + auto lhs_id = context.constant_values().GetInstId(SubstPeriodSelf( + context, callbacks, context.constant_values().Get(rewrite.lhs_id))); + auto rhs_id = context.constant_values().GetInstId(SubstPeriodSelf( + context, callbacks, context.constant_values().Get(rewrite.rhs_id))); + if (lhs_id != rhs_id) { // TODO: Provide a diagnostic note and location for which rewrite // constraint was not satisfied, if a diagnostic is going to be - // displayed for the LookupImplWitessFailure. This will require plumbing - // through a callback that lets us add a Note to another diagnostic. + // displayed for the LookupImplWitness() failure. This may require + // plumbing through a callback that lets us add a Note to another + // diagnostic. return false; } } @@ -1021,6 +968,33 @@ auto LookupImplWitness(Context& context, SemIR::LocId loc_id, return context.inst_blocks().AddCanonical(result_witness_ids); } +auto GetCanonicalQuerySelfForLookupImplWitness(Context& context, + SemIR::ConstantId self, + SemIR::InstId* out_facet_value) + -> SemIR::ConstantId { + auto self_inst_id = context.constant_values().GetInstId(self); + + // If the monomorphized query self is a FacetValue, we may get a witness from + // it under limited circumstances. If no final witness is found though, we + // don't need to preserve it for future evaluations, so we strip it from the + // LookupImplWitness instruction to reduce the number of distinct constant + // values. + if (auto facet_value = + context.insts().TryGetAs(self_inst_id)) { + if (out_facet_value) { + *out_facet_value = self_inst_id; + } + self_inst_id = facet_value->type_inst_id; + } + + // The self value is canonicalized in order to produce a canonical + // LookupImplWitness instruction, avoiding multiple constant values for + // `` and ` as type`, which always have the same + // lookup result. + return GetCanonicalFacetOrTypeValue( + context, context.constant_values().Get(self_inst_id)); +} + // Record the query which found a final impl witness. It's illegal to // write a final impl afterward that would match the same query. static auto PoisonImplLookupQuery(Context& context, SemIR::LocId loc_id, diff --git a/toolchain/check/impl_lookup.h b/toolchain/check/impl_lookup.h index 64f4491dafe8..cd42003fe688 100644 --- a/toolchain/check/impl_lookup.h +++ b/toolchain/check/impl_lookup.h @@ -47,6 +47,17 @@ auto LookupMatchesImpl(Context& context, SemIR::LocId loc_id, SemIR::SpecificInterface query_specific_interface, SemIR::ImplId target_impl) -> bool; +// Given a self facet, returns the canonical query self for a LookupImplWitness +// instruction. The canonicalization looks through `FacetValue` and makes a +// canonical form for `facet` and `facet as type`. +// +// If the input self facet is a `FacetValue` that is looked through, it can be +// returned in `out_facet_value`, in order to preserve its facet type and +// witnesses. +auto GetCanonicalQuerySelfForLookupImplWitness( + Context& context, SemIR::ConstantId self, + SemIR::InstId* out_facet_value = nullptr) -> SemIR::ConstantId; + // The kind of impl lookup being performed by a call to // `EvalLookupSingleFinalWitness`. enum class EvalImplLookupMode { diff --git a/toolchain/check/testdata/facet/access.carbon b/toolchain/check/testdata/facet/access.carbon index 2c52bfd6a9a6..802c605aa996 100644 --- a/toolchain/check/testdata/facet/access.carbon +++ b/toolchain/check/testdata/facet/access.carbon @@ -80,7 +80,7 @@ fn UseIndirect[T:! I](x: T) -> T { //@dump-sem-ir-end } -// --- fail_todo_convert_from_period_self_to_full_facet_value.carbon +// --- convert_from_period_self_to_full_facet_value.carbon library "[[@TEST_NAME]]"; interface I { @@ -88,15 +88,7 @@ interface I { } fn F(U:! I where .I1 = .Self) { - // CHECK:STDERR: fail_todo_convert_from_period_self_to_full_facet_value.carbon:[[@LINE+4]]:3: error: cannot convert type `U` that implements `I where .(I.I1) = .Self` into type implementing `I where .(I.I1) = U` [ConversionFailureFacetToFacet] - // CHECK:STDERR: U as (I where .I1 = U); - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: U as (I where .I1 = U); - // CHECK:STDERR: fail_todo_convert_from_period_self_to_full_facet_value.carbon:[[@LINE+4]]:3: error: cannot convert type `U` that implements `I where .(I.I1) = .Self` into type implementing `I where .(I.I1) = U` [ConversionFailureFacetToFacet] - // CHECK:STDERR: (U as type) as (I where .I1 = U); - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: (U as type) as (I where .I1 = U); } @@ -134,7 +126,7 @@ fn F(U:! I where .X = .Self, unused V: U) { F2(U.G()); } -// --- fail_todo_access_through_call.carbon +// --- access_through_call.carbon library "[[@TEST_NAME]]"; interface I { @@ -147,55 +139,18 @@ fn F3[U:! I where .X = .Self](unused V: U*) {} fn F(U:! I where .X = .Self, unused V: U*) { // The returned value of `G` type `U` which has access to the methods of `I`. - // - // TODO: These should work. - // - The first `.` is on a NameRef of type FacetType for `I where .X = .Self`. - // - This finds `G` through the FacetType. - // - The second `.` is on a Call of type FacetAccessType into `SymbolicBinding` with type FacetType for `I`. - // - This finds `G` through the FacetType (impl lookup strips off FacetAccessType). - // - The third `.` is on a Call of type FacetAccessType into `ImplWitnessAccess` of `I.X` into `LookupImplWitness`, which has type `type` - // - Can't make calls on an `ImplWitnessAccess`. - // - We could expect that the constant value of the `ImplWitnessAccess` would - // be the same type that we got for the second lookup. - // CHECK:STDERR: fail_todo_access_through_call.carbon:[[@LINE+4]]:3: error: type `.(I.X)` does not support qualified expressions [QualifiedExprUnsupported] - // CHECK:STDERR: U.G()->G()->G(); - // CHECK:STDERR: ^~~~~~~~~~~~~ - // CHECK:STDERR: U.G()->G()->G(); - // CHECK:STDERR: fail_todo_access_through_call.carbon:[[@LINE+4]]:3: error: type `.(I.X)` does not support qualified expressions [QualifiedExprUnsupported] - // CHECK:STDERR: (U as type).G()->G()->G(); - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: (U as type).G()->G()->G(); // The returned value of type `U` can be used as a value of type `U`. - // - // TODO: This should work. - // CHECK:STDERR: fail_todo_access_through_call.carbon:[[@LINE+4]]:6: error: type `.(I.X)` does not support qualified expressions [QualifiedExprUnsupported] - // CHECK:STDERR: F2(U.G()->G()->G()); - // CHECK:STDERR: ^~~~~~~~~~~~~ - // CHECK:STDERR: F2(U.G()->G()->G()); // The constraints in the type `U` are preserved. - // - // TODO: These should work. - // CHECK:STDERR: fail_todo_access_through_call.carbon:[[@LINE+7]]:3: error: cannot convert type `.Self` that implements `I` into type implementing `I where .(I.X) = .Self` [ConversionFailureFacetToFacet] - // CHECK:STDERR: F3(U.G()); - // CHECK:STDERR: ^~~~~~~~~ - // CHECK:STDERR: fail_todo_access_through_call.carbon:[[@LINE-40]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] - // CHECK:STDERR: fn F3[U:! I where .X = .Self](unused V: U*) {} - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: F3(U.G()); - // CHECK:STDERR: fail_todo_access_through_call.carbon:[[@LINE+4]]:6: error: type `.(I.X)` does not support qualified expressions [QualifiedExprUnsupported] - // CHECK:STDERR: F3(U.G()->G()->G()); - // CHECK:STDERR: ^~~~~~~~~~~~~ - // CHECK:STDERR: F3(U.G()->G()->G()); } -// --- fail_todo_compound_access_through_call.carbon +// --- fail_compound_access_through_call.carbon library "[[@TEST_NAME]]"; interface I { @@ -203,30 +158,21 @@ interface I { fn G() -> X; } -fn F(U:! I where .X = .Self) { +fn F(U:! Core.Destroy & I where .X = .Self) { // Compound member lookup through a non-type value is possible for methods // which take a `self` parameter. But it's not possible for methods without // `self`. For those you need to go directly throug the type. // See: https://github.com/carbon-language/carbon-lang/issues/6025 - // TODO: This step should work. - // - // CHECK:STDERR: fail_todo_compound_access_through_call.carbon:[[@LINE+7]]:14: error: cannot implicitly convert expression of type `.Self` to `U` [ConversionFailure] - // CHECK:STDERR: let u: U = U.(I.G)(); - // CHECK:STDERR: ^~~~~~~~~ - // CHECK:STDERR: fail_todo_compound_access_through_call.carbon:[[@LINE+4]]:14: note: type `.Self` does not implement interface `Core.ImplicitAs(U)` [MissingImplInMemberAccessInContext] - // CHECK:STDERR: let u: U = U.(I.G)(); - // CHECK:STDERR: ^~~~~~~~~ - // CHECK:STDERR: let u: U = U.(I.G)(); // `u` is a non-type value. Can call methods with `self` through compound // member lookup, but can't call methods without `self`. See the // `compound_access_through_call_with_self_param.carbon` test for the former. // - // CHECK:STDERR: fail_todo_compound_access_through_call.carbon:[[@LINE+7]]:3: error: cannot implicitly convert non-type value of type `U` into type implementing `I` [ConversionFailureNonTypeToFacet] + // CHECK:STDERR: fail_compound_access_through_call.carbon:[[@LINE+7]]:3: error: cannot implicitly convert non-type value of type `U` into type implementing `I` [ConversionFailureNonTypeToFacet] // CHECK:STDERR: u.(I.G)(); // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: fail_todo_compound_access_through_call.carbon:[[@LINE+4]]:3: note: type `U` does not implement interface `Core.ImplicitAs(I)` [MissingImplInMemberAccessInContext] + // CHECK:STDERR: fail_compound_access_through_call.carbon:[[@LINE+4]]:3: note: type `U` does not implement interface `Core.ImplicitAs(I)` [MissingImplInMemberAccessInContext] // CHECK:STDERR: u.(I.G)(); // CHECK:STDERR: ^~~~~~~ // CHECK:STDERR: @@ -235,17 +181,17 @@ fn F(U:! I where .X = .Self) { // This is the same as the above, since G() returns a non-type value of type // `U`. // - // CHECK:STDERR: fail_todo_compound_access_through_call.carbon:[[@LINE+7]]:3: error: cannot implicitly convert non-type value of type `.Self` into type implementing `I` [ConversionFailureNonTypeToFacet] + // CHECK:STDERR: fail_compound_access_through_call.carbon:[[@LINE+7]]:3: error: cannot implicitly convert non-type value of type `U` into type implementing `I` [ConversionFailureNonTypeToFacet] // CHECK:STDERR: U.(I.G)().(I.G)(); // CHECK:STDERR: ^~~~~~~~~~~~~~~ - // CHECK:STDERR: fail_todo_compound_access_through_call.carbon:[[@LINE+4]]:3: note: type `.Self` does not implement interface `Core.ImplicitAs(I)` [MissingImplInMemberAccessInContext] + // CHECK:STDERR: fail_compound_access_through_call.carbon:[[@LINE+4]]:3: note: type `U` does not implement interface `Core.ImplicitAs(I)` [MissingImplInMemberAccessInContext] // CHECK:STDERR: U.(I.G)().(I.G)(); // CHECK:STDERR: ^~~~~~~~~~~~~~~ // CHECK:STDERR: U.(I.G)().(I.G)(); } -// --- fail_todo_compound_access_through_call_with_self_param.carbon +// --- compound_access_through_call_with_self_param.carbon library "[[@TEST_NAME]]"; interface I { @@ -257,15 +203,6 @@ fn F(U:! I where .X = .Self, v: U) { // Compound member lookup through a non-type value is possible for methods // which take a `self` parameter. - // TODO: This should all work. - - // CHECK:STDERR: fail_todo_compound_access_through_call_with_self_param.carbon:[[@LINE+7]]:15: error: cannot implicitly convert expression of type `.Self*` to `U*` [ConversionFailure] - // CHECK:STDERR: let u: U* = v.(I.G)(); - // CHECK:STDERR: ^~~~~~~~~ - // CHECK:STDERR: fail_todo_compound_access_through_call_with_self_param.carbon:[[@LINE+4]]:15: note: type `.Self*` does not implement interface `Core.ImplicitAs(U*)` [MissingImplInMemberAccessInContext] - // CHECK:STDERR: let u: U* = v.(I.G)(); - // CHECK:STDERR: ^~~~~~~~~ - // CHECK:STDERR: let u: U* = v.(I.G)(); // `u` is a non-type value. Can call methods with `self` through compound // member lookup, but can't call methods without `self`. See the @@ -831,11 +768,11 @@ fn F2(U:! Z) { // CHECK:STDOUT: %AB: %facet_type.82c = symbolic_binding AB, 0 [symbolic] // CHECK:STDOUT: %AB.binding.as_type: type = symbolic_binding_type AB, 0, %AB [symbolic] // CHECK:STDOUT: %A.lookup_impl_witness.1b9: = lookup_impl_witness %AB, @A [symbolic] +// CHECK:STDOUT: %B.lookup_impl_witness.97b: = lookup_impl_witness %AB, @B [symbolic] // CHECK:STDOUT: %.262: Core.Form = init_form %empty_tuple.type [concrete] // CHECK:STDOUT: %pattern_type.cb1: type = pattern_type %empty_tuple.type [concrete] // CHECK:STDOUT: %F.type: type = fn_type @F [concrete] // CHECK:STDOUT: %F: %F.type = struct_value () [concrete] -// CHECK:STDOUT: %B.lookup_impl_witness.97b: = lookup_impl_witness %AB, @B [symbolic] // CHECK:STDOUT: %.469: Core.Form = init_form %empty_struct_type [concrete] // CHECK:STDOUT: %pattern_type.a96: type = pattern_type %empty_struct_type [concrete] // CHECK:STDOUT: %G.type: type = fn_type @G [concrete] diff --git a/toolchain/check/testdata/facet/early_rewrites.carbon b/toolchain/check/testdata/facet/early_rewrites.carbon index 83023f06667c..8729e78a79ae 100644 --- a/toolchain/check/testdata/facet/early_rewrites.carbon +++ b/toolchain/check/testdata/facet/early_rewrites.carbon @@ -293,7 +293,7 @@ fn G(T:! J where .J1 = D) { F(T); } -// --- fail_todo_early_rewrite_applied_extra_indirection.carbon +// --- early_rewrite_applied_extra_indirection.carbon library "[[@TEST_NAME]]"; interface Z { @@ -310,20 +310,15 @@ impl () as Tuple {} class C(T:! Tuple) {} interface J { - // Implied: .Z1 == (), but this is also explicitly required for J1. + // .Z2 depends on an two nested accesses of rewrite constraints. let J1:! Y & Z where .Y1 = .Self and .Z1 = () and .Z2 = C(.Y1.Z1); } fn F(unused T:! J) {} class D; -// Satisfies the implied constraint in J.J1. impl D as Z where .Z1 = () and .Z2 = C(()) {} impl D as Y where .Y1 = D {} -// CHECK:STDERR: fail_todo_early_rewrite_applied_extra_indirection.carbon:[[@LINE+4]]:24: error: cannot convert type `D` into type implementing `Z & Y where .(Y.Y1) = .Self as Z and .(Z.Z1) = () and .(Z.Z2) = C(() as Tuple)` [ConversionFailureTypeToFacet] -// CHECK:STDERR: fn G(T:! J where .J1 = D) { -// CHECK:STDERR: ^ -// CHECK:STDERR: fn G(T:! J where .J1 = D) { F(T); } diff --git a/toolchain/check/testdata/facet/period_self.carbon b/toolchain/check/testdata/facet/period_self.carbon index f731cfcdab11..2122b1b8b196 100644 --- a/toolchain/check/testdata/facet/period_self.carbon +++ b/toolchain/check/testdata/facet/period_self.carbon @@ -54,25 +54,17 @@ interface I(T:! .Self) { fn G() -> T; } -// --- fail_todo_convert_period_self_to_full_facet_value.carbon +// --- convert_period_self_to_full_facet_value.carbon library "[[@TEST_NAME]]"; interface I(T:! type) {} fn F(U:! I(.Self)) { - // CHECK:STDERR: fail_todo_convert_period_self_to_full_facet_value.carbon:[[@LINE+4]]:3: error: cannot convert type `U` that implements `I(.Self)` into type implementing `I(U)` [ConversionFailureFacetToFacet] - // CHECK:STDERR: U as I(U); - // CHECK:STDERR: ^~~~~~~~~ - // CHECK:STDERR: U as I(U); - // CHECK:STDERR: fail_todo_convert_period_self_to_full_facet_value.carbon:[[@LINE+4]]:3: error: cannot convert type `U` that implements `I(.Self)` into type implementing `I(U)` [ConversionFailureFacetToFacet] - // CHECK:STDERR: (U as type) as I(U); - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: (U as type) as I(U); } -// --- fail_todo_convert_period_self_to_full_facet_value_with_assoc_constant.carbon +// --- convert_period_self_to_full_facet_value_with_assoc_constant.carbon library "[[@TEST_NAME]]"; interface I(T:! type) { @@ -80,15 +72,7 @@ interface I(T:! type) { } fn F(U:! I(.Self) where .X = .Self) { - // CHECK:STDERR: fail_todo_convert_period_self_to_full_facet_value_with_assoc_constant.carbon:[[@LINE+4]]:3: error: cannot convert type `U` that implements `I(.Self) where .(I(.Self).X) = .Self` into type implementing `I(U) where .(I(U).X) = U` [ConversionFailureFacetToFacet] - // CHECK:STDERR: U as (I(U) where .X = U); - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: U as (I(U) where .X = U); - // CHECK:STDERR: fail_todo_convert_period_self_to_full_facet_value_with_assoc_constant.carbon:[[@LINE+4]]:3: error: cannot convert type `U` that implements `I(.Self) where .(I(.Self).X) = .Self` into type implementing `I(U) where .(I(U).X) = U` [ConversionFailureFacetToFacet] - // CHECK:STDERR: (U as type) as (I(U) where .X = U); - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: (U as type) as (I(U) where .X = U); } @@ -228,7 +212,7 @@ fn F(U:! I(.Self)) { let unused a: U = U.G(); } -// --- fail_todo_return_of_type_period_self_assoc_const_has_type_u.carbon +// --- return_of_type_period_self_assoc_const_has_type_u.carbon library "[[@TEST_NAME]]"; interface I { @@ -236,14 +220,7 @@ interface I { fn G() -> X; } -fn F(U:! I where .X = .Self) { - // CHECK:STDERR: fail_todo_return_of_type_period_self_assoc_const_has_type_u.carbon:[[@LINE+7]]:21: error: cannot implicitly convert expression of type `.Self` to `U` [ConversionFailure] - // CHECK:STDERR: let unused a: U = U.G(); - // CHECK:STDERR: ^~~~~ - // CHECK:STDERR: fail_todo_return_of_type_period_self_assoc_const_has_type_u.carbon:[[@LINE+4]]:21: note: type `.Self` does not implement interface `Core.ImplicitAs(U)` [MissingImplInMemberAccessInContext] - // CHECK:STDERR: let unused a: U = U.G(); - // CHECK:STDERR: ^~~~~ - // CHECK:STDERR: +fn F(U:! Core.Destroy & I where .X = .Self) { let unused a: U = U.G(); } @@ -330,7 +307,7 @@ interface I(T:! Core.Destroy) {} // CHECK:STDERR: fn F(unused U:! Core.Destroy & I(.Self)) {} -// --- fail_todo_compound_lookup_on_returned_period_self_parameter.carbon +// --- compound_lookup_on_returned_period_self_parameter.carbon library "[[@TEST_NAME]]"; interface I(T:! Core.Destroy) { @@ -341,14 +318,160 @@ fn F[U:! Core.Destroy where .Self impls I(.Self)](u: U) { // This tests that both `I.G` is accessible and that `Destroy` is preserved; // we'd get an error for missing Destroy otherwise since G() returns an // initializing expression. - - // CHECK:STDERR: fail_todo_compound_lookup_on_returned_period_self_parameter.carbon:[[@LINE+4]]:3: error: cannot access member of interface `I(U as Core.Destroy)` in type `U` that does not implement that interface [MissingImplInMemberAccess] - // CHECK:STDERR: u.(I(U).G)().(I(U).G)().(I(U).G)(); - // CHECK:STDERR: ^~~~~~~~~~ - // CHECK:STDERR: u.(I(U).G)().(I(U).G)().(I(U).G)(); } +// --- unambiguous_period_self.carbon +library "[[@TEST_NAME]]"; + +interface Z(T:! type) {} +interface Y(T:! type) { + let Y1:! type; + let Y2:! type; +} +interface X(T:! type) {} + +class P; +class Q(T:! type); +class R(T:! type); + +fn A(unused T:! Z(.Self) where .Self impls (Y(.Self) where .Self impls X(.Self))) {} +// ^T as type ^T as Z(T) ^T as Z(T) ^T as Z(T) & Y(T) +// ^ T as Z(T) & Y(T) + +fn B(unused T:! Z(.Self) where .Self impls (Y(.Self) where Q(.Self) impls X(.Self))) {} +// ^T as type ^T as Z(T) ^T as Z(T) ^T as Z(T) & Y(T) +// ^ T as Z(T) & Y(T) + +fn C(unused T:! Z(.Self) where .Self impls (Y(.Self) where .Y1 = .Self)) {} +// ^T as type ^T as Z(T) ^T as Z(T) ^T as Z(T) & Y(T) +// ^ T as Z(T) & Y(T) + +// This introduces a different meaning of `.Self`, but we allow it here. +fn D(unused T:! Z(.Self) where R(.Self) impls (Y(.Self) where .Self impls X(P))) {} +// ^T as type ^T as Z(T) ^T as Z(T) ^R(T as Z(T)) as Y(T as Z(T)) + +// This introduces a different meaning of `.Self`, but we allow it here. +fn E(unused T:! Z(.Self) where R(.Self) impls (Y(.Self) where .Y1 = .Y2)) {} +// ^T as type ^T as Z(T) ^T as Z(T) ^R(T as Z(T)) as Y(T as Z(T)) +// ^R(T as Z(T)) as Y(T as Z(T)) + +// --- fail_todo_period_self_impls_ambiguous_period_self_access_argument.carbon +library "[[@TEST_NAME]]"; + +interface Z(T:! type) {} +interface Y(T:! type) { + let Y1:! type; +} +interface X(T:! type) {} + +class R(T:! type); + +// CHECK:STDERR: fail_todo_period_self_impls_ambiguous_period_self_access_argument.carbon:[[@LINE+4]]:32: error: `.Self` is ambiguous after nested `where` in ` impls ...` clause. [AmbiguousPeriodSelf] +// CHECK:STDERR: fn C(unused T:! Z(.Self) where R(.Self) impls (Y(.Self) where .Self impls X(.Y1))) {} +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn C(unused T:! Z(.Self) where R(.Self) impls (Y(.Self) where .Self impls X(.Y1))) {} +// ^T as type ^T as Z(T) ^T as Z(T) ^R(T as Z(T)) as Y(T as Z(T)) +// ^ERROR: R(T as Z(T)) as Y(T as Z(T)) + +// --- fail_type_impls_ambiguous_period_self_argument.carbon +library "[[@TEST_NAME]]"; + +interface Z(T:! type) {} +interface Y(T:! type) {} +interface X(T:! type) {} +interface W {} + +class P; +class Q(T:! type); +class R(T:! type); + +// CHECK:STDERR: fail_type_impls_ambiguous_period_self_argument.carbon:[[@LINE+4]]:32: error: `.Self` is ambiguous after nested `where` in ` impls ...` clause. [AmbiguousPeriodSelf] +// CHECK:STDERR: fn A(unused T:! Z(.Self) where R(.Self) impls (Y(.Self) where P impls X(.Self))) {} +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn A(unused T:! Z(.Self) where R(.Self) impls (Y(.Self) where P impls X(.Self))) {} +// ^T as type ^T as Z(T) ^T as Z(T) ^ERROR: R(T as Z(T)) as Y(T as Z(T)) + +// --- fail_ambiguous_period_self_argument_impls.carbon +library "[[@TEST_NAME]]"; + +interface Z(T:! type) {} +interface Y(T:! type) {} +interface X {} + +class Q(T:! type); +class R(T:! type); + +// CHECK:STDERR: fail_ambiguous_period_self_argument_impls.carbon:[[@LINE+4]]:32: error: `.Self` is ambiguous after nested `where` in ` impls ...` clause. [AmbiguousPeriodSelf] +// CHECK:STDERR: fn B(unused T:! Z(.Self) where R(.Self) impls (Y(.Self) where Q(.Self) impls X)) {} +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn B(unused T:! Z(.Self) where R(.Self) impls (Y(.Self) where Q(.Self) impls X)) {} +// ^T as type ^T as Z(T) ^T as Z(T) ^ERROR: R(T as Z(T)) as Y(T as Z(T)) + +// --- fail_period_self_impls_ambiguous_period_self_argument.carbon +library "[[@TEST_NAME]]"; + +interface Z(T:! type) {} +interface Y(T:! type) {} +interface X(T:! type) {} + +class R(T:! type); + +// CHECK:STDERR: fail_period_self_impls_ambiguous_period_self_argument.carbon:[[@LINE+4]]:32: error: `.Self` is ambiguous after nested `where` in ` impls ...` clause. [AmbiguousPeriodSelf] +// CHECK:STDERR: fn C(unused T:! Z(.Self) where R(.Self) impls (Y(.Self) where .Self impls X(.Self))) {} +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn C(unused T:! Z(.Self) where R(.Self) impls (Y(.Self) where .Self impls X(.Self))) {} +// ^T as type ^T as Z(T) ^T as Z(T) ^R(T as Z(T)) as Y(T as Z(T)) +// ^ERROR: R(T as Z(T)) as Y(T as Z(T)) + +// --- todo_fail_rewrite_rhs_ambiguous_period_self.carbon +library "[[@TEST_NAME]]"; + +interface Z(T:! type) {} +interface Y(T:! type) { + let Y1:! type; +} + +class R(T:! type); + +fn D(unused T:! Z(.Self) where R(.Self) impls (Y(.Self) where .Y1 = .Self)) {} +// ^T as type ^T as Z(T) ^T as Z(T) ^R(T as Z(T)) as Y(T as Z(T)) +// ^ERROR: R(T as Z(T)) as Y(T as Z(T)) + +// --- impl_as_rewrite_with_period_self.carbon +library "[[@TEST_NAME]]"; + +interface Z { + let Z1:! type; +} + +class C; +impl C as Z where .Z1 = .Self {} + +fn F() { + C as (Z where .Z1 = C); +} + +// --- impl_as_impls_with_period_self.carbon +library "[[@TEST_NAME]]"; + +interface Z { + let Z1:! type; +} +interface Y {} + +class C; +impl C as Z where .Z1 = .Self {} +impl C as Y {} + +fn F() { + C as (Z where .Z1 impls Y); +} + // CHECK:STDOUT: --- period_self_param.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -377,8 +500,9 @@ fn F[U:! Core.Destroy where .Self impls I(.Self)](u: U) { // CHECK:STDOUT: %pattern_type.033: type = pattern_type %I_where.type [symbolic_self] // CHECK:STDOUT: %T.706: %I_where.type = symbolic_binding T, 0 [symbolic] // CHECK:STDOUT: %T.binding.as_type: type = symbolic_binding_type T, 0, %T.706 [symbolic] -// CHECK:STDOUT: %I.lookup_impl_witness.94d: = lookup_impl_witness %T.706, @I, @I(%.Self.binding.as_type.8db) [symbolic] -// CHECK:STDOUT: %I.facet: %I.type.bee = facet_value %T.binding.as_type, (%I.lookup_impl_witness.94d) [symbolic] +// CHECK:STDOUT: %facet_value: %type = facet_value %T.binding.as_type, () [symbolic] +// CHECK:STDOUT: %I.lookup_impl_witness.7f4: = lookup_impl_witness %T.706, @I, @I(%T.binding.as_type) [symbolic] +// CHECK:STDOUT: %I.facet: %I.type.bee = facet_value %T.binding.as_type, (%I.lookup_impl_witness.7f4) [symbolic] // CHECK:STDOUT: %.262: Core.Form = init_form %empty_tuple.type [concrete] // CHECK:STDOUT: %pattern_type.cb1: type = pattern_type %empty_tuple.type [concrete] // CHECK:STDOUT: %F.type: type = fn_type @F [concrete] @@ -403,12 +527,20 @@ fn F[U:! Core.Destroy where .Self impls I(.Self)](u: U) { // CHECK:STDOUT: %return.patt: %pattern_type.cb1 = return_slot_pattern %return.param_patt, %impl.elem0.loc8_39 [concrete] // CHECK:STDOUT: } { // CHECK:STDOUT: %T.ref: %I_where.type = name_ref T, %T.loc8_7.2 [symbolic = %T.loc8_7.1 (constants.%T.706)] -// CHECK:STDOUT: %T.as_type: type = facet_access_type %T.ref [symbolic = %T.binding.as_type (constants.%T.binding.as_type)] -// CHECK:STDOUT: %.loc8_39.1: type = converted %T.ref, %T.as_type [symbolic = %T.binding.as_type (constants.%T.binding.as_type)] +// CHECK:STDOUT: %T.as_type.loc8_39.1: type = facet_access_type %T.ref [symbolic = %T.binding.as_type (constants.%T.binding.as_type)] +// CHECK:STDOUT: %.loc8_39.1: type = converted %T.ref, %T.as_type.loc8_39.1 [symbolic = %T.binding.as_type (constants.%T.binding.as_type)] // CHECK:STDOUT: %.loc8_39.2: %I.assoc_type.c03 = specific_constant @I1.%assoc0, @I.WithSelf(constants.%.Self.binding.as_type.8db, constants.%T.706) [symbolic_self = constants.%assoc0.fe4] // CHECK:STDOUT: %I1.ref.loc8_39: %I.assoc_type.c03 = name_ref I1, %.loc8_39.2 [symbolic_self = constants.%assoc0.fe4] -// CHECK:STDOUT: %impl.elem0.loc8_39: type = impl_witness_access constants.%I.lookup_impl_witness.94d, element0 [concrete = constants.%empty_tuple.type] -// CHECK:STDOUT: %.loc8_39.3: Core.Form = init_form %impl.elem0.loc8_39 [concrete = constants.%.262] +// CHECK:STDOUT: %facet_value.loc8_39.2: %type = facet_value constants.%T.binding.as_type, () [symbolic = %facet_value.loc8_39.1 (constants.%facet_value)] +// CHECK:STDOUT: %.loc8_39.3: %type = converted constants.%T.binding.as_type, %facet_value.loc8_39.2 [symbolic = %facet_value.loc8_39.1 (constants.%facet_value)] +// CHECK:STDOUT: %T.as_type.loc8_39.2: type = facet_access_type constants.%T.706 [symbolic = %T.binding.as_type (constants.%T.binding.as_type)] +// CHECK:STDOUT: %facet_value.loc8_39.3: %type = facet_value %T.as_type.loc8_39.2, () [symbolic = %facet_value.loc8_39.1 (constants.%facet_value)] +// CHECK:STDOUT: %.loc8_39.4: %type = converted constants.%T.706, %facet_value.loc8_39.3 [symbolic = %facet_value.loc8_39.1 (constants.%facet_value)] +// CHECK:STDOUT: %T.as_type.loc8_39.3: type = facet_access_type constants.%T.706 [symbolic = %T.binding.as_type (constants.%T.binding.as_type)] +// CHECK:STDOUT: %facet_value.loc8_39.4: %type = facet_value %T.as_type.loc8_39.3, () [symbolic = %facet_value.loc8_39.1 (constants.%facet_value)] +// CHECK:STDOUT: %.loc8_39.5: %type = converted constants.%T.706, %facet_value.loc8_39.4 [symbolic = %facet_value.loc8_39.1 (constants.%facet_value)] +// CHECK:STDOUT: %impl.elem0.loc8_39: type = impl_witness_access constants.%I.lookup_impl_witness.7f4, element0 [concrete = constants.%empty_tuple.type] +// CHECK:STDOUT: %.loc8_39.6: Core.Form = init_form %impl.elem0.loc8_39 [concrete = constants.%.262] // CHECK:STDOUT: %.loc8_19.1: type = splice_block %.loc8_19.2 [symbolic_self = constants.%I_where.type] { // CHECK:STDOUT: // CHECK:STDOUT: %I.ref: %I.type.609 = name_ref I, file.%I.decl [concrete = constants.%I.generic] @@ -440,12 +572,15 @@ fn F[U:! Core.Destroy where .Self impls I(.Self)](u: U) { // CHECK:STDOUT: %return.patt: %pattern_type.cb1 = return_slot_pattern %return.param_patt, %impl.elem0.loc12_47 [concrete] // CHECK:STDOUT: } { // CHECK:STDOUT: %T.ref: %I_where.type = name_ref T, %T.loc12_7.2 [symbolic = %T.loc12_7.1 (constants.%T.706)] -// CHECK:STDOUT: %T.as_type: type = facet_access_type %T.ref [symbolic = %T.binding.as_type (constants.%T.binding.as_type)] -// CHECK:STDOUT: %.loc12_47.1: type = converted %T.ref, %T.as_type [symbolic = %T.binding.as_type (constants.%T.binding.as_type)] +// CHECK:STDOUT: %T.as_type.loc12_47.1: type = facet_access_type %T.ref [symbolic = %T.binding.as_type (constants.%T.binding.as_type)] +// CHECK:STDOUT: %.loc12_47.1: type = converted %T.ref, %T.as_type.loc12_47.1 [symbolic = %T.binding.as_type (constants.%T.binding.as_type)] // CHECK:STDOUT: %.loc12_47.2: %I.assoc_type.c03 = specific_constant @I1.%assoc0, @I.WithSelf(constants.%.Self.binding.as_type.8db, constants.%T.706) [symbolic_self = constants.%assoc0.fe4] // CHECK:STDOUT: %I1.ref.loc12_47: %I.assoc_type.c03 = name_ref I1, %.loc12_47.2 [symbolic_self = constants.%assoc0.fe4] -// CHECK:STDOUT: %impl.elem0.loc12_47: type = impl_witness_access constants.%I.lookup_impl_witness.94d, element0 [concrete = constants.%empty_tuple.type] -// CHECK:STDOUT: %.loc12_47.3: Core.Form = init_form %impl.elem0.loc12_47 [concrete = constants.%.262] +// CHECK:STDOUT: %T.as_type.loc12_47.2: type = facet_access_type constants.%T.706 [symbolic = %T.binding.as_type (constants.%T.binding.as_type)] +// CHECK:STDOUT: %facet_value.loc12_47.2: %type = facet_value %T.as_type.loc12_47.2, () [symbolic = %facet_value.loc12_47.1 (constants.%facet_value)] +// CHECK:STDOUT: %.loc12_47.3: %type = converted constants.%T.706, %facet_value.loc12_47.2 [symbolic = %facet_value.loc12_47.1 (constants.%facet_value)] +// CHECK:STDOUT: %impl.elem0.loc12_47: type = impl_witness_access constants.%I.lookup_impl_witness.7f4, element0 [concrete = constants.%empty_tuple.type] +// CHECK:STDOUT: %.loc12_47.4: Core.Form = init_form %impl.elem0.loc12_47 [concrete = constants.%.262] // CHECK:STDOUT: %.loc12_27.1: type = splice_block %.loc12_27.2 [symbolic_self = constants.%I_where.type] { // CHECK:STDOUT: // CHECK:STDOUT: %I.ref: %I.type.609 = name_ref I, file.%I.decl [concrete = constants.%I.generic] @@ -502,6 +637,7 @@ fn F[U:! Core.Destroy where .Self impls I(.Self)](u: U) { // CHECK:STDOUT: generic fn @F(%T.loc8_7.2: %I_where.type) { // CHECK:STDOUT: %T.loc8_7.1: %I_where.type = symbolic_binding T, 0 [symbolic = %T.loc8_7.1 (constants.%T.706)] // CHECK:STDOUT: %T.binding.as_type: type = symbolic_binding_type T, 0, %T.loc8_7.1 [symbolic = %T.binding.as_type (constants.%T.binding.as_type)] +// CHECK:STDOUT: %facet_value.loc8_39.1: %type = facet_value %T.binding.as_type, () [symbolic = %facet_value.loc8_39.1 (constants.%facet_value)] // CHECK:STDOUT: // CHECK:STDOUT: !definition: // CHECK:STDOUT: @@ -517,6 +653,7 @@ fn F[U:! Core.Destroy where .Self impls I(.Self)](u: U) { // CHECK:STDOUT: generic fn @G(%T.loc12_7.2: %I_where.type) { // CHECK:STDOUT: %T.loc12_7.1: %I_where.type = symbolic_binding T, 0 [symbolic = %T.loc12_7.1 (constants.%T.706)] // CHECK:STDOUT: %T.binding.as_type: type = symbolic_binding_type T, 0, %T.loc12_7.1 [symbolic = %T.binding.as_type (constants.%T.binding.as_type)] +// CHECK:STDOUT: %facet_value.loc12_47.1: %type = facet_value %T.binding.as_type, () [symbolic = %facet_value.loc12_47.1 (constants.%facet_value)] // CHECK:STDOUT: // CHECK:STDOUT: !definition: // CHECK:STDOUT: @@ -564,6 +701,10 @@ fn F[U:! Core.Destroy where .Self impls I(.Self)](u: U) { // CHECK:STDOUT: %assoc0 => constants.%assoc0.fe4 // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @I(constants.%T.binding.as_type) { +// CHECK:STDOUT: %T.loc4_14.1 => constants.%T.binding.as_type +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: specific @I.WithSelf(constants.%.Self.binding.as_type.8db, constants.%I.facet) { // CHECK:STDOUT: !definition: // CHECK:STDOUT: %T => constants.%.Self.binding.as_type.8db @@ -574,10 +715,12 @@ fn F[U:! Core.Destroy where .Self impls I(.Self)](u: U) { // CHECK:STDOUT: specific @F(constants.%T.706) { // CHECK:STDOUT: %T.loc8_7.1 => constants.%T.706 // CHECK:STDOUT: %T.binding.as_type => constants.%T.binding.as_type +// CHECK:STDOUT: %facet_value.loc8_39.1 => constants.%facet_value // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @G(constants.%T.706) { // CHECK:STDOUT: %T.loc12_7.1 => constants.%T.706 // CHECK:STDOUT: %T.binding.as_type => constants.%T.binding.as_type +// CHECK:STDOUT: %facet_value.loc12_47.1 => constants.%facet_value // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/facet/self_in_interface_param.carbon b/toolchain/check/testdata/facet/self_in_interface_param.carbon index e24c7dbee027..874562a9aaf4 100644 --- a/toolchain/check/testdata/facet/self_in_interface_param.carbon +++ b/toolchain/check/testdata/facet/self_in_interface_param.carbon @@ -43,7 +43,8 @@ fn G(_:! I(.Self) where .I1 = ()) {} // CHECK:STDOUT: %pattern_type.033: type = pattern_type %I_where.type [symbolic_self] // CHECK:STDOUT: %T.706: %I_where.type = symbolic_binding T, 0 [symbolic] // CHECK:STDOUT: %T.binding.as_type: type = symbolic_binding_type T, 0, %T.706 [symbolic] -// CHECK:STDOUT: %I.lookup_impl_witness.94d: = lookup_impl_witness %T.706, @I, @I(%.Self.binding.as_type.8db) [symbolic] +// CHECK:STDOUT: %facet_value: %type = facet_value %T.binding.as_type, () [symbolic] +// CHECK:STDOUT: %I.lookup_impl_witness.7f4: = lookup_impl_witness %T.706, @I, @I(%T.binding.as_type) [symbolic] // CHECK:STDOUT: %.262: Core.Form = init_form %empty_tuple.type [concrete] // CHECK:STDOUT: %pattern_type.cb1: type = pattern_type %empty_tuple.type [concrete] // CHECK:STDOUT: %F.type: type = fn_type @F [concrete] @@ -57,12 +58,20 @@ fn G(_:! I(.Self) where .I1 = ()) {} // CHECK:STDOUT: %return.patt: %pattern_type.cb1 = return_slot_pattern %return.param_patt, %impl.elem0.loc18_39 [concrete] // CHECK:STDOUT: } { // CHECK:STDOUT: %T.ref: %I_where.type = name_ref T, %T.loc18_7.2 [symbolic = %T.loc18_7.1 (constants.%T.706)] -// CHECK:STDOUT: %T.as_type: type = facet_access_type %T.ref [symbolic = %T.binding.as_type (constants.%T.binding.as_type)] -// CHECK:STDOUT: %.loc18_39.1: type = converted %T.ref, %T.as_type [symbolic = %T.binding.as_type (constants.%T.binding.as_type)] +// CHECK:STDOUT: %T.as_type.loc18_39.1: type = facet_access_type %T.ref [symbolic = %T.binding.as_type (constants.%T.binding.as_type)] +// CHECK:STDOUT: %.loc18_39.1: type = converted %T.ref, %T.as_type.loc18_39.1 [symbolic = %T.binding.as_type (constants.%T.binding.as_type)] // CHECK:STDOUT: %.loc18_39.2: %I.assoc_type.c03 = specific_constant @I1.%assoc0, @I.WithSelf(constants.%.Self.binding.as_type.8db, constants.%T.706) [symbolic_self = constants.%assoc0.fe4] // CHECK:STDOUT: %I1.ref.loc18_39: %I.assoc_type.c03 = name_ref I1, %.loc18_39.2 [symbolic_self = constants.%assoc0.fe4] -// CHECK:STDOUT: %impl.elem0.loc18_39: type = impl_witness_access constants.%I.lookup_impl_witness.94d, element0 [concrete = constants.%empty_tuple.type] -// CHECK:STDOUT: %.loc18_39.3: Core.Form = init_form %impl.elem0.loc18_39 [concrete = constants.%.262] +// CHECK:STDOUT: %facet_value.loc18_39.2: %type = facet_value constants.%T.binding.as_type, () [symbolic = %facet_value.loc18_39.1 (constants.%facet_value)] +// CHECK:STDOUT: %.loc18_39.3: %type = converted constants.%T.binding.as_type, %facet_value.loc18_39.2 [symbolic = %facet_value.loc18_39.1 (constants.%facet_value)] +// CHECK:STDOUT: %T.as_type.loc18_39.2: type = facet_access_type constants.%T.706 [symbolic = %T.binding.as_type (constants.%T.binding.as_type)] +// CHECK:STDOUT: %facet_value.loc18_39.3: %type = facet_value %T.as_type.loc18_39.2, () [symbolic = %facet_value.loc18_39.1 (constants.%facet_value)] +// CHECK:STDOUT: %.loc18_39.4: %type = converted constants.%T.706, %facet_value.loc18_39.3 [symbolic = %facet_value.loc18_39.1 (constants.%facet_value)] +// CHECK:STDOUT: %T.as_type.loc18_39.3: type = facet_access_type constants.%T.706 [symbolic = %T.binding.as_type (constants.%T.binding.as_type)] +// CHECK:STDOUT: %facet_value.loc18_39.4: %type = facet_value %T.as_type.loc18_39.3, () [symbolic = %facet_value.loc18_39.1 (constants.%facet_value)] +// CHECK:STDOUT: %.loc18_39.5: %type = converted constants.%T.706, %facet_value.loc18_39.4 [symbolic = %facet_value.loc18_39.1 (constants.%facet_value)] +// CHECK:STDOUT: %impl.elem0.loc18_39: type = impl_witness_access constants.%I.lookup_impl_witness.7f4, element0 [concrete = constants.%empty_tuple.type] +// CHECK:STDOUT: %.loc18_39.6: Core.Form = init_form %impl.elem0.loc18_39 [concrete = constants.%.262] // CHECK:STDOUT: %.loc18_19.1: type = splice_block %.loc18_19.2 [symbolic_self = constants.%I_where.type] { // CHECK:STDOUT: // CHECK:STDOUT: %I.ref: %I.type.609 = name_ref I, file.%I.decl [concrete = constants.%I.generic] @@ -93,6 +102,7 @@ fn G(_:! I(.Self) where .I1 = ()) {} // CHECK:STDOUT: generic fn @F(%T.loc18_7.2: %I_where.type) { // CHECK:STDOUT: %T.loc18_7.1: %I_where.type = symbolic_binding T, 0 [symbolic = %T.loc18_7.1 (constants.%T.706)] // CHECK:STDOUT: %T.binding.as_type: type = symbolic_binding_type T, 0, %T.loc18_7.1 [symbolic = %T.binding.as_type (constants.%T.binding.as_type)] +// CHECK:STDOUT: %facet_value.loc18_39.1: %type = facet_value %T.binding.as_type, () [symbolic = %facet_value.loc18_39.1 (constants.%facet_value)] // CHECK:STDOUT: // CHECK:STDOUT: !definition: // CHECK:STDOUT: @@ -108,5 +118,6 @@ fn G(_:! I(.Self) where .I1 = ()) {} // CHECK:STDOUT: specific @F(constants.%T.706) { // CHECK:STDOUT: %T.loc18_7.1 => constants.%T.706 // CHECK:STDOUT: %T.binding.as_type => constants.%T.binding.as_type +// CHECK:STDOUT: %facet_value.loc18_39.1 => constants.%facet_value // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/facet/validate_impl_constraints.carbon b/toolchain/check/testdata/facet/validate_impl_constraints.carbon index 0ec8156d374d..5f8f254f6ef6 100644 --- a/toolchain/check/testdata/facet/validate_impl_constraints.carbon +++ b/toolchain/check/testdata/facet/validate_impl_constraints.carbon @@ -39,7 +39,7 @@ fn G(T:! I where .Self impls (I where .X = {})) { F(T); } -// --- fail_todo_where_impls_tests_associated_constant_of_generic_type.carbon +// --- fail_where_impls_tests_associated_constant_of_generic_type_non_final_impl.carbon library "[[@TEST_NAME]]"; class C(U:! type) {} @@ -55,16 +55,39 @@ impl forall [U:! L] C(U) as M where .M0 = {} {} fn F(unused U:! type where C(.Self) impls (M where .M0 = {})) {} fn G(T:! L) { - // CHECK:STDERR: fail_todo_where_impls_tests_associated_constant_of_generic_type.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `L` into type implementing `type where C(.Self) impls M and .(M.M0) = {}` [ConversionFailureFacetToFacet] + // We have no final impl for `C(T) as M`, so we don't know the value of + // `(C(T) as M).M0` concretely, so we don't know that it is `{}` and we can't + // convert assuming it is. + // + // CHECK:STDERR: fail_where_impls_tests_associated_constant_of_generic_type_non_final_impl.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `L` into type implementing `type where C(.Self) impls M and C(.Self).(M.M0) = {}` [ConversionFailureFacetToFacet] // CHECK:STDERR: F(T); // CHECK:STDERR: ^~~~ - // CHECK:STDERR: fail_todo_where_impls_tests_associated_constant_of_generic_type.carbon:[[@LINE-6]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] + // CHECK:STDERR: fail_where_impls_tests_associated_constant_of_generic_type_non_final_impl.carbon:[[@LINE-10]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] // CHECK:STDERR: fn F(unused U:! type where C(.Self) impls (M where .M0 = {})) {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: F(T); } +// --- where_impls_tests_associated_constant_of_generic_type.carbon +library "[[@TEST_NAME]]"; + +class C(U:! type) {} + +// C(U) impls M if U impls L. +interface L {} +interface M { let M0:! type; } +final impl forall [U:! L] C(U) as M where .M0 = {} {} + +// U requires that C(.Self) impls M. +// - C(.Self) impls M can be rewritten as C(U) impls M. +// - C(U) impls M if U impls L => Requires U impls L. +fn F(unused U:! type where C(.Self) impls (M where .M0 = {})) {} + +fn G(T:! L) { + F(T); +} + // --- fail_where_impls_tests_associated_constant_of_generic_type_type_differs.carbon library "[[@TEST_NAME]]"; @@ -73,7 +96,7 @@ class C(U:! type) {} // C(U) impls M if U impls L. interface L {} interface M { let M0:! type; } -impl forall [U:! L] C(U) as M where .M0 = () {} +final impl forall [U:! L] C(U) as M where .M0 = () {} // U requires that C(.Self) impls M. // - C(.Self) impls M can be rewritten as C(U) impls M. @@ -81,7 +104,7 @@ impl forall [U:! L] C(U) as M where .M0 = () {} fn F(unused U:! type where C(.Self) impls (M where .M0 = {})) {} fn G(T:! L) { - // CHECK:STDERR: fail_where_impls_tests_associated_constant_of_generic_type_type_differs.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `L` into type implementing `type where C(.Self) impls M and .(M.M0) = {}` [ConversionFailureFacetToFacet] + // CHECK:STDERR: fail_where_impls_tests_associated_constant_of_generic_type_type_differs.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `L` into type implementing `type where C(.Self) impls M and C(.Self).(M.M0) = {}` [ConversionFailureFacetToFacet] // CHECK:STDERR: F(T); // CHECK:STDERR: ^~~~ // CHECK:STDERR: fail_where_impls_tests_associated_constant_of_generic_type_type_differs.carbon:[[@LINE-6]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] @@ -91,6 +114,81 @@ fn G(T:! L) { F(T); } +// --- fail_where_impls_tests_associated_constant_of_generic_interface_non_final_impl.carbon +library "[[@TEST_NAME]]"; + +class C {} + +// C impls M(U) if U impls L. +interface L {} +interface M(U:! type) { let M0:! type; } +impl forall [U:! L] C as M(U) where .M0 = {} {} + +// U requires that C impls M(.Self). +// - C impls M(.Self) can be rewritten as C impls M(U). +// - C impls M(U) if U impls L => Requires U impls L. +fn F(unused U:! type where C impls (M(.Self) where .M0 = {})) {} + +fn G(T:! L) { + // We have no final impl for `C as M(T)`, so we don't know the value of + // `(C as M(T)).M0` concretely, so we don't know that it is `{}` and we can't + // convert assuming it is. + // + // CHECK:STDERR: fail_where_impls_tests_associated_constant_of_generic_interface_non_final_impl.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `L` into type implementing `type where C impls M(.Self) and C.(M(.Self).M0) = {}` [ConversionFailureFacetToFacet] + // CHECK:STDERR: F(T); + // CHECK:STDERR: ^~~~ + // CHECK:STDERR: fail_where_impls_tests_associated_constant_of_generic_interface_non_final_impl.carbon:[[@LINE-10]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] + // CHECK:STDERR: fn F(unused U:! type where C impls (M(.Self) where .M0 = {})) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + F(T); +} + +// --- where_impls_tests_associated_constant_of_generic_interface.carbon +library "[[@TEST_NAME]]"; + +class C {} + +// C impls M(U) if U impls L. +interface L {} +interface M(U:! type) { let M0:! type; } +final impl forall [U:! L] C as M(U) where .M0 = {} {} + +// U requires that C impls M(.Self). +// - C impls M(.Self) can be rewritten as C impls M(U). +// - C impls M(U) if U impls L => Requires U impls L. +fn F(unused U:! type where C impls (M(.Self) where .M0 = {})) {} + +fn G(T:! L) { + F(T); +} + +// --- fail_where_impls_tests_associated_constant_of_generic_interface_type_differs.carbon +library "[[@TEST_NAME]]"; + +class C {} + +// C impls M(U) if U impls L. +interface L {} +interface M(U:! type) { let M0:! type; } +final impl forall [U:! L] C as M(U) where .M0 = () {} + +// U requires that C impls M(.Self). +// - C impls M(.Self) can be rewritten as C impls M(U). +// - C impls M(U) if U impls L => Requires U impls L. +fn F(unused U:! type where C impls (M(.Self) where .M0 = {})) {} + +fn G(T:! L) { + // CHECK:STDERR: fail_where_impls_tests_associated_constant_of_generic_interface_type_differs.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `L` into type implementing `type where C impls M(.Self) and C.(M(.Self).M0) = {}` [ConversionFailureFacetToFacet] + // CHECK:STDERR: F(T); + // CHECK:STDERR: ^~~~ + // CHECK:STDERR: fail_where_impls_tests_associated_constant_of_generic_interface_type_differs.carbon:[[@LINE-6]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] + // CHECK:STDERR: fn F(unused U:! type where C impls (M(.Self) where .M0 = {})) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + F(T); +} + // --- self_in_interface_generic_param_unconstrained.carbon library "[[@TEST_NAME]]"; @@ -109,12 +207,13 @@ library "[[@TEST_NAME]]"; interface Z {} interface I(T:! Z) {} -// Implied constraint: .Self impls Z, which is satisfied and checked at the end -// of the fn signature. +// TODO: I(.Self) introduces an implied constraint `.Self impls Z`, which is +// satisfied and checked at the end of the fn signature. +// // CHECK:STDERR: fail_todo_self_in_interface_generic_param_constrained.carbon:[[@LINE+7]]:17: error: cannot convert type `.Self` that implements `type` into type implementing `Z` [ConversionFailureFacetToFacet] // CHECK:STDERR: fn F(unused T:! I(.Self) where .Self impls Z) {} // CHECK:STDERR: ^~~~~~~~ -// CHECK:STDERR: fail_todo_self_in_interface_generic_param_constrained.carbon:[[@LINE-7]]:13: note: initializing generic parameter `T` declared here [InitializingGenericParam] +// CHECK:STDERR: fail_todo_self_in_interface_generic_param_constrained.carbon:[[@LINE-8]]:13: note: initializing generic parameter `T` declared here [InitializingGenericParam] // CHECK:STDERR: interface I(T:! Z) {} // CHECK:STDERR: ^~~~~ // CHECK:STDERR: @@ -123,7 +222,7 @@ fn F(unused T:! I(.Self) where .Self impls Z) {} // CHECK:STDERR: fail_todo_self_in_interface_generic_param_constrained.carbon:[[@LINE+7]]:14: error: cannot convert type `.Self` that implements `type` into type implementing `Z` [ConversionFailureFacetToFacet] // CHECK:STDERR: fn G(T:! Z & I(.Self)) { // CHECK:STDERR: ^~~~~~~~ -// CHECK:STDERR: fail_todo_self_in_interface_generic_param_constrained.carbon:[[@LINE-16]]:13: note: initializing generic parameter `T` declared here [InitializingGenericParam] +// CHECK:STDERR: fail_todo_self_in_interface_generic_param_constrained.carbon:[[@LINE-17]]:13: note: initializing generic parameter `T` declared here [InitializingGenericParam] // CHECK:STDERR: interface I(T:! Z) {} // CHECK:STDERR: ^~~~~ // CHECK:STDERR: @@ -131,7 +230,7 @@ fn G(T:! Z & I(.Self)) { F(T); } -// --- fail_todo_where_period_self_rhs_sees_lhs.carbon +// --- where_period_self_rhs_sees_lhs.carbon library "[[@TEST_NAME]]"; interface Z {} @@ -150,17 +249,10 @@ fn G() { impl C as Z {} impl C as Y {} impl C as X(C) {} - // CHECK:STDERR: fail_todo_where_period_self_rhs_sees_lhs.carbon:[[@LINE+7]]:3: error: cannot convert type `C` into type implementing `Z & N where .Self impls X(.Self as Z & Y)` [ConversionFailureTypeToFacet] - // CHECK:STDERR: F(C); - // CHECK:STDERR: ^~~~ - // CHECK:STDERR: fail_todo_where_period_self_rhs_sees_lhs.carbon:[[@LINE-10]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] - // CHECK:STDERR: fn F(_:! Z & N where .Self impls X(.Self)) {} - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: F(C); } -// --- fail_todo_where_type_rhs_sees_lhs.carbon +// --- where_type_rhs_sees_lhs.carbon library "[[@TEST_NAME]]"; interface Z {} @@ -181,12 +273,125 @@ fn G() { impl C as Z {} impl C as Y {} impl R(C) as X(C) {} - // CHECK:STDERR: fail_todo_where_type_rhs_sees_lhs.carbon:[[@LINE+7]]:3: error: cannot convert type `C` into type implementing `Z & N where R(.Self as Z & Y) impls X(.Self as Z & Y)` [ConversionFailureTypeToFacet] + F(C); +} + +// --- fail_todo_where_period_self_rhs_impls_nested_period_self.carbon +library "[[@TEST_NAME]]"; + +interface Z {} +interface Y {} +interface X(T:! Z & Y) {} + +constraint N { + require impls Y; +} + +// TODO: The inner nested facet type (`N where...`) does not know about +// constraints on the outer facet type (`Z where...`). But it should produce an +// implied constraint that `.Self impls Z & Y` that is checked once the full +// facet type is known. +// +// CHECK:STDERR: fail_todo_where_period_self_rhs_impls_nested_period_self.carbon:[[@LINE+7]]:51: error: cannot convert type `.Self` that implements `N` into type implementing `Z & Y` [ConversionFailureFacetToFacet] +// CHECK:STDERR: fn F(_:! Z where .Self impls (N where .Self impls X(.Self))) {} +// CHECK:STDERR: ^~~~~~~~ +// CHECK:STDERR: fail_todo_where_period_self_rhs_impls_nested_period_self.carbon:[[@LINE-14]]:13: note: initializing generic parameter `T` declared here [InitializingGenericParam] +// CHECK:STDERR: interface X(T:! Z & Y) {} +// CHECK:STDERR: ^~~~~~~~~ +// CHECK:STDERR: +fn F(_:! Z where .Self impls (N where .Self impls X(.Self))) {} + +fn G() { + class C; + impl C as Z {} + impl C as Y {} + impl C as X(C) {} + F(C); +} + +// --- associated_const_impls_interface_with_period_self.carbon +library "[[@TEST_NAME]]"; + +interface I { + let I1:! type; +} + +interface J(T:! I) {} + +// There is a .Self reference on the LHS and RHS of the `impls` constraint, +// which must be replaced, each with `C as I` +fn F(_:! I where .I1 impls J(.Self)) {} + +fn G() { + class C; + class D; + + impl C as I where .I1 = D {} + impl D as J(C) {} + + F(C); +} + +// --- fail_concrete_witness_without_impl.carbon +library "[[@TEST_NAME]]"; + +interface I { + let I1:! type; +} +interface J {} + +fn F(_:! I where .I1 impls J) {} + +fn G() { + class C; + + // This identifies `C as (I where .I1 impls J)`, which replaces `.Self.I1` + // with `C.(I.I1)`. This is a concrete lookup since C and I are both concrete, + // but it doesn't find anything as there is no impl. + // + // This tests that we correctly handle the case where the witness in an + // ImplWitnessAccess would become concrete without being able to provide any + // value, since it's still a `LookupImplWitness` type of witness. + + // CHECK:STDERR: fail_concrete_witness_without_impl.carbon:[[@LINE+7]]:3: error: cannot convert type `C` into type implementing `I where .(I.I1) impls J` [ConversionFailureTypeToFacet] // CHECK:STDERR: F(C); // CHECK:STDERR: ^~~~ - // CHECK:STDERR: fail_todo_where_type_rhs_sees_lhs.carbon:[[@LINE-10]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] - // CHECK:STDERR: fn F(_:! Z & N where R(.Self) impls X(.Self)) {} - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_concrete_witness_without_impl.carbon:[[@LINE-16]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] + // CHECK:STDERR: fn F(_:! I where .I1 impls J) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: F(C); } + +// --- fail_todo_convert_to_period_self_preserves_self_facet_impls.carbon +library "[[@TEST_NAME]]"; + +interface K {} +interface J {} +interface I { + let I1:! type; +} + +fn F(unused U:! I & J where .I1 impls K) {} + +impl forall [T:! type] T as J {} + +fn G(T:! I where .I1 impls K) { + // Replaces `.Self` with `T`, which converts `T` to `I & J`. Doing so has to + // invent a witness for `J`, and this tests we do so without losing the + // information that `.I1 impls K`. + // + // TODO: When converting T to the type of U, the identified facet type + // includes `.Self.I1 impls K`, which is replaced with `T.I1 impls K`. The + // identified facet type of `T` also contains `T.I1 impls K` so we should find + // a witness for that. + // + // CHECK:STDERR: fail_todo_convert_to_period_self_preserves_self_facet_impls.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `I where .(I.I1) impls K` into type implementing `J & I where .(I.I1) impls K` [ConversionFailureFacetToFacet] + // CHECK:STDERR: F(T); + // CHECK:STDERR: ^~~~ + // CHECK:STDERR: fail_todo_convert_to_period_self_preserves_self_facet_impls.carbon:[[@LINE-17]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] + // CHECK:STDERR: fn F(unused U:! I & J where .I1 impls K) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + F(T); +} diff --git a/toolchain/check/testdata/facet/validate_rewrite_constraints.carbon b/toolchain/check/testdata/facet/validate_rewrite_constraints.carbon index 5c52517af221..c683202193fe 100644 --- a/toolchain/check/testdata/facet/validate_rewrite_constraints.carbon +++ b/toolchain/check/testdata/facet/validate_rewrite_constraints.carbon @@ -1009,6 +1009,52 @@ fn G1() { } } +// --- rewrite_rhs_satisfies_lhs_requirement.carbon +library "[[@TEST_NAME]]"; + +interface I(T:! type) {} +interface J(T:! type) { + let J1:! I(T); +} + +class C; +constraint L { + // J(.Self).J1 requires that its RHS impls I(.Self), which is provided for + // here. + // + // We look for this witness in `L` because the assignment is to `J(.Self).J1` + // so we look in the facet type of `.Self` which is `L & J(.Self)`. + require C impls I(Self); +} + +fn F(unused T:! L & J(.Self) where .J1 = C) {} + +fn G(T:! L & J(.Self) where .J1 = C) { + F(T); +} + +// --- todo_fail_rewrite_rhs_does_not_satisfy_lhs_requirement.carbon +library "[[@TEST_NAME]]"; + +interface I(T:! type) {} +interface J(T:! type) { + let J1:! I(T); +} + +class C; +constraint L { + // Without this, C does not impl I(T), which is required by J(T).J1. + // require C impls I(Self); +} + +// TODO: This should be an error that C does not impl I(.Self). We don't yet try +// convert the RHS of a rewrite to the type of the LHS when the LHS is symbolic. +fn F(unused T:! L & J(.Self) where .J1 = C) {} + +fn G(T:! L & J(.Self) where .J1 = C) { + F(T); +} + // --- rewrite_requires_subst_in_nested_access_of_self.carbon library "[[@TEST_NAME]]"; @@ -1085,7 +1131,7 @@ fn G3(T:! I & J & K where .K1 = .Self and .J1 = .Self and .I2 = {}) { F(T); } -// --- fail_todo_rewrite_requires_subst_in_nested_access_of_other.carbon +// --- rewrite_requires_subst_in_nested_access_of_other.carbon library "[[@TEST_NAME]]"; interface I { @@ -1107,13 +1153,6 @@ interface K { fn F(unused U:! I, unused T:! J & K where .J2 = (.K1.J1).I1) {} fn G(U:! I where .I1 = (), T:! J & K where .K1 = .Self and .J1 = U and .J2 = ()) { - // CHECK:STDERR: fail_todo_rewrite_requires_subst_in_nested_access_of_other.carbon:[[@LINE+7]]:3: error: cannot convert type `T` that implements `J & K where .(J.J2) = () and .(K.K1) = .Self as J and .(J.J1) = U as I` into type implementing `J & K where .(J.J2) = .(K.K1).(J.J1).(I.I1)` [ConversionFailureFacetToFacet] - // CHECK:STDERR: F(U, T); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: fail_todo_rewrite_requires_subst_in_nested_access_of_other.carbon:[[@LINE-6]]:27: note: initializing generic parameter `T` declared here [InitializingGenericParam] - // CHECK:STDERR: fn F(unused U:! I, unused T:! J & K where .J2 = (.K1.J1).I1) {} - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: F(U, T); } @@ -1309,3 +1348,68 @@ fn F(T:! I where .X = (I where .Y = {}), unused U:! T.X) {} fn G(T:! I where .X = (I where .Y = {}), U:! I where .Y = {}) { F(T, U); } + +// --- period_self_in_rewrite_values.carbon +library "[[@TEST_NAME]]"; + +interface I { + let I1:! type; + let I2:! type; + let I3:! type; + let I4:! type; +} + +class E(T:! type) {} + +// * The LHS of `.I1` contains a `.Self` which is replaced by `C` to form +// `C.(I.I1)` and resolves to `()`. +// * The RHS of `.I1` is `()` which then compares equal. +fn F1(_:! I where .I1 = ()) {} + +// * The LHS of `.I2` contains a `.Self` which is replaced by `C` to form +// `C.(I.I1)` and resolves to `C`. +// * The RHS of `.I2` is `.Self` which is replaced by `C` and then compares +// equal. +fn F2(_:! I where .I2 = .Self) {} + +// * The LHS of `.I3` contains a `.Self` which is replaced by `C` to form +// `C.(I.I1)` and resolves to `E(C)`. +// * The RHS of `.I3` contains a `.Self` which is replaced by `C` to form +// `E(C)`, and then compares equal. +fn F3(_:! I where .I3 = E(.Self)) {} + +// * The LHS of `.I4` contains a `.Self` which is replaced by `C` to form +// `C.(I.I4)` and resolves to `.Self`. That `.Self` then is replaced by `C` so +// the LHS untimately resolves to `C`. +// * The RHS of `.I4` is `.Self` which is replaced by `C` and then compares +// equal. +fn F4(_:! I where .I4 = .Self) {} + +fn G() { + class C; + impl C as I where .I1 = () and .I2 = C and .I3 = E(C) and .I4 = .Self {} + + F1(C); + F2(C); + F3(C); + F4(C); +} + +// --- convert_to_period_self_preserves_self_facet_rewrite.carbon +library "[[@TEST_NAME]]"; + +interface J {} +interface I { + let I1:! type; +} + +fn F(unused U:! I & J where .I1 = {}) {} + +impl forall [T:! type] T as J {} + +fn G(T:! I where .I1 = {}) { + // Replaces `.Self` with `T`, which converts `T` to `I & J`. Doing so has to + // invent a witness for `J`, and this tests we do so without losing the + // information that `.I1 = {}`. + F(T); +} diff --git a/toolchain/check/testdata/impl/lookup/lookup_interface_with_enclosing_generic_inside_rewrite_constraint.carbon b/toolchain/check/testdata/impl/lookup/lookup_interface_with_enclosing_generic_inside_rewrite_constraint.carbon index e4dcbeb0c0a8..2a81cce364a3 100644 --- a/toolchain/check/testdata/impl/lookup/lookup_interface_with_enclosing_generic_inside_rewrite_constraint.carbon +++ b/toolchain/check/testdata/impl/lookup/lookup_interface_with_enclosing_generic_inside_rewrite_constraint.carbon @@ -449,7 +449,7 @@ fn F() { // CHECK:STDOUT: %C.521: type = class_type @C, @C(%OuterParam) [symbolic] // CHECK:STDOUT: %Y.impl_witness.26b: = impl_witness @C.as.Y.impl.%Y.impl_witness_table, @C.as.Y.impl(%OuterParam) [symbolic] // CHECK:STDOUT: %require_complete.4a2: = require_complete_type %Y_where.type.b0f [symbolic] -// CHECK:STDOUT: %Y.facet: %Y.type.6ae = facet_value %C.521, (%Y.impl_witness.26b) [symbolic] +// CHECK:STDOUT: %Y.facet.892: %Y.type.6ae = facet_value %C.521, (%Y.impl_witness.26b) [symbolic] // CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] // CHECK:STDOUT: %complete_type.357: = complete_type_witness %empty_struct_type [concrete] // CHECK:STDOUT: %Z1.impl_witness: = impl_witness @empty_tuple.type.as.Z1.impl.%Z1.impl_witness_table [concrete] @@ -829,7 +829,7 @@ fn F() { // CHECK:STDOUT: %Y.impl_witness.loc14_29.2 => constants.%Y.impl_witness.26b // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @Y.WithSelf(constants.%OuterParam, constants.%Y.facet) { +// CHECK:STDOUT: specific @Y.WithSelf(constants.%OuterParam, constants.%Y.facet.892) { // CHECK:STDOUT: !definition: // CHECK:STDOUT: %OuterParam => constants.%OuterParam // CHECK:STDOUT: %Y.assoc_type => constants.%Y.assoc_type.aab diff --git a/toolchain/check/testdata/named_constraint/require.carbon b/toolchain/check/testdata/named_constraint/require.carbon index 0982332e5e0b..0fea95a67d93 100644 --- a/toolchain/check/testdata/named_constraint/require.carbon +++ b/toolchain/check/testdata/named_constraint/require.carbon @@ -554,6 +554,24 @@ fn F() { () as N; } +// --- require_with_rewrite_constraint_period_self.carbon +library "[[@TEST_NAME]]"; + +interface Z(T:! type) { + let X:! type; +} + +constraint N(T:! type) { + require T impls Z(Self) where .X = .Self; +} + +// Will satisfy `() as N({})`. +impl {} as Z(()) where .X = {} {} + +fn F() { + () as N({}); +} + // --- todo_fail_require_with_mismatching_rewrite_constraint.carbon library "[[@TEST_NAME]]"; @@ -575,6 +593,112 @@ fn F() { () as N; } +// --- todo_fail_require_with_mismatching_rewrite_constraint_period_self.carbon +library "[[@TEST_NAME]]"; + +interface Z(T:! type) { + let X:! type; +} + +constraint N(T:! type) { + require T impls Z(Self) where .X = .Self; +} + +// Will not satisfy `() as N({})` as the rewrite does not match. +impl {} as Z(()) where .X = () {} + +fn F() { + // TODO: Should fail, but we're currently checking the requirements of `N` + // rather than of the identified facet type of `N` (which would include the + // require decl's requirements). + () as N({}); +} + +// --- fail_require_with_period_self_impls_not_satisfied.carbon +library "[[@TEST_NAME]]"; + +interface Z {} +interface Y(T:! type) {} + +class C(T:! type); + +constraint N { + require impls Z where .Self impls Y(.Self); +} + +fn F(_:! N) {} + +fn G(T:! Z) { + // CHECK:STDERR: fail_require_with_period_self_impls_not_satisfied.carbon:[[@LINE+4]]:3: error: cannot convert type `T` that implements `Z` into type implementing `N` [ConversionFailureFacetToFacet] + // CHECK:STDERR: T as N; + // CHECK:STDERR: ^~~~~~ + // CHECK:STDERR: + T as N; +} + +// --- require_with_period_self_impls.carbon +library "[[@TEST_NAME]]"; + +interface Z {} +interface Y(T:! type) {} + +class C(T:! type); + +//@dump-sem-ir-begin +constraint N { + require impls Z where .Self impls Y(.Self); +} +//@dump-sem-ir-end + +fn F(_:! N) {} + +fn G(T:! Z & Y(.Self)) { + T as N; +} + +// --- fail_require_with_specific_period_self_not_satisfied.carbon +library "[[@TEST_NAME]]"; + +interface Z {} +interface Y(T:! type) {} + +class C(T:! type); + +constraint N { + require impls Z where C(.Self) impls Y(.Self); +} + +fn F(_:! N) {} + +fn G(T:! Z) { + // CHECK:STDERR: fail_require_with_specific_period_self_not_satisfied.carbon:[[@LINE+4]]:3: error: cannot convert type `T` that implements `Z` into type implementing `N` [ConversionFailureFacetToFacet] + // CHECK:STDERR: T as N; + // CHECK:STDERR: ^~~~~~ + // CHECK:STDERR: + T as N; +} + +// --- require_with_specific_period_self.carbon +library "[[@TEST_NAME]]"; + +interface Z {} +interface Y(T:! type) {} + +class C(T:! type); + +//@dump-sem-ir-begin +constraint N { + require impls Z where C(.Self) impls Y(.Self); +} +//@dump-sem-ir-end + +fn F(_:! N) {} + +fn G(T:! Z) { + impl C(T) as Y(T) {} + T as N; +} + // CHECK:STDOUT: --- extend.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -1245,3 +1369,195 @@ fn F() { // CHECK:STDOUT: %Y_where.type => constants.%Y_where.type // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: --- require_with_period_self_impls.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %Z.type: type = facet_type <@Z> [concrete] +// CHECK:STDOUT: %type: type = facet_type [concrete] +// CHECK:STDOUT: %.Self.c39: %type = symbolic_binding .Self [symbolic_self] +// CHECK:STDOUT: %Y.type.82b: type = generic_interface_type @Y [concrete] +// CHECK:STDOUT: %Y.generic: %Y.type.82b = struct_value () [concrete] +// CHECK:STDOUT: %N.type: type = facet_type <@N> [concrete] +// CHECK:STDOUT: %Self.550: %N.type = symbolic_binding Self, 0 [symbolic] +// CHECK:STDOUT: %Self.binding.as_type.5cb: type = symbolic_binding_type Self, 0, %Self.550 [symbolic] +// CHECK:STDOUT: %.Self.aac: %Z.type = symbolic_binding .Self [symbolic_self] +// CHECK:STDOUT: %.Self.binding.as_type.5a0: type = symbolic_binding_type .Self, %.Self.aac [symbolic_self] +// CHECK:STDOUT: %Y.type.dfc: type = facet_type <@Y, @Y(%.Self.binding.as_type.5a0)> [symbolic_self] +// CHECK:STDOUT: %Z_where.type.455: type = facet_type <@Z where .Self impls @Y, @Y(%.Self.binding.as_type.5a0)> [symbolic_self] +// CHECK:STDOUT: %Z_where.type.820: type = facet_type <@Z where .Self impls @Y, @Y(%Self.binding.as_type.5cb)> [symbolic] +// CHECK:STDOUT: %.Self.binding.as_type.8db: type = symbolic_binding_type .Self, %.Self.c39 [symbolic_self] +// CHECK:STDOUT: %facet_type: type = facet_type <@Z & @Y, @Y(%.Self.binding.as_type.8db)> [symbolic_self] +// CHECK:STDOUT: %T.e40: %facet_type = symbolic_binding T, 0 [symbolic] +// CHECK:STDOUT: %T.binding.as_type: type = symbolic_binding_type T, 0, %T.e40 [symbolic] +// CHECK:STDOUT: %Z_where.type.c36: type = facet_type <@Z where .Self impls @Y, @Y(%T.binding.as_type)> [symbolic] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: %N.decl: type = constraint_decl @N [concrete = constants.%N.type] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: constraint @N { +// CHECK:STDOUT: %Self: %N.type = symbolic_binding Self, 0 [symbolic = constants.%Self.550] +// CHECK:STDOUT: %N.WithSelf.decl = constraint_with_self_decl @N [concrete] +// CHECK:STDOUT: +// CHECK:STDOUT: !with Self: +// CHECK:STDOUT: %N.WithSelf.Self.binding.as_type.impls.Z_where.type.require.decl = require_decl @N.WithSelf.Self.binding.as_type.impls.Z_where.type.require [concrete] { +// CHECK:STDOUT: require %Self.as_type impls %Z_where.type.loc10_19.1 +// CHECK:STDOUT: } { +// CHECK:STDOUT: %Self.as_type: type = facet_access_type @N.%Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type.5cb)] +// CHECK:STDOUT: %Z.ref: type = name_ref Z, file.%Z.decl [concrete = constants.%Z.type] +// CHECK:STDOUT: +// CHECK:STDOUT: %.Self.ref.loc10_25: %Z.type = name_ref .Self, %.Self [symbolic_self = constants.%.Self.aac] +// CHECK:STDOUT: %Y.ref: %Y.type.82b = name_ref Y, file.%Y.decl [concrete = constants.%Y.generic] +// CHECK:STDOUT: %.Self.ref.loc10_39: %Z.type = name_ref .Self, %.Self [symbolic_self = constants.%.Self.aac] +// CHECK:STDOUT: %.Self.as_type.loc10_44: type = facet_access_type %.Self.ref.loc10_39 [symbolic_self = constants.%.Self.binding.as_type.5a0] +// CHECK:STDOUT: %.loc10_44: type = converted %.Self.ref.loc10_39, %.Self.as_type.loc10_44 [symbolic_self = constants.%.Self.binding.as_type.5a0] +// CHECK:STDOUT: %Y.type: type = facet_type <@Y, @Y(constants.%.Self.binding.as_type.5a0)> [symbolic_self = constants.%Y.type.dfc] +// CHECK:STDOUT: %.Self.as_type.loc10_25: type = facet_access_type %.Self.ref.loc10_25 [symbolic_self = constants.%.Self.binding.as_type.5a0] +// CHECK:STDOUT: %.loc10_25: type = converted %.Self.ref.loc10_25, %.Self.as_type.loc10_25 [symbolic_self = constants.%.Self.binding.as_type.5a0] +// CHECK:STDOUT: %.loc10_19: type = where_expr %.Self [symbolic_self = constants.%Z_where.type.455] { +// CHECK:STDOUT: requirement_base_facet_type constants.%Z.type +// CHECK:STDOUT: requirement_impls %.loc10_25, %Y.type +// CHECK:STDOUT: } +// CHECK:STDOUT: %Z_where.type.loc10_19.1: type = facet_type <@Z where .Self impls @Y, @Y(constants.%Self.binding.as_type.5cb)> [symbolic = %Z_where.type.loc10_19.2 (constants.%Z_where.type.820)] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Z = +// CHECK:STDOUT: .Y = +// CHECK:STDOUT: .Z = +// CHECK:STDOUT: .Y = +// CHECK:STDOUT: +// CHECK:STDOUT: !requires: +// CHECK:STDOUT: @N.WithSelf.Self.binding.as_type.impls.Z_where.type.require { +// CHECK:STDOUT: require @N.WithSelf.Self.binding.as_type.impls.Z_where.type.require.%Self.as_type impls @N.WithSelf.Self.binding.as_type.impls.Z_where.type.require.%Z_where.type.loc10_19.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic require @N.WithSelf.Self.binding.as_type.impls.Z_where.type.require(@N.%Self: %N.type) { +// CHECK:STDOUT: %Self: %N.type = symbolic_binding Self, 0 [symbolic = %Self (constants.%Self.550)] +// CHECK:STDOUT: %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type.5cb)] +// CHECK:STDOUT: %Z_where.type.loc10_19.2: type = facet_type <@Z where .Self impls @Y, @Y(%Self.binding.as_type)> [symbolic = %Z_where.type.loc10_19.2 (constants.%Z_where.type.820)] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @N.WithSelf(constants.%Self.550) { +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @N.WithSelf.Self.binding.as_type.impls.Z_where.type.require(constants.%Self.550) { +// CHECK:STDOUT: %Self => constants.%Self.550 +// CHECK:STDOUT: %Self.binding.as_type => constants.%Self.binding.as_type.5cb +// CHECK:STDOUT: %Z_where.type.loc10_19.2 => constants.%Z_where.type.820 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @N.WithSelf(constants.%T.e40) { +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @N.WithSelf.Self.binding.as_type.impls.Z_where.type.require(constants.%T.e40) { +// CHECK:STDOUT: %Self => constants.%T.e40 +// CHECK:STDOUT: %Self.binding.as_type => constants.%T.binding.as_type +// CHECK:STDOUT: %Z_where.type.loc10_19.2 => constants.%Z_where.type.c36 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- require_with_specific_period_self.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %Z.type: type = facet_type <@Z> [concrete] +// CHECK:STDOUT: %Y.type.82b: type = generic_interface_type @Y [concrete] +// CHECK:STDOUT: %Y.generic: %Y.type.82b = struct_value () [concrete] +// CHECK:STDOUT: %C.type: type = generic_class_type @C [concrete] +// CHECK:STDOUT: %C.generic: %C.type = struct_value () [concrete] +// CHECK:STDOUT: %N.type: type = facet_type <@N> [concrete] +// CHECK:STDOUT: %Self.550: %N.type = symbolic_binding Self, 0 [symbolic] +// CHECK:STDOUT: %Self.binding.as_type: type = symbolic_binding_type Self, 0, %Self.550 [symbolic] +// CHECK:STDOUT: %.Self.aac: %Z.type = symbolic_binding .Self [symbolic_self] +// CHECK:STDOUT: %.Self.binding.as_type: type = symbolic_binding_type .Self, %.Self.aac [symbolic_self] +// CHECK:STDOUT: %C.646: type = class_type @C, @C(%.Self.binding.as_type) [symbolic_self] +// CHECK:STDOUT: %Y.type.dfc: type = facet_type <@Y, @Y(%.Self.binding.as_type)> [symbolic_self] +// CHECK:STDOUT: %Z_where.type.a6d533.1: type = facet_type <@Z where %C.646 impls @Y, @Y(%.Self.binding.as_type)> [symbolic_self] +// CHECK:STDOUT: %C.237: type = class_type @C, @C(%Self.binding.as_type) [symbolic] +// CHECK:STDOUT: %Z_where.type.a6d533.2: type = facet_type <@Z where %C.237 impls @Y, @Y(%Self.binding.as_type)> [symbolic] +// CHECK:STDOUT: %T.ea3: %Z.type = symbolic_binding T, 0 [symbolic] +// CHECK:STDOUT: %T.binding.as_type: type = symbolic_binding_type T, 0, %T.ea3 [symbolic] +// CHECK:STDOUT: %C.3e1: type = class_type @C, @C(%T.binding.as_type) [symbolic] +// CHECK:STDOUT: %Z_where.type.a6d533.3: type = facet_type <@Z where %C.3e1 impls @Y, @Y(%T.binding.as_type)> [symbolic] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: %N.decl: type = constraint_decl @N [concrete = constants.%N.type] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: constraint @N { +// CHECK:STDOUT: %Self: %N.type = symbolic_binding Self, 0 [symbolic = constants.%Self.550] +// CHECK:STDOUT: %N.WithSelf.decl = constraint_with_self_decl @N [concrete] +// CHECK:STDOUT: +// CHECK:STDOUT: !with Self: +// CHECK:STDOUT: %N.WithSelf.Self.binding.as_type.impls.Z_where.type.require.decl = require_decl @N.WithSelf.Self.binding.as_type.impls.Z_where.type.require [concrete] { +// CHECK:STDOUT: require %Self.as_type impls %Z_where.type.loc10_19.1 +// CHECK:STDOUT: } { +// CHECK:STDOUT: %Self.as_type: type = facet_access_type @N.%Self [symbolic = %Self.binding.as_type (constants.%Self.binding.as_type)] +// CHECK:STDOUT: %Z.ref: type = name_ref Z, file.%Z.decl [concrete = constants.%Z.type] +// CHECK:STDOUT: +// CHECK:STDOUT: %C.ref: %C.type = name_ref C, file.%C.decl [concrete = constants.%C.generic] +// CHECK:STDOUT: %.Self.ref.loc10_27: %Z.type = name_ref .Self, %.Self [symbolic_self = constants.%.Self.aac] +// CHECK:STDOUT: %.Self.as_type.loc10_32: type = facet_access_type %.Self.ref.loc10_27 [symbolic_self = constants.%.Self.binding.as_type] +// CHECK:STDOUT: %.loc10_32: type = converted %.Self.ref.loc10_27, %.Self.as_type.loc10_32 [symbolic_self = constants.%.Self.binding.as_type] +// CHECK:STDOUT: %C.loc10_32: type = class_type @C, @C(constants.%.Self.binding.as_type) [symbolic_self = constants.%C.646] +// CHECK:STDOUT: %Y.ref: %Y.type.82b = name_ref Y, file.%Y.decl [concrete = constants.%Y.generic] +// CHECK:STDOUT: %.Self.ref.loc10_42: %Z.type = name_ref .Self, %.Self [symbolic_self = constants.%.Self.aac] +// CHECK:STDOUT: %.Self.as_type.loc10_47: type = facet_access_type %.Self.ref.loc10_42 [symbolic_self = constants.%.Self.binding.as_type] +// CHECK:STDOUT: %.loc10_47: type = converted %.Self.ref.loc10_42, %.Self.as_type.loc10_47 [symbolic_self = constants.%.Self.binding.as_type] +// CHECK:STDOUT: %Y.type: type = facet_type <@Y, @Y(constants.%.Self.binding.as_type)> [symbolic_self = constants.%Y.type.dfc] +// CHECK:STDOUT: %.loc10_19: type = where_expr %.Self [symbolic_self = constants.%Z_where.type.a6d533.1] { +// CHECK:STDOUT: requirement_base_facet_type constants.%Z.type +// CHECK:STDOUT: requirement_impls %C.loc10_32, %Y.type +// CHECK:STDOUT: } +// CHECK:STDOUT: %Z_where.type.loc10_19.1: type = facet_type <@Z where constants.%C.237 impls @Y, @Y(constants.%Self.binding.as_type)> [symbolic = %Z_where.type.loc10_19.2 (constants.%Z_where.type.a6d533.2)] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Z = +// CHECK:STDOUT: .C = +// CHECK:STDOUT: .Y = +// CHECK:STDOUT: .Z = +// CHECK:STDOUT: .C = +// CHECK:STDOUT: .Y = +// CHECK:STDOUT: +// CHECK:STDOUT: !requires: +// CHECK:STDOUT: @N.WithSelf.Self.binding.as_type.impls.Z_where.type.require { +// CHECK:STDOUT: require @N.WithSelf.Self.binding.as_type.impls.Z_where.type.require.%Self.as_type impls @N.WithSelf.Self.binding.as_type.impls.Z_where.type.require.%Z_where.type.loc10_19.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic require @N.WithSelf.Self.binding.as_type.impls.Z_where.type.require(@N.%Self: %N.type) { +// CHECK:STDOUT: %Self: %N.type = symbolic_binding Self, 0 [symbolic = %Self (constants.%Self.550)] +// 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: %C.loc10_19: type = class_type @C, @C(%Self.binding.as_type) [symbolic = %C.loc10_19 (constants.%C.237)] +// CHECK:STDOUT: %Z_where.type.loc10_19.2: type = facet_type <@Z where %C.loc10_19 impls @Y, @Y(%Self.binding.as_type)> [symbolic = %Z_where.type.loc10_19.2 (constants.%Z_where.type.a6d533.2)] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @N.WithSelf(constants.%Self.550) { +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @N.WithSelf.Self.binding.as_type.impls.Z_where.type.require(constants.%Self.550) { +// CHECK:STDOUT: %Self => constants.%Self.550 +// CHECK:STDOUT: %Self.binding.as_type => constants.%Self.binding.as_type +// CHECK:STDOUT: %C.loc10_19 => constants.%C.237 +// CHECK:STDOUT: %Z_where.type.loc10_19.2 => constants.%Z_where.type.a6d533.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @N.WithSelf(constants.%T.ea3) { +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @N.WithSelf.Self.binding.as_type.impls.Z_where.type.require(constants.%T.ea3) { +// CHECK:STDOUT: %Self => constants.%T.ea3 +// CHECK:STDOUT: %Self.binding.as_type => constants.%T.binding.as_type +// CHECK:STDOUT: %C.loc10_19 => constants.%C.3e1 +// CHECK:STDOUT: %Z_where.type.loc10_19.2 => constants.%Z_where.type.a6d533.3 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/type_completion.cpp b/toolchain/check/type_completion.cpp index 11e1c60850d4..0df82bcf7c6c 100644 --- a/toolchain/check/type_completion.cpp +++ b/toolchain/check/type_completion.cpp @@ -962,7 +962,7 @@ static auto GetSelfFacetValue(Context& context, SemIR::ConstantId self_const_id) } static auto IdentifyFacetType(Context& context, SemIR::LocId loc_id, - SemIR::ConstantId self_const_id, + SemIR::ConstantId initial_self_const_id, const SemIR::FacetType& facet_type, bool allow_partially_identified, bool diagnose) -> SemIR::IdentifiedFacetTypeId { @@ -975,7 +975,7 @@ static auto IdentifyFacetType(Context& context, SemIR::LocId loc_id, // constant values into specifics). auto key = SemIR::IdentifiedFacetTypeKey{.facet_type_id = facet_type.facet_type_id, - .self_const_id = self_const_id}; + .self_const_id = initial_self_const_id}; if (auto identified_id = context.identified_facet_types().Lookup(key); identified_id.has_value()) { return identified_id; @@ -989,13 +989,16 @@ static auto IdentifyFacetType(Context& context, SemIR::LocId loc_id, // Work queue. llvm::SmallVector work = { - {true, self_const_id, facet_type.facet_type_id}}; + {true, initial_self_const_id, facet_type.facet_type_id}}; // Outputs for the IdentifiedFacetType. bool partially_identified = false; llvm::SmallVector extends; llvm::SmallVector impls; + // `.Self` is always replaced with the top-level self type. + SubstPeriodSelfCallbacks callbacks(&context, loc_id, initial_self_const_id); + while (!work.empty()) { SelfImplsFacetType next_impls = work.pop_back_val(); bool facet_type_extends = next_impls.extend; @@ -1005,13 +1008,19 @@ static auto IdentifyFacetType(Context& context, SemIR::LocId loc_id, auto self_and_interface = [&](SemIR::SpecificInterface interface) -> SemIR::IdentifiedFacetType::RequiredImpl { - return {self_const_id, interface}; + // Note that we subst `.Self` in the interface, but we do not in the + // self type here, as that would be cyclical, replacing part of the self + // type with itself. + return {self_const_id, SubstPeriodSelf(context, callbacks, interface)}; }; auto type_and_interface = - [&](const SemIR::FacetTypeInfo::TypeImplsInterface& impls) + [&](SemIR::FacetTypeInfo::TypeImplsInterface impls) -> SemIR::IdentifiedFacetType::RequiredImpl { - return {context.constant_values().Get(impls.self_type), - impls.specific_interface}; + auto self = SubstPeriodSelf( + context, callbacks, context.constant_values().Get(impls.self_type)); + auto interface = + SubstPeriodSelf(context, callbacks, impls.specific_interface); + return {self, interface}; }; if (facet_type_extends) { diff --git a/toolchain/diagnostics/kind.def b/toolchain/diagnostics/kind.def index a2c3f7afd750..0a0d879e08c4 100644 --- a/toolchain/diagnostics/kind.def +++ b/toolchain/diagnostics/kind.def @@ -189,6 +189,7 @@ CARBON_DIAGNOSTIC_KIND(ExpectedAliasInitializer) // Where requirement diagnostics. CARBON_DIAGNOSTIC_KIND(ExpectedRequirementOperator) CARBON_DIAGNOSTIC_KIND(RequirementEqualAfterNonDesignator) +CARBON_DIAGNOSTIC_KIND(AmbiguousPeriodSelf) // ============================================================================ // Semantics diagnostics