Change TypeId to be a thin wrapper around ConstantId. (#4140)

This better follows the principle that types are simply constants of
type `type`, and allows more uniform treatment of types as just another
kind of constant from generics handling.

Use a hash table to map from `TypeId` to information about the complete
type. This makes basic operations on types a bit simpler, and operations
that actually need to access the complete class information a bit more
complex.
This commit is contained in:
Richard Smith
2024-07-17 22:46:03 +00:00
committed by GitHub
parent 65d6e3e221
commit dde0bd0ffe
17 changed files with 355 additions and 277 deletions
+10 -4
View File
@@ -734,7 +734,7 @@ class TypeCompleter {
case Phase::BuildValueRepr: {
auto value_rep = BuildValueRepr(type_id, inst);
context_.sem_ir().CompleteType(type_id, value_rep);
context_.types().SetValueRepr(type_id, value_rep);
CARBON_CHECK(old_work_list_size == work_list_.size())
<< "BuildValueRepr should not change work items";
work_list_.pop_back();
@@ -1107,10 +1107,16 @@ auto Context::GetTypeIdForTypeConstant(SemIR::ConstantId constant_id)
-> SemIR::TypeId {
CARBON_CHECK(constant_id.is_constant())
<< "Canonicalizing non-constant type: " << constant_id;
auto type_id =
insts().Get(constant_values().GetInstId(constant_id)).type_id();
// TODO: For now, we allow values of facet type to be used as types.
CARBON_CHECK(type_id == SemIR::TypeId::TypeType ||
types().Is<SemIR::InterfaceType>(type_id) ||
constant_id == SemIR::ConstantId::Error)
<< "Forming type ID for non-type constant of type "
<< types().GetAsInst(type_id);
auto result = type_ids_for_type_constants_.Insert(
constant_id, [&]() { return types().Add({.constant_id = constant_id}); });
return result.value();
return SemIR::TypeId::ForTypeConstant(constant_id);
}
// Gets or forms a type_id for a type, given the instruction kind and arguments.
+15 -12
View File
@@ -24,7 +24,9 @@
// CHECK:STDOUT: generics: {}
// CHECK:STDOUT: generic_instances: {}
// CHECK:STDOUT: types:
// CHECK:STDOUT: type0: {constant: template instNamespaceType, value_rep: {kind: copy, type: type0}}
// CHECK:STDOUT: typeTypeType: {kind: copy, type: typeTypeType}
// CHECK:STDOUT: typeError: {kind: copy, type: typeError}
// CHECK:STDOUT: 'type(instNamespaceType)': {kind: copy, type: type(instNamespaceType)}
// CHECK:STDOUT: type_blocks: {}
// CHECK:STDOUT: insts:
// CHECK:STDOUT: instTypeType: {kind: BuiltinInst, arg0: TypeType, type: typeTypeType}
@@ -36,18 +38,19 @@
// CHECK:STDOUT: instBoundMethodType: {kind: BuiltinInst, arg0: BoundMethodType, type: typeTypeType}
// CHECK:STDOUT: instNamespaceType: {kind: BuiltinInst, arg0: NamespaceType, type: typeTypeType}
// CHECK:STDOUT: instWitnessType: {kind: BuiltinInst, arg0: WitnessType, type: typeTypeType}
// CHECK:STDOUT: 'inst+0': {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type0}
// CHECK:STDOUT: 'inst+0': {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type(instNamespaceType)}
// CHECK:STDOUT: constant_values:
// CHECK:STDOUT: instTypeType: template instTypeType
// CHECK:STDOUT: instError: template instError
// CHECK:STDOUT: instBoolType: template instBoolType
// CHECK:STDOUT: instIntType: template instIntType
// CHECK:STDOUT: instFloatType: template instFloatType
// CHECK:STDOUT: instStringType: template instStringType
// CHECK:STDOUT: instBoundMethodType: template instBoundMethodType
// CHECK:STDOUT: instNamespaceType: template instNamespaceType
// CHECK:STDOUT: instWitnessType: template instWitnessType
// CHECK:STDOUT: 'inst+0': template inst+0
// CHECK:STDOUT: instTypeType: templateConstant(instTypeType)
// CHECK:STDOUT: instError: templateConstant(instError)
// CHECK:STDOUT: instBoolType: templateConstant(instBoolType)
// CHECK:STDOUT: instIntType: templateConstant(instIntType)
// CHECK:STDOUT: instFloatType: templateConstant(instFloatType)
// CHECK:STDOUT: instStringType: templateConstant(instStringType)
// CHECK:STDOUT: instBoundMethodType: templateConstant(instBoundMethodType)
// CHECK:STDOUT: instNamespaceType: templateConstant(instNamespaceType)
// CHECK:STDOUT: instWitnessType: templateConstant(instWitnessType)
// CHECK:STDOUT: 'inst+0': templateConstant(inst+0)
// CHECK:STDOUT: symbolic_constants: {}
// CHECK:STDOUT: inst_blocks:
// CHECK:STDOUT: empty: {}
// CHECK:STDOUT: exports: {}
@@ -41,24 +41,27 @@ fn B() {
// 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}}
// CHECK:STDOUT: type2: {constant: template inst+3, value_rep: {kind: none, type: type2}}
// CHECK:STDOUT: typeTypeType: {kind: copy, type: typeTypeType}
// CHECK:STDOUT: typeError: {kind: copy, type: typeError}
// CHECK:STDOUT: 'type(instNamespaceType)': {kind: copy, type: type(instNamespaceType)}
// CHECK:STDOUT: 'type(inst+2)': {kind: none, type: type(inst+3)}
// CHECK:STDOUT: 'type(inst+3)': {kind: none, type: type(inst+3)}
// CHECK:STDOUT: type_blocks:
// CHECK:STDOUT: type_block0: {}
// CHECK:STDOUT: insts:
// CHECK:STDOUT: 'inst+0': {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type0}
// CHECK:STDOUT: 'inst+1': {kind: FunctionDecl, arg0: function0, arg1: empty, type: type1}
// CHECK:STDOUT: 'inst+0': {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type(instNamespaceType)}
// CHECK:STDOUT: 'inst+1': {kind: FunctionDecl, arg0: function0, arg1: empty, type: type(inst+2)}
// CHECK:STDOUT: 'inst+2': {kind: FunctionType, arg0: function0, type: typeTypeType}
// CHECK:STDOUT: 'inst+3': {kind: TupleType, arg0: type_block0, type: typeTypeType}
// CHECK:STDOUT: 'inst+4': {kind: StructValue, arg0: empty, type: type1}
// CHECK:STDOUT: 'inst+4': {kind: StructValue, arg0: empty, type: type(inst+2)}
// CHECK:STDOUT: 'inst+5': {kind: Return}
// CHECK:STDOUT: constant_values:
// CHECK:STDOUT: 'inst+0': template inst+0
// CHECK:STDOUT: 'inst+1': template inst+4
// CHECK:STDOUT: 'inst+2': template inst+2
// CHECK:STDOUT: 'inst+3': template inst+3
// CHECK:STDOUT: 'inst+4': template inst+4
// CHECK:STDOUT: 'inst+0': templateConstant(inst+0)
// CHECK:STDOUT: 'inst+1': templateConstant(inst+4)
// CHECK:STDOUT: 'inst+2': templateConstant(inst+2)
// CHECK:STDOUT: 'inst+3': templateConstant(inst+3)
// CHECK:STDOUT: 'inst+4': templateConstant(inst+4)
// CHECK:STDOUT: symbolic_constants: {}
// CHECK:STDOUT: inst_blocks:
// CHECK:STDOUT: empty: {}
// CHECK:STDOUT: exports:
@@ -113,41 +116,44 @@ fn B() {
// 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+4, value_rep: {kind: none, type: type2}}
// CHECK:STDOUT: type2: {constant: template inst+5, value_rep: {kind: none, type: type2}}
// CHECK:STDOUT: type3: {constant: template inst+10, value_rep: {kind: none, type: type2}}
// CHECK:STDOUT: typeTypeType: {kind: copy, type: typeTypeType}
// CHECK:STDOUT: typeError: {kind: copy, type: typeError}
// CHECK:STDOUT: 'type(instNamespaceType)': {kind: copy, type: type(instNamespaceType)}
// CHECK:STDOUT: 'type(inst+4)': {kind: none, type: type(inst+5)}
// CHECK:STDOUT: 'type(inst+5)': {kind: none, type: type(inst+5)}
// CHECK:STDOUT: 'type(inst+10)': {kind: none, type: type(inst+5)}
// CHECK:STDOUT: type_blocks:
// CHECK:STDOUT: type_block0: {}
// CHECK:STDOUT: insts:
// CHECK:STDOUT: 'inst+0': {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type0}
// CHECK:STDOUT: 'inst+0': {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type(instNamespaceType)}
// CHECK:STDOUT: 'inst+1': {kind: ImportDecl, arg0: name1}
// CHECK:STDOUT: 'inst+2': {kind: Namespace, arg0: name_scope1, arg1: inst+1, type: type0}
// CHECK:STDOUT: 'inst+3': {kind: FunctionDecl, arg0: function0, arg1: empty, type: type1}
// CHECK:STDOUT: 'inst+2': {kind: Namespace, arg0: name_scope1, arg1: inst+1, type: type(instNamespaceType)}
// CHECK:STDOUT: 'inst+3': {kind: FunctionDecl, arg0: function0, arg1: empty, type: type(inst+4)}
// CHECK:STDOUT: 'inst+4': {kind: FunctionType, arg0: function0, type: typeTypeType}
// CHECK:STDOUT: 'inst+5': {kind: TupleType, arg0: type_block0, type: typeTypeType}
// CHECK:STDOUT: 'inst+6': {kind: StructValue, arg0: empty, type: type1}
// CHECK:STDOUT: 'inst+7': {kind: NameRef, arg0: name1, arg1: inst+2, type: type0}
// CHECK:STDOUT: 'inst+8': {kind: ImportRefLoaded, arg0: import_ir_inst0, arg1: bind_name0, type: type3}
// CHECK:STDOUT: 'inst+9': {kind: FunctionDecl, arg0: function1, arg1: empty, type: type3}
// CHECK:STDOUT: 'inst+6': {kind: StructValue, arg0: empty, type: type(inst+4)}
// CHECK:STDOUT: 'inst+7': {kind: NameRef, arg0: name1, arg1: inst+2, type: type(instNamespaceType)}
// CHECK:STDOUT: 'inst+8': {kind: ImportRefLoaded, arg0: import_ir_inst0, arg1: bind_name0, type: type(inst+10)}
// CHECK:STDOUT: 'inst+9': {kind: FunctionDecl, arg0: function1, arg1: empty, type: type(inst+10)}
// CHECK:STDOUT: 'inst+10': {kind: FunctionType, arg0: function1, type: typeTypeType}
// CHECK:STDOUT: 'inst+11': {kind: StructValue, arg0: empty, type: type3}
// CHECK:STDOUT: 'inst+12': {kind: NameRef, arg0: name1, arg1: inst+8, type: type3}
// CHECK:STDOUT: 'inst+13': {kind: Call, arg0: inst+12, arg1: block5, type: type2}
// CHECK:STDOUT: 'inst+11': {kind: StructValue, arg0: empty, type: type(inst+10)}
// CHECK:STDOUT: 'inst+12': {kind: NameRef, arg0: name1, arg1: inst+8, type: type(inst+10)}
// CHECK:STDOUT: 'inst+13': {kind: Call, arg0: inst+12, arg1: block5, type: type(inst+5)}
// CHECK:STDOUT: 'inst+14': {kind: Return}
// CHECK:STDOUT: constant_values:
// CHECK:STDOUT: 'inst+0': template inst+0
// CHECK:STDOUT: 'inst+2': template inst+2
// CHECK:STDOUT: 'inst+3': template inst+6
// CHECK:STDOUT: 'inst+4': template inst+4
// CHECK:STDOUT: 'inst+5': template inst+5
// CHECK:STDOUT: 'inst+6': template inst+6
// CHECK:STDOUT: 'inst+7': template inst+2
// CHECK:STDOUT: 'inst+8': template inst+11
// CHECK:STDOUT: 'inst+9': template inst+11
// CHECK:STDOUT: 'inst+10': template inst+10
// CHECK:STDOUT: 'inst+11': template inst+11
// CHECK:STDOUT: 'inst+12': template inst+11
// CHECK:STDOUT: 'inst+0': templateConstant(inst+0)
// CHECK:STDOUT: 'inst+2': templateConstant(inst+2)
// CHECK:STDOUT: 'inst+3': templateConstant(inst+6)
// CHECK:STDOUT: 'inst+4': templateConstant(inst+4)
// CHECK:STDOUT: 'inst+5': templateConstant(inst+5)
// CHECK:STDOUT: 'inst+6': templateConstant(inst+6)
// CHECK:STDOUT: 'inst+7': templateConstant(inst+2)
// CHECK:STDOUT: 'inst+8': templateConstant(inst+11)
// CHECK:STDOUT: 'inst+9': templateConstant(inst+11)
// CHECK:STDOUT: 'inst+10': templateConstant(inst+10)
// CHECK:STDOUT: 'inst+11': templateConstant(inst+11)
// CHECK:STDOUT: 'inst+12': templateConstant(inst+11)
// CHECK:STDOUT: symbolic_constants: {}
// CHECK:STDOUT: inst_blocks:
// CHECK:STDOUT: empty: {}
// CHECK:STDOUT: exports:
@@ -41,24 +41,27 @@ fn B() {
// 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}}
// CHECK:STDOUT: type2: {constant: template inst+3, value_rep: {kind: none, type: type2}}
// CHECK:STDOUT: typeTypeType: {kind: copy, type: typeTypeType}
// CHECK:STDOUT: typeError: {kind: copy, type: typeError}
// CHECK:STDOUT: 'type(instNamespaceType)': {kind: copy, type: type(instNamespaceType)}
// CHECK:STDOUT: 'type(inst+2)': {kind: none, type: type(inst+3)}
// CHECK:STDOUT: 'type(inst+3)': {kind: none, type: type(inst+3)}
// CHECK:STDOUT: type_blocks:
// CHECK:STDOUT: type_block0: {}
// CHECK:STDOUT: insts:
// CHECK:STDOUT: 'inst+0': {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type0}
// CHECK:STDOUT: 'inst+1': {kind: FunctionDecl, arg0: function0, arg1: empty, type: type1}
// CHECK:STDOUT: 'inst+0': {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type(instNamespaceType)}
// CHECK:STDOUT: 'inst+1': {kind: FunctionDecl, arg0: function0, arg1: empty, type: type(inst+2)}
// CHECK:STDOUT: 'inst+2': {kind: FunctionType, arg0: function0, type: typeTypeType}
// CHECK:STDOUT: 'inst+3': {kind: TupleType, arg0: type_block0, type: typeTypeType}
// CHECK:STDOUT: 'inst+4': {kind: StructValue, arg0: empty, type: type1}
// CHECK:STDOUT: 'inst+4': {kind: StructValue, arg0: empty, type: type(inst+2)}
// CHECK:STDOUT: 'inst+5': {kind: Return}
// CHECK:STDOUT: constant_values:
// CHECK:STDOUT: 'inst+0': template inst+0
// CHECK:STDOUT: 'inst+1': template inst+4
// CHECK:STDOUT: 'inst+2': template inst+2
// CHECK:STDOUT: 'inst+3': template inst+3
// CHECK:STDOUT: 'inst+4': template inst+4
// CHECK:STDOUT: 'inst+0': templateConstant(inst+0)
// CHECK:STDOUT: 'inst+1': templateConstant(inst+4)
// CHECK:STDOUT: 'inst+2': templateConstant(inst+2)
// CHECK:STDOUT: 'inst+3': templateConstant(inst+3)
// CHECK:STDOUT: 'inst+4': templateConstant(inst+4)
// CHECK:STDOUT: symbolic_constants: {}
// CHECK:STDOUT: inst_blocks:
// CHECK:STDOUT: empty: {}
// CHECK:STDOUT: exports:
@@ -92,41 +95,44 @@ fn B() {
// 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+4, value_rep: {kind: none, type: type2}}
// CHECK:STDOUT: type2: {constant: template inst+5, value_rep: {kind: none, type: type2}}
// CHECK:STDOUT: type3: {constant: template inst+10, value_rep: {kind: none, type: type2}}
// CHECK:STDOUT: typeTypeType: {kind: copy, type: typeTypeType}
// CHECK:STDOUT: typeError: {kind: copy, type: typeError}
// CHECK:STDOUT: 'type(instNamespaceType)': {kind: copy, type: type(instNamespaceType)}
// CHECK:STDOUT: 'type(inst+4)': {kind: none, type: type(inst+5)}
// CHECK:STDOUT: 'type(inst+5)': {kind: none, type: type(inst+5)}
// CHECK:STDOUT: 'type(inst+10)': {kind: none, type: type(inst+5)}
// CHECK:STDOUT: type_blocks:
// CHECK:STDOUT: type_block0: {}
// CHECK:STDOUT: insts:
// CHECK:STDOUT: 'inst+0': {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type0}
// CHECK:STDOUT: 'inst+0': {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type(instNamespaceType)}
// CHECK:STDOUT: 'inst+1': {kind: ImportDecl, arg0: name1}
// CHECK:STDOUT: 'inst+2': {kind: Namespace, arg0: name_scope1, arg1: inst+1, type: type0}
// CHECK:STDOUT: 'inst+3': {kind: FunctionDecl, arg0: function0, arg1: empty, type: type1}
// CHECK:STDOUT: 'inst+2': {kind: Namespace, arg0: name_scope1, arg1: inst+1, type: type(instNamespaceType)}
// CHECK:STDOUT: 'inst+3': {kind: FunctionDecl, arg0: function0, arg1: empty, type: type(inst+4)}
// CHECK:STDOUT: 'inst+4': {kind: FunctionType, arg0: function0, type: typeTypeType}
// CHECK:STDOUT: 'inst+5': {kind: TupleType, arg0: type_block0, type: typeTypeType}
// CHECK:STDOUT: 'inst+6': {kind: StructValue, arg0: empty, type: type1}
// CHECK:STDOUT: 'inst+7': {kind: NameRef, arg0: name1, arg1: inst+2, type: type0}
// CHECK:STDOUT: 'inst+8': {kind: ImportRefLoaded, arg0: import_ir_inst0, arg1: bind_name0, type: type3}
// CHECK:STDOUT: 'inst+9': {kind: FunctionDecl, arg0: function1, arg1: empty, type: type3}
// CHECK:STDOUT: 'inst+6': {kind: StructValue, arg0: empty, type: type(inst+4)}
// CHECK:STDOUT: 'inst+7': {kind: NameRef, arg0: name1, arg1: inst+2, type: type(instNamespaceType)}
// CHECK:STDOUT: 'inst+8': {kind: ImportRefLoaded, arg0: import_ir_inst0, arg1: bind_name0, type: type(inst+10)}
// CHECK:STDOUT: 'inst+9': {kind: FunctionDecl, arg0: function1, arg1: empty, type: type(inst+10)}
// CHECK:STDOUT: 'inst+10': {kind: FunctionType, arg0: function1, type: typeTypeType}
// CHECK:STDOUT: 'inst+11': {kind: StructValue, arg0: empty, type: type3}
// CHECK:STDOUT: 'inst+12': {kind: NameRef, arg0: name1, arg1: inst+8, type: type3}
// CHECK:STDOUT: 'inst+13': {kind: Call, arg0: inst+12, arg1: block5, type: type2}
// CHECK:STDOUT: 'inst+11': {kind: StructValue, arg0: empty, type: type(inst+10)}
// CHECK:STDOUT: 'inst+12': {kind: NameRef, arg0: name1, arg1: inst+8, type: type(inst+10)}
// CHECK:STDOUT: 'inst+13': {kind: Call, arg0: inst+12, arg1: block5, type: type(inst+5)}
// CHECK:STDOUT: 'inst+14': {kind: Return}
// CHECK:STDOUT: constant_values:
// CHECK:STDOUT: 'inst+0': template inst+0
// CHECK:STDOUT: 'inst+2': template inst+2
// CHECK:STDOUT: 'inst+3': template inst+6
// CHECK:STDOUT: 'inst+4': template inst+4
// CHECK:STDOUT: 'inst+5': template inst+5
// CHECK:STDOUT: 'inst+6': template inst+6
// CHECK:STDOUT: 'inst+7': template inst+2
// CHECK:STDOUT: 'inst+8': template inst+11
// CHECK:STDOUT: 'inst+9': template inst+11
// CHECK:STDOUT: 'inst+10': template inst+10
// CHECK:STDOUT: 'inst+11': template inst+11
// CHECK:STDOUT: 'inst+12': template inst+11
// CHECK:STDOUT: 'inst+0': templateConstant(inst+0)
// CHECK:STDOUT: 'inst+2': templateConstant(inst+2)
// CHECK:STDOUT: 'inst+3': templateConstant(inst+6)
// CHECK:STDOUT: 'inst+4': templateConstant(inst+4)
// CHECK:STDOUT: 'inst+5': templateConstant(inst+5)
// CHECK:STDOUT: 'inst+6': templateConstant(inst+6)
// CHECK:STDOUT: 'inst+7': templateConstant(inst+2)
// CHECK:STDOUT: 'inst+8': templateConstant(inst+11)
// CHECK:STDOUT: 'inst+9': templateConstant(inst+11)
// CHECK:STDOUT: 'inst+10': templateConstant(inst+10)
// CHECK:STDOUT: 'inst+11': templateConstant(inst+11)
// CHECK:STDOUT: 'inst+12': templateConstant(inst+11)
// CHECK:STDOUT: symbolic_constants: {}
// CHECK:STDOUT: inst_blocks:
// CHECK:STDOUT: empty: {}
// CHECK:STDOUT: exports:
@@ -32,69 +32,72 @@ fn Foo(n: ()) -> ((), ()) {
// 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}}
// CHECK:STDOUT: type2: {constant: template inst+8, value_rep: {kind: pointer, type: type4}}
// CHECK:STDOUT: type3: {constant: template inst+15, value_rep: {kind: none, type: type1}}
// CHECK:STDOUT: type4: {constant: template inst+17, value_rep: {kind: copy, type: type4}}
// CHECK:STDOUT: typeTypeType: {kind: copy, type: typeTypeType}
// CHECK:STDOUT: typeError: {kind: copy, type: typeError}
// CHECK:STDOUT: 'type(instNamespaceType)': {kind: copy, type: type(instNamespaceType)}
// CHECK:STDOUT: 'type(inst+15)': {kind: none, type: type(inst+1)}
// CHECK:STDOUT: 'type(inst+1)': {kind: none, type: type(inst+1)}
// CHECK:STDOUT: 'type(inst+8)': {kind: pointer, type: type(inst+17)}
// CHECK:STDOUT: 'type(inst+17)': {kind: copy, type: type(inst+17)}
// CHECK:STDOUT: type_blocks:
// CHECK:STDOUT: type_block0: {}
// CHECK:STDOUT: type_block1:
// CHECK:STDOUT: 0: type1
// CHECK:STDOUT: 1: type1
// CHECK:STDOUT: 0: type(inst+1)
// CHECK:STDOUT: 1: type(inst+1)
// CHECK:STDOUT: insts:
// CHECK:STDOUT: 'inst+0': {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type0}
// CHECK:STDOUT: 'inst+0': {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type(instNamespaceType)}
// CHECK:STDOUT: 'inst+1': {kind: TupleType, arg0: type_block0, type: typeTypeType}
// CHECK:STDOUT: 'inst+2': {kind: TupleLiteral, arg0: empty, type: type1}
// CHECK:STDOUT: 'inst+2': {kind: TupleLiteral, arg0: empty, type: type(inst+1)}
// CHECK:STDOUT: 'inst+3': {kind: Converted, arg0: inst+2, arg1: inst+1, type: typeTypeType}
// CHECK:STDOUT: 'inst+4': {kind: Param, arg0: name1, type: type1}
// CHECK:STDOUT: 'inst+5': {kind: BindName, arg0: bind_name0, arg1: inst+4, type: type1}
// CHECK:STDOUT: 'inst+6': {kind: TupleLiteral, arg0: empty, type: type1}
// CHECK:STDOUT: 'inst+7': {kind: TupleLiteral, arg0: empty, type: type1}
// CHECK:STDOUT: 'inst+4': {kind: Param, arg0: name1, type: type(inst+1)}
// CHECK:STDOUT: 'inst+5': {kind: BindName, arg0: bind_name0, arg1: inst+4, type: type(inst+1)}
// CHECK:STDOUT: 'inst+6': {kind: TupleLiteral, arg0: empty, type: type(inst+1)}
// CHECK:STDOUT: 'inst+7': {kind: TupleLiteral, arg0: empty, type: type(inst+1)}
// CHECK:STDOUT: 'inst+8': {kind: TupleType, arg0: type_block1, type: typeTypeType}
// CHECK:STDOUT: 'inst+9': {kind: TupleLiteral, arg0: block5, type: type2}
// CHECK:STDOUT: 'inst+9': {kind: TupleLiteral, arg0: block5, type: type(inst+8)}
// CHECK:STDOUT: 'inst+10': {kind: Converted, arg0: inst+6, arg1: inst+1, type: typeTypeType}
// CHECK:STDOUT: 'inst+11': {kind: Converted, arg0: inst+7, arg1: inst+1, type: typeTypeType}
// CHECK:STDOUT: 'inst+12': {kind: Converted, arg0: inst+9, arg1: inst+8, type: typeTypeType}
// CHECK:STDOUT: 'inst+13': {kind: VarStorage, arg0: nameReturnSlot, type: type2}
// CHECK:STDOUT: 'inst+14': {kind: FunctionDecl, arg0: function0, arg1: block6, type: type3}
// CHECK:STDOUT: 'inst+13': {kind: VarStorage, arg0: nameReturnSlot, type: type(inst+8)}
// CHECK:STDOUT: 'inst+14': {kind: FunctionDecl, arg0: function0, arg1: block6, type: type(inst+15)}
// CHECK:STDOUT: 'inst+15': {kind: FunctionType, arg0: function0, type: typeTypeType}
// CHECK:STDOUT: 'inst+16': {kind: StructValue, arg0: empty, type: type3}
// CHECK:STDOUT: 'inst+17': {kind: PointerType, arg0: type2, type: typeTypeType}
// CHECK:STDOUT: 'inst+18': {kind: NameRef, arg0: name1, arg1: inst+5, type: type1}
// CHECK:STDOUT: 'inst+19': {kind: TupleLiteral, arg0: empty, type: type1}
// CHECK:STDOUT: 'inst+20': {kind: TupleLiteral, arg0: block8, type: type2}
// CHECK:STDOUT: 'inst+21': {kind: TupleAccess, arg0: inst+13, arg1: element0, type: type1}
// CHECK:STDOUT: 'inst+22': {kind: TupleInit, arg0: block9, arg1: inst+21, type: type1}
// CHECK:STDOUT: 'inst+23': {kind: TupleValue, arg0: block10, type: type1}
// CHECK:STDOUT: 'inst+24': {kind: Converted, arg0: inst+18, arg1: inst+22, type: type1}
// CHECK:STDOUT: 'inst+25': {kind: TupleAccess, arg0: inst+13, arg1: element1, type: type1}
// CHECK:STDOUT: 'inst+26': {kind: TupleInit, arg0: empty, arg1: inst+25, type: type1}
// CHECK:STDOUT: 'inst+27': {kind: Converted, arg0: inst+19, arg1: inst+26, type: type1}
// CHECK:STDOUT: 'inst+28': {kind: TupleInit, arg0: block11, arg1: inst+13, type: type2}
// CHECK:STDOUT: 'inst+29': {kind: TupleValue, arg0: block12, type: type2}
// CHECK:STDOUT: 'inst+30': {kind: Converted, arg0: inst+20, arg1: inst+28, type: type2}
// CHECK:STDOUT: 'inst+16': {kind: StructValue, arg0: empty, type: type(inst+15)}
// CHECK:STDOUT: 'inst+17': {kind: PointerType, arg0: type(inst+8), type: typeTypeType}
// CHECK:STDOUT: 'inst+18': {kind: NameRef, arg0: name1, arg1: inst+5, type: type(inst+1)}
// CHECK:STDOUT: 'inst+19': {kind: TupleLiteral, arg0: empty, type: type(inst+1)}
// CHECK:STDOUT: 'inst+20': {kind: TupleLiteral, arg0: block8, type: type(inst+8)}
// CHECK:STDOUT: 'inst+21': {kind: TupleAccess, arg0: inst+13, arg1: element0, type: type(inst+1)}
// CHECK:STDOUT: 'inst+22': {kind: TupleInit, arg0: block9, arg1: inst+21, type: type(inst+1)}
// CHECK:STDOUT: 'inst+23': {kind: TupleValue, arg0: block10, type: type(inst+1)}
// CHECK:STDOUT: 'inst+24': {kind: Converted, arg0: inst+18, arg1: inst+22, type: type(inst+1)}
// CHECK:STDOUT: 'inst+25': {kind: TupleAccess, arg0: inst+13, arg1: element1, type: type(inst+1)}
// CHECK:STDOUT: 'inst+26': {kind: TupleInit, arg0: empty, arg1: inst+25, type: type(inst+1)}
// CHECK:STDOUT: 'inst+27': {kind: Converted, arg0: inst+19, arg1: inst+26, type: type(inst+1)}
// CHECK:STDOUT: 'inst+28': {kind: TupleInit, arg0: block11, arg1: inst+13, type: type(inst+8)}
// CHECK:STDOUT: 'inst+29': {kind: TupleValue, arg0: block12, type: type(inst+8)}
// CHECK:STDOUT: 'inst+30': {kind: Converted, arg0: inst+20, arg1: inst+28, type: type(inst+8)}
// CHECK:STDOUT: 'inst+31': {kind: ReturnExpr, arg0: inst+30, arg1: inst+13}
// CHECK:STDOUT: constant_values:
// CHECK:STDOUT: 'inst+0': template inst+0
// CHECK:STDOUT: 'inst+1': template inst+1
// CHECK:STDOUT: 'inst+3': template inst+1
// CHECK:STDOUT: 'inst+8': template inst+8
// CHECK:STDOUT: 'inst+10': template inst+1
// CHECK:STDOUT: 'inst+11': template inst+1
// CHECK:STDOUT: 'inst+12': template inst+8
// CHECK:STDOUT: 'inst+14': template inst+16
// CHECK:STDOUT: 'inst+15': template inst+15
// CHECK:STDOUT: 'inst+16': template inst+16
// CHECK:STDOUT: 'inst+17': template inst+17
// CHECK:STDOUT: 'inst+22': template inst+23
// CHECK:STDOUT: 'inst+23': template inst+23
// CHECK:STDOUT: 'inst+24': template inst+23
// CHECK:STDOUT: 'inst+26': template inst+23
// CHECK:STDOUT: 'inst+27': template inst+23
// CHECK:STDOUT: 'inst+28': template inst+29
// CHECK:STDOUT: 'inst+29': template inst+29
// CHECK:STDOUT: 'inst+30': template inst+29
// CHECK:STDOUT: 'inst+0': templateConstant(inst+0)
// CHECK:STDOUT: 'inst+1': templateConstant(inst+1)
// CHECK:STDOUT: 'inst+3': templateConstant(inst+1)
// CHECK:STDOUT: 'inst+8': templateConstant(inst+8)
// CHECK:STDOUT: 'inst+10': templateConstant(inst+1)
// CHECK:STDOUT: 'inst+11': templateConstant(inst+1)
// CHECK:STDOUT: 'inst+12': templateConstant(inst+8)
// CHECK:STDOUT: 'inst+14': templateConstant(inst+16)
// CHECK:STDOUT: 'inst+15': templateConstant(inst+15)
// CHECK:STDOUT: 'inst+16': templateConstant(inst+16)
// CHECK:STDOUT: 'inst+17': templateConstant(inst+17)
// CHECK:STDOUT: 'inst+22': templateConstant(inst+23)
// CHECK:STDOUT: 'inst+23': templateConstant(inst+23)
// CHECK:STDOUT: 'inst+24': templateConstant(inst+23)
// CHECK:STDOUT: 'inst+26': templateConstant(inst+23)
// CHECK:STDOUT: 'inst+27': templateConstant(inst+23)
// CHECK:STDOUT: 'inst+28': templateConstant(inst+29)
// CHECK:STDOUT: 'inst+29': templateConstant(inst+29)
// CHECK:STDOUT: 'inst+30': templateConstant(inst+29)
// CHECK:STDOUT: symbolic_constants: {}
// CHECK:STDOUT: inst_blocks:
// CHECK:STDOUT: empty: {}
// CHECK:STDOUT: exports:
+56 -49
View File
@@ -35,74 +35,81 @@ fn Foo[T:! type](n: T) -> (T, ()) {
// CHECK:STDOUT: generic_instances:
// CHECK:STDOUT: genericInstance0: {generic: generic0, args: block10}
// CHECK:STDOUT: types:
// CHECK:STDOUT: type0: {constant: template instNamespaceType, value_rep: {kind: copy, type: type0}}
// CHECK:STDOUT: type1: {constant: symbolic 0, value_rep: {kind: copy, type: type1}}
// CHECK:STDOUT: type2: {constant: template inst+8, value_rep: {kind: none, type: type2}}
// CHECK:STDOUT: type3: {constant: template inst+10, value_rep: {kind: unknown, type: type<invalid>}}
// CHECK:STDOUT: type4: {constant: symbolic 1, value_rep: {kind: pointer, type: type8}}
// CHECK:STDOUT: type5: {constant: symbolic 2, value_rep: {kind: copy, type: type5}}
// CHECK:STDOUT: type6: {constant: symbolic 3, value_rep: {kind: pointer, type: type8}}
// CHECK:STDOUT: type7: {constant: template inst+17, value_rep: {kind: none, type: type2}}
// CHECK:STDOUT: type8: {constant: symbolic 4, value_rep: {kind: copy, type: type8}}
// CHECK:STDOUT: typeTypeType: {kind: copy, type: typeTypeType}
// CHECK:STDOUT: typeError: {kind: copy, type: typeError}
// CHECK:STDOUT: 'type(instNamespaceType)': {kind: copy, type: type(instNamespaceType)}
// CHECK:STDOUT: 'type(inst+17)': {kind: none, type: type(inst+8)}
// CHECK:STDOUT: 'type(inst+8)': {kind: none, type: type(inst+8)}
// CHECK:STDOUT: 'type(symbolicConstant0)': {kind: copy, type: type(symbolicConstant0)}
// CHECK:STDOUT: 'type(symbolicConstant1)': {kind: pointer, type: type(symbolicConstant4)}
// CHECK:STDOUT: 'type(symbolicConstant4)': {kind: copy, type: type(symbolicConstant4)}
// CHECK:STDOUT: 'type(symbolicConstant2)': {kind: copy, type: type(symbolicConstant2)}
// CHECK:STDOUT: 'type(symbolicConstant3)': {kind: pointer, type: type(symbolicConstant4)}
// CHECK:STDOUT: type_blocks:
// CHECK:STDOUT: type_block0: {}
// CHECK:STDOUT: type_block1:
// CHECK:STDOUT: 0: typeTypeType
// CHECK:STDOUT: 1: type2
// CHECK:STDOUT: 1: type(inst+8)
// CHECK:STDOUT: type_block2:
// CHECK:STDOUT: 0: type1
// CHECK:STDOUT: 1: type2
// CHECK:STDOUT: 0: type(symbolicConstant0)
// CHECK:STDOUT: 1: type(inst+8)
// CHECK:STDOUT: insts:
// CHECK:STDOUT: 'inst+0': {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type0}
// CHECK:STDOUT: 'inst+0': {kind: Namespace, arg0: name_scope0, arg1: inst<invalid>, type: type(instNamespaceType)}
// CHECK:STDOUT: 'inst+1': {kind: Param, arg0: name1, type: typeTypeType}
// CHECK:STDOUT: 'inst+2': {kind: BindSymbolicName, arg0: bind_name0, arg1: inst+1, type: typeTypeType}
// CHECK:STDOUT: 'inst+3': {kind: BindSymbolicName, arg0: bind_name0, arg1: inst<invalid>, type: typeTypeType}
// CHECK:STDOUT: 'inst+4': {kind: NameRef, arg0: name1, arg1: inst+2, type: typeTypeType}
// CHECK:STDOUT: 'inst+5': {kind: Param, arg0: name2, type: type5}
// CHECK:STDOUT: 'inst+6': {kind: BindName, arg0: bind_name1, arg1: inst+5, type: type5}
// CHECK:STDOUT: 'inst+5': {kind: Param, arg0: name2, type: type(symbolicConstant2)}
// CHECK:STDOUT: 'inst+6': {kind: BindName, arg0: bind_name1, arg1: inst+5, type: type(symbolicConstant2)}
// CHECK:STDOUT: 'inst+7': {kind: NameRef, arg0: name1, arg1: inst+2, type: typeTypeType}
// CHECK:STDOUT: 'inst+8': {kind: TupleType, arg0: type_block0, type: typeTypeType}
// CHECK:STDOUT: 'inst+9': {kind: TupleLiteral, arg0: empty, type: type2}
// CHECK:STDOUT: 'inst+9': {kind: TupleLiteral, arg0: empty, type: type(inst+8)}
// CHECK:STDOUT: 'inst+10': {kind: TupleType, arg0: type_block1, type: typeTypeType}
// CHECK:STDOUT: 'inst+11': {kind: TupleLiteral, arg0: block6, type: type3}
// CHECK:STDOUT: 'inst+11': {kind: TupleLiteral, arg0: block6, type: type(inst+10)}
// CHECK:STDOUT: 'inst+12': {kind: Converted, arg0: inst+9, arg1: inst+8, type: typeTypeType}
// CHECK:STDOUT: 'inst+13': {kind: TupleType, arg0: type_block2, type: typeTypeType}
// CHECK:STDOUT: 'inst+14': {kind: Converted, arg0: inst+11, arg1: inst+13, type: typeTypeType}
// CHECK:STDOUT: 'inst+15': {kind: VarStorage, arg0: nameReturnSlot, type: type4}
// CHECK:STDOUT: 'inst+16': {kind: FunctionDecl, arg0: function0, arg1: block7, type: type7}
// CHECK:STDOUT: 'inst+15': {kind: VarStorage, arg0: nameReturnSlot, type: type(symbolicConstant1)}
// CHECK:STDOUT: 'inst+16': {kind: FunctionDecl, arg0: function0, arg1: block7, type: type(inst+17)}
// CHECK:STDOUT: 'inst+17': {kind: FunctionType, arg0: function0, type: typeTypeType}
// CHECK:STDOUT: 'inst+18': {kind: StructValue, arg0: empty, type: type7}
// CHECK:STDOUT: 'inst+19': {kind: PointerType, arg0: type4, type: typeTypeType}
// CHECK:STDOUT: 'inst+20': {kind: NameRef, arg0: name2, arg1: inst+6, type: type5}
// CHECK:STDOUT: 'inst+21': {kind: TupleLiteral, arg0: empty, type: type2}
// CHECK:STDOUT: 'inst+22': {kind: TupleLiteral, arg0: block13, type: type6}
// CHECK:STDOUT: 'inst+23': {kind: TupleAccess, arg0: inst+15, arg1: element0, type: type5}
// CHECK:STDOUT: 'inst+24': {kind: InitializeFrom, arg0: inst+20, arg1: inst+23, type: type5}
// CHECK:STDOUT: 'inst+25': {kind: TupleAccess, arg0: inst+15, arg1: element1, type: type2}
// CHECK:STDOUT: 'inst+26': {kind: TupleInit, arg0: empty, arg1: inst+25, type: type2}
// CHECK:STDOUT: 'inst+27': {kind: TupleValue, arg0: block15, type: type2}
// CHECK:STDOUT: 'inst+28': {kind: Converted, arg0: inst+21, arg1: inst+26, type: type2}
// CHECK:STDOUT: 'inst+29': {kind: TupleInit, arg0: block14, arg1: inst+15, type: type6}
// CHECK:STDOUT: 'inst+30': {kind: Converted, arg0: inst+22, arg1: inst+29, type: type6}
// CHECK:STDOUT: 'inst+18': {kind: StructValue, arg0: empty, type: type(inst+17)}
// CHECK:STDOUT: 'inst+19': {kind: PointerType, arg0: type(symbolicConstant1), type: typeTypeType}
// CHECK:STDOUT: 'inst+20': {kind: NameRef, arg0: name2, arg1: inst+6, type: type(symbolicConstant2)}
// CHECK:STDOUT: 'inst+21': {kind: TupleLiteral, arg0: empty, type: type(inst+8)}
// CHECK:STDOUT: 'inst+22': {kind: TupleLiteral, arg0: block13, type: type(symbolicConstant3)}
// CHECK:STDOUT: 'inst+23': {kind: TupleAccess, arg0: inst+15, arg1: element0, type: type(symbolicConstant2)}
// CHECK:STDOUT: 'inst+24': {kind: InitializeFrom, arg0: inst+20, arg1: inst+23, type: type(symbolicConstant2)}
// CHECK:STDOUT: 'inst+25': {kind: TupleAccess, arg0: inst+15, arg1: element1, type: type(inst+8)}
// CHECK:STDOUT: 'inst+26': {kind: TupleInit, arg0: empty, arg1: inst+25, type: type(inst+8)}
// CHECK:STDOUT: 'inst+27': {kind: TupleValue, arg0: block15, type: type(inst+8)}
// CHECK:STDOUT: 'inst+28': {kind: Converted, arg0: inst+21, arg1: inst+26, type: type(inst+8)}
// CHECK:STDOUT: 'inst+29': {kind: TupleInit, arg0: block14, arg1: inst+15, type: type(symbolicConstant3)}
// CHECK:STDOUT: 'inst+30': {kind: Converted, arg0: inst+22, arg1: inst+29, type: type(symbolicConstant3)}
// CHECK:STDOUT: 'inst+31': {kind: ReturnExpr, arg0: inst+30, arg1: inst+15}
// CHECK:STDOUT: constant_values:
// CHECK:STDOUT: 'inst+0': template inst+0
// CHECK:STDOUT: 'inst+2': symbolic 2
// CHECK:STDOUT: 'inst+3': symbolic 0
// CHECK:STDOUT: 'inst+4': symbolic 2
// CHECK:STDOUT: 'inst+7': symbolic 2
// CHECK:STDOUT: 'inst+8': template inst+8
// CHECK:STDOUT: 'inst+10': template inst+10
// CHECK:STDOUT: 'inst+12': template inst+8
// CHECK:STDOUT: 'inst+13': symbolic 1
// CHECK:STDOUT: 'inst+14': symbolic 3
// CHECK:STDOUT: 'inst+16': template inst+18
// CHECK:STDOUT: 'inst+17': template inst+17
// CHECK:STDOUT: 'inst+18': template inst+18
// CHECK:STDOUT: 'inst+19': symbolic 4
// CHECK:STDOUT: 'inst+26': template inst+27
// CHECK:STDOUT: 'inst+27': template inst+27
// CHECK:STDOUT: 'inst+28': template inst+27
// CHECK:STDOUT: 'inst+0': templateConstant(inst+0)
// CHECK:STDOUT: 'inst+2': symbolicConstant2
// CHECK:STDOUT: 'inst+3': symbolicConstant0
// CHECK:STDOUT: 'inst+4': symbolicConstant2
// CHECK:STDOUT: 'inst+7': symbolicConstant2
// CHECK:STDOUT: 'inst+8': templateConstant(inst+8)
// CHECK:STDOUT: 'inst+10': templateConstant(inst+10)
// CHECK:STDOUT: 'inst+12': templateConstant(inst+8)
// CHECK:STDOUT: 'inst+13': symbolicConstant1
// CHECK:STDOUT: 'inst+14': symbolicConstant3
// CHECK:STDOUT: 'inst+16': templateConstant(inst+18)
// CHECK:STDOUT: 'inst+17': templateConstant(inst+17)
// CHECK:STDOUT: 'inst+18': templateConstant(inst+18)
// CHECK:STDOUT: 'inst+19': symbolicConstant4
// CHECK:STDOUT: 'inst+26': templateConstant(inst+27)
// CHECK:STDOUT: 'inst+27': templateConstant(inst+27)
// CHECK:STDOUT: 'inst+28': templateConstant(inst+27)
// CHECK:STDOUT: symbolic_constants:
// CHECK:STDOUT: symbolicConstant0: {inst: inst+3, generic: generic<invalid>, index: genericInst<invalid>}
// CHECK:STDOUT: symbolicConstant1: {inst: inst+13, generic: generic<invalid>, index: genericInst<invalid>}
// CHECK:STDOUT: symbolicConstant2: {inst: inst+3, generic: generic0, index: genericInstInDecl0}
// CHECK:STDOUT: symbolicConstant3: {inst: inst+13, generic: generic0, index: genericInstInDecl1}
// CHECK:STDOUT: symbolicConstant4: {inst: inst+19, generic: generic<invalid>, index: genericInst<invalid>}
// CHECK:STDOUT: inst_blocks:
// CHECK:STDOUT: empty: {}
// CHECK:STDOUT: exports:
+1 -1
View File
@@ -9,7 +9,7 @@
// SET-CHECK-SUBSET
// CHECK:STDERR: Node Push 0: FunctionIntroducer -> <none>
// CHECK:STDERR: AddPlaceholderInst: {kind: FunctionDecl, arg0: function<invalid>, arg1: empty}
// CHECK:STDERR: ReplaceInst: inst+{{[0-9]+}} -> {kind: FunctionDecl, arg0: function{{[0-9]+}}, arg1: empty, type: type{{[0-9]+}}}
// CHECK:STDERR: ReplaceInst: inst+{{[0-9]+}} -> {kind: FunctionDecl, arg0: function{{[0-9]+}}, arg1: empty, type: type(inst+{{[0-9]+}})}
// CHECK:STDERR: inst_block_stack_ Push 1
// CHECK:STDERR: AddInst: {kind: Return}
// CHECK:STDERR: inst_block_stack_ Pop 1: block{{[0-9]+}}
+20 -10
View File
@@ -35,12 +35,12 @@ FileContext::FileContext(llvm::LLVMContext& llvm_context,
auto FileContext::Run() -> std::unique_ptr<llvm::Module> {
CARBON_CHECK(llvm_module_) << "Run can only be called once.";
// Lower all types that were required to be complete. Note that this may
// leave some entries in `types_` null, if those types were mentioned but not
// used.
types_.resize(sem_ir_->types().size());
for (auto type_id : sem_ir_->complete_types()) {
types_[type_id.index] = BuildType(sem_ir_->types().GetInstId(type_id));
// Lower all types that were required to be complete.
types_.resize(sem_ir_->insts().size());
for (auto type_id : sem_ir_->types().complete_types()) {
if (type_id.index >= 0) {
types_[type_id.index] = BuildType(sem_ir_->types().GetInstId(type_id));
}
}
// Lower function declarations.
@@ -122,9 +122,11 @@ auto FileContext::BuildFunctionDecl(SemIR::FunctionId function_id)
-> llvm::Function* {
const auto& function = sem_ir().functions().Get(function_id);
// Don't lower associated functions.
// TODO: We shouldn't lower any function that has generic parameters.
if (sem_ir().insts().Is<SemIR::InterfaceDecl>(
// Don't lower generic functions or associated functions.
// TODO: Associated functions have `Self` in scope so should be treated as
// generic functions.
if (function.generic_id.is_valid() ||
sem_ir().insts().Is<SemIR::InterfaceDecl>(
sem_ir().name_scopes().Get(function.parent_scope_id).inst_id)) {
return nullptr;
}
@@ -240,6 +242,12 @@ auto FileContext::BuildFunctionDefinition(SemIR::FunctionId function_id)
}
llvm::Function* llvm_function = GetFunction(function_id);
if (!llvm_function) {
// We chose not to lower this function at all, for example because it's a
// generic function.
return;
}
FunctionContext function_lowering(*this, llvm_function, vlog_stream_);
const bool has_return_slot = function.has_return_slot();
@@ -320,8 +328,10 @@ static auto BuildTypeForInst(FileContext& context, SemIR::BuiltinInst inst)
-> llvm::Type* {
switch (inst.builtin_inst_kind) {
case SemIR::BuiltinInstKind::Invalid:
case SemIR::BuiltinInstKind::Error:
CARBON_FATAL() << "Unexpected builtin type in lowering.";
case SemIR::BuiltinInstKind::Error:
// This is a complete type but uses of it should never be lowered.
return nullptr;
case SemIR::BuiltinInstKind::TypeType:
return context.GetTypeType();
case SemIR::BuiltinInstKind::FloatType:
-3
View File
@@ -33,9 +33,6 @@ class FileContext {
// Returns a lowered type for the given type_id.
auto GetType(SemIR::TypeId type_id) -> llvm::Type* {
// InvalidType should not be passed in.
if (type_id == SemIR::TypeId::TypeType) {
return GetTypeType();
}
CARBON_CHECK(type_id.index >= 0) << type_id;
CARBON_CHECK(types_[type_id.index]) << "Missing type " << type_id;
return types_[type_id.index];
@@ -15,13 +15,3 @@ fn F(T:! type) {
// CHECK:STDOUT: ; ModuleID = 'type_param.carbon'
// CHECK:STDOUT: source_filename = "type_param.carbon"
// CHECK:STDOUT:
// CHECK:STDOUT: %type = type {}
// CHECK:STDOUT:
// CHECK:STDOUT: define void @F(%type %T) {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %p.var = alloca ptr, align 8
// CHECK:STDOUT: %.loc13_15 = load ptr, ptr %p.var, align 8
// CHECK:STDOUT: %.loc13_14.2 = load {}, ptr %.loc13_15, align 1
// CHECK:STDOUT: ret void
// CHECK:STDOUT: }
+13 -1
View File
@@ -6,6 +6,7 @@
#define CARBON_TOOLCHAIN_SEM_IR_CONSTANT_H_
#include "common/map.h"
#include "toolchain/base/yaml.h"
#include "toolchain/sem_ir/ids.h"
#include "toolchain/sem_ir/inst.h"
@@ -13,7 +14,7 @@ namespace Carbon::SemIR {
// Information about a symbolic constant value. These are indexed by
// `ConstantId`s for which `is_symbolic` is true.
struct SymbolicConstant {
struct SymbolicConstant : Printable<SymbolicConstant> {
// The constant instruction that defines the value of this symbolic constant.
InstId inst_id;
// The enclosing generic. If this is invalid, then this is an abstract
@@ -23,6 +24,11 @@ struct SymbolicConstant {
// The index of this symbolic constant within the generic's list of symbolic
// constants, or invalid if `generic_id` is invalid.
GenericInstIndex index;
auto Print(llvm::raw_ostream& out) const -> void {
out << "{inst: " << inst_id << ", generic: " << generic_id
<< ", index: " << index << "}";
}
};
// Provides a ValueStore wrapper for tracking the constant values of
@@ -109,6 +115,12 @@ class ConstantValueStore {
// NotConstant.
auto array_ref() const -> llvm::ArrayRef<ConstantId> { return values_; }
// Returns the symbolic constants mapping as an ArrayRef whose keys are
// symbolic indexes of constants.
auto symbolic_constants() const -> llvm::ArrayRef<SymbolicConstant> {
return symbolic_constants_;
}
private:
const ConstantId default_;
+20 -5
View File
@@ -58,8 +58,8 @@ auto ValueRepr::Print(llvm::raw_ostream& out) const -> void {
out << ", type: " << type_id << "}";
}
auto TypeInfo::Print(llvm::raw_ostream& out) const -> void {
out << "{constant: " << constant_id << ", value_rep: " << value_repr << "}";
auto CompleteTypeInfo::Print(llvm::raw_ostream& out) const -> void {
out << "{value_rep: " << value_repr << "}";
}
File::File(CheckIRId check_ir_id, SharedValueStores& value_stores,
@@ -72,6 +72,12 @@ File::File(CheckIRId check_ir_id, SharedValueStores& value_stores,
constant_values_(ConstantId::NotConstant),
inst_blocks_(allocator_),
constants_(*this, allocator_) {
// `type` and the error type are both complete types.
types_.SetValueRepr(TypeId::TypeType,
{.kind = ValueRepr::Copy, .type_id = TypeId::TypeType});
types_.SetValueRepr(TypeId::Error,
{.kind = ValueRepr::Copy, .type_id = TypeId::Error});
insts_.Reserve(BuiltinInstKind::ValidCount);
// Error uses a self-referential type so that it's not accidentally treated as
// a normal type. Every other builtin is a type, including the
@@ -167,6 +173,16 @@ auto File::OutputYaml(bool include_builtins) const -> Yaml::OutputMapping {
}
}
}));
map.Add(
"symbolic_constants",
Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) {
for (const auto& [i, symbolic] :
llvm::enumerate(constant_values().symbolic_constants())) {
map.Add(
PrintToString(ConstantId::ForSymbolicConstantIndex(i)),
Yaml::OutputScalar(symbolic));
}
}));
map.Add("inst_blocks", inst_blocks_.OutputYaml());
}));
});
@@ -194,8 +210,6 @@ auto File::CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
mem_usage.Collect(MemUsage::ConcatLabel(label, "inst_blocks_"), inst_blocks_);
mem_usage.Collect(MemUsage::ConcatLabel(label, "constants_"), constants_);
mem_usage.Collect(MemUsage::ConcatLabel(label, "types_"), types_);
mem_usage.Add(MemUsage::ConcatLabel(label, "complete_types_"),
complete_types_);
}
// Map an instruction kind representing a type into an integer describing the
@@ -706,7 +720,8 @@ auto GetInitRepr(const File& file, TypeId type_id) -> InitRepr {
case ValueRepr::Unknown:
CARBON_FATAL()
<< "Attempting to perform initialization of incomplete type";
<< "Attempting to perform initialization of incomplete type "
<< file.types().GetAsInst(type_id);
}
}
-23
View File
@@ -64,19 +64,6 @@ class File : public Printable<File> {
.getZExtValue();
}
// Marks a type as complete, and sets its value representation.
auto CompleteType(TypeId object_type_id, ValueRepr value_repr) -> void {
if (object_type_id.index < 0) {
// We already know our builtin types are complete.
return;
}
CARBON_CHECK(types().Get(object_type_id).value_repr.kind ==
ValueRepr::Unknown)
<< "Type " << object_type_id << " completed more than once";
types().Get(object_type_id).value_repr = value_repr;
complete_types_.push_back(object_type_id);
}
// Gets the pointee type of the given type, which must be a pointer type.
auto GetPointeeType(TypeId pointer_id) const -> TypeId {
return types().GetAs<PointerType>(pointer_id).pointee_id;
@@ -173,13 +160,6 @@ class File : public Printable<File> {
auto constants() -> ConstantStore& { return constants_; }
auto constants() const -> const ConstantStore& { return constants_; }
// A list of types that were completed in this file, in the order in which
// they were completed. Earlier types in this list cannot contain instances of
// later types.
auto complete_types() const -> llvm::ArrayRef<TypeId> {
return complete_types_;
}
auto top_inst_block_id() const -> InstBlockId { return top_inst_block_id_; }
auto set_top_inst_block_id(InstBlockId block_id) -> void {
top_inst_block_id_ = block_id;
@@ -261,9 +241,6 @@ class File : public Printable<File> {
// Descriptions of types used in this file.
TypeStore types_ = TypeStore(&insts_, &constant_values_);
// Types that were completed in this file.
llvm::SmallVector<TypeId> complete_types_;
};
// The expression category of a sem_ir instruction. See /docs/design/values.md
+30 -7
View File
@@ -141,13 +141,23 @@ struct ConstantId : public IdBase, public Printable<ConstantId> {
return index >= 0;
}
auto Print(llvm::raw_ostream& out) const -> void {
// Prints this ID to the given output stream. `disambiguate` indicates whether
// template constants should be wrapped with "templateConstant(...)" so that
// they aren't printed the same as an InstId. This can be set to false if
// there is no risk of ambiguity.
auto Print(llvm::raw_ostream& out, bool disambiguate = true) const -> void {
if (!is_valid()) {
IdBase::Print(out);
} else if (is_template()) {
out << "template " << template_inst_id();
if (disambiguate) {
out << "templateConstant(";
}
out << template_inst_id();
if (disambiguate) {
out << ")";
}
} else if (is_symbolic()) {
out << "symbolic " << symbolic_index();
out << "symbolicConstant" << symbolic_index();
} else {
out << "runtime";
}
@@ -615,7 +625,6 @@ constexpr InstBlockId InstBlockId::Unreachable = InstBlockId(InvalidIndex - 1);
// The ID of a type.
struct TypeId : public IdBase, public Printable<TypeId> {
using ValueType = TypeInfo;
// StringifyType() is used for diagnostics.
using DiagnosticType = DiagnosticTypeInfo<std::string>;
@@ -629,6 +638,17 @@ struct TypeId : public IdBase, public Printable<TypeId> {
static const TypeId Invalid;
using IdBase::IdBase;
// Returns the ID of the type corresponding to the constant `const_id`, which
// must be of type `type`. As an exception, the type `Error` is of type
// `Error`.
static constexpr auto ForTypeConstant(ConstantId const_id) -> TypeId {
return TypeId(const_id.index);
}
// Returns the constant ID that defines the type.
auto AsConstantId() const -> ConstantId { return ConstantId(index); }
auto Print(llvm::raw_ostream& out) const -> void {
out << "type";
if (*this == TypeType) {
@@ -636,13 +656,16 @@ struct TypeId : public IdBase, public Printable<TypeId> {
} else if (*this == Error) {
out << "Error";
} else {
IdBase::Print(out);
out << "(";
AsConstantId().Print(out, /*disambiguate=*/false);
out << ")";
}
}
};
constexpr TypeId TypeId::TypeType = TypeId(InvalidIndex - 2);
constexpr TypeId TypeId::Error = TypeId(InvalidIndex - 1);
constexpr TypeId TypeId::TypeType = TypeId::ForTypeConstant(
ConstantId::ForTemplateConstant(InstId::BuiltinTypeType));
constexpr TypeId TypeId::Error = TypeId::ForTypeConstant(ConstantId::Error);
constexpr TypeId TypeId::Invalid = TypeId(InvalidIndex);
// The ID of a type block.
+45 -19
View File
@@ -14,23 +14,18 @@
namespace Carbon::SemIR {
// Provides a ValueStore wrapper with an API specific to types.
class TypeStore : public ValueStore<TypeId> {
class TypeStore : public Yaml::Printable<TypeStore> {
public:
explicit TypeStore(InstStore* insts, ConstantValueStore* constants)
: insts_(insts), constants_(constants) {}
// Returns the ID of the constant used to define the specified type.
auto GetConstantId(TypeId type_id) const -> ConstantId {
if (type_id == TypeId::TypeType) {
return ConstantId::ForTemplateConstant(InstId::BuiltinTypeType);
} else if (type_id == TypeId::Error) {
return ConstantId::Error;
} else if (!type_id.is_valid()) {
// TODO: Can we CHECK-fail on this?
if (!type_id.is_valid()) {
// TODO: Investigate replacing this with a CHECK or returning Invalid.
return ConstantId::NotConstant;
} else {
return Get(type_id).constant_id;
}
return type_id.AsConstantId();
}
// Returns the ID of the instruction used to define the specified type.
@@ -58,7 +53,7 @@ class TypeStore : public ValueStore<TypeId> {
return GetAsInst(type_id).As<InstT>();
} else {
// The type is not a builtin, so no need to check for special values.
auto inst_id = constants_->GetInstId(Get(type_id).constant_id);
auto inst_id = constants_->GetInstId(GetConstantId(type_id));
return insts_->GetAs<InstT>(inst_id);
}
}
@@ -80,17 +75,27 @@ class TypeStore : public ValueStore<TypeId> {
// Gets the value representation to use for a type. This returns an
// invalid type if the given type is not complete.
auto GetValueRepr(TypeId type_id) const -> ValueRepr {
if (type_id.index < 0) {
// TypeType and InvalidType are their own value representation.
return {.kind = ValueRepr::Copy, .type_id = type_id};
if (auto type_info = complete_type_info_.Lookup(type_id)) {
return type_info.value().value_repr;
}
return Get(type_id).value_repr;
return {.kind = ValueRepr::Unknown};
}
// Sets the value representation associated with a type.
auto SetValueRepr(TypeId type_id, ValueRepr value_repr) -> void {
CARBON_CHECK(value_repr.kind != ValueRepr::Unknown);
auto insert_info =
complete_type_info_.Insert(type_id, {.value_repr = value_repr});
CARBON_CHECK(insert_info.is_inserted())
<< "Type " << type_id << " completed more than once";
complete_types_.push_back(type_id);
CARBON_CHECK(IsComplete(type_id));
}
// Determines whether the given type is known to be complete. This does not
// determine whether the type could be completed, only whether it has been.
auto IsComplete(TypeId type_id) const -> bool {
return GetValueRepr(type_id).kind != ValueRepr::Unknown;
return complete_type_info_.Contains(type_id);
}
// Determines whether the given type is a signed integer type.
@@ -103,14 +108,35 @@ class TypeStore : public ValueStore<TypeId> {
return int_type && int_type->int_kind.is_signed();
}
// This has no direct storage, so there's no interesting memory usage to
// collect.
auto CollectMemUsage(MemUsage& /*mem_usage*/, llvm::StringRef /*label*/) const
-> void {}
// Returns a list of types that were completed in this file, in the order in
// which they were completed. Earlier types in this list cannot contain
// instances of later types.
auto complete_types() const -> llvm::ArrayRef<TypeId> {
return complete_types_;
}
auto OutputYaml() const -> Yaml::OutputMapping {
return Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) {
for (auto type_id : complete_types_) {
map.Add(PrintToString(type_id),
Yaml::OutputScalar(GetValueRepr(type_id)));
}
});
}
auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
-> void {
mem_usage.Add(MemUsage::ConcatLabel(label, "complete_type_info_"),
complete_type_info_);
mem_usage.Add(MemUsage::ConcatLabel(label, "complete_types_"),
complete_types_);
}
private:
InstStore* insts_;
ConstantValueStore* constants_;
Map<TypeId, CompleteTypeInfo> complete_type_info_;
llvm::SmallVector<TypeId> complete_types_;
};
} // namespace Carbon::SemIR
+2 -4
View File
@@ -62,12 +62,10 @@ struct ValueRepr : public Printable<ValueRepr> {
TypeId type_id = TypeId::Invalid;
};
// Information stored about a TypeId.
struct TypeInfo : public Printable<TypeInfo> {
// Information stored about a TypeId corresponding to a complete type.
struct CompleteTypeInfo : public Printable<CompleteTypeInfo> {
auto Print(llvm::raw_ostream& out) const -> void;
// The constant type value that defines this type.
ConstantId constant_id;
// The value representation for this type. Will be `Unknown` if the type is
// not complete.
ValueRepr value_repr = ValueRepr();
+4 -5
View File
@@ -49,12 +49,10 @@ TEST(SemIRTest, YAML) {
auto type_block_id = Yaml::Scalar(MatchesRegex(R"(type_block\d+)"));
auto inst_id = Yaml::Scalar(MatchesRegex(R"(inst\+\d+)"));
auto constant_id =
Yaml::Scalar(MatchesRegex(R"((template|symbolic) inst(\w+|\+\d+))"));
Yaml::Scalar(MatchesRegex(R"(templateConstant\(inst(\w+|\+\d+)\))"));
auto inst_builtin = Yaml::Scalar(MatchesRegex(R"(inst\w+)"));
auto type_id = Yaml::Scalar(MatchesRegex(R"(type\d+)"));
auto type_builtin = Pair(
type_id, Yaml::Mapping(ElementsAre(Pair("constant", constant_id),
Pair("value_rep", Yaml::Mapping(_)))));
auto type_id = Yaml::Scalar(MatchesRegex(R"(type(\w+|\(inst(\w+|\+\d+)\)))"));
auto type_builtin = Pair(type_id, Yaml::Mapping(_));
auto file = Yaml::Mapping(ElementsAre(
Pair("import_irs", Yaml::Mapping(SizeIs(1))),
@@ -87,6 +85,7 @@ TEST(SemIRTest, YAML) {
Pair("arg1", inst_id)))))))),
Pair("constant_values",
Yaml::Mapping(AllOf(Each(Pair(inst_id, constant_id))))),
Pair("symbolic_constants", Yaml::Mapping(SizeIs(0))),
// This production has only two instruction blocks.
Pair("inst_blocks",
Yaml::Mapping(ElementsAre(