Fix import of val and ref return forms. (#7989)

Importing a function with a `-> val` return form, such as `fn F() -> val
i32`, crashed because `TryResolveInstCanonical` had no case for
`ValueForm`. Also, an imported `RefForm` was given type `type` rather
than `Core.Form`.

Import all three primitive forms with a single function template.

Assisted-by: Claude via Antigravity
This commit is contained in:
Richard Smith authored and GitHub committed 2026-10-15 23:54:56 +00:00
1 parent fea77fe598
commit 14a3de9ff1
3 files changed
+156 -25

No files matched your search

+12 -25
View File
@@ -4194,24 +4194,6 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
{.elements_id = elements_id, .impl_id = impl_id});
}
static auto TryResolveTypedInst(ImportRefResolver& resolver,
SemIR::InitForm inst) -> ResolveResult {
auto type_const_id = GetLocalConstantId(resolver, inst.type_id);
auto type_component_const_id =
GetLocalConstantId(resolver, inst.type_component_inst_id);
if (resolver.HasNewWork()) {
return ResolveResult::Retry();
}
return ResolveResult::Deduplicated<SemIR::InitForm>(
resolver,
SemIR::InitForm{
.type_id =
resolver.local_types().GetTypeIdForTypeConstantId(type_const_id),
.type_component_inst_id = resolver.local_types().GetTypeInstId(
resolver.local_types().GetTypeIdForTypeConstantId(
type_component_const_id))});
}
static auto TryResolveTypedInst(ImportRefResolver& resolver,
SemIR::IntValue inst) -> ResolveResult {
auto type_id = GetLocalConstantId(resolver, inst.type_id);
@@ -4337,19 +4319,21 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
resolver, {.type_id = SemIR::TypeType::TypeId, .pointee_id = pointee_id});
}
template <typename PrimitiveFormT>
requires SemIR::Internal::HasInstCategory<SemIR::AnyPrimitiveForm,
PrimitiveFormT>
static auto TryResolveTypedInst(ImportRefResolver& resolver,
SemIR::RefForm inst) -> ResolveResult {
PrimitiveFormT inst) -> ResolveResult {
CARBON_CHECK(inst.type_id == SemIR::FormType::TypeId);
auto type_component_inst_id =
GetLocalConstantId(resolver, inst.type_component_inst_id);
GetLocalTypeInstId(resolver, inst.type_component_inst_id);
if (resolver.HasNewWork()) {
return ResolveResult::Retry();
}
return ResolveResult::Deduplicated<SemIR::RefForm>(
resolver, {.type_id = SemIR::TypeType::TypeId,
.type_component_inst_id = resolver.local_types().GetTypeInstId(
resolver.local_types().GetTypeIdForTypeConstantId(
type_component_inst_id))});
return ResolveResult::Deduplicated<PrimitiveFormT>(
resolver, {.type_id = SemIR::FormType::TypeId,
.type_component_inst_id = type_component_inst_id});
}
static auto TryResolveTypedInst(ImportRefResolver& resolver,
@@ -4925,6 +4909,9 @@ static auto TryResolveInstCanonical(ImportRefResolver& resolver,
case CARBON_KIND(SemIR::ValueBindingPattern inst): {
return TryResolveTypedInst(resolver, inst);
}
case CARBON_KIND(SemIR::ValueForm inst): {
return TryResolveTypedInst(resolver, inst);
}
case CARBON_KIND(SemIR::ValueParamPattern inst): {
return TryResolveTypedInst(resolver, inst);
}
@@ -37,6 +37,26 @@ library "[[@TEST_NAME]]";
// CHECK:STDERR:
fn F() -> (ref i32);
// --- ref_return_lib.carbon
library "[[@TEST_NAME]]";
var g: i32 = 0;
fn F() -> ref i32 { return g; }
// --- import_ref_return.carbon
library "[[@TEST_NAME]]";
import library "ref_return_lib";
//@include-in-dumps
fn G() {
let unused ref x: i32 = F();
}
// CHECK:STDOUT: --- ref_return.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
@@ -99,3 +119,56 @@ fn F() -> (ref i32);
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- import_ref_return.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: type: type = facet_type <type> [concrete]
// CHECK:STDOUT: %G.type: type = fn_type @G [concrete]
// CHECK:STDOUT: %G: %G.type = struct_value () [concrete]
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete]
// CHECK:STDOUT: %Int.type: type = parameterized_class_name_type @Int [concrete]
// CHECK:STDOUT: %Int.generic: %Int.type = struct_value () [concrete]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete]
// CHECK:STDOUT: %pattern_type.d94: type = pattern_type %i32 [concrete]
// CHECK:STDOUT: %x.patt: %pattern_type.d94 = ref_binding_pattern x [concrete]
// CHECK:STDOUT: %F.type: type = fn_type @F [concrete]
// CHECK:STDOUT: %F: %F.type = struct_value () [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Main.g = import_ref Main//ref_return_lib, g, unloaded
// CHECK:STDOUT: %Main.F: %F.type = import_ref Main//ref_return_lib, F, loaded [concrete = constants.%F]
// CHECK:STDOUT: %Core: <namespace> = namespace file.%Core.import, [concrete] {
// CHECK:STDOUT: .Int = %Core.Int
// CHECK:STDOUT: import Core//prelude
// CHECK:STDOUT: import Core//prelude/...
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core.Int: %Int.type = import_ref Core//prelude/parts/int, Int, loaded [concrete = constants.%Int.generic]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
// CHECK:STDOUT: .g = imports.%Main.g
// CHECK:STDOUT: .F = imports.%Main.F
// CHECK:STDOUT: .Core = imports.%Core
// CHECK:STDOUT: .G = %G.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core.import = import Core
// CHECK:STDOUT: %default.import = import <none>
// CHECK:STDOUT: %G.decl: %G.type = fn_decl @G [concrete = constants.%G] {} {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @G() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %F.ref: %F.type = name_ref F, imports.%Main.F [concrete = constants.%F]
// CHECK:STDOUT: %F.call: ref %i32 = call %F.ref()
// CHECK:STDOUT: %i32: type = type_literal constants.%i32 [concrete = constants.%i32]
// CHECK:STDOUT: %x: ref %i32 = wrapper_binding x, %F.call
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %x.patt: %pattern_type.d94 = ref_binding_pattern x [concrete = constants.%x.patt]
// CHECK:STDOUT: }
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F [from "ref_return_lib.carbon"];
// CHECK:STDOUT:
@@ -95,6 +95,26 @@ fn F() -> var i32 {
return 1;
}
// --- val_return_lib.carbon
library "[[@TEST_NAME]]";
fn F() -> val i32 {
return 1;
}
// --- import_val_return.carbon
library "[[@TEST_NAME]]";
import library "val_return_lib";
//@include-in-dumps
fn G() {
let unused x: i32 = F();
}
// CHECK:STDOUT: --- val_return.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
@@ -298,3 +318,54 @@ fn F() -> var i32 {
// CHECK:STDOUT: return %.loc7_11.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- import_val_return.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: type: type = facet_type <type> [concrete]
// CHECK:STDOUT: %G.type: type = fn_type @G [concrete]
// CHECK:STDOUT: %G: %G.type = struct_value () [concrete]
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete]
// CHECK:STDOUT: %Int.type: type = parameterized_class_name_type @Int [concrete]
// CHECK:STDOUT: %Int.generic: %Int.type = struct_value () [concrete]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete]
// CHECK:STDOUT: %pattern_type.d94: type = pattern_type %i32 [concrete]
// CHECK:STDOUT: %x.patt: %pattern_type.d94 = value_binding_pattern x [concrete]
// CHECK:STDOUT: %F.type: type = fn_type @F [concrete]
// CHECK:STDOUT: %F: %F.type = struct_value () [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Main.F: %F.type = import_ref Main//val_return_lib, F, loaded [concrete = constants.%F]
// CHECK:STDOUT: %Core: <namespace> = namespace file.%Core.import, [concrete] {
// CHECK:STDOUT: .Int = %Core.Int
// CHECK:STDOUT: import Core//prelude
// CHECK:STDOUT: import Core//prelude/...
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core.Int: %Int.type = import_ref Core//prelude/parts/int, Int, loaded [concrete = constants.%Int.generic]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [concrete] {
// CHECK:STDOUT: .F = imports.%Main.F
// CHECK:STDOUT: .Core = imports.%Core
// CHECK:STDOUT: .G = %G.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core.import = import Core
// CHECK:STDOUT: %default.import = import <none>
// CHECK:STDOUT: %G.decl: %G.type = fn_decl @G [concrete = constants.%G] {} {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @G() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %F.ref: %F.type = name_ref F, imports.%Main.F [concrete = constants.%F]
// CHECK:STDOUT: %F.call: %i32 = call %F.ref()
// CHECK:STDOUT: %i32: type = type_literal constants.%i32 [concrete = constants.%i32]
// CHECK:STDOUT: %x: %i32 = wrapper_binding x, %F.call
// CHECK:STDOUT: name_binding_decl {
// CHECK:STDOUT: %x.patt: %pattern_type.d94 = value_binding_pattern x [concrete = constants.%x.patt]
// CHECK:STDOUT: }
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F [from "val_return_lib.carbon"];
// CHECK:STDOUT: