Treat the empty inst block as being canonical. (#4199)

TryEvalInst was assuming this to be the case when forming canonical
constants, but it previously wasn't.

This fixes an issue where we can end up with two identical-looking
constants for an empty struct value: one with an `Empty` block and
another with the canonical empty block.
This commit is contained in:
Richard Smith
2024-08-07 21:58:28 +00:00
committed by GitHub
parent 3d13b8f71c
commit 3c4c234d01
16 changed files with 107 additions and 131 deletions
@@ -198,9 +198,8 @@ fn Interface.C.F[self: Self](U:! type, u: U) -> U { return u; }
// CHECK:STDOUT: %U: type = bind_symbolic_name U 1 [symbolic]
// CHECK:STDOUT: %F.type: type = fn_type @F, @C(%Self) [symbolic]
// CHECK:STDOUT: %.2: type = tuple_type () [template]
// CHECK:STDOUT: %F.1: %F.type = struct_value () [symbolic]
// CHECK:STDOUT: %F: %F.type = struct_value () [symbolic]
// CHECK:STDOUT: %.3: type = struct_type {} [template]
// CHECK:STDOUT: %F.2: %F.type = struct_value () [symbolic]
// CHECK:STDOUT: %.4: type = ptr_type %.3 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -223,7 +222,7 @@ fn Interface.C.F[self: Self](U:! type, u: U) -> U { return u; }
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core.import = import Core
// CHECK:STDOUT: %Interface.decl: type = interface_decl @Interface [template = constants.%.1] {}
// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [symbolic = constants.%F.1] {
// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [symbolic = constants.%F] {
// CHECK:STDOUT: %.loc20: type = specific_constant constants.%C.2, @C(constants.%Self) [symbolic = constants.%C.2]
// CHECK:STDOUT: %Self.ref: type = name_ref Self, %.loc20 [symbolic = constants.%C.2]
// CHECK:STDOUT: %self.loc20_18.1: %C.2 = param self
@@ -252,10 +251,10 @@ fn Interface.C.F[self: Self](U:! type, u: U) -> U { return u; }
// CHECK:STDOUT: !definition:
// CHECK:STDOUT: %Self: %.1 = bind_symbolic_name Self 0 [symbolic = %Self (constants.%Self)]
// CHECK:STDOUT: %F.type: type = fn_type @F, @C(%Self) [symbolic = %F.type (constants.%F.type)]
// CHECK:STDOUT: %F: @C.%F.type (%F.type) = struct_value () [symbolic = %F (constants.%F.1)]
// CHECK:STDOUT: %F: @C.%F.type (%F.type) = struct_value () [symbolic = %F (constants.%F)]
// CHECK:STDOUT:
// CHECK:STDOUT: class {
// CHECK:STDOUT: %F.decl: @C.%F.type (%F.type) = fn_decl @F [symbolic = %F (constants.%F.1)] {
// CHECK:STDOUT: %F.decl: @C.%F.type (%F.type) = fn_decl @F [symbolic = %F (constants.%F)] {
// CHECK:STDOUT: %.loc14: type = specific_constant constants.%C.2, @C(constants.%Self) [symbolic = @F.%C (constants.%C.2)]
// CHECK:STDOUT: %Self.ref: type = name_ref Self, %.loc14 [symbolic = @F.%C (constants.%C.2)]
// CHECK:STDOUT: %self.loc14_10.1: @F.%C (%C.2) = param self
@@ -293,7 +292,7 @@ fn Interface.C.F[self: Self](U:! type, u: U) -> U { return u; }
// CHECK:STDOUT: !definition:
// CHECK:STDOUT: %Self => constants.%Self
// CHECK:STDOUT: %F.type => constants.%F.type
// CHECK:STDOUT: %F => constants.%F.2
// CHECK:STDOUT: %F => constants.%F
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @C(@F.%Self) {}
@@ -46,7 +46,6 @@ interface Outer {
// CHECK:STDOUT: %Self.3: %.5 = bind_symbolic_name Self 1 [symbolic]
// CHECK:STDOUT: %.type: type = fn_type @.1, @Inner(%Self.2) [symbolic]
// CHECK:STDOUT: %.6: %.type = struct_value () [symbolic]
// CHECK:STDOUT: %.7: %.type = struct_value () [symbolic]
// CHECK:STDOUT: %F.type.2: type = fn_type @F.2, @Inner(%Self.2) [symbolic]
// CHECK:STDOUT: %F.2: %F.type.2 = struct_value () [symbolic]
// CHECK:STDOUT: }
@@ -127,7 +126,7 @@ interface Outer {
// CHECK:STDOUT: %.1 => constants.%.5
// CHECK:STDOUT: %Self.3 => constants.%Self.3
// CHECK:STDOUT: %.type => constants.%.type
// CHECK:STDOUT: %.2 => constants.%.7
// CHECK:STDOUT: %.2 => constants.%.6
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @.1(constants.%Self.2, constants.%Self.3) {}
@@ -31,10 +31,9 @@ fn I(T:! type).F[self: Self]() -> Self { return self; }
// CHECK:STDOUT: %.2: type = interface_type @I, @I(%T) [symbolic]
// CHECK:STDOUT: %Self: %.2 = bind_symbolic_name Self 1 [symbolic]
// CHECK:STDOUT: %F.type: type = fn_type @F, @I(%T) [symbolic]
// CHECK:STDOUT: %F.1: %F.type = struct_value () [symbolic]
// CHECK:STDOUT: %F: %F.type = struct_value () [symbolic]
// CHECK:STDOUT: %.3: type = assoc_entity_type %.2, %F.type [symbolic]
// CHECK:STDOUT: %.4: %.3 = assoc_entity element0, @I.%F.decl [symbolic]
// CHECK:STDOUT: %F.2: %F.type = struct_value () [symbolic]
// CHECK:STDOUT: %.type: type = fn_type @.1, @I(%T) [symbolic]
// CHECK:STDOUT: %.5: %.type = struct_value () [symbolic]
// CHECK:STDOUT: }
@@ -71,13 +70,13 @@ fn I(T:! type).F[self: Self]() -> Self { return self; }
// CHECK:STDOUT: %.1: type = interface_type @I, @I(%T) [symbolic = %.1 (constants.%.2)]
// CHECK:STDOUT: %Self.2: %.2 = bind_symbolic_name Self 1 [symbolic = %Self.2 (constants.%Self)]
// CHECK:STDOUT: %F.type: type = fn_type @F, @I(%T) [symbolic = %F.type (constants.%F.type)]
// CHECK:STDOUT: %F: @I.%F.type (%F.type) = struct_value () [symbolic = %F (constants.%F.1)]
// CHECK:STDOUT: %F: @I.%F.type (%F.type) = struct_value () [symbolic = %F (constants.%F)]
// CHECK:STDOUT: %.2: type = assoc_entity_type @I.%.1 (%.2), @I.%F.type (%F.type) [symbolic = %.2 (constants.%.3)]
// CHECK:STDOUT: %.3: @I.%.2 (%.3) = assoc_entity element0, %F.decl [symbolic = %.3 (constants.%.4)]
// CHECK:STDOUT:
// CHECK:STDOUT: interface {
// CHECK:STDOUT: %Self.1: @I.%.1 (%.2) = bind_symbolic_name Self 1 [symbolic = %Self.2 (constants.%Self)]
// CHECK:STDOUT: %F.decl: @I.%F.type (%F.type) = fn_decl @F [symbolic = %F (constants.%F.1)] {
// CHECK:STDOUT: %F.decl: @I.%F.type (%F.type) = fn_decl @F [symbolic = %F (constants.%F)] {
// CHECK:STDOUT: %.loc13_14.1: @F.%.1 (%.2) = specific_constant %Self.1, @I(constants.%T) [symbolic = @F.%Self (constants.%Self)]
// CHECK:STDOUT: %Self.ref.loc13_14: @F.%.1 (%.2) = name_ref Self, %.loc13_14.1 [symbolic = @F.%Self (constants.%Self)]
// CHECK:STDOUT: %.loc13_14.2: type = facet_type_access %Self.ref.loc13_14 [symbolic = @F.%Self (constants.%Self)]
@@ -128,7 +127,7 @@ fn I(T:! type).F[self: Self]() -> Self { return self; }
// CHECK:STDOUT: %.1 => constants.%.2
// CHECK:STDOUT: %Self.2 => constants.%Self
// CHECK:STDOUT: %F.type => constants.%F.type
// CHECK:STDOUT: %F => constants.%F.2
// CHECK:STDOUT: %F => constants.%F
// CHECK:STDOUT: %.2 => constants.%.3
// CHECK:STDOUT: %.3 => constants.%.4
// CHECK:STDOUT: }