Files
carbon-lang/toolchain/check/impl_lookup.h
T
Dana Jansens f51c075f8b Avoid symbolic witnesses for .Self in an impl decl (#7564)
Point symbolic witnesses into `.Self` written inside an impl decl at the
impl that is being declared. This is tricky because the impl does not
yet exist. So we use a new instruction `ImplSelfWitness` which _will_ be
replaced by the `ImplWitness` once it becomes available. The
`ImplSelfWitness` acts like a symbolic witness, except it does not
perform lookup, since we know which impl we will get a witness from.

This prevents us from finding other impls when performing lookups into
`.Self` in an impl decl, which produces incorrect/incoherent results.
2026-07-29 16:25:23 +00:00

101 lines
4.8 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/identified_facet_type.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;
// Construct witnesses for a `facet_value` from the facet type of a `.Self`.
//
// This does not actually perform lookup, but constructs witnesses anyways, so
// can't be used in most cases. This is specifically for the case where we are
// replacing `.Self` with another facet. Since it is replacing `.Self` we know
// that it implements the facet type of the `.Self`. So we can construct
// witnesses for the interfaces in that facet type.
auto MakeWitnessesForPeriodSelfTypeWithoutLookup(Context& context,
SemIR::LocId loc_id,
SemIR::ConstantId facet_value,
SemIR::ConstantId period_self)
-> 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_id) -> 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_