diff --git a/toolchain/check/context.cpp b/toolchain/check/context.cpp index 0a9606ebfa50..14014d870b19 100644 --- a/toolchain/check/context.cpp +++ b/toolchain/check/context.cpp @@ -712,17 +712,9 @@ class TypeCompleter { return value_rep; }; - auto BuildImportRefUsedValueRepr(SemIR::TypeId type_id, - SemIR::ImportRefUsed import_ref) const - -> SemIR::ValueRepr { - CARBON_CHECK(import_ref.inst_id.is_builtin()) - << "TODO: Handle non-builtin ImportRefUsed cases, such as functions, " - "classes, and interfaces"; - - const auto& import_ir = context_.import_irs().Get(import_ref.ir_id); - auto import_inst = import_ir->insts().Get(import_ref.inst_id); - - switch (import_inst.As().builtin_kind) { + auto BuildBuiltinValueRepr(SemIR::TypeId type_id, + SemIR::Builtin builtin) const -> SemIR::ValueRepr { + switch (builtin.builtin_kind) { case SemIR::BuiltinKind::TypeType: case SemIR::BuiltinKind::Error: case SemIR::BuiltinKind::Invalid: @@ -743,6 +735,16 @@ class TypeCompleter { llvm_unreachable("All builtin kinds were handled above"); } + auto BuildImportRefUsedValueRepr(SemIR::TypeId type_id, + SemIR::ImportRefUsed import_ref) const + -> SemIR::ValueRepr { + const auto& import_ir = context_.import_irs().Get(import_ref.ir_id); + auto import_inst = import_ir->insts().Get(import_ref.inst_id); + CARBON_CHECK(import_inst.kind() != SemIR::InstKind::ImportRefUsed) + << "If ImportRefUsed can point at another, this would be recursive."; + return BuildValueRepr(type_id, import_inst); + } + auto BuildStructOrTupleValueRepr(std::size_t num_elements, SemIR::TypeId elementwise_rep, bool same_as_object_rep) const @@ -928,7 +930,7 @@ class TypeCompleter { return MakeEmptyValueRepr(); case SemIR::Builtin::Kind: - CARBON_FATAL() << "Builtins should be named as ImportRefUsed"; + return BuildBuiltinValueRepr(type_id, inst.As()); case SemIR::BindSymbolicName::Kind: case SemIR::PointerType::Kind: diff --git a/toolchain/check/handle_let.cpp b/toolchain/check/handle_let.cpp index c4acaf20102b..3b7db5089169 100644 --- a/toolchain/check/handle_let.cpp +++ b/toolchain/check/handle_let.cpp @@ -71,6 +71,9 @@ auto HandleLetDecl(Context& context, Parse::LetDeclId parse_node) -> bool { // Add the name of the binding to the current scope. auto name_id = context.bind_names().Get(bind_name.bind_name_id).name_id; context.AddNameToLookup(name_id, pattern_id); + if (context.scope_stack().PeekNameScopeId() == SemIR::NameScopeId::Package) { + context.AddExport(pattern_id); + } return true; } diff --git a/toolchain/check/import.cpp b/toolchain/check/import.cpp index bdb12c6d4353..068d171e330d 100644 --- a/toolchain/check/import.cpp +++ b/toolchain/check/import.cpp @@ -21,9 +21,10 @@ static auto GetImportName(const SemIR::File& import_sem_ir, SemIR::Inst import_inst) -> std::pair { switch (import_inst.kind()) { - case SemIR::InstKind::BindName: { + case SemIR::InstKind::BindName: + case SemIR::InstKind::BindSymbolicName: { const auto& bind_name = import_sem_ir.bind_names().Get( - import_inst.As().bind_name_id); + import_inst.As().bind_name_id); return {bind_name.name_id, bind_name.enclosing_scope_id}; } diff --git a/toolchain/check/import_ref.cpp b/toolchain/check/import_ref.cpp index 8844b4fe1c55..ace52473b425 100644 --- a/toolchain/check/import_ref.cpp +++ b/toolchain/check/import_ref.cpp @@ -55,6 +55,23 @@ class ImportRefResolver { return constant_id; } + // Wraps constant evaluation with logic to handle types. + auto ResolveType(SemIR::TypeId import_type_id) -> SemIR::TypeId { + if (!import_type_id.is_valid()) { + return import_type_id; + } + + auto import_type_inst_id = import_ir_.types().GetInstId(import_type_id); + CARBON_CHECK(import_type_inst_id.is_valid()); + + if (import_type_inst_id.is_builtin()) { + // Builtins don't require constant resolution; we can use them directly. + return context_.GetBuiltinType(import_type_inst_id.builtin_kind()); + } else { + return context_.GetTypeIdForTypeConstant(Resolve(import_type_inst_id)); + } + } + private: // Returns the ConstantId for an instruction, or adds it to the stack and // returns Invalid if the ConstantId is not ready. @@ -104,6 +121,21 @@ class ImportRefResolver { case SemIR::InstKind::TupleType: return TryResolveTypedInst(inst.As()); + case SemIR::InstKind::BindName: + case SemIR::InstKind::BindSymbolicName: + // Can use TryEvalInst because the resulting constant doesn't really use + // `inst`. + return TryEvalInst(context_, inst_id, inst); + + case SemIR::InstKind::ClassDecl: + case SemIR::InstKind::InterfaceDecl: + // TODO: Not implemented. + return SemIR::ConstantId::Error; + + case SemIR::InstKind::FunctionDecl: + // TODO: Allowed to work for testing, but not really implemented. + return SemIR::ConstantId::NotConstant; + default: context_.TODO( Parse::NodeId::Invalid, @@ -219,57 +251,36 @@ class ImportRefResolver { auto TryResolveImportRefUnused(Context& context, SemIR::InstId inst_id) -> void { auto inst = context.insts().Get(inst_id); - auto unused_inst = inst.TryAs(); - if (!unused_inst) { + auto import_ref = inst.TryAs(); + if (!import_ref) { return; } - const SemIR::File& import_ir = *context.import_irs().Get(unused_inst->ir_id); - auto import_inst = import_ir.insts().Get(unused_inst->inst_id); + const SemIR::File& import_ir = *context.import_irs().Get(import_ref->ir_id); + auto& import_ir_constant_values = + context.import_ir_constant_values()[import_ref->ir_id.index]; + auto import_inst = import_ir.insts().Get(import_ref->inst_id); - // TODO: Types need to be specifically addressed here to prevent crashes in - // constant evaluation while support is incomplete. Functions are also - // incomplete, but are allowed to fail differently because they aren't a type. - // The partial function support is useful for some namespace validation. - if (import_inst.Is() || - import_inst.Is()) { - context.TODO( - Parse::NodeId::Invalid, - llvm::formatv("TryResolveImportRefUnused on {0}", import_inst.kind()) - .str()); - context.ReplaceInstBeforeConstantUse( - inst_id, {SemIR::ImportRefUsed{SemIR::TypeId::Error, unused_inst->ir_id, - unused_inst->inst_id}}); - return; + ImportRefResolver resolver(context, import_ir, import_ir_constant_values); + auto type_id = resolver.ResolveType(import_inst.type_id()); + auto constant_id = resolver.Resolve(import_ref->inst_id); + + // TODO: Once ClassDecl/InterfaceDecl are supported (no longer return Error), + // remove this. + if (constant_id == SemIR::ConstantId::Error) { + type_id = SemIR::TypeId::Error; } - // If the type ID isn't a normal value, forward it directly. - if (!import_inst.type_id().is_valid()) { - context.ReplaceInstBeforeConstantUse( - inst_id, - {SemIR::ImportRefUsed{import_inst.type_id(), unused_inst->ir_id, - unused_inst->inst_id}}); - return; - } + // Replace the ImportRefUnused instruction with an ImportRefUsed. This doesn't + // use ReplaceInstBeforeConstantUse because it would trigger TryEvalInst, and + // we're instead doing constant evaluation here in order to minimize recursion + // risks. + context.sem_ir().insts().Set( + inst_id, + SemIR::ImportRefUsed{type_id, import_ref->ir_id, import_ref->inst_id}); - auto import_type_inst_id = import_ir.types().GetInstId(import_inst.type_id()); - CARBON_CHECK(import_type_inst_id.is_valid()); - - auto type_id = SemIR::TypeId::Invalid; - if (import_type_inst_id.is_builtin()) { - // Builtins don't require constant resolution; we can use them directly. - type_id = context.GetBuiltinType(import_type_inst_id.builtin_kind()); - } else { - ImportRefResolver resolver( - context, import_ir, - context.import_ir_constant_values()[unused_inst->ir_id.index]); - type_id = - context.GetTypeIdForTypeConstant(resolver.Resolve(import_type_inst_id)); - } - // TODO: Add breadcrumbs for lowering. - context.ReplaceInstBeforeConstantUse( - inst_id, {SemIR::ImportRefUsed{type_id, unused_inst->ir_id, - unused_inst->inst_id}}); + // Store the constant for both the ImportRefUsed and imported instruction. + context.constant_values().Set(inst_id, constant_id); } } // namespace Carbon::Check diff --git a/toolchain/check/testdata/class/fail_todo_import.carbon b/toolchain/check/testdata/class/fail_todo_import.carbon index 4783a3df58da..be2e598675fd 100644 --- a/toolchain/check/testdata/class/fail_todo_import.carbon +++ b/toolchain/check/testdata/class/fail_todo_import.carbon @@ -3,8 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // AUTOUPDATE -// CHECK:STDERR: b.carbon: ERROR: Semantics TODO: `TryResolveImportRefUnused on ClassDecl`. -// CHECK:STDERR: b.carbon: ERROR: Semantics TODO: `TryResolveImportRefUnused on ClassDecl`. // CHECK:STDERR: b.carbon: ERROR: Semantics TODO: `TryResolveInst on ClassType`. // CHECK:STDERR: b.carbon: ERROR: Semantics TODO: `TryResolveInst on ClassType`. @@ -114,23 +112,23 @@ var d: (ForwardDeclared,) = d_ref; // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {.Empty = %import_ref.1, .ForwardDeclared = %import_ref.2, .a_ref = %import_ref.3, .b_ref = %import_ref.4, .c_ref = %import_ref.5, .Run = %Run, .a = %a, .b = %b, .c = %c, .d = %d} [template] -// CHECK:STDOUT: %import_ref.1: = import_ref ir1, inst+1, used -// CHECK:STDOUT: %import_ref.2: = import_ref ir1, inst+4, used +// CHECK:STDOUT: %import_ref.1: = import_ref ir1, inst+1, used [template = ] +// CHECK:STDOUT: %import_ref.2: = import_ref ir1, inst+4, used [template = ] // CHECK:STDOUT: %import_ref.3: ref = import_ref ir1, inst+12, used // CHECK:STDOUT: %import_ref.4: ref = import_ref ir1, inst+20, used // CHECK:STDOUT: %import_ref.5: ref = import_ref ir1, inst+30, used // CHECK:STDOUT: %Run: = fn_decl @Run [template] -// CHECK:STDOUT: %Empty.ref: = name_ref Empty, %import_ref.1 +// CHECK:STDOUT: %Empty.ref: = name_ref Empty, %import_ref.1 [template = ] // CHECK:STDOUT: %a.var: ref = var a // CHECK:STDOUT: %a: ref = bind_name a, %a.var -// CHECK:STDOUT: %ForwardDeclared.ref.loc13: = name_ref ForwardDeclared, %import_ref.2 +// CHECK:STDOUT: %ForwardDeclared.ref.loc13: = name_ref ForwardDeclared, %import_ref.2 [template = ] // CHECK:STDOUT: %b.var: ref = var b // CHECK:STDOUT: %b: ref = bind_name b, %b.var -// CHECK:STDOUT: %ForwardDeclared.ref.loc14: = name_ref ForwardDeclared, %import_ref.2 +// CHECK:STDOUT: %ForwardDeclared.ref.loc14: = name_ref ForwardDeclared, %import_ref.2 [template = ] // CHECK:STDOUT: %.loc14: type = ptr_type [template = ] // CHECK:STDOUT: %c.var: ref = var c // CHECK:STDOUT: %c: ref = bind_name c, %c.var -// CHECK:STDOUT: %ForwardDeclared.ref.loc18: = name_ref ForwardDeclared, %import_ref.2 +// CHECK:STDOUT: %ForwardDeclared.ref.loc18: = name_ref ForwardDeclared, %import_ref.2 [template = ] // CHECK:STDOUT: %.loc18: = tuple_literal (%ForwardDeclared.ref.loc18) // CHECK:STDOUT: %d.var: ref = var d // CHECK:STDOUT: %d: ref = bind_name d, %d.var @@ -138,12 +136,12 @@ var d: (ForwardDeclared,) = d_ref; // CHECK:STDOUT: // CHECK:STDOUT: fn @Run() { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %Empty.ref: = name_ref Empty, file.%import_ref.1 +// CHECK:STDOUT: %Empty.ref: = name_ref Empty, file.%import_ref.1 [template = ] // CHECK:STDOUT: %x.var: ref = var x // CHECK:STDOUT: %x: ref = bind_name x, %x.var // CHECK:STDOUT: %.loc7: {} = struct_literal () // CHECK:STDOUT: assign %x.var, -// CHECK:STDOUT: %ForwardDeclared.ref: = name_ref ForwardDeclared, file.%import_ref.2 +// CHECK:STDOUT: %ForwardDeclared.ref: = name_ref ForwardDeclared, file.%import_ref.2 [template = ] // CHECK:STDOUT: %y.var: ref = var y // CHECK:STDOUT: %y: ref = bind_name y, %y.var // CHECK:STDOUT: %.loc8: {} = struct_literal () diff --git a/toolchain/check/testdata/let/fail_generic_import.carbon b/toolchain/check/testdata/let/fail_generic_import.carbon new file mode 100644 index 000000000000..cd9231b0be7e --- /dev/null +++ b/toolchain/check/testdata/let/fail_generic_import.carbon @@ -0,0 +1,43 @@ +// 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 + +// --- implicit.carbon + +package Implicit api; + +let T:! type = i32; + +// --- implicit.impl.carbon + +package Implicit impl; + +// TODO: Should this be valid? +// CHECK:STDERR: implicit.impl.carbon:[[@LINE+3]]:1: ERROR: Cannot implicitly convert from `i32` to `T`. +// CHECK:STDERR: let a: T = 0; +// CHECK:STDERR: ^~~~~~~~~~~~~ +let a: T = 0; + +// CHECK:STDOUT: --- implicit.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace {} [template] +// CHECK:STDOUT: %T: type = bind_symbolic_name T, i32 [symbolic] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- implicit.impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: i32 = int_literal 0 [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace {.T = %import_ref} [template] +// CHECK:STDOUT: %import_ref: type = import_ref ir1, inst+1, used [symbolic] +// CHECK:STDOUT: %T.ref: type = name_ref T, %import_ref [symbolic = %import_ref] +// CHECK:STDOUT: %.loc8: i32 = int_literal 0 [template = constants.%.1] +// CHECK:STDOUT: %a: T = bind_name a, +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/let/generic_import.carbon b/toolchain/check/testdata/let/generic_import.carbon new file mode 100644 index 000000000000..5536b03c632b --- /dev/null +++ b/toolchain/check/testdata/let/generic_import.carbon @@ -0,0 +1,54 @@ +// 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 + +// --- implicit.carbon + +package Implicit api; + +let T:! type = i32; + +// --- implicit.impl.carbon + +package Implicit impl; + +var a: T*; +var b: T = *a; + +// CHECK:STDOUT: --- implicit.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace {} [template] +// CHECK:STDOUT: %T: type = bind_symbolic_name T, i32 [symbolic] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- implicit.impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = ptr_type T [symbolic] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace {.T = %import_ref, .a = %a, .b = %b} [template] +// CHECK:STDOUT: %import_ref: type = import_ref ir1, inst+1, used [symbolic] +// CHECK:STDOUT: %T.ref.loc4: type = name_ref T, %import_ref [symbolic = %import_ref] +// CHECK:STDOUT: %.loc4: type = ptr_type T [symbolic = constants.%.1] +// CHECK:STDOUT: %a.var: ref T* = var a +// CHECK:STDOUT: %a: ref T* = bind_name a, %a.var +// CHECK:STDOUT: %T.ref.loc5: type = name_ref T, %import_ref [symbolic = %import_ref] +// CHECK:STDOUT: %b.var: ref T = var b +// CHECK:STDOUT: %b: ref T = bind_name b, %b.var +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @__global_init() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %a.ref: ref T* = name_ref a, file.%a +// CHECK:STDOUT: %.loc5_13: T* = bind_value %a.ref +// CHECK:STDOUT: %.loc5_12.1: ref T = deref %.loc5_13 +// CHECK:STDOUT: %.loc5_12.2: T = bind_value %.loc5_12.1 +// CHECK:STDOUT: assign file.%b.var, %.loc5_12.2 +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/let/import.carbon b/toolchain/check/testdata/let/import.carbon new file mode 100644 index 000000000000..38d3d551b775 --- /dev/null +++ b/toolchain/check/testdata/let/import.carbon @@ -0,0 +1,39 @@ +// 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 + +// --- implicit.carbon + +package Implicit api; + +let a:! bool = true; + +// --- implicit.impl.carbon + +package Implicit impl; + +let b:! bool = a; + +// CHECK:STDOUT: --- implicit.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: bool = bool_literal true [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace {} [template] +// CHECK:STDOUT: %.loc4: bool = bool_literal true [template = constants.%.1] +// CHECK:STDOUT: %a: bool = bind_symbolic_name a, %.loc4 [symbolic] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- implicit.impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace {.a = %import_ref} [template] +// CHECK:STDOUT: %import_ref: bool = import_ref ir1, inst+1, used [symbolic] +// CHECK:STDOUT: %a.ref: bool = name_ref a, %import_ref [symbolic = %import_ref] +// CHECK:STDOUT: %b: bool = bind_symbolic_name b, %a.ref [symbolic] +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/sem_ir/file.cpp b/toolchain/sem_ir/file.cpp index 58910b9f7b42..b8be1a3cf196 100644 --- a/toolchain/sem_ir/file.cpp +++ b/toolchain/sem_ir/file.cpp @@ -261,25 +261,27 @@ static auto GetTypePrecedence(InstKind kind) -> int { } } -auto File::StringifyType(TypeId type_id) const -> std::string { - return StringifyTypeExpr(types().GetInstId(type_id)); -} - -auto File::StringifyTypeExpr(InstId outer_inst_id) const -> std::string { +// Implements File::StringifyTypeExpr. Static to prevent accidental use of +// member functions while traversing IRs. +static auto StringifyTypeExprImpl(const SemIR::File& outer_sem_ir, + InstId outer_inst_id) { std::string str; llvm::raw_string_ostream out(str); struct Step { + // The instruction's file. + const File& sem_ir; // The instruction to print. InstId inst_id; // The index into inst_id to print. Not used by all types. int index = 0; auto Next() const -> Step { - return {.inst_id = inst_id, .index = index + 1}; + return {.sem_ir = sem_ir, .inst_id = inst_id, .index = index + 1}; } }; - llvm::SmallVector steps = {{.inst_id = outer_inst_id}}; + llvm::SmallVector steps = { + Step{.sem_ir = outer_sem_ir, .inst_id = outer_inst_id}}; while (!steps.empty()) { auto step = steps.pop_back_val(); @@ -294,29 +296,35 @@ auto File::StringifyTypeExpr(InstId outer_inst_id) const -> std::string { continue; } - auto inst = insts().Get(step.inst_id); + const auto& sem_ir = step.sem_ir; + // Helper for instructions with the current sem_ir. + auto push_inst_id = [&](InstId inst_id) { + steps.push_back({.sem_ir = sem_ir, .inst_id = inst_id}); + }; + + auto inst = sem_ir.insts().Get(step.inst_id); switch (inst.kind()) { case ArrayType::Kind: { auto array = inst.As(); if (step.index == 0) { out << "["; steps.push_back(step.Next()); - steps.push_back( - {.inst_id = types().GetInstId(array.element_type_id)}); + push_inst_id(sem_ir.types().GetInstId(array.element_type_id)); } else if (step.index == 1) { - out << "; " << GetArrayBoundValue(array.bound_id) << "]"; + out << "; " << sem_ir.GetArrayBoundValue(array.bound_id) << "]"; } break; } case BindSymbolicName::Kind: { auto name_id = inst.As().bind_name_id; - out << names().GetFormatted(bind_names().Get(name_id).name_id); + out << sem_ir.names().GetFormatted( + sem_ir.bind_names().Get(name_id).name_id); break; } case ClassType::Kind: { auto class_name_id = - classes().Get(inst.As().class_id).name_id; - out << names().GetFormatted(class_name_id); + sem_ir.classes().Get(inst.As().class_id).name_id; + out << sem_ir.names().GetFormatted(class_name_id); break; } case ConstType::Kind: { @@ -325,44 +333,48 @@ auto File::StringifyTypeExpr(InstId outer_inst_id) const -> std::string { // Add parentheses if required. auto inner_type_inst_id = - types().GetInstId(inst.As().inner_id); - if (GetTypePrecedence(insts().Get(inner_type_inst_id).kind()) < + sem_ir.types().GetInstId(inst.As().inner_id); + if (GetTypePrecedence(sem_ir.insts().Get(inner_type_inst_id).kind()) < GetTypePrecedence(inst.kind())) { out << "("; steps.push_back(step.Next()); } - steps.push_back({.inst_id = inner_type_inst_id}); + push_inst_id(inner_type_inst_id); } else if (step.index == 1) { out << ")"; } break; } - case ImportRefUsed::Kind: - out << ""; + case ImportRefUsed::Kind: { + auto import_ref = inst.As(); + steps.push_back({.sem_ir = *sem_ir.import_irs().Get(import_ref.ir_id), + .inst_id = import_ref.inst_id}); break; + } case InterfaceType::Kind: { - auto interface_name_id = - interfaces().Get(inst.As().interface_id).name_id; - out << names().GetFormatted(interface_name_id); + auto interface_name_id = sem_ir.interfaces() + .Get(inst.As().interface_id) + .name_id; + out << sem_ir.names().GetFormatted(interface_name_id); break; } case NameRef::Kind: { - out << names().GetFormatted(inst.As().name_id); + out << sem_ir.names().GetFormatted(inst.As().name_id); break; } case PointerType::Kind: { if (step.index == 0) { steps.push_back(step.Next()); - steps.push_back({.inst_id = types().GetInstId( - inst.As().pointee_id)}); + push_inst_id( + sem_ir.types().GetInstId(inst.As().pointee_id)); } else if (step.index == 1) { out << "*"; } break; } case StructType::Kind: { - auto refs = inst_blocks().Get(inst.As().fields_id); + auto refs = sem_ir.inst_blocks().Get(inst.As().fields_id); if (refs.empty()) { out << "{}"; break; @@ -376,17 +388,17 @@ auto File::StringifyTypeExpr(InstId outer_inst_id) const -> std::string { } steps.push_back(step.Next()); - steps.push_back({.inst_id = refs[step.index]}); + push_inst_id(refs[step.index]); break; } case StructTypeField::Kind: { auto field = inst.As(); - out << "." << names().GetFormatted(field.name_id) << ": "; - steps.push_back({.inst_id = types().GetInstId(field.field_type_id)}); + out << "." << sem_ir.names().GetFormatted(field.name_id) << ": "; + push_inst_id(sem_ir.types().GetInstId(field.field_type_id)); break; } case TupleType::Kind: { - auto refs = type_blocks().Get(inst.As().elements_id); + auto refs = sem_ir.type_blocks().Get(inst.As().elements_id); if (refs.empty()) { out << "()"; break; @@ -404,15 +416,15 @@ auto File::StringifyTypeExpr(InstId outer_inst_id) const -> std::string { break; } steps.push_back(step.Next()); - steps.push_back({.inst_id = types().GetInstId(refs[step.index])}); + push_inst_id(sem_ir.types().GetInstId(refs[step.index])); break; } case UnboundElementType::Kind: { if (step.index == 0) { out << "().class_type_id)}); + push_inst_id(sem_ir.types().GetInstId( + inst.As().class_type_id)); } else { out << ">"; } @@ -480,6 +492,14 @@ auto File::StringifyTypeExpr(InstId outer_inst_id) const -> std::string { return str; } +auto File::StringifyType(TypeId type_id) const -> std::string { + return StringifyTypeExprImpl(*this, types().GetInstId(type_id)); +} + +auto File::StringifyTypeExpr(InstId outer_inst_id) const -> std::string { + return StringifyTypeExprImpl(*this, outer_inst_id); +} + auto GetExprCategory(const File& file, InstId inst_id) -> ExprCategory { const File* ir = &file;