Files
carbon-lang/toolchain/check/impl_lookup.h
T
Dana Jansens d9841992cb Replace .Self in facet types (#7097)
This allows `T impls X` constraints to function, since they must contain
some reference to `.Self` in order to be valid. This should be
sufficient to support the interfaces we need for for loops over C++
range-for-compatible types.

We replace `.Self` in the following places:
- In a require decl, as we have a specific self facet to replace it with
from the declaration, either a user-specified facet or the symbolic
`Self`.
- When identifying a facet type, as we have a specific self that we are
identifying the facet type with. That self gets used for all `.Self`
references.
- Implicit `.Self` references on the RHS of an `impls` constraint when
building a facet type. The `.Self` references there no longer refer to
the top level self facet, so replace them with the facet that we now
know they refer to, which is found on the LHS of the `where` before the
`impls`.
- Rewrite constraints in impl lookup when validating them and comparing
them with constants from witnesses, which come from identifying a facet
type.
- Rewrite constraints in ImplWitnessAccess eval when comparing them with
constants from witnesses, which come from identifying a facet type.

Substitution is done through `SubstPeriodSelf`. It handles replacing
`.Self` and `.Self as type`, for a replacement facet that is either of
type FacetType or TypeType.

Eval currently diagnoses some ambiguous `.Self` references when doing
substitution of `.Self` but this is the incorrect place to do it, so
there are TODOs about moving this to name lookup. To support these
diagnostics there's some additional complexity in `SubstPeriodSelf` that
can go away once the TODOs are addressed, such as asking the caller if
they want to replace each `.Self`, in order for it to report a
diagnostic.

There are a number of follow-up work items here:
- Some TODO tests.
- Remove `SymbolicBindingType` since its intention was to support
`.Self` but we don't need it with this approach.
- Replace `.Self` in rewrite constraints of require decls.
- Replace `.Self` in rewrite constraints of impl as when constructing
the witness table.
- Reject explicit `.Self` in name lookup when it would be ambiguous.
- Officially disallow `.Self.A = B` in rewrite constraints in the design
docs, so that we don't have the case where `.A` is allowed but `.Self.A`
is not due to ambiguity.
2026-04-24 19:08:11 +00:00

87 lines
4.0 KiB
C++

// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef CARBON_TOOLCHAIN_CHECK_IMPL_LOOKUP_H_
#define CARBON_TOOLCHAIN_CHECK_IMPL_LOOKUP_H_
#include <variant>
#include "toolchain/check/context.h"
#include "toolchain/sem_ir/ids.h"
#include "toolchain/sem_ir/inst.h"
#include "toolchain/sem_ir/typed_insts.h"
namespace Carbon::Check {
// Looks up the witnesses to use for a type value or facet value, and a facet
// type naming a set of interfaces required to be implemented for that type, as
// well as possible constraints on those interfaces.
//
// N.B. In the future, `TypeType` will become a facet type, at which point type
// values will also be facet values.
//
// The return value is one of:
// - An InstBlockId value, containing an `ImplWitness` instruction for each
// required interface in the `query_facet_type_const_id`. This verifies the
// facet type is satisfied for the type in `type_const_id`, and provides a
// witness for accessing the impl of each interface.
//
// - `InstBlockId::None`, indicating lookup failed for at least one required
// interface in the `query_facet_type_const_id`. The facet type is not
// satisfied for the type in `type_const_id`. This represents lookup failure,
// but is not an error, so no diagnostic is emitted.
//
// - An error value, indicating the program is invalid and a diagonstic has been
// produced, either in this function or before.
auto LookupImplWitness(Context& context, SemIR::LocId loc_id,
SemIR::ConstantId query_self_const_id,
SemIR::ConstantId query_facet_type_const_id,
bool diagnose = true) -> SemIR::InstBlockIdOrError;
// Returns whether the query matches against the given impl. This is like a
// `LookupImplWitness` operation but for a single interface, and against only
// the single impl.
auto LookupMatchesImpl(Context& context, SemIR::LocId loc_id,
SemIR::ConstantId query_self_const_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 {
// This is a regular impl lookup performed during check. If we produce a final
// witness value that uses a specializable impl, the query will be poisoned so
// that we will recheck it at the end of the compilation.
Normal,
// This is a re-check of a poisoned lookup being performed at the end of a
// file. This disables any caching of lookup results for this query and redoes
// the impl lookup.
RecheckPoisonedLookup,
};
// Looks for a final witness for an impl lookup query consisting of a self (type
// or facet) and a single interface. This is for eval to execute lookup via the
// `LookupImplWitness` instruction. Since this query is re-evaluated against
// specifics, it provides monomorphization of the impl lookup, which allows for
// finding specializations.
auto EvalLookupSingleFinalWitness(Context& context, SemIR::LocId loc_id,
SemIR::LookupImplWitness eval_query,
SemIR::InstId self_facet_value_inst_id,
EvalImplLookupMode mode) -> SemIR::ConstantId;
} // namespace Carbon::Check
#endif // CARBON_TOOLCHAIN_CHECK_IMPL_LOOKUP_H_