Skip to content

Commit

Permalink
Import support for tuple, struct and integer values. (carbon-language…
Browse files Browse the repository at this point in the history
…#4042)

These can be imported as the argument values for a generic. Also, the
name of a generic is modeled as a `StructValue`.
  • Loading branch information
zygoloid authored Jun 7, 2024
1 parent ac2428a commit 4aa3497
Show file tree
Hide file tree
Showing 6 changed files with 573 additions and 32 deletions.
69 changes: 61 additions & 8 deletions toolchain/check/import_ref.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ class ImportRefResolver {
inst_ids.reserve(import_block.size());
for (auto import_inst_id : import_block) {
auto const_id = GetLocalConstantId(import_inst_id);
inst_ids.push_back(const_id.inst_id());
inst_ids.push_back(const_id.inst_id_if_valid());
}

return inst_ids;
Expand Down Expand Up @@ -692,15 +692,24 @@ class ImportRefResolver {
case CARBON_KIND(SemIR::InterfaceType inst): {
return TryResolveTypedInst(inst);
}
case CARBON_KIND(SemIR::IntLiteral inst): {
return TryResolveTypedInst(inst);
}
case CARBON_KIND(SemIR::PointerType inst): {
return TryResolveTypedInst(inst);
}
case CARBON_KIND(SemIR::StructType inst): {
return TryResolveTypedInst(inst, inst_id);
}
case CARBON_KIND(SemIR::StructValue inst): {
return TryResolveTypedInst(inst);
}
case CARBON_KIND(SemIR::TupleType inst): {
return TryResolveTypedInst(inst);
}
case CARBON_KIND(SemIR::TupleValue inst): {
return TryResolveTypedInst(inst);
}
case CARBON_KIND(SemIR::UnboundElementType inst): {
return TryResolveTypedInst(inst);
}
Expand Down Expand Up @@ -1314,11 +1323,25 @@ class ImportRefResolver {
<< "Failed to import an element without adding new work.";

auto elements_id = context_.inst_blocks().Add(elements);
return {.const_id = TryEvalInst(
context_, SemIR::InstId::Invalid,
SemIR::InterfaceWitness{.type_id = context_.GetBuiltinType(
SemIR::BuiltinKind::WitnessType),
.elements_id = elements_id})};
SemIR::InterfaceWitness new_inst = {
.type_id = context_.GetBuiltinType(SemIR::BuiltinKind::WitnessType),
.elements_id = elements_id};
return {.const_id =
TryEvalInst(context_, SemIR::InstId::Invalid, new_inst)};
}

auto TryResolveTypedInst(SemIR::IntLiteral inst) -> ResolveResult {
auto initial_work = work_stack_.size();
auto type_id = GetLocalConstantId(inst.type_id);
if (HasNewWork(initial_work)) {
return ResolveResult::Retry();
}

SemIR::IntLiteral new_inst = {
.type_id = context_.GetTypeIdForTypeConstant(type_id),
.int_id = context_.ints().Add(import_ir_.ints().Get(inst.int_id))};
return {.const_id =
TryEvalInst(context_, SemIR::InstId::Invalid, new_inst)};
}

auto TryResolveTypedInst(SemIR::PointerType inst) -> ResolveResult {
Expand Down Expand Up @@ -1369,6 +1392,21 @@ class ImportRefResolver {
context_.GetStructType(context_.inst_blocks().Add(fields)))};
}

auto TryResolveTypedInst(SemIR::StructValue inst) -> ResolveResult {
auto initial_work = work_stack_.size();
auto type_id = GetLocalConstantId(inst.type_id);
auto elems = GetLocalInstBlockContents(inst.elements_id);
if (HasNewWork(initial_work)) {
return ResolveResult::Retry();
}

SemIR::StructValue new_inst = {
.type_id = context_.GetTypeIdForTypeConstant(type_id),
.elements_id = GetLocalCanonicalInstBlockId(inst.elements_id, elems)};
return {.const_id =
TryEvalInst(context_, SemIR::InstId::Invalid, new_inst)};
}

auto TryResolveTypedInst(SemIR::TupleType inst) -> ResolveResult {
CARBON_CHECK(inst.type_id == SemIR::TypeId::TypeType);

Expand All @@ -1391,8 +1429,23 @@ class ImportRefResolver {
elem_type_ids.push_back(context_.GetTypeIdForTypeConstant(elem_const_id));
}

return {
context_.types().GetConstantId(context_.GetTupleType(elem_type_ids))};
return {.const_id = context_.types().GetConstantId(
context_.GetTupleType(elem_type_ids))};
}

auto TryResolveTypedInst(SemIR::TupleValue inst) -> ResolveResult {
auto initial_work = work_stack_.size();
auto type_id = GetLocalConstantId(inst.type_id);
auto elems = GetLocalInstBlockContents(inst.elements_id);
if (HasNewWork(initial_work)) {
return ResolveResult::Retry();
}

SemIR::TupleValue new_inst = {
.type_id = context_.GetTypeIdForTypeConstant(type_id),
.elements_id = GetLocalCanonicalInstBlockId(inst.elements_id, elems)};
return {.const_id =
TryEvalInst(context_, SemIR::InstId::Invalid, new_inst)};
}

auto TryResolveTypedInst(SemIR::UnboundElementType inst) -> ResolveResult {
Expand Down
25 changes: 11 additions & 14 deletions toolchain/check/testdata/interface/no_prelude/generic_import.carbon
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,9 @@ interface AddWith(T:! type) {
fn F();
}

// --- fail_todo_b.carbon
// --- b.carbon

library "b";
// CHECK:STDERR: fail_todo_b.carbon:[[@LINE+4]]:1: In import.
// CHECK:STDERR: import library "a";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: a.carbon: ERROR: Semantics TODO: `TryResolveInst on StructValue`.
import library "a";

class C {}
Expand Down Expand Up @@ -68,16 +64,17 @@ impl C as AddWith(C) {
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F();
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_b.carbon
// CHECK:STDOUT: --- b.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [template]
// CHECK:STDOUT: %.1: type = struct_type {} [template]
// CHECK:STDOUT: %AddWith.type: type = generic_interface_type @AddWith [template]
// CHECK:STDOUT: %.2: type = tuple_type () [template]
// CHECK:STDOUT: %AddWith: %AddWith.type = struct_value () [template]
// CHECK:STDOUT: %Self: <error> = bind_symbolic_name Self 1 [symbolic]
// CHECK:STDOUT: %T: type = bind_symbolic_name T 0, <unexpected instref inst+14> [symbolic]
// CHECK:STDOUT: %AddWith.1: %AddWith.type = struct_value () [template]
// CHECK:STDOUT: %AddWith.2: %AddWith.type = struct_value () [template]
// CHECK:STDOUT: %Self: %AddWith.2 = bind_symbolic_name Self 1 [symbolic]
// CHECK:STDOUT: %T: type = bind_symbolic_name T 0, <unexpected instref inst+15> [symbolic]
// CHECK:STDOUT: %.3: type = interface_type @AddWith, (%C) [template]
// CHECK:STDOUT: %F.type.1: type = fn_type @F.1 [template]
// CHECK:STDOUT: %F.1: %F.type.1 = struct_value () [template]
Expand All @@ -91,16 +88,16 @@ impl C as AddWith(C) {
// CHECK:STDOUT: .AddWith = %import_ref.1
// CHECK:STDOUT: .C = %C.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref.1: %AddWith.type = import_ref ir1, inst+4, loaded [template = constants.%AddWith]
// CHECK:STDOUT: %import_ref.1: %AddWith.type = import_ref ir1, inst+4, loaded [template = constants.%AddWith.1]
// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: %import_ref.2 = import_ref ir1, inst+8, unloaded
// CHECK:STDOUT: %import_ref.3 = import_ref ir1, inst+14, unloaded
// CHECK:STDOUT: %import_ref.4: %F.type.2 = import_ref ir1, inst+10, loaded [template = constants.%F.2]
// CHECK:STDOUT: impl_decl @impl {
// CHECK:STDOUT: %C.ref.loc11_6: type = name_ref C, %C.decl [template = constants.%C]
// CHECK:STDOUT: %AddWith.ref: %AddWith.type = name_ref AddWith, %import_ref.1 [template = constants.%AddWith]
// CHECK:STDOUT: %C.ref.loc11_19: type = name_ref C, %C.decl [template = constants.%C]
// CHECK:STDOUT: %.loc11: type = interface_type @AddWith, (%C.ref.loc11_19) [template = constants.%.3]
// CHECK:STDOUT: %C.ref.loc7_6: type = name_ref C, %C.decl [template = constants.%C]
// CHECK:STDOUT: %AddWith.ref: %AddWith.type = name_ref AddWith, %import_ref.1 [template = constants.%AddWith.1]
// CHECK:STDOUT: %C.ref.loc7_19: type = name_ref C, %C.decl [template = constants.%C]
// CHECK:STDOUT: %.loc7: type = interface_type @AddWith, (%C.ref.loc7_19) [template = constants.%.3]
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
Expand Down
Loading

0 comments on commit 4aa3497

Please sign in to comment.