Files
carbon-lang/toolchain/check/impl_lookup.h
T
Dana Jansens b6a55c0818 Diagnose impls that are fully overlapped by a final impl (#5417)
Such impls will never be used, so they should not exist. And test that a
final impl partially overlapping a non-final impl is accepted.

There is a question about a final impl partially overlapping a final
impl that is part of
https://github.com/carbon-language/carbon-lang/pull/5337
2025-05-10 17:36:28 +00:00

114 lines
4.9 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)
-> 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;
// The result of EvalLookupSingleImplWitness(). It can be one of:
// - No value. Lookup failed to find an impl declaration.
// - A concrete value. Lookup found a concrete impl declaration that can be
// used definitively.
// - A symbolic value. Lookup found an impl but it is not returned since lookup
// will need to be done again with a more specific query to look for
// specializations.
class [[nodiscard]] EvalImplLookupResult {
public:
static auto MakeNone() -> EvalImplLookupResult {
return EvalImplLookupResult(SemIR::InstId::None);
}
static auto MakeFinal(SemIR::InstId inst_id) -> EvalImplLookupResult {
return EvalImplLookupResult(inst_id);
}
static auto MakeNonFinal() -> EvalImplLookupResult {
return EvalImplLookupResult(FoundNonFinalImpl());
}
// True if a concrete impl witness was found or a non-final impl. In the
// latter case the InstId of the impl's witness is not returned, only the fact
// that it exists.
auto has_value() const -> bool {
return std::holds_alternative<FoundNonFinalImpl>(result_) ||
std::get<SemIR::InstId>(result_).has_value();
}
// True if there is a concrete witness in the result. If false, and
// `has_value()` is true, it means a non-final impl was found and a further
// more specific query will need to be done.
auto has_concrete_value() const -> bool {
const auto* inst_id = std::get_if<SemIR::InstId>(&result_);
return inst_id && inst_id->has_value();
}
// Only valid if `has_concrete_value()` is true. Returns the witness id for
// the found impl declaration, or None if `has_value()` is false.
auto concrete_witness() const -> SemIR::InstId {
return std::get<SemIR::InstId>(result_);
}
private:
struct FoundNonFinalImpl {};
explicit EvalImplLookupResult(SemIR::InstId inst_id) : result_(inst_id) {}
explicit EvalImplLookupResult(FoundNonFinalImpl f) : result_(f) {}
std::variant<SemIR::InstId, FoundNonFinalImpl> result_;
};
// Looks for a witness instruction of an impl declaration for a query consisting
// of a type value or facet value, and a single interface. This is for eval to
// execute lookup via the LookupImplWitness instruction. It does not consider
// the self facet value for finding a witness, since LookupImplWitness() would
// have found that and not caused us to defer lookup to here.
auto EvalLookupSingleImplWitness(Context& context, SemIR::LocId loc_id,
SemIR::LookupImplWitness eval_query,
SemIR::InstId non_canonical_query_self_inst_id,
bool poison_concrete_results)
-> EvalImplLookupResult;
} // namespace Carbon::Check
#endif // CARBON_TOOLCHAIN_CHECK_IMPL_LOOKUP_H_