mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 21:10:12 +01:00
Add a full entity representation for associated constants, and build a `Generic` object for them. This `Generic` is parameterized by the enclosing `Self` type, allowing the use of `Self` within the type of the associated constant to be supported. When performing impl lookup for an associated constant, produce the type with the provided self type substituted for its `Self` along with any generic parameters of the interface. Split the handling of associated constant declarations into two parts, corresponding to the code before the `=`, and the code between the `=` and `;` (if any). The former goes into the generic declaration region; the latter into the generic definition region. This prepares us to handle the default value for an associated constant, but for now we're just storing the information and not actually using it. Remove the entity type field from `assoc_entity_type`, because it's almost unused and is an attractive nuisance -- it must necessarily be a type in the generic scope of the associated constant rather than in the scope of the instruction (because there is no `Self` anywhere else), which means that it's hard to substitute into or derive meaning from. See `toolchain/check/testdata/impl/assoc_const_self.carbon` for tests of the new functionality; these used to cause the toolchain to crash.
102 lines
3.5 KiB
C++
102 lines
3.5 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(llvm::ArrayRef<Specific> specifics)
|
|
: specifics_(specifics) {}
|
|
|
|
auto TranslateKey(SpecificId id) const -> Key {
|
|
const auto& specific = specifics_[id.index];
|
|
return {.generic_id = specific.generic_id, .args_id = specific.args_id};
|
|
}
|
|
|
|
private:
|
|
llvm::ArrayRef<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_.array_ref()))
|
|
.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_.array_ref()));
|
|
}
|
|
|
|
auto GetConstantInSpecific(const File& sem_ir, SpecificId specific_id,
|
|
ConstantId const_id) -> ConstantId {
|
|
if (!const_id.is_symbolic()) {
|
|
// Type does not depend on a generic parameter.
|
|
return const_id;
|
|
}
|
|
|
|
const auto& symbolic = sem_ir.constant_values().GetSymbolicConstant(const_id);
|
|
if (!symbolic.generic_id.has_value()) {
|
|
// Constant is an abstract symbolic constant, not associated with some
|
|
// particular generic.
|
|
return const_id;
|
|
}
|
|
|
|
if (!specific_id.has_value()) {
|
|
// We have a generic constant but no specific. We treat as a request for the
|
|
// canonical value of the constant.
|
|
return sem_ir.constant_values().Get(symbolic.inst_id);
|
|
}
|
|
|
|
const auto& specific = sem_ir.specifics().Get(specific_id);
|
|
CARBON_CHECK(specific.generic_id == symbolic.generic_id,
|
|
"Given a specific for the wrong generic");
|
|
|
|
auto value_block_id = specific.GetValueBlock(symbolic.index.region());
|
|
CARBON_CHECK(
|
|
value_block_id.has_value(),
|
|
"Queried {0} in {1} for {2} before it was resolved.", symbolic.index,
|
|
specific_id,
|
|
sem_ir.insts().Get(sem_ir.generics().Get(specific.generic_id).decl_id));
|
|
return sem_ir.constant_values().Get(
|
|
sem_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.constant_values().Get(inst_id));
|
|
}
|
|
|
|
auto GetTypeInSpecific(const File& sem_ir, SpecificId specific_id,
|
|
TypeId type_id) -> TypeId {
|
|
return TypeId::ForTypeConstant(GetConstantInSpecific(
|
|
sem_ir, specific_id, sem_ir.types().GetConstantId(type_id)));
|
|
}
|
|
|
|
} // namespace Carbon::SemIR
|