Rebuild all constants in the eval block. (#4155)

Instead of reusing instructions from the generic entity in the eval
block, rebuild constants in the same way we rebuild types. The previous
attempt to not rebuild these constants assumed that every constant used
in a generic would be built in that generic, and not referenced directly
or referenced from some enclosing scope, which isn't true in practice
and is a fragile assumption in any case.

We could add back some reuse of instructions from the generic -- if we
happen to see the right instruction to build a constant, we could
opportunistically reuse it -- but given the complexity added by doing
so, I'm not pursuing that here.

Now that the eval block for a generic consists of instructions uniquely
owned by that generic, rather than often being shared with another
entity, include the generic in the formatted SemIR output. I'm using the
same scope name for the generic object itself as for the parameterized
class / function / interface, because there are very frequently
references between them and this keeps the IR simpler and more readable,
and avoids needing to invent a second name for the scope.
This commit is contained in:
Richard Smith
2024-07-23 21:51:08 +00:00
committed by GitHub
parent db022658c6
commit fc8e686607
96 changed files with 3038 additions and 2385 deletions
+112 -67
View File
@@ -21,6 +21,7 @@ class Class(T:! type) {
var k: T;
}
class Declaration(T:! type);
// CHECK:STDOUT: --- basic.carbon
// CHECK:STDOUT:
@@ -29,7 +30,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, file.%Class.decl(%T) [symbolic]
// CHECK:STDOUT: %Class.2: type = class_type @Class, @Class(%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]
@@ -39,12 +40,16 @@ class Class(T:! type) {
// CHECK:STDOUT: %.4: type = unbound_element_type %Class.2, %T [symbolic]
// CHECK:STDOUT: %.5: type = struct_type {.k: %T} [symbolic]
// CHECK:STDOUT: %.6: type = ptr_type %.5 [symbolic]
// CHECK:STDOUT: %Declaration.type: type = generic_class_type @Declaration [template]
// CHECK:STDOUT: %Declaration.1: %Declaration.type = struct_value () [template]
// CHECK:STDOUT: %Declaration.2: type = class_type @Declaration, @Declaration(%T) [symbolic]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .Class = %Class.decl
// CHECK:STDOUT: .Declaration = %Declaration.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core.import = import Core
// CHECK:STDOUT: %Core: <namespace> = namespace %Core.import, [template] {
@@ -58,88 +63,128 @@ class Class(T:! type) {
// CHECK:STDOUT: }
// CHECK:STDOUT: %Class.decl: %Class.type = class_decl @Class [template = constants.%Class.1] {
// CHECK:STDOUT: %T.loc11_13.1: type = param T
// CHECK:STDOUT: %T.loc11_13.2: type = bind_symbolic_name T 0, %T.loc11_13.1 [symbolic = %T.loc11_13.2 (constants.%T)]
// CHECK:STDOUT: %T.loc11_13.2: type = bind_symbolic_name T 0, %T.loc11_13.1 [symbolic = @Class.%T (constants.%T)]
// CHECK:STDOUT: }
// CHECK:STDOUT: %Declaration.decl: %Declaration.type = class_decl @Declaration [template = constants.%Declaration.1] {
// CHECK:STDOUT: %T.loc24_19.1: type = param T
// CHECK:STDOUT: %T.loc24_19.2: type = bind_symbolic_name T 0, %T.loc24_19.1 [symbolic = @Declaration.%T (constants.%T)]
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// 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, 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
// CHECK:STDOUT: %self.loc12_19.3: @Class.%.loc12_29 (%.2) = bind_name self, %self.loc12_19.1
// CHECK:STDOUT: %.loc12_14: @Class.%.loc12_29 (%.2) = addr_pattern %self.loc12_19.3
// CHECK:STDOUT: %T.ref.loc12: type = name_ref T, file.%T.loc11_13.2 [symbolic = %T.ref.loc12 (constants.%T)]
// CHECK:STDOUT: %.loc12_38: type = ptr_type %T [symbolic = %.loc12_38 (constants.%.3)]
// CHECK:STDOUT: %return.var.loc12: ref %.3 = var <return slot>
// CHECK:STDOUT: generic class @Class(file.%T.loc11_13.2: type) {
// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic = %T (constants.%T)]
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT: %Class: type = class_type @Class, @Class(%T) [symbolic = %Class (constants.%Class.2)]
// CHECK:STDOUT: %.1: type = unbound_element_type @Class.%Class (%Class.2), @Class.%T (%T) [symbolic = %.1 (constants.%.4)]
// CHECK:STDOUT:
// CHECK:STDOUT: class {
// CHECK:STDOUT: %GetAddr.decl: %GetAddr.type = fn_decl @GetAddr [template = constants.%GetAddr] {
// CHECK:STDOUT: %.loc12_25: type = specific_constant constants.%Class.2, @Class(constants.%T) [symbolic = @GetAddr.%Class (constants.%Class.2)]
// CHECK:STDOUT: %Self.ref.loc12: type = name_ref Self, %.loc12_25 [symbolic = @GetAddr.%Class (constants.%Class.2)]
// CHECK:STDOUT: %.loc12_29: type = ptr_type %Class.2 [symbolic = @GetAddr.%.1 (constants.%.2)]
// CHECK:STDOUT: %self.loc12_19.1: @GetAddr.%.1 (%.2) = param self
// CHECK:STDOUT: %self.loc12_19.3: @GetAddr.%.1 (%.2) = bind_name self, %self.loc12_19.1
// CHECK:STDOUT: %.loc12_14: @GetAddr.%.1 (%.2) = addr_pattern %self.loc12_19.3
// CHECK:STDOUT: %T.ref.loc12: type = name_ref T, file.%T.loc11_13.2 [symbolic = @GetAddr.%T (constants.%T)]
// CHECK:STDOUT: %.loc12_38: type = ptr_type %T [symbolic = @GetAddr.%.2 (constants.%.3)]
// 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, @Class(constants.%T) [symbolic = @GetValue.%Class (constants.%Class.2)]
// CHECK:STDOUT: %Self.ref.loc17: type = name_ref Self, %.loc17 [symbolic = @GetValue.%Class (constants.%Class.2)]
// CHECK:STDOUT: %self.loc17_15.1: @GetValue.%Class (%Class.2) = param self
// CHECK:STDOUT: %self.loc17_15.2: @GetValue.%Class (%Class.2) = bind_name self, %self.loc17_15.1
// CHECK:STDOUT: %T.ref.loc17: type = name_ref T, file.%T.loc11_13.2 [symbolic = @GetValue.%T (constants.%T)]
// CHECK:STDOUT: %return.var.loc17: ref %T = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT: %T.ref.loc21: type = name_ref T, file.%T.loc11_13.2 [symbolic = %T (constants.%T)]
// CHECK:STDOUT: %.loc21: @Class.%.1 (%.4) = field_decl k, element0 [template]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%Class.2
// CHECK:STDOUT: .GetAddr = %GetAddr.decl
// CHECK:STDOUT: .GetValue = %GetValue.decl
// CHECK:STDOUT: .k = %.loc21
// CHECK:STDOUT: }
// CHECK:STDOUT: %GetValue.decl: %GetValue.type = fn_decl @GetValue [template = constants.%GetValue] {
// 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
// CHECK:STDOUT: %T.ref.loc17: type = name_ref T, file.%T.loc11_13.2 [symbolic = %T.ref.loc17 (constants.%T)]
// CHECK:STDOUT: %return.var.loc17: ref %T = var <return slot>
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic class @Declaration(file.%T.loc24_19.2: type) {
// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic = %T (constants.%T)]
// CHECK:STDOUT:
// CHECK:STDOUT: class;
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: generic fn @GetAddr(file.%T.loc11_13.2: type) {
// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic = %T (constants.%T)]
// CHECK:STDOUT: %Class: type = class_type @Class, @Class(%T) [symbolic = %Class (constants.%Class.2)]
// CHECK:STDOUT: %.1: type = ptr_type @GetAddr.%Class (%Class.2) [symbolic = %.1 (constants.%.2)]
// CHECK:STDOUT: %.2: type = ptr_type @GetAddr.%T (%T) [symbolic = %.2 (constants.%.3)]
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT: %.3: type = unbound_element_type @GetAddr.%Class (%Class.2), @GetAddr.%T (%T) [symbolic = %.3 (constants.%.4)]
// CHECK:STDOUT:
// CHECK:STDOUT: fn[addr @Class.%self.loc12_19.3: @GetAddr.%.1 (%.2)]() -> %.3 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %self.ref: @GetAddr.%.1 (%.2) = name_ref self, @Class.%self.loc12_19.3
// CHECK:STDOUT: %.loc13_17.1: ref @GetAddr.%Class (%Class.2) = deref %self.ref
// CHECK:STDOUT: %k.ref: @GetAddr.%.3 (%.4) = name_ref k, @Class.%.loc21 [template = @Class.%.loc21]
// CHECK:STDOUT: %.loc13_17.2: ref @GetAddr.%T (%T) = class_element_access %.loc13_17.1, element0
// CHECK:STDOUT: %.loc13_12: @GetAddr.%.2 (%.3) = addr_of %.loc13_17.2
// CHECK:STDOUT: return %.loc13_12
// CHECK:STDOUT: }
// CHECK:STDOUT: %T.ref.loc21: type = name_ref T, file.%T.loc11_13.2 [symbolic = file.%T.loc11_13.2 (constants.%T)]
// CHECK:STDOUT: %.loc21: <unexpected>.inst+41 (%.4) = field_decl k, element0 [template]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%Class.2
// CHECK:STDOUT: .GetAddr = %GetAddr.decl
// CHECK:STDOUT: .GetValue = %GetValue.decl
// CHECK:STDOUT: .k = %.loc21
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @GetAddr[addr @Class.%self.loc12_19.3: @Class.%.loc12_29 (%.2)]() -> %.3
// CHECK:STDOUT: generic [file.%T.loc11_13.2: type] {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %self.ref: @Class.%.loc12_29 (%.2) = name_ref self, @Class.%self.loc12_19.3
// CHECK:STDOUT: %.loc13_17.1: ref @Class.%.loc12_25 (%Class.2) = deref %self.ref
// CHECK:STDOUT: %k.ref: <unexpected>.inst+49 (%.4) = name_ref k, @Class.%.loc21 [template = @Class.%.loc21]
// CHECK:STDOUT: %.loc13_17.2: ref @Class.%T.ref.loc12 (%T) = class_element_access %.loc13_17.1, element0
// CHECK:STDOUT: %.loc13_12: @Class.%.loc12_38 (%.3) = addr_of %.loc13_17.2
// CHECK:STDOUT: return %.loc13_12
// CHECK:STDOUT: generic fn @GetValue(file.%T.loc11_13.2: type) {
// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic = %T (constants.%T)]
// CHECK:STDOUT: %Class: type = class_type @Class, @Class(%T) [symbolic = %Class (constants.%Class.2)]
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT: %.1: type = unbound_element_type @GetValue.%Class (%Class.2), @GetValue.%T (%T) [symbolic = %.1 (constants.%.4)]
// CHECK:STDOUT:
// CHECK:STDOUT: fn[@Class.%self.loc17_15.2: @GetValue.%Class (%Class.2)]() -> %T {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %self.ref: @GetValue.%Class (%Class.2) = name_ref self, @Class.%self.loc17_15.2
// CHECK:STDOUT: %k.ref: @GetValue.%.1 (%.4) = name_ref k, @Class.%.loc21 [template = @Class.%.loc21]
// CHECK:STDOUT: %.loc18_16.1: ref @GetValue.%T (%T) = class_element_access %self.ref, element0
// CHECK:STDOUT: %.loc18_16.2: @GetValue.%T (%T) = bind_value %.loc18_16.1
// CHECK:STDOUT: return %.loc18_16.2
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @GetValue[@Class.%self.loc17_15.2: @Class.%.loc17 (%Class.2)]() -> %T
// CHECK:STDOUT: generic [file.%T.loc11_13.2: type] {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %self.ref: @Class.%.loc17 (%Class.2) = name_ref self, @Class.%self.loc17_15.2
// CHECK:STDOUT: %k.ref: <unexpected>.inst+55 (%.4) = name_ref k, @Class.%.loc21 [template = @Class.%.loc21]
// CHECK:STDOUT: %.loc18_16.1: ref @Class.%T.ref.loc17 (%T) = class_element_access %self.ref, element0
// CHECK:STDOUT: %.loc18_16.2: @Class.%T.ref.loc17 (%T) = bind_value %.loc18_16.1
// CHECK:STDOUT: return %.loc18_16.2
// CHECK:STDOUT: specific @Class(constants.%T) {
// CHECK:STDOUT: %T => constants.%T
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
// CHECK:STDOUT: %Class => constants.%Class.2
// CHECK:STDOUT: %.1 => constants.%.4
// 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: definition:
// CHECK:STDOUT: <unexpected>.inst+40 => constants.%Class.2
// CHECK:STDOUT: <unexpected>.inst+41 => constants.%.4
// CHECK:STDOUT: <unexpected>.inst+37.loc21_8 => <unexpected>.inst+38
// CHECK:STDOUT: specific @Class(@GetAddr.%T) {
// CHECK:STDOUT: %T => 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: specific @GetAddr(constants.%T) {
// CHECK:STDOUT: %T => constants.%T
// CHECK:STDOUT: %Class => constants.%Class.2
// CHECK:STDOUT: %.1 => constants.%.2
// CHECK:STDOUT: %.2 => 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: specific @Class(@GetValue.%T) {
// CHECK:STDOUT: %T => constants.%T
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific file.%Class.decl(file.%T.loc11_13.2) {
// CHECK:STDOUT: declaration:
// CHECK:STDOUT: file.%T.loc11_13.2 => constants.%T
// CHECK:STDOUT: specific @GetValue(constants.%T) {
// CHECK:STDOUT: %T => constants.%T
// CHECK:STDOUT: %Class => constants.%Class.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @Class(@Class.%T) {
// CHECK:STDOUT: %T => constants.%T
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @Declaration(constants.%T) {
// CHECK:STDOUT: %T => constants.%T
// CHECK:STDOUT: }
// CHECK:STDOUT: