mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-11-15 15:48:10 +00:00
Add support for initializing types like `GenericClass(i32)` from a struct literal. A new kind of instruction, `complete_type_witness`, is added to the class definition to track the object representation type so that it's visible to the generics machinery. Accesses to the object representation of a class have all been updated to pass in the class's `SpecificId` so that the types of the fields of the specific class are used instead of the types of the fields of the generic class in places that look at the object representation -- primarily class initialization.
101 lines
3.4 KiB
C++
101 lines
3.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"
|
|
|
|
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.is_valid());
|
|
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.Add(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.is_valid()) {
|
|
// Constant is an abstract symbolic constant, not associated with some
|
|
// particular generic.
|
|
return const_id;
|
|
}
|
|
|
|
if (!specific_id.is_valid()) {
|
|
// 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.is_valid(),
|
|
"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
|