mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 15:51:07 +01:00
Import support for generics and specifics (#4179)
Import generics and specifics when they are referenced by imported entities. When importing a generic, we import the symbolic constants required by its eval block, and then rebuild the eval block itself given the list of constants it needs to compute. This is likely a bit less efficient than directly importing the contents of the eval block, but avoids needing to either extend the importer code to be able to import the instructions that can appear in the eval block or extend the evaluator to cope with instructions from a different `SemIR::File`. Importing a symbolic constant is unaffected, and does not yet preserve the associated generic and index within that generic, so uses of a generic from an imported IR still don't pick up values from the specific, but the improved functionality can be seen in the changes to the SemIR in the testcases.
This commit is contained in:
@@ -99,21 +99,26 @@ impl C as AddWith(C) {
|
||||
// CHECK:STDOUT: %.2: type = tuple_type () [template]
|
||||
// CHECK:STDOUT: %AddWith: %AddWith.type = struct_value () [template]
|
||||
// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic]
|
||||
// CHECK:STDOUT: %.3: type = interface_type @AddWith, invalid(%T) [symbolic]
|
||||
// CHECK:STDOUT: %.3: type = interface_type @AddWith, @AddWith(%T) [symbolic]
|
||||
// CHECK:STDOUT: %Self: %.3 = bind_symbolic_name Self 1 [symbolic]
|
||||
// CHECK:STDOUT: %.4: type = interface_type @AddWith, invalid(%C) [template]
|
||||
// CHECK:STDOUT: %F.type.1: type = fn_type @F.1 [template]
|
||||
// CHECK:STDOUT: %F.1: %F.type.1 = struct_value () [template]
|
||||
// CHECK:STDOUT: %F.type.2: type = fn_type @F.2 [template]
|
||||
// CHECK:STDOUT: %F.2: %F.type.2 = struct_value () [template]
|
||||
// CHECK:STDOUT: %.5: <witness> = interface_witness (%F.1) [template]
|
||||
// CHECK:STDOUT: %F.type.2: type = fn_type @F.1, @AddWith(%T) [symbolic]
|
||||
// CHECK:STDOUT: %.4: type = assoc_entity_type @AddWith, %F.type.2 [symbolic]
|
||||
// CHECK:STDOUT: %.5: %.4 = assoc_entity element0, imports.%import_ref.2 [symbolic]
|
||||
// CHECK:STDOUT: %F.2: %F.type.2 = struct_value () [symbolic]
|
||||
// CHECK:STDOUT: %.6: type = interface_type @AddWith, @AddWith(%C) [template]
|
||||
// CHECK:STDOUT: %F.type.3: type = fn_type @F.2 [template]
|
||||
// CHECK:STDOUT: %F.3: %F.type.3 = struct_value () [template]
|
||||
// CHECK:STDOUT: %.7: <witness> = interface_witness (%F.3) [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %import_ref.1: %AddWith.type = import_ref Main//a, inst+4, loaded [template = constants.%AddWith]
|
||||
// CHECK:STDOUT: %import_ref.2 = import_ref Main//a, inst+10, unloaded
|
||||
// CHECK:STDOUT: %import_ref.3 = import_ref Main//a, inst+16, unloaded
|
||||
// CHECK:STDOUT: %import_ref.4: %F.type.2 = import_ref Main//a, inst+12, loaded [template = constants.%F.2]
|
||||
// CHECK:STDOUT: %import_ref.2 = import_ref Main//a, inst+12, unloaded
|
||||
// CHECK:STDOUT: %import_ref.3 = import_ref Main//a, inst+10, unloaded
|
||||
// CHECK:STDOUT: %import_ref.4 = import_ref Main//a, inst+16, unloaded
|
||||
// CHECK:STDOUT: %import_ref.5: %F.type.2 = import_ref Main//a, inst+12, loaded [template = constants.%F.1]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
@@ -123,26 +128,38 @@ impl C as AddWith(C) {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %default.import = import <invalid>
|
||||
// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {}
|
||||
// CHECK:STDOUT: %.loc7_20.1: type = value_of_initializer %.loc7_18 [template = constants.%.4]
|
||||
// CHECK:STDOUT: %.loc7_20.2: type = converted %.loc7_18, %.loc7_20.1 [template = constants.%.4]
|
||||
// CHECK:STDOUT: %.loc7_20.1: type = value_of_initializer %.loc7_18 [template = constants.%.6]
|
||||
// CHECK:STDOUT: %.loc7_20.2: type = converted %.loc7_18, %.loc7_20.1 [template = constants.%.6]
|
||||
// CHECK:STDOUT: impl_decl @impl {
|
||||
// CHECK:STDOUT: %C.ref.loc7_6: type = name_ref C, %C.decl [template = constants.%C]
|
||||
// CHECK:STDOUT: %AddWith.ref: %AddWith.type = name_ref AddWith, imports.%import_ref.1 [template = constants.%AddWith]
|
||||
// CHECK:STDOUT: %C.ref.loc7_19: type = name_ref C, %C.decl [template = constants.%C]
|
||||
// CHECK:STDOUT: %.loc7_18: init type = call %AddWith.ref(%C.ref.loc7_19) [template = constants.%.4]
|
||||
// CHECK:STDOUT: %.loc7_18: init type = call %AddWith.ref(%C.ref.loc7_19) [template = constants.%.6]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: interface @AddWith {
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = imports.%import_ref.2
|
||||
// CHECK:STDOUT: .F = imports.%import_ref.3
|
||||
// CHECK:STDOUT: witness = (imports.%import_ref.4)
|
||||
// CHECK:STDOUT: generic interface @AddWith(constants.%T: type) {
|
||||
// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic = %T (constants.%T)]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !definition:
|
||||
// CHECK:STDOUT: %.1: type = interface_type @AddWith, @AddWith(%T) [symbolic = %.1 (constants.%.3)]
|
||||
// CHECK:STDOUT: %Self: %.3 = bind_symbolic_name Self 1 [symbolic = %Self (constants.%Self)]
|
||||
// CHECK:STDOUT: %F.type: type = fn_type @F.1, @AddWith(%T) [symbolic = %F.type (constants.%F.type.2)]
|
||||
// CHECK:STDOUT: %F: @AddWith.%F.type (%F.type.2) = struct_value () [symbolic = %F (constants.%F.2)]
|
||||
// CHECK:STDOUT: %.2: type = assoc_entity_type @AddWith, @AddWith.%F.type (%F.type.2) [symbolic = %.2 (constants.%.4)]
|
||||
// CHECK:STDOUT: %.3: @AddWith.%.2 (%.4) = assoc_entity element0, imports.%import_ref.2 [symbolic = %.3 (constants.%.5)]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: interface {
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = imports.%import_ref.3
|
||||
// CHECK:STDOUT: .F = imports.%import_ref.4
|
||||
// CHECK:STDOUT: witness = (imports.%import_ref.5)
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: impl @impl: %C as %.4 {
|
||||
// CHECK:STDOUT: %F.decl: %F.type.1 = fn_decl @F.1 [template = constants.%F.1] {}
|
||||
// CHECK:STDOUT: %.1: <witness> = interface_witness (%F.decl) [template = constants.%.5]
|
||||
// CHECK:STDOUT: impl @impl: %C as %.6 {
|
||||
// CHECK:STDOUT: %F.decl: %F.type.3 = fn_decl @F.2 [template = constants.%F.3] {}
|
||||
// CHECK:STDOUT: %.1: <witness> = interface_witness (%F.decl) [template = constants.%.7]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .F = %F.decl
|
||||
@@ -154,14 +171,25 @@ impl C as AddWith(C) {
|
||||
// CHECK:STDOUT: .Self = constants.%C
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F.1() {
|
||||
// CHECK:STDOUT: generic fn @F.1(constants.%T: type, constants.%Self: %.3) {
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn();
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F.2() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F.2();
|
||||
// CHECK:STDOUT: specific @AddWith(constants.%T) {
|
||||
// CHECK:STDOUT: %T => constants.%T
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: specific invalid(constants.%T);
|
||||
// CHECK:STDOUT: specific @AddWith(@AddWith.%T) {
|
||||
// CHECK:STDOUT: %T => constants.%T
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: specific invalid(constants.%C);
|
||||
// CHECK:STDOUT: specific @AddWith(constants.%C) {
|
||||
// CHECK:STDOUT: %T => constants.%C
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
|
||||
@@ -281,9 +281,15 @@ var f: ForwardDeclared* = &f_ref.f;
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F.1();
|
||||
// CHECK:STDOUT: generic fn @F.1(constants.%Self.2: %.3) {
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F.2();
|
||||
// CHECK:STDOUT: fn();
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: generic fn @F.2(constants.%Self.3: %.4) {
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn();
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @__global_init() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
|
||||
Reference in New Issue
Block a user