mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 19:01:07 +01:00
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.
101 lines
4.8 KiB
C++
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_
|