mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-06 10:54:49 +01:00
Add GenericInstance type to represent instances of generics. (#4085)
Also add a corresponding value store and YAML output. We don't create any generic instances in this change; this is just adding infrastructure for future changes.
This commit is contained in:
@@ -390,6 +390,9 @@ class Context {
|
||||
auto generics() -> ValueStore<SemIR::GenericId>& {
|
||||
return sem_ir().generics();
|
||||
}
|
||||
auto generic_instances() -> SemIR::GenericInstanceStore& {
|
||||
return sem_ir().generic_instances();
|
||||
}
|
||||
auto import_irs() -> ValueStore<SemIR::ImportIRId>& {
|
||||
return sem_ir().import_irs();
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
// CHECK:STDOUT: functions: {}
|
||||
// CHECK:STDOUT: classes: {}
|
||||
// CHECK:STDOUT: generics: {}
|
||||
// CHECK:STDOUT: generic_instances: {}
|
||||
// CHECK:STDOUT: types:
|
||||
// CHECK:STDOUT: type0: {constant: template instNamespaceType, value_rep: {kind: copy, type: type0}}
|
||||
// CHECK:STDOUT: type_blocks: {}
|
||||
|
||||
+2
@@ -33,6 +33,7 @@ fn B() {}
|
||||
// CHECK:STDOUT: function0: {name: name0, parent_scope: name_scope0, param_refs: empty, body: [block3]}
|
||||
// CHECK:STDOUT: classes: {}
|
||||
// CHECK:STDOUT: generics: {}
|
||||
// CHECK:STDOUT: generic_instances: {}
|
||||
// CHECK:STDOUT: types:
|
||||
// CHECK:STDOUT: type0: {constant: template instNamespaceType, value_rep: {kind: copy, type: type0}}
|
||||
// CHECK:STDOUT: type1: {constant: template inst+2, value_rep: {kind: none, type: type2}}
|
||||
@@ -95,6 +96,7 @@ fn B() {}
|
||||
// CHECK:STDOUT: function0: {name: name0, parent_scope: name_scope0, param_refs: empty, body: [block3]}
|
||||
// CHECK:STDOUT: classes: {}
|
||||
// CHECK:STDOUT: generics: {}
|
||||
// CHECK:STDOUT: generic_instances: {}
|
||||
// CHECK:STDOUT: types:
|
||||
// CHECK:STDOUT: type0: {constant: template instNamespaceType, value_rep: {kind: copy, type: type0}}
|
||||
// CHECK:STDOUT: type1: {constant: template inst+2, value_rep: {kind: none, type: type2}}
|
||||
|
||||
@@ -33,6 +33,7 @@ fn B() {}
|
||||
// CHECK:STDOUT: function0: {name: name0, parent_scope: name_scope0, param_refs: empty, body: [block3]}
|
||||
// CHECK:STDOUT: classes: {}
|
||||
// CHECK:STDOUT: generics: {}
|
||||
// CHECK:STDOUT: generic_instances: {}
|
||||
// CHECK:STDOUT: types:
|
||||
// CHECK:STDOUT: type0: {constant: template instNamespaceType, value_rep: {kind: copy, type: type0}}
|
||||
// CHECK:STDOUT: type1: {constant: template inst+2, value_rep: {kind: none, type: type2}}
|
||||
@@ -74,6 +75,7 @@ fn B() {}
|
||||
// CHECK:STDOUT: function0: {name: name0, parent_scope: name_scope0, param_refs: empty, body: [block3]}
|
||||
// CHECK:STDOUT: classes: {}
|
||||
// CHECK:STDOUT: generics: {}
|
||||
// CHECK:STDOUT: generic_instances: {}
|
||||
// CHECK:STDOUT: types:
|
||||
// CHECK:STDOUT: type0: {constant: template instNamespaceType, value_rep: {kind: copy, type: type0}}
|
||||
// CHECK:STDOUT: type1: {constant: template inst+2, value_rep: {kind: none, type: type2}}
|
||||
|
||||
@@ -28,6 +28,7 @@ fn Foo(n: ()) -> ((), ()) {
|
||||
// CHECK:STDOUT: function0: {name: name0, parent_scope: name_scope0, param_refs: block3, return_storage: inst+13, return_slot: present, body: [block6]}
|
||||
// CHECK:STDOUT: classes: {}
|
||||
// CHECK:STDOUT: generics: {}
|
||||
// CHECK:STDOUT: generic_instances: {}
|
||||
// CHECK:STDOUT: types:
|
||||
// CHECK:STDOUT: type0: {constant: template instNamespaceType, value_rep: {kind: copy, type: type0}}
|
||||
// CHECK:STDOUT: type1: {constant: template inst+1, value_rep: {kind: none, type: type1}}
|
||||
|
||||
@@ -30,6 +30,7 @@ fn Foo[T:! type](n: T) -> (T, ()) {
|
||||
// CHECK:STDOUT: classes: {}
|
||||
// CHECK:STDOUT: generics:
|
||||
// CHECK:STDOUT: generic0: {decl: inst+16, bindings: block7}
|
||||
// CHECK:STDOUT: generic_instances: {}
|
||||
// CHECK:STDOUT: types:
|
||||
// CHECK:STDOUT: type0: {constant: template instNamespaceType, value_rep: {kind: copy, type: type0}}
|
||||
// CHECK:STDOUT: type1: {constant: symbolic inst+3, value_rep: {kind: copy, type: type1}}
|
||||
|
||||
@@ -84,6 +84,7 @@ cc_library(
|
||||
"constant.cpp",
|
||||
"file.cpp",
|
||||
"function.cpp",
|
||||
"generic.cpp",
|
||||
"name.cpp",
|
||||
],
|
||||
hdrs = [
|
||||
@@ -116,6 +117,7 @@ cc_library(
|
||||
"//common:enum_base",
|
||||
"//common:error",
|
||||
"//common:hashing",
|
||||
"//common:set",
|
||||
"//toolchain/base:kind_switch",
|
||||
"//toolchain/base:value_store",
|
||||
"//toolchain/base:yaml",
|
||||
|
||||
@@ -141,6 +141,7 @@ auto File::OutputYaml(bool include_builtins) const -> Yaml::OutputMapping {
|
||||
map.Add("functions", functions_.OutputYaml());
|
||||
map.Add("classes", classes_.OutputYaml());
|
||||
map.Add("generics", generics_.OutputYaml());
|
||||
map.Add("generic_instances", generic_instances_.OutputYaml());
|
||||
map.Add("types", types_.OutputYaml());
|
||||
map.Add("type_blocks", type_blocks_.OutputYaml());
|
||||
map.Add("insts",
|
||||
|
||||
@@ -131,6 +131,12 @@ class File : public Printable<File> {
|
||||
auto impls() const -> const ImplStore& { return impls_; }
|
||||
auto generics() -> ValueStore<GenericId>& { return generics_; }
|
||||
auto generics() const -> const ValueStore<GenericId>& { return generics_; }
|
||||
auto generic_instances() -> GenericInstanceStore& {
|
||||
return generic_instances_;
|
||||
}
|
||||
auto generic_instances() const -> const GenericInstanceStore& {
|
||||
return generic_instances_;
|
||||
}
|
||||
auto import_irs() -> ValueStore<ImportIRId>& { return import_irs_; }
|
||||
auto import_irs() const -> const ValueStore<ImportIRId>& {
|
||||
return import_irs_;
|
||||
@@ -214,6 +220,9 @@ class File : public Printable<File> {
|
||||
// Storage for generics.
|
||||
ValueStore<GenericId> generics_;
|
||||
|
||||
// Storage for instances of generics.
|
||||
GenericInstanceStore generic_instances_;
|
||||
|
||||
// Related IRs. There are some fixed entries at the start; see ImportIRId.
|
||||
ValueStore<ImportIRId> import_irs_;
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
// 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"
|
||||
|
||||
namespace Carbon::SemIR {
|
||||
|
||||
class GenericInstanceStore::KeyContext {
|
||||
public:
|
||||
// A lookup key for a generic instance.
|
||||
struct Key {
|
||||
GenericId generic_id;
|
||||
InstBlockId args_id;
|
||||
|
||||
friend auto operator==(const Key&, const Key&) -> bool = default;
|
||||
};
|
||||
|
||||
explicit KeyContext(llvm::ArrayRef<GenericInstance> instances)
|
||||
: instances_(instances) {}
|
||||
|
||||
auto AsKey(GenericInstanceId id) const -> Key {
|
||||
const auto& instance = instances_[id.index];
|
||||
return {.generic_id = instance.generic_id, .args_id = instance.args_id};
|
||||
}
|
||||
static auto AsKey(Key key) -> Key { return key; }
|
||||
|
||||
template <typename KeyT>
|
||||
auto HashKey(KeyT key, uint64_t seed) const -> HashCode {
|
||||
return HashValue(AsKey(key), seed);
|
||||
}
|
||||
|
||||
template <typename LHSKeyT, typename RHSKeyT>
|
||||
auto KeyEq(const LHSKeyT& lhs_key, const RHSKeyT& rhs_key) const -> bool {
|
||||
return AsKey(lhs_key) == AsKey(rhs_key);
|
||||
}
|
||||
|
||||
private:
|
||||
llvm::ArrayRef<GenericInstance> instances_;
|
||||
};
|
||||
|
||||
auto GenericInstanceStore::GetOrAdd(GenericId generic_id, InstBlockId args_id)
|
||||
-> GenericInstanceId {
|
||||
return lookup_table_
|
||||
.Insert(
|
||||
KeyContext::Key{.generic_id = generic_id, .args_id = args_id},
|
||||
[&] {
|
||||
return generic_instances_.Add(
|
||||
{.generic_id = generic_id, .args_id = args_id});
|
||||
},
|
||||
KeyContext(generic_instances_.array_ref()))
|
||||
.key();
|
||||
}
|
||||
|
||||
} // namespace Carbon::SemIR
|
||||
@@ -5,6 +5,7 @@
|
||||
#ifndef CARBON_TOOLCHAIN_SEM_IR_GENERIC_H_
|
||||
#define CARBON_TOOLCHAIN_SEM_IR_GENERIC_H_
|
||||
|
||||
#include "common/set.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
|
||||
namespace Carbon::SemIR {
|
||||
@@ -29,6 +30,43 @@ struct Generic : public Printable<Generic> {
|
||||
InstBlockId bindings_id;
|
||||
};
|
||||
|
||||
// An instance of a generic entity, such as an instance of a generic function.
|
||||
// For each construct that depends on a compile-time parameter in the generic
|
||||
// entity, this contains the corresponding non-generic value. This includes
|
||||
// values for the compile-time parameters themselves.
|
||||
struct GenericInstance : Printable<GenericInstance> {
|
||||
auto Print(llvm::raw_ostream& out) const -> void {
|
||||
out << "{generic: " << generic_id << ", args: " << args_id << "}";
|
||||
}
|
||||
|
||||
// The generic that this is an instance of.
|
||||
GenericId generic_id;
|
||||
// Argument values, corresponding to the bindings in `Generic::bindings_id`.
|
||||
InstBlockId args_id;
|
||||
};
|
||||
|
||||
// Provides storage for deduplicated instances of generics.
|
||||
class GenericInstanceStore : public Yaml::Printable<GenericInstanceStore> {
|
||||
public:
|
||||
// Adds a new generic instance, or gets the existing generic instance for a
|
||||
// specified generic and argument list. Returns the ID of the generic
|
||||
// instance. The argument IDs must be for instructions in the constant block,
|
||||
// and must be a canonical instruction block ID.
|
||||
auto GetOrAdd(GenericId generic_id, InstBlockId args_id) -> GenericInstanceId;
|
||||
|
||||
// These are to support printable structures, and are not guaranteed.
|
||||
auto OutputYaml() const -> Yaml::OutputMapping {
|
||||
return generic_instances_.OutputYaml();
|
||||
}
|
||||
|
||||
private:
|
||||
// Context for hashing keys.
|
||||
class KeyContext;
|
||||
|
||||
ValueStore<GenericInstanceId> generic_instances_;
|
||||
Carbon::Set<GenericInstanceId, 0, KeyContext> lookup_table_;
|
||||
};
|
||||
|
||||
} // namespace Carbon::SemIR
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_SEM_IR_GENERIC_H_
|
||||
|
||||
@@ -22,6 +22,7 @@ struct BindNameInfo;
|
||||
struct Class;
|
||||
struct Function;
|
||||
struct Generic;
|
||||
struct GenericInstance;
|
||||
struct ImportIR;
|
||||
struct ImportIRInst;
|
||||
struct Interface;
|
||||
@@ -300,6 +301,24 @@ struct GenericId : public IdBase, public Printable<GenericId> {
|
||||
|
||||
constexpr GenericId GenericId::Invalid = GenericId(InvalidIndex);
|
||||
|
||||
// The ID of an instance of a generic.
|
||||
struct GenericInstanceId : public IdBase, public Printable<GenericInstanceId> {
|
||||
using ValueType = GenericInstance;
|
||||
|
||||
// An explicitly invalid ID. This is typically used to represent a non-generic
|
||||
// instance.
|
||||
static const GenericInstanceId Invalid;
|
||||
|
||||
using IdBase::IdBase;
|
||||
auto Print(llvm::raw_ostream& out) const -> void {
|
||||
out << "genericInstance";
|
||||
IdBase::Print(out);
|
||||
}
|
||||
};
|
||||
|
||||
constexpr GenericInstanceId GenericInstanceId::Invalid =
|
||||
GenericInstanceId(InvalidIndex);
|
||||
|
||||
// The ID of an IR within the set of imported IRs, both direct and indirect.
|
||||
struct ImportIRId : public IdBase, public Printable<ImportIRId> {
|
||||
using ValueType = ImportIR;
|
||||
|
||||
@@ -63,6 +63,7 @@ TEST(SemIRTest, YAML) {
|
||||
Pair("functions", Yaml::Mapping(SizeIs(1))),
|
||||
Pair("classes", Yaml::Mapping(SizeIs(0))),
|
||||
Pair("generics", Yaml::Mapping(SizeIs(0))),
|
||||
Pair("generic_instances", Yaml::Mapping(SizeIs(0))),
|
||||
Pair("types", Yaml::Mapping(Each(type_builtin))),
|
||||
Pair("type_blocks", Yaml::Mapping(SizeIs(Ge(1)))),
|
||||
Pair("insts",
|
||||
|
||||
Reference in New Issue
Block a user