Skip to content

Commit

Permalink
Compute specific constant values. (carbon-language#4128)
Browse files Browse the repository at this point in the history
When forming a specific (previously called a generic instance), evaluate
the eval block of the generic to determine the values of any constants
used in that specific. The majority of the work here is updating
eval.cpp so that it can use the results of prior evaluations in the same
block when computing later values.

Include the computed results in the formatted SemIR output.

---------

Co-authored-by: Jon Ross-Perkins <[email protected]>
  • Loading branch information
2 people authored and brymer-meneses committed Aug 15, 2024
1 parent 67b6fd3 commit d2f8972
Show file tree
Hide file tree
Showing 73 changed files with 1,429 additions and 272 deletions.
465 changes: 319 additions & 146 deletions toolchain/check/eval.cpp

Large diffs are not rendered by default.

10 changes: 8 additions & 2 deletions toolchain/check/eval.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,17 @@ namespace Carbon::Check {
// Determines the phase of the instruction `inst`, and returns its constant
// value if it has constant phase. If it has runtime phase, returns
// `SemIR::ConstantId::NotConstant`.
//
// TODO: Support symbolic phase.
auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst)
-> SemIR::ConstantId;

// Evaluates the eval block for a region of a specific. Produces a block
// containing the evaluated constant values of the instructions in the eval
// block.
auto TryEvalBlockForSpecific(Context& context,
SemIR::GenericInstanceId specific_id,
SemIR::GenericInstIndex::Region region)
-> SemIR::InstBlockId;

} // namespace Carbon::Check

#endif // CARBON_TOOLCHAIN_CHECK_EVAL_H_
30 changes: 23 additions & 7 deletions toolchain/check/generic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "toolchain/check/generic.h"

#include "common/map.h"
#include "toolchain/check/eval.h"
#include "toolchain/check/generic_region_stack.h"
#include "toolchain/check/subst.h"
#include "toolchain/sem_ir/ids.h"
Expand Down Expand Up @@ -130,8 +131,6 @@ static auto MakeGenericEvalBlock(Context& context, SemIR::GenericId generic_id,

Map<SemIR::InstId, SemIR::InstId> constants_in_generic;
// TODO: For the definition region, populate constants from the declaration.
// TODO: Add `BindSymbolicName` instructions for enclosing generics to the
// map.

// The work done in this loop might invalidate iterators into the generic
// region stack, but shouldn't add new dependent instructions to the current
Expand Down Expand Up @@ -194,6 +193,10 @@ auto FinishGenericDecl(Context& context, SemIR::InstId decl_id)
return SemIR::GenericId::Invalid;
}

// Build the new Generic object. Note that we intentionally do not hold a
// persistent reference to it throughout this function, because the `generics`
// collection can have items added to it by import resolution while we are
// building this generic.
auto bindings_id = context.inst_blocks().Add(all_bindings);
auto generic_id = context.generics().Add(
SemIR::Generic{.decl_id = decl_id,
Expand All @@ -203,12 +206,10 @@ auto FinishGenericDecl(Context& context, SemIR::InstId decl_id)
auto decl_block_id = MakeGenericEvalBlock(
context, generic_id, SemIR::GenericInstIndex::Region::Declaration);
context.generic_region_stack().Pop();
context.generics().Get(generic_id).decl_block_id = decl_block_id;

auto self_instance_id = MakeGenericSelfInstance(context, generic_id);

auto& generic_info = context.generics().Get(generic_id);
generic_info.decl_block_id = decl_block_id;
generic_info.self_instance_id = self_instance_id;
context.generics().Get(generic_id).self_instance_id = self_instance_id;
return generic_id;
}

Expand Down Expand Up @@ -238,7 +239,22 @@ auto MakeGenericInstance(Context& context, SemIR::GenericId generic_id,
SemIR::InstBlockId args_id)
-> SemIR::GenericInstanceId {
auto instance_id = context.generic_instances().GetOrAdd(generic_id, args_id);
// TODO: Perform substitution into the generic declaration if needed.

// TODO: Remove this once we import generics properly.
if (!generic_id.is_valid()) {
return instance_id;
}

// If this is the first time we've formed this instance, evaluate its decl
// block to form information about the instance.
if (!context.generic_instances().Get(instance_id).decl_block_id.is_valid()) {
auto decl_block_id = TryEvalBlockForSpecific(
context, instance_id, SemIR::GenericInstIndex::Region::Declaration);
// Note that TryEvalBlockForSpecific may reallocate the list of generic
// instances, so re-lookup the instance here.
context.generic_instances().Get(instance_id).decl_block_id = decl_block_id;
}

return instance_id;
}

Expand Down
5 changes: 5 additions & 0 deletions toolchain/check/testdata/array/generic_empty.carbon
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,8 @@ fn G(T:! type) {
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific file.%G.decl(constants.%T) {
// CHECK:STDOUT: declaration:
// CHECK:STDOUT: @G.%T => constants.%T
// CHECK:STDOUT: }
// CHECK:STDOUT:
19 changes: 11 additions & 8 deletions toolchain/check/testdata/basics/no_prelude/raw_ir.carbon
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fn Foo[T:! type](n: T) -> (T, ()) {
// CHECK:STDOUT: bind_name0: {name: name1, parent_scope: name_scope<invalid>, index: comp_time_bind0}
// CHECK:STDOUT: bind_name1: {name: name2, parent_scope: name_scope<invalid>, index: comp_time_bind<invalid>}
// CHECK:STDOUT: functions:
// CHECK:STDOUT: function0: {name: name0, parent_scope: name_scope0, param_refs: block5, return_storage: inst+15, return_slot: present, body: [block11]}
// CHECK:STDOUT: function0: {name: name0, parent_scope: name_scope0, param_refs: block5, return_storage: inst+15, return_slot: present, body: [block12]}
// CHECK:STDOUT: classes: {}
// CHECK:STDOUT: generics:
// CHECK:STDOUT: generic0: {decl: inst+16, bindings: block8}
Expand Down Expand Up @@ -75,14 +75,14 @@ fn Foo[T:! type](n: T) -> (T, ()) {
// CHECK:STDOUT: 'inst+19': {kind: PointerType, arg0: type4, type: typeTypeType}
// CHECK:STDOUT: 'inst+20': {kind: NameRef, arg0: name2, arg1: inst+6, type: type1}
// CHECK:STDOUT: 'inst+21': {kind: TupleLiteral, arg0: empty, type: type2}
// CHECK:STDOUT: 'inst+22': {kind: TupleLiteral, arg0: block12, type: type4}
// CHECK:STDOUT: 'inst+22': {kind: TupleLiteral, arg0: block13, type: type4}
// CHECK:STDOUT: 'inst+23': {kind: TupleAccess, arg0: inst+15, arg1: element0, type: type1}
// CHECK:STDOUT: 'inst+24': {kind: InitializeFrom, arg0: inst+20, arg1: inst+23, type: type1}
// 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: block14, 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: block13, arg1: inst+15, type: type4}
// CHECK:STDOUT: 'inst+29': {kind: TupleInit, arg0: block14, arg1: inst+15, type: type4}
// CHECK:STDOUT: 'inst+30': {kind: Converted, arg0: inst+22, arg1: inst+29, type: type4}
// CHECK:STDOUT: 'inst+31': {kind: ReturnExpr, arg0: inst+30, arg1: inst+15}
// CHECK:STDOUT: constant_values:
Expand Down Expand Up @@ -136,6 +136,9 @@ fn Foo[T:! type](n: T) -> (T, ()) {
// CHECK:STDOUT: block10:
// CHECK:STDOUT: 0: inst+3
// CHECK:STDOUT: block11:
// CHECK:STDOUT: 0: inst+3
// CHECK:STDOUT: 1: inst+13
// CHECK:STDOUT: block12:
// CHECK:STDOUT: 0: inst+20
// CHECK:STDOUT: 1: inst+21
// CHECK:STDOUT: 2: inst+22
Expand All @@ -147,14 +150,14 @@ fn Foo[T:! type](n: T) -> (T, ()) {
// CHECK:STDOUT: 8: inst+29
// CHECK:STDOUT: 9: inst+30
// CHECK:STDOUT: 10: inst+31
// CHECK:STDOUT: block12:
// CHECK:STDOUT: block13:
// CHECK:STDOUT: 0: inst+20
// CHECK:STDOUT: 1: inst+21
// CHECK:STDOUT: block13:
// CHECK:STDOUT: block14:
// CHECK:STDOUT: 0: inst+24
// CHECK:STDOUT: 1: inst+28
// CHECK:STDOUT: block14: {}
// CHECK:STDOUT: block15:
// CHECK:STDOUT: block15: {}
// CHECK:STDOUT: block16:
// CHECK:STDOUT: 0: inst+0
// CHECK:STDOUT: 1: inst+16
// CHECK:STDOUT: ...
6 changes: 6 additions & 0 deletions toolchain/check/testdata/builtins/int/make_type_signed.carbon
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,12 @@ var m: Int(1000000000);
// CHECK:STDOUT: return %x.ref
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific file.%Symbolic.decl(constants.%N) {
// CHECK:STDOUT: declaration:
// CHECK:STDOUT: @Symbolic.%N => constants.%N
// CHECK:STDOUT: file.%int.make_type_signed.loc14_28 => constants.%.6
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_zero_size.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,12 @@ var m: UInt(1000000000);
// CHECK:STDOUT: return %x.ref
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific file.%Symbolic.decl(constants.%N) {
// CHECK:STDOUT: declaration:
// CHECK:STDOUT: @Symbolic.%N => constants.%N
// CHECK:STDOUT: file.%int.make_type_unsigned.loc14_29 => constants.%.6
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_zero_size.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
Expand Down
20 changes: 18 additions & 2 deletions toolchain/check/testdata/class/fail_generic_method.carbon
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ fn Class(N:! i32).F[self: Self](n: T) {}
// CHECK:STDOUT: %Class.type: type = generic_class_type @Class [template]
// CHECK:STDOUT: %.1: type = tuple_type () [template]
// CHECK:STDOUT: %Class.1: %Class.type = struct_value () [template]
// CHECK:STDOUT: %Class.2: type = class_type @Class, (%T) [symbolic]
// CHECK:STDOUT: %Class.2: type = class_type @Class, file.%Class.decl(%T) [symbolic]
// CHECK:STDOUT: %.2: type = unbound_element_type %Class.2, %T [symbolic]
// CHECK:STDOUT: %F.type: type = fn_type @F [template]
// CHECK:STDOUT: %F: %F.type = struct_value () [template]
Expand Down Expand Up @@ -85,7 +85,7 @@ fn Class(N:! i32).F[self: Self](n: T) {}
// CHECK:STDOUT: %T.ref.loc12: type = name_ref T, file.%T.loc11_13.2 [symbolic = constants.%T]
// CHECK:STDOUT: %.loc12: %.2 = field_decl a, element0 [template]
// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] {
// CHECK:STDOUT: %.loc13: type = specific_constant constants.%Class.2, (constants.%T) [symbolic = %.loc13 (constants.%Class.2)]
// CHECK:STDOUT: %.loc13: type = specific_constant constants.%Class.2, file.%Class.decl(constants.%T) [symbolic = %.loc13 (constants.%Class.2)]
// CHECK:STDOUT: %Self.ref: type = name_ref Self, %.loc13 [symbolic = %.loc13 (constants.%Class.2)]
// CHECK:STDOUT: %self.loc13_8.1: @Class.%.loc13 (%Class.2) = param self
// CHECK:STDOUT: %self.loc13_8.2: @Class.%.loc13 (%Class.2) = bind_name self, %self.loc13_8.1
Expand All @@ -111,3 +111,19 @@ fn Class(N:! i32).F[self: Self](n: T) {}
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific file.%Class.decl(constants.%T) {
// CHECK:STDOUT: declaration:
// CHECK:STDOUT: file.%T.loc11_13.2 => constants.%T
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @Class.%F.decl(constants.%T) {
// CHECK:STDOUT: declaration:
// CHECK:STDOUT: @Class.%.loc13 => constants.%Class.2
// CHECK:STDOUT: @Class.%T.ref.loc13 => constants.%T
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific file.%.decl(constants.%N) {
// CHECK:STDOUT: declaration:
// CHECK:STDOUT: file.%N.loc32_10.2 => constants.%N
// CHECK:STDOUT: }
// CHECK:STDOUT:
25 changes: 22 additions & 3 deletions toolchain/check/testdata/class/generic/basic.carbon
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class Class(T:! type) {
// CHECK:STDOUT: %Class.type: type = generic_class_type @Class [template]
// CHECK:STDOUT: %.1: type = tuple_type () [template]
// CHECK:STDOUT: %Class.1: %Class.type = struct_value () [template]
// CHECK:STDOUT: %Class.2: type = class_type @Class, (%T) [symbolic]
// CHECK:STDOUT: %Class.2: type = class_type @Class, file.%Class.decl(%T) [symbolic]
// CHECK:STDOUT: %.2: type = ptr_type %Class.2 [symbolic]
// CHECK:STDOUT: %.3: type = ptr_type %T [symbolic]
// CHECK:STDOUT: %GetAddr.type: type = fn_type @GetAddr [template]
Expand Down Expand Up @@ -57,7 +57,7 @@ class Class(T:! type) {
// CHECK:STDOUT: class @Class
// CHECK:STDOUT: generic [file.%T.loc11_13.2: type] {
// CHECK:STDOUT: %GetAddr.decl: %GetAddr.type = fn_decl @GetAddr [template = constants.%GetAddr] {
// CHECK:STDOUT: %.loc12_25: type = specific_constant constants.%Class.2, (constants.%T) [symbolic = %.loc12_25 (constants.%Class.2)]
// CHECK:STDOUT: %.loc12_25: type = specific_constant constants.%Class.2, file.%Class.decl(constants.%T) [symbolic = %.loc12_25 (constants.%Class.2)]
// CHECK:STDOUT: %Self.ref.loc12: type = name_ref Self, %.loc12_25 [symbolic = %.loc12_25 (constants.%Class.2)]
// CHECK:STDOUT: %.loc12_29: type = ptr_type %Class.2 [symbolic = %.loc12_29 (constants.%.2)]
// CHECK:STDOUT: %self.loc12_19.1: @Class.%.loc12_29 (%.2) = param self
Expand All @@ -68,7 +68,7 @@ class Class(T:! type) {
// CHECK:STDOUT: %return.var.loc12: ref %.3 = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %GetValue.decl: %GetValue.type = fn_decl @GetValue [template = constants.%GetValue] {
// CHECK:STDOUT: %.loc17: type = specific_constant constants.%Class.2, (constants.%T) [symbolic = %.loc17 (constants.%Class.2)]
// CHECK:STDOUT: %.loc17: type = specific_constant constants.%Class.2, file.%Class.decl(constants.%T) [symbolic = %.loc17 (constants.%Class.2)]
// CHECK:STDOUT: %Self.ref.loc17: type = name_ref Self, %.loc17 [symbolic = %.loc17 (constants.%Class.2)]
// CHECK:STDOUT: %self.loc17_15.1: @Class.%.loc17 (%Class.2) = param self
// CHECK:STDOUT: %self.loc17_15.2: @Class.%.loc17 (%Class.2) = bind_name self, %self.loc17_15.1
Expand Down Expand Up @@ -106,3 +106,22 @@ class Class(T:! type) {
// CHECK:STDOUT: return %.loc18_16.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific file.%Class.decl(constants.%T) {
// CHECK:STDOUT: declaration:
// CHECK:STDOUT: file.%T.loc11_13.2 => constants.%T
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @Class.%GetAddr.decl(constants.%T) {
// CHECK:STDOUT: declaration:
// CHECK:STDOUT: @Class.%.loc12_25 => constants.%Class.2
// CHECK:STDOUT: @Class.%.loc12_29 => constants.%.2
// CHECK:STDOUT: @Class.%T.ref.loc12 => constants.%T
// CHECK:STDOUT: @Class.%.loc12_38 => constants.%.3
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @Class.%GetValue.decl(constants.%T) {
// CHECK:STDOUT: declaration:
// CHECK:STDOUT: @Class.%.loc17 => constants.%Class.2
// CHECK:STDOUT: @Class.%T.ref.loc17 => constants.%T
// CHECK:STDOUT: }
// CHECK:STDOUT:
48 changes: 42 additions & 6 deletions toolchain/check/testdata/class/generic/call.carbon
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,14 @@ var a: Class(5, i32*);
// CHECK:STDOUT: %N: i32 = bind_symbolic_name N 1 [symbolic]
// CHECK:STDOUT: %Class.type: type = generic_class_type @Class [template]
// CHECK:STDOUT: %Class.1: %Class.type = struct_value () [template]
// CHECK:STDOUT: %Class.2: type = class_type @Class, (%T, %N) [symbolic]
// CHECK:STDOUT: %Class.2: type = class_type @Class, file.%Class.decl(%T, %N) [symbolic]
// CHECK:STDOUT: %.2: type = struct_type {} [template]
// CHECK:STDOUT: %.3: type = ptr_type i32 [template]
// CHECK:STDOUT: %.4: i32 = int_literal 5 [template]
// CHECK:STDOUT: %Class.3: type = class_type @Class, (%.3, %.4) [template]
// CHECK:STDOUT: %Class.3: type = class_type @Class, file.%Class.decl(%.3, %.4) [template]
// CHECK:STDOUT: %.5: type = ptr_type %.2 [template]
// CHECK:STDOUT: %.6: i32 = int_literal 0 [template]
// CHECK:STDOUT: %Class.4: type = class_type @Class, (%.1, %.6) [template]
// CHECK:STDOUT: %Class.4: type = class_type @Class, file.%Class.decl(%.1, %.6) [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
Expand Down Expand Up @@ -136,6 +136,24 @@ var a: Class(5, i32*);
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32";
// CHECK:STDOUT:
// CHECK:STDOUT: specific file.%Class.decl(constants.%T, constants.%N) {
// CHECK:STDOUT: declaration:
// CHECK:STDOUT: file.%T.loc4_13.2 => constants.%T
// CHECK:STDOUT: file.%N.loc4_23.2 => constants.%N
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific file.%Class.decl(constants.%.3, constants.%.4) {
// CHECK:STDOUT: declaration:
// CHECK:STDOUT: file.%T.loc4_13.2 => constants.%.3
// CHECK:STDOUT: file.%N.loc4_23.2 => constants.%.4
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific file.%Class.decl(constants.%.1, constants.%.6) {
// CHECK:STDOUT: declaration:
// CHECK:STDOUT: file.%T.loc4_13.2 => constants.%.1
// CHECK:STDOUT: file.%N.loc4_23.2 => constants.%.6
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_too_few.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
Expand All @@ -146,7 +164,7 @@ var a: Class(5, i32*);
// CHECK:STDOUT: %N: i32 = bind_symbolic_name N 1 [symbolic]
// CHECK:STDOUT: %Class.type: type = generic_class_type @Class [template]
// CHECK:STDOUT: %Class.1: %Class.type = struct_value () [template]
// CHECK:STDOUT: %Class.2: type = class_type @Class, (%T, %N) [symbolic]
// CHECK:STDOUT: %Class.2: type = class_type @Class, file.%Class.decl(%T, %N) [symbolic]
// CHECK:STDOUT: %.2: type = struct_type {} [template]
// CHECK:STDOUT: %.3: type = ptr_type i32 [template]
// CHECK:STDOUT: }
Expand Down Expand Up @@ -193,6 +211,12 @@ var a: Class(5, i32*);
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32";
// CHECK:STDOUT:
// CHECK:STDOUT: specific file.%Class.decl(constants.%T, constants.%N) {
// CHECK:STDOUT: declaration:
// CHECK:STDOUT: file.%T.loc4_13.2 => constants.%T
// CHECK:STDOUT: file.%N.loc4_23.2 => constants.%N
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_too_many.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
Expand All @@ -203,7 +227,7 @@ var a: Class(5, i32*);
// CHECK:STDOUT: %N: i32 = bind_symbolic_name N 1 [symbolic]
// CHECK:STDOUT: %Class.type: type = generic_class_type @Class [template]
// CHECK:STDOUT: %Class.1: %Class.type = struct_value () [template]
// CHECK:STDOUT: %Class.2: type = class_type @Class, (%T, %N) [symbolic]
// CHECK:STDOUT: %Class.2: type = class_type @Class, file.%Class.decl(%T, %N) [symbolic]
// CHECK:STDOUT: %.2: type = struct_type {} [template]
// CHECK:STDOUT: %.3: type = ptr_type i32 [template]
// CHECK:STDOUT: %.4: i32 = int_literal 1 [template]
Expand Down Expand Up @@ -254,6 +278,12 @@ var a: Class(5, i32*);
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32";
// CHECK:STDOUT:
// CHECK:STDOUT: specific file.%Class.decl(constants.%T, constants.%N) {
// CHECK:STDOUT: declaration:
// CHECK:STDOUT: file.%T.loc4_13.2 => constants.%T
// CHECK:STDOUT: file.%N.loc4_23.2 => constants.%N
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_no_conversion.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
Expand All @@ -264,7 +294,7 @@ var a: Class(5, i32*);
// CHECK:STDOUT: %N: i32 = bind_symbolic_name N 1 [symbolic]
// CHECK:STDOUT: %Class.type: type = generic_class_type @Class [template]
// CHECK:STDOUT: %Class.1: %Class.type = struct_value () [template]
// CHECK:STDOUT: %Class.2: type = class_type @Class, (%T, %N) [symbolic]
// CHECK:STDOUT: %Class.2: type = class_type @Class, file.%Class.decl(%T, %N) [symbolic]
// CHECK:STDOUT: %.2: type = struct_type {} [template]
// CHECK:STDOUT: %.3: i32 = int_literal 5 [template]
// CHECK:STDOUT: %.4: type = ptr_type i32 [template]
Expand Down Expand Up @@ -313,3 +343,9 @@ var a: Class(5, i32*);
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32";
// CHECK:STDOUT:
// CHECK:STDOUT: specific file.%Class.decl(constants.%T, constants.%N) {
// CHECK:STDOUT: declaration:
// CHECK:STDOUT: file.%T.loc4_13.2 => constants.%T
// CHECK:STDOUT: file.%N.loc4_23.2 => constants.%N
// CHECK:STDOUT: }
// CHECK:STDOUT:
Loading

0 comments on commit d2f8972

Please sign in to comment.