mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 22:02:23 +01:00
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.
125 lines
5.9 KiB
Plaintext
125 lines
5.9 KiB
Plaintext
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
|
// Exceptions. See /LICENSE for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
// AUTOUPDATE
|
|
// TIP: To test this file alone, run:
|
|
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/class/generic_method.carbon
|
|
// TIP: To dump output, run:
|
|
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/generic_method.carbon
|
|
|
|
class Class(T:! type) {
|
|
var a: T;
|
|
fn F[self: Self](n: T);
|
|
}
|
|
|
|
fn Class(T:! type).F[self: Self](n: T) {}
|
|
|
|
// CHECK:STDOUT: --- generic_method.carbon
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: constants {
|
|
// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic]
|
|
// 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, @Class(%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]
|
|
// CHECK:STDOUT: %.3: type = struct_type {.a: %T} [symbolic]
|
|
// CHECK:STDOUT: %.4: type = ptr_type %.3 [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: }
|
|
// CHECK:STDOUT: %Core.import = import Core
|
|
// CHECK:STDOUT: %Core: <namespace> = namespace %Core.import, [template] {
|
|
// CHECK:STDOUT: import Core//prelude
|
|
// CHECK:STDOUT: import Core//prelude/operators
|
|
// CHECK:STDOUT: import Core//prelude/types
|
|
// CHECK:STDOUT: import Core//prelude/operators/arithmetic
|
|
// CHECK:STDOUT: import Core//prelude/operators/bitwise
|
|
// CHECK:STDOUT: import Core//prelude/operators/comparison
|
|
// CHECK:STDOUT: import Core//prelude/types/bool
|
|
// 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 = @Class.%T (constants.%T)]
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] {
|
|
// CHECK:STDOUT: %T.loc16_10.1: type = param T
|
|
// CHECK:STDOUT: %T.loc16_10.2: type = bind_symbolic_name T 0, %T.loc16_10.1 [symbolic = constants.%T]
|
|
// CHECK:STDOUT: %.loc16: type = specific_constant constants.%Class.2, @Class(constants.%T) [symbolic = constants.%Class.2]
|
|
// CHECK:STDOUT: %Self.ref: type = name_ref Self, %.loc16 [symbolic = constants.%Class.2]
|
|
// CHECK:STDOUT: %self.loc16_22.1: %Class.2 = param self
|
|
// CHECK:STDOUT: @F.%self: %Class.2 = bind_name self, %self.loc16_22.1
|
|
// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc16_10.2 [symbolic = constants.%T]
|
|
// CHECK:STDOUT: %n.loc16_34.1: %T = param n
|
|
// CHECK:STDOUT: @F.%n: %T = bind_name n, %n.loc16_34.1
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// 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.%.2)]
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: class {
|
|
// CHECK:STDOUT: %T.ref.loc12: type = name_ref T, file.%T.loc11_13.2 [symbolic = %T (constants.%T)]
|
|
// CHECK:STDOUT: %.loc12: @Class.%.1 (%.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, @Class(constants.%T) [symbolic = @F.%Class (constants.%Class.2)]
|
|
// CHECK:STDOUT: %Self.ref: type = name_ref Self, %.loc13 [symbolic = @F.%Class (constants.%Class.2)]
|
|
// CHECK:STDOUT: %self.loc13_8.1: @F.%Class (%Class.2) = param self
|
|
// CHECK:STDOUT: %self.loc13_8.2: @F.%Class (%Class.2) = bind_name self, %self.loc13_8.1
|
|
// CHECK:STDOUT: %T.ref.loc13: type = name_ref T, file.%T.loc11_13.2 [symbolic = @F.%T (constants.%T)]
|
|
// CHECK:STDOUT: %n.loc13_20.1: @F.%T (%T) = param n
|
|
// CHECK:STDOUT: %n.loc13_20.2: @F.%T (%T) = bind_name n, %n.loc13_20.1
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: !members:
|
|
// CHECK:STDOUT: .Self = constants.%Class.2
|
|
// CHECK:STDOUT: .a = %.loc12
|
|
// CHECK:STDOUT: .F = %F.decl
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: generic fn @F(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:
|
|
// CHECK:STDOUT: fn[%self: %Class.2](%n: %T) {
|
|
// CHECK:STDOUT: !entry:
|
|
// CHECK:STDOUT: return
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// 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.%.2
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: specific @Class(@F.%T) {
|
|
// CHECK:STDOUT: %T => constants.%T
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: specific @F(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:
|