mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 21:10:12 +01:00
This is reducing ValueStore inference of types from `using`, and removes `using ValueType = ...` from affected id types. I'm adding a number of `using FooStore = ValueStore<FooId, Foo>` because I think it's a little repetitive otherwise; often 4 cases where I'm doing this: getter, const getter, member, and getter on `Context`. Note we also have a number of `-> decltype(auto)` that were added I think mainly to avoid repeating the type, but I'm not sure whether there'll be agreement on replacing those and so am not changing them here. I'm placing these aliases with the value type in general, because I think it's probably easier to view that way. An alternative would be to put all the types on `File`, but: - That would be inconsistent with things like `InstStore`, which are very `ValueStore`-adjacent and put with their value type. - `File` would have a _lot_ of using's, and the accessors are already noisy -- I think it would just make the file harder to skim. Note this is the heart of what I'd brought up [on Discord](https://discord.com/channels/655572317891461132/655578254970716160/1388199282250613019). This PR still leaves CanonicalValueStore and BlockValueStore as things to also add parameters to, but I thought it best to try breaking the set of changes apart by type. Both of those rely on ValueStore, so ValueStore needs to change first.
141 lines
5.4 KiB
C++
141 lines
5.4 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
|
|
|
|
#include "toolchain/sem_ir/generic.h"
|
|
|
|
#include "toolchain/sem_ir/file.h"
|
|
#include "toolchain/sem_ir/typed_insts.h"
|
|
|
|
namespace Carbon::SemIR {
|
|
|
|
class SpecificStore::KeyContext : public TranslatingKeyContext<KeyContext> {
|
|
public:
|
|
// A lookup key for a specific.
|
|
struct Key {
|
|
GenericId generic_id;
|
|
InstBlockId args_id;
|
|
|
|
friend auto operator==(const Key&, const Key&) -> bool = default;
|
|
};
|
|
|
|
explicit KeyContext(const ValueStore<SpecificId, Specific>* specifics)
|
|
: specifics_(specifics) {}
|
|
|
|
auto TranslateKey(SpecificId id) const -> Key {
|
|
const auto& specific = specifics_->Get(id);
|
|
return {.generic_id = specific.generic_id, .args_id = specific.args_id};
|
|
}
|
|
|
|
private:
|
|
const ValueStore<SpecificId, Specific>* specifics_;
|
|
};
|
|
|
|
auto SpecificStore::GetOrAdd(GenericId generic_id, InstBlockId args_id)
|
|
-> SpecificId {
|
|
CARBON_CHECK(generic_id.has_value());
|
|
return lookup_table_
|
|
.Insert(
|
|
KeyContext::Key{.generic_id = generic_id, .args_id = args_id},
|
|
[&] {
|
|
return specifics_.Add(
|
|
{.generic_id = generic_id, .args_id = args_id});
|
|
},
|
|
KeyContext(&specifics_))
|
|
.key();
|
|
}
|
|
|
|
auto SpecificStore::CollectMemUsage(MemUsage& mem_usage,
|
|
llvm::StringRef label) const -> void {
|
|
mem_usage.Collect(MemUsage::ConcatLabel(label, "specifics_"), specifics_);
|
|
mem_usage.Collect(MemUsage::ConcatLabel(label, "lookup_table_"),
|
|
lookup_table_, KeyContext(&specifics_));
|
|
}
|
|
|
|
static auto GetConstantInSpecific(const File& specific_ir,
|
|
SpecificId specific_id, const File& const_ir,
|
|
ConstantId const_id)
|
|
-> std::pair<const File*, ConstantId> {
|
|
if (!const_id.is_symbolic()) {
|
|
// The constant does not depend on a generic parameter.
|
|
return {&const_ir, const_id};
|
|
}
|
|
|
|
const auto& symbolic =
|
|
const_ir.constant_values().GetSymbolicConstant(const_id);
|
|
if (!symbolic.generic_id.has_value()) {
|
|
// The constant is an unattached symbolic constant, not associated with some
|
|
// particular generic.
|
|
return {&const_ir, const_id};
|
|
}
|
|
|
|
if (!specific_id.has_value()) {
|
|
// We have a generic constant but no specific. We treat this as a request
|
|
// for the value that should be used within the generic itself, which is the
|
|
// unattached constant.
|
|
return {&const_ir, const_ir.constant_values().Get(symbolic.inst_id)};
|
|
}
|
|
|
|
const auto& specific = specific_ir.specifics().Get(specific_id);
|
|
// TODO: Enforce this check even if the generic and specific are in different
|
|
// IRs.
|
|
CARBON_CHECK(
|
|
&specific_ir != &const_ir || specific.generic_id == symbolic.generic_id,
|
|
"Given a specific for the wrong generic");
|
|
|
|
auto value_block_id = specific.GetValueBlock(symbolic.index.region());
|
|
if (!value_block_id.has_value()) {
|
|
// For the self specific, we can see queries before the definition is
|
|
// resolved. Return the unattached constant value.
|
|
CARBON_CHECK(
|
|
specific_ir.generics().GetSelfSpecific(
|
|
specific_ir.specifics().Get(specific_id).generic_id) == specific_id,
|
|
"Queried {0} in {1} for {2} before it was resolved.", symbolic.index,
|
|
specific_id,
|
|
specific_ir.insts().Get(
|
|
specific_ir.generics().Get(specific.generic_id).decl_id));
|
|
// TODO: Make sure this is the same value that we put in the self specific
|
|
// when it's resolved. Consider not building value blocks for a self
|
|
// specific.
|
|
return {&const_ir, const_ir.constant_values().Get(symbolic.inst_id)};
|
|
}
|
|
return {&specific_ir,
|
|
specific_ir.constant_values().Get(specific_ir.inst_blocks().Get(
|
|
value_block_id)[symbolic.index.index()])};
|
|
}
|
|
|
|
auto GetConstantValueInSpecific(const File& sem_ir, SpecificId specific_id,
|
|
InstId inst_id) -> ConstantId {
|
|
return GetConstantInSpecific(sem_ir, specific_id, sem_ir,
|
|
sem_ir.constant_values().GetAttached(inst_id))
|
|
.second;
|
|
}
|
|
|
|
auto GetConstantValueInSpecific(const File& specific_ir, SpecificId specific_id,
|
|
const File& inst_ir, InstId inst_id)
|
|
-> std::pair<const File*, ConstantId> {
|
|
return GetConstantInSpecific(specific_ir, specific_id, inst_ir,
|
|
inst_ir.constant_values().GetAttached(inst_id));
|
|
}
|
|
|
|
auto GetTypeOfInstInSpecific(const File& sem_ir, SpecificId specific_id,
|
|
InstId inst_id) -> TypeId {
|
|
auto type_id = sem_ir.insts().GetAttachedType(inst_id);
|
|
auto const_id = sem_ir.types().GetConstantId(type_id);
|
|
auto [_, specific_const_id] =
|
|
GetConstantInSpecific(sem_ir, specific_id, sem_ir, const_id);
|
|
return TypeId::ForTypeConstant(specific_const_id);
|
|
}
|
|
|
|
auto GetTypeOfInstInSpecific(const File& specific_ir, SpecificId specific_id,
|
|
const File& inst_ir, InstId inst_id)
|
|
-> std::pair<const File*, TypeId> {
|
|
auto type_id = inst_ir.insts().GetAttachedType(inst_id);
|
|
auto const_id = inst_ir.types().GetConstantId(type_id);
|
|
auto [result_ir, result_const_id] =
|
|
GetConstantInSpecific(specific_ir, specific_id, inst_ir, const_id);
|
|
return {result_ir, TypeId::ForTypeConstant(result_const_id)};
|
|
}
|
|
|
|
} // namespace Carbon::SemIR
|