diff --git a/toolchain/check/check.cpp b/toolchain/check/check.cpp index f1835605fe97..529326e529c2 100644 --- a/toolchain/check/check.cpp +++ b/toolchain/check/check.cpp @@ -40,16 +40,21 @@ class SemIRDiagnosticConverter : public DiagnosticConverter { -> DiagnosticLocation override { // Parse nodes always refer to the current IR. if (!loc.is_inst_id) { - return ConvertLocationInFile(sem_ir_, loc.node_location, context_fn); + CARBON_CHECK(loc.loc_id.is_node_id() || !loc.loc_id.is_valid()) + << "TODO: Handle non-NodeId locs"; + return ConvertLocationInFile(sem_ir_, loc.loc_id.node_id(), + loc.token_only, context_fn); } const auto* cursor_ir = sem_ir_; auto cursor_inst_id = loc.inst_id; while (true) { // If the parse node is valid, use it for the location. - if (auto node_id = cursor_ir->insts().GetNodeId(cursor_inst_id); - node_id.is_valid()) { - return ConvertLocationInFile(cursor_ir, node_id, context_fn); + if (auto loc_id = cursor_ir->insts().GetLocationId(cursor_inst_id); + loc_id.is_valid()) { + CARBON_CHECK(loc_id.is_node_id()) << "TODO: Handle non-NodeId locs"; + return ConvertLocationInFile(cursor_ir, loc_id.node_id(), + loc.token_only, context_fn); } // If the parse node was invalid, recurse through import references when @@ -57,8 +62,8 @@ class SemIRDiagnosticConverter : public DiagnosticConverter { if (auto import_ref = cursor_ir->insts().TryGetAs( cursor_inst_id)) { const auto& import_ir = cursor_ir->import_irs().Get(import_ref->ir_id); - auto context_loc = - ConvertLocationInFile(cursor_ir, import_ir.node_id, context_fn); + auto context_loc = ConvertLocationInFile(cursor_ir, import_ir.node_id, + loc.token_only, context_fn); CARBON_DIAGNOSTIC(InImport, Note, "In import."); context_fn(context_loc, InImport); cursor_ir = import_ir.sem_ir; @@ -78,7 +83,7 @@ class SemIRDiagnosticConverter : public DiagnosticConverter { // Invalid parse node but not an import; just nothing to point at. return ConvertLocationInFile(cursor_ir, Parse::NodeId::Invalid, - context_fn); + loc.token_only, context_fn); } } @@ -97,13 +102,13 @@ class SemIRDiagnosticConverter : public DiagnosticConverter { } private: - auto ConvertLocationInFile(const SemIR::File* sem_ir, - Parse::NodeLocation node_location, - ContextFnT context_fn) const + auto ConvertLocationInFile(const SemIR::File* sem_ir, Parse::NodeId node_id, + bool token_only, ContextFnT context_fn) const -> DiagnosticLocation { auto it = node_converters_->find(sem_ir); CARBON_CHECK(it != node_converters_->end()); - return it->second->ConvertLocation(node_location, context_fn); + return it->second->ConvertLocation(Parse::NodeLocation(node_id, token_only), + context_fn); } const llvm::DenseMap* diff --git a/toolchain/check/context.cpp b/toolchain/check/context.cpp index bdb3a61c2542..13e59a77ce16 100644 --- a/toolchain/check/context.cpp +++ b/toolchain/check/context.cpp @@ -68,14 +68,14 @@ auto Context::VerifyOnFinish() -> void { param_and_arg_refs_stack_.VerifyOnFinish(); } -auto Context::AddInstInNoBlock(SemIR::NodeIdAndInst node_id_and_inst) +auto Context::AddInstInNoBlock(SemIR::LocationIdAndInst loc_id_and_inst) -> SemIR::InstId { - auto inst_id = sem_ir().insts().AddInNoBlock(node_id_and_inst); - CARBON_VLOG() << "AddInst: " << node_id_and_inst.inst << "\n"; + auto inst_id = sem_ir().insts().AddInNoBlock(loc_id_and_inst); + CARBON_VLOG() << "AddInst: " << loc_id_and_inst.inst << "\n"; - auto const_id = TryEvalInst(*this, inst_id, node_id_and_inst.inst); + auto const_id = TryEvalInst(*this, inst_id, loc_id_and_inst.inst); if (const_id.is_constant()) { - CARBON_VLOG() << "Constant: " << node_id_and_inst.inst << " -> " + CARBON_VLOG() << "Constant: " << loc_id_and_inst.inst << " -> " << const_id.inst_id() << "\n"; constant_values().Set(inst_id, const_id); } @@ -83,23 +83,24 @@ auto Context::AddInstInNoBlock(SemIR::NodeIdAndInst node_id_and_inst) return inst_id; } -auto Context::AddInst(SemIR::NodeIdAndInst node_id_and_inst) -> SemIR::InstId { - auto inst_id = AddInstInNoBlock(node_id_and_inst); +auto Context::AddInst(SemIR::LocationIdAndInst loc_id_and_inst) + -> SemIR::InstId { + auto inst_id = AddInstInNoBlock(loc_id_and_inst); inst_block_stack_.AddInstId(inst_id); return inst_id; } -auto Context::AddPlaceholderInstInNoBlock(SemIR::NodeIdAndInst node_id_and_inst) - -> SemIR::InstId { - auto inst_id = sem_ir().insts().AddInNoBlock(node_id_and_inst); - CARBON_VLOG() << "AddPlaceholderInst: " << node_id_and_inst.inst << "\n"; +auto Context::AddPlaceholderInstInNoBlock( + SemIR::LocationIdAndInst loc_id_and_inst) -> SemIR::InstId { + auto inst_id = sem_ir().insts().AddInNoBlock(loc_id_and_inst); + CARBON_VLOG() << "AddPlaceholderInst: " << loc_id_and_inst.inst << "\n"; constant_values().Set(inst_id, SemIR::ConstantId::Invalid); return inst_id; } -auto Context::AddPlaceholderInst(SemIR::NodeIdAndInst node_id_and_inst) +auto Context::AddPlaceholderInst(SemIR::LocationIdAndInst loc_id_and_inst) -> SemIR::InstId { - auto inst_id = AddPlaceholderInstInNoBlock(node_id_and_inst); + auto inst_id = AddPlaceholderInstInNoBlock(loc_id_and_inst); inst_block_stack_.AddInstId(inst_id); return inst_id; } @@ -111,24 +112,24 @@ auto Context::AddConstant(SemIR::Inst inst, bool is_symbolic) return const_id; } -auto Context::AddInstAndPush(SemIR::NodeIdAndInst node_id_and_inst) -> void { - auto inst_id = AddInst(node_id_and_inst); - node_stack_.Push(node_id_and_inst.node_id, inst_id); +auto Context::AddInstAndPush(SemIR::LocationIdAndInst loc_id_and_inst) -> void { + auto inst_id = AddInst(loc_id_and_inst); + node_stack_.Push(loc_id_and_inst.loc_id.node_id(), inst_id); } auto Context::ReplaceInstBeforeConstantUse( - SemIR::InstId inst_id, SemIR::NodeIdAndInst node_id_and_inst) -> void { - sem_ir().insts().Set(inst_id, node_id_and_inst); + SemIR::InstId inst_id, SemIR::LocationIdAndInst loc_id_and_inst) -> void { + sem_ir().insts().Set(inst_id, loc_id_and_inst); - CARBON_VLOG() << "ReplaceInst: " << inst_id << " -> " << node_id_and_inst.inst + CARBON_VLOG() << "ReplaceInst: " << inst_id << " -> " << loc_id_and_inst.inst << "\n"; // Redo evaluation. This is only safe to do if this instruction has not // already been used as a constant, which is the caller's responsibility to // ensure. - auto const_id = TryEvalInst(*this, inst_id, node_id_and_inst.inst); + auto const_id = TryEvalInst(*this, inst_id, loc_id_and_inst.inst); if (const_id.is_constant()) { - CARBON_VLOG() << "Constant: " << node_id_and_inst.inst << " -> " + CARBON_VLOG() << "Constant: " << loc_id_and_inst.inst << " -> " << const_id.inst_id() << "\n"; } constant_values().Set(inst_id, const_id); @@ -162,11 +163,11 @@ auto Context::DiagnoseDuplicateName(SemIRLocation dup_def, .Emit(); } -auto Context::DiagnoseNameNotFound(Parse::NodeId node_id, SemIR::NameId name_id) - -> void { +auto Context::DiagnoseNameNotFound(SemIR::LocationId loc_id, + SemIR::NameId name_id) -> void { CARBON_DIAGNOSTIC(NameNotFound, Error, "Name `{0}` not found.", SemIR::NameId); - emitter_->Emit(node_id, NameNotFound, name_id); + emitter_->Emit(loc_id, NameNotFound, name_id); } auto Context::NoteIncompleteClass(SemIR::ClassId class_id, @@ -208,7 +209,7 @@ auto Context::AddNameToLookup(SemIR::NameId name_id, SemIR::InstId target_id) } } -auto Context::LookupNameInDecl(Parse::NodeId node_id, SemIR::NameId name_id, +auto Context::LookupNameInDecl(SemIR::LocationId loc_id, SemIR::NameId name_id, SemIR::NameScopeId scope_id) -> SemIR::InstId { if (!scope_id.is_valid()) { // Look for a name in the current scope only. There are two cases where the @@ -245,8 +246,7 @@ auto Context::LookupNameInDecl(Parse::NodeId node_id, SemIR::NameId name_id, // // // Error, no `F` in `B`. // fn B.F() {} - return LookupNameInExactScope(node_id, name_id, - name_scopes().Get(scope_id)); + return LookupNameInExactScope(loc_id, name_id, name_scopes().Get(scope_id)); } } diff --git a/toolchain/check/context.h b/toolchain/check/context.h index 1f8234474315..c66493604ff9 100644 --- a/toolchain/check/context.h +++ b/toolchain/check/context.h @@ -41,38 +41,39 @@ class Context { auto VerifyOnFinish() -> void; // Adds an instruction to the current block, returning the produced ID. - auto AddInst(SemIR::NodeIdAndInst node_id_and_inst) -> SemIR::InstId; + auto AddInst(SemIR::LocationIdAndInst loc_id_and_inst) -> SemIR::InstId; // Adds an instruction in no block, returning the produced ID. Should be used // rarely. - auto AddInstInNoBlock(SemIR::NodeIdAndInst node_id_and_inst) -> SemIR::InstId; + auto AddInstInNoBlock(SemIR::LocationIdAndInst loc_id_and_inst) + -> SemIR::InstId; // Adds an instruction to the current block, returning the produced ID. The // instruction is a placeholder that is expected to be replaced by // `ReplaceInstBeforeConstantUse`. - auto AddPlaceholderInst(SemIR::NodeIdAndInst node_id_and_inst) + auto AddPlaceholderInst(SemIR::LocationIdAndInst loc_id_and_inst) -> SemIR::InstId; // Adds an instruction in no block, returning the produced ID. Should be used // rarely. The instruction is a placeholder that is expected to be replaced by // `ReplaceInstBeforeConstantUse`. - auto AddPlaceholderInstInNoBlock(SemIR::NodeIdAndInst node_id_and_inst) + auto AddPlaceholderInstInNoBlock(SemIR::LocationIdAndInst loc_id_and_inst) -> SemIR::InstId; // Adds an instruction to the constants block, returning the produced ID. auto AddConstant(SemIR::Inst inst, bool is_symbolic) -> SemIR::ConstantId; // Pushes a parse tree node onto the stack, storing the SemIR::Inst as the - // result. - auto AddInstAndPush(SemIR::NodeIdAndInst node_id_and_inst) -> void; + // result. Only valid if the LocationId is for a NodeId. + auto AddInstAndPush(SemIR::LocationIdAndInst loc_id_and_inst) -> void; - // Replaces the value of the instruction `inst_id` with `node_id_and_inst`. + // Replaces the value of the instruction `inst_id` with `loc_id_and_inst`. // The instruction is required to not have been used in any constant // evaluation, either because it's newly created and entirely unused, or // because it's only used in a position that constant evaluation ignores, such // as a return slot. auto ReplaceInstBeforeConstantUse(SemIR::InstId inst_id, - SemIR::NodeIdAndInst node_id_and_inst) + SemIR::LocationIdAndInst loc_id_and_inst) -> void; // Adds an import_ref instruction for the specified instruction in the @@ -87,7 +88,7 @@ class Context { // remain const. auto SetNamespaceNodeId(SemIR::InstId inst_id, Parse::NodeId node_id) -> void { - sem_ir().insts().SetNodeId(inst_id, node_id); + sem_ir().insts().SetLocationId(inst_id, SemIR::LocationId(node_id)); } // Adds a name to name lookup. Prints a diagnostic for name conflicts. @@ -96,7 +97,7 @@ class Context { // Performs name lookup in a specified scope for a name appearing in a // declaration, returning the referenced instruction. If scope_id is invalid, // uses the current contextual scope. - auto LookupNameInDecl(Parse::NodeId node_id, SemIR::NameId name_id, + auto LookupNameInDecl(SemIR::LocationId loc_id, SemIR::NameId name_id, SemIR::NameScopeId scope_id) -> SemIR::InstId; // Performs an unqualified name lookup, returning the referenced instruction. @@ -120,7 +121,7 @@ class Context { -> void; // Prints a diagnostic for a missing name. - auto DiagnoseNameNotFound(Parse::NodeId node_id, SemIR::NameId name_id) + auto DiagnoseNameNotFound(SemIR::LocationId loc_id, SemIR::NameId name_id) -> void; // Adds a note to a diagnostic explaining that a class is incomplete. @@ -323,6 +324,9 @@ class Context { auto import_irs() -> ValueStore& { return sem_ir().import_irs(); } + auto import_ir_insts() -> ValueStore& { + return sem_ir().import_ir_insts(); + } auto names() -> SemIR::NameStoreWrapper { return sem_ir().names(); } auto name_scopes() -> SemIR::NameScopeStore& { return sem_ir().name_scopes(); diff --git a/toolchain/check/convert.cpp b/toolchain/check/convert.cpp index 9f44b2c0a391..aafd9a6c25b4 100644 --- a/toolchain/check/convert.cpp +++ b/toolchain/check/convert.cpp @@ -96,7 +96,7 @@ static auto FinalizeTemporary(Context& context, SemIR::InstId init_id, << sem_ir.insts().Get(return_slot_id); auto init = sem_ir.insts().Get(init_id); return context.AddInst( - {sem_ir.insts().GetNodeId(init_id), + {sem_ir.insts().GetLocationId(init_id), SemIR::Temporary{init.type_id(), return_slot_id, init_id}}); } @@ -111,11 +111,11 @@ static auto FinalizeTemporary(Context& context, SemIR::InstId init_id, // materialize and initialize a temporary, rather than two separate // instructions. auto init = sem_ir.insts().Get(init_id); - auto node_id = sem_ir.insts().GetNodeId(init_id); + auto loc_id = sem_ir.insts().GetLocationId(init_id); auto temporary_id = - context.AddInst({node_id, SemIR::TemporaryStorage{init.type_id()}}); + context.AddInst({loc_id, SemIR::TemporaryStorage{init.type_id()}}); return context.AddInst( - {node_id, SemIR::Temporary{init.type_id(), temporary_id, init_id}}); + {loc_id, SemIR::Temporary{init.type_id(), temporary_id, init_id}}); } // Materialize a temporary to hold the result of the given expression if it is @@ -131,7 +131,7 @@ static auto MaterializeIfInitializing(Context& context, SemIR::InstId expr_id) // Creates and adds an instruction to perform element access into an aggregate. template -static auto MakeElementAccessInst(Context& context, Parse::NodeId node_id, +static auto MakeElementAccessInst(Context& context, SemIR::LocationId loc_id, SemIR::InstId aggregate_id, SemIR::TypeId elem_type_id, InstBlockT& block, std::size_t i) { @@ -140,14 +140,14 @@ static auto MakeElementAccessInst(Context& context, Parse::NodeId node_id, // index so that we don't need an integer literal instruction here, and // remove this special case. auto index_id = block.AddInst( - {node_id, + {loc_id, SemIR::IntLiteral{context.GetBuiltinType(SemIR::BuiltinKind::IntType), context.ints().Add(llvm::APInt(32, i))}}); return block.AddInst( - {node_id, AccessInstT{elem_type_id, aggregate_id, index_id}}); + {loc_id, AccessInstT{elem_type_id, aggregate_id, index_id}}); } else { - return block.AddInst({node_id, AccessInstT{elem_type_id, aggregate_id, - SemIR::ElementIndex(i)}}); + return block.AddInst({loc_id, AccessInstT{elem_type_id, aggregate_id, + SemIR::ElementIndex(i)}}); } } @@ -166,7 +166,7 @@ static auto MakeElementAccessInst(Context& context, Parse::NodeId node_id, // instruction used to access the destination element. template static auto ConvertAggregateElement( - Context& context, Parse::NodeId node_id, SemIR::InstId src_id, + Context& context, SemIR::LocationId loc_id, SemIR::InstId src_id, SemIR::TypeId src_elem_type, llvm::ArrayRef src_literal_elems, ConversionTarget::Kind kind, SemIR::InstId target_id, @@ -177,22 +177,22 @@ static auto ConvertAggregateElement( auto src_elem_id = !src_literal_elems.empty() ? src_literal_elems[i] - : MakeElementAccessInst(context, node_id, src_id, + : MakeElementAccessInst(context, loc_id, src_id, src_elem_type, context, i); // If we're performing a conversion rather than an initialization, we won't // have or need a target. ConversionTarget target = {.kind = kind, .type_id = target_elem_type}; if (!target.is_initializer()) { - return Convert(context, node_id, src_elem_id, target); + return Convert(context, loc_id, src_elem_id, target); } // Compute the location of the target element and initialize it. PendingBlock::DiscardUnusedInstsScope scope(target_block); target.init_block = target_block; target.init_id = MakeElementAccessInst( - context, node_id, target_id, target_elem_type, *target_block, i); - return Convert(context, node_id, src_elem_id, target); + context, loc_id, target_id, target_elem_type, *target_block, i); + return Convert(context, loc_id, src_elem_id, target); } // Performs a conversion from a tuple to an array type. This function only @@ -206,7 +206,7 @@ static auto ConvertTupleToArray(Context& context, SemIR::TupleType tuple_type, auto tuple_elem_types = sem_ir.type_blocks().Get(tuple_type.elements_id); auto value = sem_ir.insts().Get(value_id); - auto value_node_id = sem_ir.insts().GetNodeId(value_id); + auto value_loc_id = sem_ir.insts().GetLocationId(value_id); // If we're initializing from a tuple literal, we will use its elements // directly. Otherwise, materialize a temporary if needed and index into the @@ -229,7 +229,7 @@ static auto ConvertTupleToArray(Context& context, SemIR::TupleType tuple_type, "Cannot initialize array of {0} element(s) from tuple " "with {1} element(s).", uint64_t, size_t); - context.emitter().Emit(value_node_id, + context.emitter().Emit(value_loc_id, literal_elems.empty() ? ArrayInitFromExprArgCountMismatch : ArrayInitFromLiteralArgCountMismatch, @@ -246,7 +246,7 @@ static auto ConvertTupleToArray(Context& context, SemIR::TupleType tuple_type, SemIR::InstId return_slot_id = target.init_id; if (!target.init_id.is_valid()) { return_slot_id = target_block->AddInst( - {value_node_id, SemIR::TemporaryStorage{target.type_id}}); + {value_loc_id, SemIR::TemporaryStorage{target.type_id}}); } // Initialize each element of the array from the corresponding element of the @@ -260,7 +260,7 @@ static auto ConvertTupleToArray(Context& context, SemIR::TupleType tuple_type, // approach. auto init_id = ConvertAggregateElement( - context, value_node_id, value_id, src_type_id, literal_elems, + context, value_loc_id, value_id, src_type_id, literal_elems, ConversionTarget::FullInitializer, return_slot_id, array_type.element_type_id, target_block, i); if (init_id == SemIR::InstId::BuiltinError) { @@ -273,7 +273,7 @@ static auto ConvertTupleToArray(Context& context, SemIR::TupleType tuple_type, // reference to the return slot. target_block->InsertHere(); return context.AddInst( - {value_node_id, + {value_loc_id, SemIR::ArrayInit{target.type_id, sem_ir.inst_blocks().Add(inits), return_slot_id}}); } @@ -290,7 +290,7 @@ static auto ConvertTupleToTuple(Context& context, SemIR::TupleType src_type, auto dest_elem_types = sem_ir.type_blocks().Get(dest_type.elements_id); auto value = sem_ir.insts().Get(value_id); - auto value_node_id = sem_ir.insts().GetNodeId(value_id); + auto value_loc_id = sem_ir.insts().GetLocationId(value_id); // If we're initializing from a tuple literal, we will use its elements // directly. Otherwise, materialize a temporary if needed and index into the @@ -310,7 +310,7 @@ static auto ConvertTupleToTuple(Context& context, SemIR::TupleType src_type, "Cannot initialize tuple of {0} element(s) from tuple " "with {1} element(s).", size_t, size_t); - context.emitter().Emit(value_node_id, TupleInitElementCountMismatch, + context.emitter().Emit(value_loc_id, TupleInitElementCountMismatch, dest_elem_types.size(), src_elem_types.size()); return SemIR::InstId::BuiltinError; } @@ -342,7 +342,7 @@ static auto ConvertTupleToTuple(Context& context, SemIR::TupleType src_type, // approach. auto init_id = ConvertAggregateElement( - context, value_node_id, value_id, src_type_id, literal_elems, + context, value_loc_id, value_id, src_type_id, literal_elems, inner_kind, target.init_id, dest_type_id, target.init_block, i); if (init_id == SemIR::InstId::BuiltinError) { return SemIR::InstId::BuiltinError; @@ -353,11 +353,11 @@ static auto ConvertTupleToTuple(Context& context, SemIR::TupleType src_type, if (is_init) { target.init_block->InsertHere(); return context.AddInst( - {value_node_id, + {value_loc_id, SemIR::TupleInit{target.type_id, new_block.id(), target.init_id}}); } else { return context.AddInst( - {value_node_id, SemIR::TupleValue{target.type_id, new_block.id()}}); + {value_loc_id, SemIR::TupleValue{target.type_id, new_block.id()}}); } } @@ -374,7 +374,7 @@ static auto ConvertStructToStructOrClass(Context& context, auto dest_elem_fields = sem_ir.inst_blocks().Get(dest_type.fields_id); auto value = sem_ir.insts().Get(value_id); - auto value_node_id = sem_ir.insts().GetNodeId(value_id); + auto value_loc_id = sem_ir.insts().GetLocationId(value_id); // If we're initializing from a struct literal, we will use its elements // directly. Otherwise, materialize a temporary if needed and index into the @@ -397,7 +397,7 @@ static auto ConvertStructToStructOrClass(Context& context, "with {2} field(s).", llvm::StringLiteral, size_t, size_t); context.emitter().Emit( - value_node_id, StructInitElementCountMismatch, + value_loc_id, StructInitElementCountMismatch, is_class ? llvm::StringLiteral("class") : llvm::StringLiteral("struct"), dest_elem_fields.size(), src_elem_fields.size()); return SemIR::InstId::BuiltinError; @@ -448,7 +448,7 @@ static auto ConvertStructToStructOrClass(Context& context, StructInitMissingFieldInLiteral, Error, "Missing value for field `{0}` in struct initialization.", SemIR::NameId); - context.emitter().Emit(value_node_id, StructInitMissingFieldInLiteral, + context.emitter().Emit(value_loc_id, StructInitMissingFieldInLiteral, dest_field.name_id); } else { CARBON_DIAGNOSTIC(StructInitMissingFieldInConversion, Error, @@ -456,8 +456,8 @@ static auto ConvertStructToStructOrClass(Context& context, "missing field `{2}` in source type.", SemIR::TypeId, SemIR::TypeId, SemIR::NameId); context.emitter().Emit( - value_node_id, StructInitMissingFieldInConversion, - value.type_id(), target.type_id, dest_field.name_id); + value_loc_id, StructInitMissingFieldInConversion, value.type_id(), + target.type_id, dest_field.name_id); } return SemIR::InstId::BuiltinError; } @@ -470,7 +470,7 @@ static auto ConvertStructToStructOrClass(Context& context, // approach. auto init_id = ConvertAggregateElement( - context, value_node_id, value_id, src_field.field_type_id, + context, value_loc_id, value_id, src_field.field_type_id, literal_elems, inner_kind, target.init_id, dest_field.field_type_id, target.init_block, src_field_index); if (init_id == SemIR::InstId::BuiltinError) { @@ -484,16 +484,16 @@ static auto ConvertStructToStructOrClass(Context& context, CARBON_CHECK(is_init) << "Converting directly to a class value is not supported"; return context.AddInst( - {value_node_id, + {value_loc_id, SemIR::ClassInit{target.type_id, new_block.id(), target.init_id}}); } else if (is_init) { target.init_block->InsertHere(); return context.AddInst( - {value_node_id, + {value_loc_id, SemIR::StructInit{target.type_id, new_block.id(), target.init_id}}); } else { return context.AddInst( - {value_node_id, SemIR::StructValue{target.type_id, new_block.id()}}); + {value_loc_id, SemIR::StructValue{target.type_id, new_block.id()}}); } } @@ -539,7 +539,7 @@ static auto ConvertStructToClass(Context& context, SemIR::StructType src_type, target.kind = ConversionTarget::Initializer; target.init_block = &target_block; target.init_id = - target_block.AddInst({context.insts().GetNodeId(value_id), + target_block.AddInst({context.insts().GetLocationId(value_id), SemIR::TemporaryStorage{target.type_id}}); } @@ -549,7 +549,7 @@ static auto ConvertStructToClass(Context& context, SemIR::StructType src_type, if (need_temporary) { target_block.InsertHere(); result_id = context.AddInst( - {context.insts().GetNodeId(value_id), + {context.insts().GetLocationId(value_id), SemIR::Temporary{target.type_id, target.init_id, result_id}}); } return result_id; @@ -596,7 +596,7 @@ static auto ComputeInheritancePath(Context& context, SemIR::TypeId derived_id, // Performs a conversion from a derived class value or reference to a base class // value or reference. -static auto ConvertDerivedToBase(Context& context, Parse::NodeId node_id, +static auto ConvertDerivedToBase(Context& context, SemIR::LocationId loc_id, SemIR::InstId value_id, const InheritancePath& path) -> SemIR::InstId { // Materialize a temporary if necessary. @@ -606,27 +606,27 @@ static auto ConvertDerivedToBase(Context& context, Parse::NodeId node_id, for (auto base_id : path) { auto base_decl = context.insts().GetAs(base_id); value_id = context.AddInst( - {node_id, SemIR::ClassElementAccess{base_decl.base_type_id, value_id, - base_decl.index}}); + {loc_id, SemIR::ClassElementAccess{base_decl.base_type_id, value_id, + base_decl.index}}); } return value_id; } // Performs a conversion from a derived class pointer to a base class pointer. static auto ConvertDerivedPointerToBasePointer( - Context& context, Parse::NodeId node_id, SemIR::PointerType src_ptr_type, + Context& context, SemIR::LocationId loc_id, SemIR::PointerType src_ptr_type, SemIR::TypeId dest_ptr_type_id, SemIR::InstId ptr_id, const InheritancePath& path) -> SemIR::InstId { // Form `*p`. ptr_id = ConvertToValueExpr(context, ptr_id); auto ref_id = - context.AddInst({node_id, SemIR::Deref{src_ptr_type.pointee_id, ptr_id}}); + context.AddInst({loc_id, SemIR::Deref{src_ptr_type.pointee_id, ptr_id}}); // Convert as a reference expression. - ref_id = ConvertDerivedToBase(context, node_id, ref_id, path); + ref_id = ConvertDerivedToBase(context, loc_id, ref_id, path); // Take the address. - return context.AddInst({node_id, SemIR::AddrOf{dest_ptr_type_id, ref_id}}); + return context.AddInst({loc_id, SemIR::AddrOf{dest_ptr_type_id, ref_id}}); } // Returns whether `category` is a valid expression category to produce as a @@ -651,7 +651,7 @@ static auto IsValidExprCategoryForConversionTarget( } } -static auto PerformBuiltinConversion(Context& context, Parse::NodeId node_id, +static auto PerformBuiltinConversion(Context& context, SemIR::LocationId loc_id, SemIR::InstId value_id, ConversionTarget target) -> SemIR::InstId { auto& sem_ir = context.sem_ir(); @@ -709,7 +709,7 @@ static auto PerformBuiltinConversion(Context& context, Parse::NodeId node_id, // value representation is a copy of the object representation, so we // already have a value of the right form. return context.AddInst( - {node_id, SemIR::ValueOfInitializer{value_type_id, value_id}}); + {loc_id, SemIR::ValueOfInitializer{value_type_id, value_id}}); } } } @@ -760,7 +760,7 @@ static auto PerformBuiltinConversion(Context& context, Parse::NodeId node_id, if (auto path = ComputeInheritancePath(context, value_type_id, target.type_id); path && !path->empty()) { - return ConvertDerivedToBase(context, node_id, value_id, *path); + return ConvertDerivedToBase(context, loc_id, value_id, *path); } } @@ -773,7 +773,7 @@ static auto PerformBuiltinConversion(Context& context, Parse::NodeId node_id, target_pointer_type->pointee_id); path && !path->empty()) { return ConvertDerivedPointerToBasePointer( - context, node_id, *src_pointer_type, target.type_id, value_id, + context, loc_id, *src_pointer_type, target.type_id, value_id, *path); } } @@ -788,7 +788,7 @@ static auto PerformBuiltinConversion(Context& context, Parse::NodeId node_id, sem_ir.inst_blocks().Get(tuple_literal->elements_id)) { // TODO: This call recurses back into conversion. Switch to an // iterative approach. - type_ids.push_back(ExprAsType(context, node_id, tuple_inst_id)); + type_ids.push_back(ExprAsType(context, loc_id, tuple_inst_id)); } auto tuple_type_id = context.GetTupleType(type_ids); return sem_ir.types().GetInstId(tuple_type_id); @@ -812,7 +812,7 @@ static auto PerformBuiltinConversion(Context& context, Parse::NodeId node_id, // combining the above conversions and this one in a single conversion. if (sem_ir.types().Is(value_type_id)) { return context.AddInst( - {node_id, SemIR::FacetTypeAccess{target.type_id, value_id}}); + {loc_id, SemIR::FacetTypeAccess{target.type_id, value_id}}); } } @@ -849,7 +849,7 @@ static auto PerformCopy(Context& context, SemIR::InstId expr_id) return SemIR::InstId::BuiltinError; } -auto Convert(Context& context, Parse::NodeId node_id, SemIR::InstId expr_id, +auto Convert(Context& context, SemIR::LocationId loc_id, SemIR::InstId expr_id, ConversionTarget target) -> SemIR::InstId { auto& sem_ir = context.sem_ir(); auto orig_expr_id = expr_id; @@ -882,7 +882,7 @@ auto Convert(Context& context, Parse::NodeId node_id, SemIR::InstId expr_id, CARBON_DIAGNOSTIC(IncompleteTypeInConversion, Error, "Invalid use of incomplete type `{0}`.", SemIR::TypeId); - return context.emitter().Build(node_id, + return context.emitter().Build(loc_id, target.is_initializer() ? IncompleteTypeInInit : target.kind == ConversionTarget::Value @@ -894,7 +894,7 @@ auto Convert(Context& context, Parse::NodeId node_id, SemIR::InstId expr_id, } // Check whether any builtin conversion applies. - expr_id = PerformBuiltinConversion(context, node_id, expr_id, target); + expr_id = PerformBuiltinConversion(context, loc_id, expr_id, target); if (expr_id == SemIR::InstId::BuiltinError) { return expr_id; } @@ -911,7 +911,7 @@ auto Convert(Context& context, Parse::NodeId node_id, SemIR::InstId expr_id, "Cannot convert from `{0}` to `{1}` with `as`.", SemIR::TypeId, SemIR::TypeId); context.emitter() - .Build(node_id, + .Build(loc_id, target.kind == ConversionTarget::ExplicitAs ? ExplicitAsConversionFailure : ImplicitAsConversionFailure, @@ -923,7 +923,7 @@ auto Convert(Context& context, Parse::NodeId node_id, SemIR::InstId expr_id, // Track that we performed a type conversion, if we did so. if (orig_expr_id != expr_id) { expr_id = context.AddInst( - {context.insts().GetNodeId(orig_expr_id), + {context.insts().GetLocationId(orig_expr_id), SemIR::Converted{target.type_id, orig_expr_id, expr_id}}); } @@ -974,7 +974,7 @@ auto Convert(Context& context, Parse::NodeId node_id, SemIR::InstId expr_id, // If we have a reference and don't want one, form a value binding. // TODO: Support types with custom value representations. - expr_id = context.AddInst({context.insts().GetNodeId(expr_id), + expr_id = context.AddInst({context.insts().GetLocationId(expr_id), SemIR::BindValue{expr.type_id(), expr_id}}); // We now have a value expression. [[fallthrough]]; @@ -993,7 +993,7 @@ auto Convert(Context& context, Parse::NodeId node_id, SemIR::InstId expr_id, init_rep.kind == SemIR::InitRepr::ByCopy) { target.init_block->InsertHere(); expr_id = context.AddInst( - {node_id, + {loc_id, SemIR::InitializeFrom{target.type_id, expr_id, target.init_id}}); } } @@ -1001,11 +1001,11 @@ auto Convert(Context& context, Parse::NodeId node_id, SemIR::InstId expr_id, return expr_id; } -auto Initialize(Context& context, Parse::NodeId node_id, +auto Initialize(Context& context, SemIR::LocationId loc_id, SemIR::InstId target_id, SemIR::InstId value_id) -> SemIR::InstId { PendingBlock target_block(context); - return Convert(context, node_id, value_id, + return Convert(context, loc_id, value_id, {.kind = ConversionTarget::Initializer, .type_id = context.insts().Get(target_id).type_id(), .init_id = target_id, @@ -1014,36 +1014,36 @@ auto Initialize(Context& context, Parse::NodeId node_id, auto ConvertToValueExpr(Context& context, SemIR::InstId expr_id) -> SemIR::InstId { - return Convert(context, context.insts().GetNodeId(expr_id), expr_id, + return Convert(context, context.insts().GetLocationId(expr_id), expr_id, {.kind = ConversionTarget::Value, .type_id = context.insts().Get(expr_id).type_id()}); } auto ConvertToValueOrRefExpr(Context& context, SemIR::InstId expr_id) -> SemIR::InstId { - return Convert(context, context.insts().GetNodeId(expr_id), expr_id, + return Convert(context, context.insts().GetLocationId(expr_id), expr_id, {.kind = ConversionTarget::ValueOrRef, .type_id = context.insts().Get(expr_id).type_id()}); } -auto ConvertToValueOfType(Context& context, Parse::NodeId node_id, +auto ConvertToValueOfType(Context& context, SemIR::LocationId loc_id, SemIR::InstId expr_id, SemIR::TypeId type_id) -> SemIR::InstId { - return Convert(context, node_id, expr_id, + return Convert(context, loc_id, expr_id, {.kind = ConversionTarget::Value, .type_id = type_id}); } -auto ConvertToValueOrRefOfType(Context& context, Parse::NodeId node_id, +auto ConvertToValueOrRefOfType(Context& context, SemIR::LocationId loc_id, SemIR::InstId expr_id, SemIR::TypeId type_id) -> SemIR::InstId { - return Convert(context, node_id, expr_id, + return Convert(context, loc_id, expr_id, {.kind = ConversionTarget::ValueOrRef, .type_id = type_id}); } -auto ConvertToBoolValue(Context& context, Parse::NodeId node_id, +auto ConvertToBoolValue(Context& context, SemIR::LocationId loc_id, SemIR::InstId value_id) -> SemIR::InstId { return ConvertToValueOfType( - context, node_id, value_id, + context, loc_id, value_id, context.GetBuiltinType(SemIR::BuiltinKind::BoolType)); } @@ -1057,7 +1057,7 @@ auto ConvertForExplicitAs(Context& context, Parse::NodeId as_node, CARBON_DIAGNOSTIC(InCallToFunction, Note, "Calling function declared here."); // Convert the object argument in a method call to match the `self` parameter. -static auto ConvertSelf(Context& context, Parse::NodeId call_node_id, +static auto ConvertSelf(Context& context, SemIR::LocationId call_loc_id, SemIR::InstId callee_id, std::optional addr_pattern, SemIR::InstId self_param_id, SemIR::Param self_param, @@ -1066,7 +1066,7 @@ static auto ConvertSelf(Context& context, Parse::NodeId call_node_id, CARBON_DIAGNOSTIC(MissingObjectInMethodCall, Error, "Missing object argument in method call."); context.emitter() - .Build(call_node_id, MissingObjectInMethodCall) + .Build(call_loc_id, MissingObjectInMethodCall) .Note(callee_id, InCallToFunction) .Emit(); return SemIR::InstId::BuiltinError; @@ -1096,20 +1096,20 @@ static auto ConvertSelf(Context& context, Parse::NodeId call_node_id, default: CARBON_DIAGNOSTIC(AddrSelfIsNonRef, Error, "`addr self` method cannot be invoked on a value."); - context.emitter().Emit(TokenOnly(call_node_id), AddrSelfIsNonRef); + context.emitter().Emit(TokenOnly(call_loc_id), AddrSelfIsNonRef); return SemIR::InstId::BuiltinError; } - auto node_id = context.insts().GetNodeId(self_or_addr_id); + auto loc_id = context.insts().GetLocationId(self_or_addr_id); self_or_addr_id = context.AddInst( - {node_id, SemIR::AddrOf{context.GetPointerType(self.type_id()), - self_or_addr_id}}); + {loc_id, SemIR::AddrOf{context.GetPointerType(self.type_id()), + self_or_addr_id}}); } - return ConvertToValueOfType(context, call_node_id, self_or_addr_id, + return ConvertToValueOfType(context, call_loc_id, self_or_addr_id, self_param.type_id); } -auto ConvertCallArgs(Context& context, Parse::NodeId call_node_id, +auto ConvertCallArgs(Context& context, SemIR::LocationId call_loc_id, SemIR::InstId self_id, llvm::ArrayRef arg_refs, SemIR::InstId return_storage_id, SemIR::InstId callee_id, @@ -1125,7 +1125,7 @@ auto ConvertCallArgs(Context& context, Parse::NodeId call_node_id, "{1} argument(s).", int, int); context.emitter() - .Build(call_node_id, CallArgCountMismatch, arg_refs.size(), + .Build(call_loc_id, CallArgCountMismatch, arg_refs.size(), param_refs.size()) .Note(callee_id, InCallToFunction) .Emit(); @@ -1145,7 +1145,7 @@ auto ConvertCallArgs(Context& context, Parse::NodeId call_node_id, context.sem_ir(), implicit_param_id); if (param.name_id == SemIR::NameId::SelfValue) { auto converted_self_id = - ConvertSelf(context, call_node_id, callee_id, addr_pattern, param_id, + ConvertSelf(context, call_loc_id, callee_id, addr_pattern, param_id, param, self_id); if (converted_self_id == SemIR::InstId::BuiltinError) { return SemIR::InstBlockId::Invalid; @@ -1153,7 +1153,7 @@ auto ConvertCallArgs(Context& context, Parse::NodeId call_node_id, args.push_back(converted_self_id); } else { // TODO: Form argument values for implicit parameters. - context.TODO(call_node_id, "Call with implicit parameters"); + context.TODO(call_loc_id, "Call with implicit parameters"); return SemIR::InstBlockId::Invalid; } } @@ -1175,7 +1175,7 @@ auto ConvertCallArgs(Context& context, Parse::NodeId call_node_id, // TODO: Convert to the proper expression category. For now, we assume // parameters are all `let` bindings. auto converted_arg_id = - ConvertToValueOfType(context, call_node_id, arg_id, param_type_id); + ConvertToValueOfType(context, call_loc_id, arg_id, param_type_id); if (converted_arg_id == SemIR::InstId::BuiltinError) { return SemIR::InstBlockId::Invalid; } @@ -1191,10 +1191,10 @@ auto ConvertCallArgs(Context& context, Parse::NodeId call_node_id, return context.inst_blocks().Add(args); } -auto ExprAsType(Context& context, Parse::NodeId node_id, SemIR::InstId value_id) - -> SemIR::TypeId { +auto ExprAsType(Context& context, SemIR::LocationId loc_id, + SemIR::InstId value_id) -> SemIR::TypeId { auto type_inst_id = - ConvertToValueOfType(context, node_id, value_id, SemIR::TypeId::TypeType); + ConvertToValueOfType(context, loc_id, value_id, SemIR::TypeId::TypeType); if (type_inst_id == SemIR::InstId::BuiltinError) { return SemIR::TypeId::Error; } @@ -1203,7 +1203,7 @@ auto ExprAsType(Context& context, Parse::NodeId node_id, SemIR::InstId value_id) if (!type_const_id.is_constant()) { CARBON_DIAGNOSTIC(TypeExprEvaluationFailure, Error, "Cannot evaluate type expression."); - context.emitter().Emit(node_id, TypeExprEvaluationFailure); + context.emitter().Emit(loc_id, TypeExprEvaluationFailure); return SemIR::TypeId::Error; } diff --git a/toolchain/check/convert.h b/toolchain/check/convert.h index 9154cf2489b2..34f2f99377ce 100644 --- a/toolchain/check/convert.h +++ b/toolchain/check/convert.h @@ -50,13 +50,13 @@ struct ConversionTarget { }; // Convert a value to another type and expression category. -auto Convert(Context& context, Parse::NodeId node_id, SemIR::InstId expr_id, +auto Convert(Context& context, SemIR::LocationId loc_id, SemIR::InstId expr_id, ConversionTarget target) -> SemIR::InstId; // Performs initialization of `target_id` from `value_id`. Returns the // possibly-converted initializing expression, which should be assigned to the // target using a suitable node for the kind of initialization. -auto Initialize(Context& context, Parse::NodeId node_id, +auto Initialize(Context& context, SemIR::LocationId loc_id, SemIR::InstId target_id, SemIR::InstId value_id) -> SemIR::InstId; @@ -70,18 +70,18 @@ auto ConvertToValueOrRefExpr(Context& context, SemIR::InstId expr_id) -> SemIR::InstId; // Converts `expr_id` to a value expression of type `type_id`. -auto ConvertToValueOfType(Context& context, Parse::NodeId node_id, +auto ConvertToValueOfType(Context& context, SemIR::LocationId loc_id, SemIR::InstId expr_id, SemIR::TypeId type_id) -> SemIR::InstId; // Convert the given expression to a value or reference expression of the given // type. -auto ConvertToValueOrRefOfType(Context& context, Parse::NodeId node_id, +auto ConvertToValueOrRefOfType(Context& context, SemIR::LocationId loc_id, SemIR::InstId expr_id, SemIR::TypeId type_id) -> SemIR::InstId; // Converts `value_id` to a value expression of type `bool`. -auto ConvertToBoolValue(Context& context, Parse::NodeId node_id, +auto ConvertToBoolValue(Context& context, SemIR::LocationId loc_id, SemIR::InstId value_id) -> SemIR::InstId; // Converts `value_id` to type `type_id` for an `as` expression. @@ -92,7 +92,7 @@ auto ConvertForExplicitAs(Context& context, Parse::NodeId as_node, // Implicitly converts a set of arguments to match the parameter types in a // function call. Returns a block containing the converted implicit and explicit // argument values. -auto ConvertCallArgs(Context& context, Parse::NodeId call_node_id, +auto ConvertCallArgs(Context& context, SemIR::LocationId call_loc_id, SemIR::InstId self_id, llvm::ArrayRef arg_refs, SemIR::InstId return_storage_id, SemIR::InstId callee_id, @@ -100,8 +100,8 @@ auto ConvertCallArgs(Context& context, Parse::NodeId call_node_id, SemIR::InstBlockId param_refs_id) -> SemIR::InstBlockId; // Converts an expression for use as a type. -auto ExprAsType(Context& context, Parse::NodeId node_id, SemIR::InstId value_id) - -> SemIR::TypeId; +auto ExprAsType(Context& context, SemIR::LocationId loc_id, + SemIR::InstId value_id) -> SemIR::TypeId; } // namespace Carbon::Check diff --git a/toolchain/check/decl_name_stack.cpp b/toolchain/check/decl_name_stack.cpp index 9c80fe02b527..7a288722a474 100644 --- a/toolchain/check/decl_name_stack.cpp +++ b/toolchain/check/decl_name_stack.cpp @@ -15,10 +15,10 @@ auto DeclNameStack::MakeEmptyNameContext() -> NameContext { .target_scope_id = context_->scope_stack().PeekNameScopeId()}; } -auto DeclNameStack::MakeUnqualifiedName(Parse::NodeId node_id, +auto DeclNameStack::MakeUnqualifiedName(SemIR::LocationId loc_id, SemIR::NameId name_id) -> NameContext { NameContext context = MakeEmptyNameContext(); - ApplyNameQualifierTo(context, node_id, name_id, /*is_unqualified=*/true); + ApplyNameQualifierTo(context, loc_id, name_id, /*is_unqualified=*/true); return context; } @@ -38,8 +38,8 @@ auto DeclNameStack::FinishName() -> NameContext { // into the name. } else { // The name had no qualifiers, so we need to process the node now. - auto [node_id, name_id] = context_->node_stack().PopNameWithNodeId(); - ApplyNameQualifier(node_id, name_id); + auto [loc_id, name_id] = context_->node_stack().PopNameWithNodeId(); + ApplyNameQualifier(loc_id, name_id); } NameContext result = decl_name_stack_.back(); @@ -92,7 +92,7 @@ auto DeclNameStack::LookupOrAddName(NameContext name_context, QualifiedDeclOutsideScopeEntity, Error, "Out-of-line declaration requires a declaration in " "scoped entity."); - context_->emitter().Emit(name_context.node_id, + context_->emitter().Emit(name_context.loc_id, QualifiedDeclOutsideScopeEntity); } } @@ -125,20 +125,20 @@ auto DeclNameStack::AddNameToLookup(NameContext name_context, } } -auto DeclNameStack::ApplyNameQualifier(Parse::NodeId node_id, +auto DeclNameStack::ApplyNameQualifier(SemIR::LocationId loc_id, SemIR::NameId name_id) -> void { - ApplyNameQualifierTo(decl_name_stack_.back(), node_id, name_id, + ApplyNameQualifierTo(decl_name_stack_.back(), loc_id, name_id, /*is_unqualified=*/false); } auto DeclNameStack::ApplyNameQualifierTo(NameContext& name_context, - Parse::NodeId node_id, + SemIR::LocationId loc_id, SemIR::NameId name_id, bool is_unqualified) -> void { - if (TryResolveQualifier(name_context, node_id)) { + if (TryResolveQualifier(name_context, loc_id)) { // For identifier nodes, we need to perform a lookup on the identifier. auto resolved_inst_id = context_->LookupNameInDecl( - name_context.node_id, name_id, name_context.target_scope_id); + name_context.loc_id, name_id, name_context.target_scope_id); if (!resolved_inst_id.is_valid()) { // Invalid indicates an unresolved name. Store it and return. name_context.state = NameContext::State::Unresolved; @@ -221,7 +221,7 @@ auto DeclNameStack::UpdateScopeIfNeeded(NameContext& name_context, CARBON_DIAGNOSTIC(QualifiedDeclOutsidePackageSource, Note, "Package imported here."); context_->emitter() - .Build(name_context.node_id, QualifiedDeclOutsidePackage) + .Build(name_context.loc_id, QualifiedDeclOutsidePackage) .Note(scope.inst_id, QualifiedDeclOutsidePackageSource) .Emit(); // Only error once per package. @@ -241,7 +241,7 @@ auto DeclNameStack::UpdateScopeIfNeeded(NameContext& name_context, } auto DeclNameStack::TryResolveQualifier(NameContext& name_context, - Parse::NodeId node_id) -> bool { + SemIR::LocationId loc_id) -> bool { // Update has_qualifiers based on the state before any possible changes. If // this is the first qualifier, it may just be the name. name_context.has_qualifiers = name_context.state != NameContext::State::Empty; @@ -255,7 +255,7 @@ auto DeclNameStack::TryResolveQualifier(NameContext& name_context, // Because more qualifiers were found, we diagnose that the earlier // qualifier failed to resolve. name_context.state = NameContext::State::Error; - context_->DiagnoseNameNotFound(name_context.node_id, + context_->DiagnoseNameNotFound(name_context.loc_id, name_context.unresolved_name_id); return false; @@ -268,7 +268,7 @@ auto DeclNameStack::TryResolveQualifier(NameContext& name_context, "Cannot declare a member of incomplete class `{0}`.", SemIR::TypeId); auto builder = context_->emitter().Build( - name_context.node_id, QualifiedDeclInIncompleteClassScope, + name_context.loc_id, QualifiedDeclInIncompleteClassScope, context_->classes().Get(class_decl->class_id).self_type_id); context_->NoteIncompleteClass(class_decl->class_id, builder); builder.Emit(); @@ -280,7 +280,7 @@ auto DeclNameStack::TryResolveQualifier(NameContext& name_context, "Cannot declare a member of undefined interface `{0}`.", std::string); auto builder = context_->emitter().Build( - name_context.node_id, QualifiedDeclInUndefinedInterfaceScope, + name_context.loc_id, QualifiedDeclInUndefinedInterfaceScope, context_->sem_ir().StringifyTypeExpr( context_->sem_ir() .constant_values() @@ -295,8 +295,8 @@ auto DeclNameStack::TryResolveQualifier(NameContext& name_context, CARBON_DIAGNOSTIC(QualifiedNameNonScopeEntity, Note, "Non-scope entity referenced here."); context_->emitter() - .Build(node_id, QualifiedNameInNonScope) - .Note(name_context.node_id, QualifiedNameNonScopeEntity) + .Build(loc_id, QualifiedNameInNonScope) + .Note(name_context.loc_id, QualifiedNameNonScopeEntity) .Emit(); } name_context.state = NameContext::State::Error; @@ -305,7 +305,7 @@ auto DeclNameStack::TryResolveQualifier(NameContext& name_context, case NameContext::State::Empty: case NameContext::State::Resolved: { - name_context.node_id = node_id; + name_context.loc_id = loc_id; return true; } diff --git a/toolchain/check/decl_name_stack.h b/toolchain/check/decl_name_stack.h index 5acdd4a4097e..2341547f9b0a 100644 --- a/toolchain/check/decl_name_stack.h +++ b/toolchain/check/decl_name_stack.h @@ -7,7 +7,6 @@ #include "llvm/ADT/SmallVector.h" #include "toolchain/check/scope_index.h" -#include "toolchain/parse/node_ids.h" #include "toolchain/sem_ir/ids.h" namespace Carbon::Check { @@ -124,8 +123,8 @@ class DeclNameStack { // should be used. SemIR::NameScopeId target_scope_id; - // The last parse node used. - Parse::NodeId node_id = Parse::NodeId::Invalid; + // The last location ID used. + SemIR::LocationId loc_id = SemIR::LocationId::Invalid; union { // The ID of a resolved qualifier, including both identifiers and @@ -177,13 +176,14 @@ class DeclNameStack { // unqualified name in the current context. This is suitable for adding to // name lookup in situations where a qualified name is not permitted, such as // a pattern binding. - auto MakeUnqualifiedName(Parse::NodeId node_id, SemIR::NameId name_id) + auto MakeUnqualifiedName(SemIR::LocationId loc_id, SemIR::NameId name_id) -> NameContext; // Applies a Name from the name stack to the top of the declaration name // stack. This will enter the scope corresponding to the name if the name // describes an existing scope, such as a namespace or a defined class. - auto ApplyNameQualifier(Parse::NodeId node_id, SemIR::NameId name_id) -> void; + auto ApplyNameQualifier(SemIR::LocationId loc_id, SemIR::NameId name_id) + -> void; // Adds a name to name lookup. Prints a diagnostic for name conflicts. auto AddNameToLookup(NameContext name_context, SemIR::InstId target_id) @@ -199,12 +199,12 @@ class DeclNameStack { auto MakeEmptyNameContext() -> NameContext; // Applies a Name from the name stack to given name context. - auto ApplyNameQualifierTo(NameContext& name_context, Parse::NodeId node_id, + auto ApplyNameQualifierTo(NameContext& name_context, SemIR::LocationId loc_id, SemIR::NameId name_id, bool is_unqualified) -> void; // Returns true if the context is in a state where it can resolve qualifiers. // Updates name_context as needed. - auto TryResolveQualifier(NameContext& name_context, Parse::NodeId node_id) + auto TryResolveQualifier(NameContext& name_context, SemIR::LocationId loc_id) -> bool; // Updates the scope on name_context as needed. This is called after diff --git a/toolchain/check/diagnostic_helpers.h b/toolchain/check/diagnostic_helpers.h index 1167587a7b3a..cb572fb4ce39 100644 --- a/toolchain/check/diagnostic_helpers.h +++ b/toolchain/check/diagnostic_helpers.h @@ -16,23 +16,31 @@ namespace Carbon::Check { // directly, or an inst ID which is later translated to a parse node. struct SemIRLocation { // NOLINTNEXTLINE(google-explicit-constructor) - SemIRLocation(SemIR::InstId inst_id) : inst_id(inst_id), is_inst_id(true) {} + SemIRLocation(SemIR::InstId inst_id) + : inst_id(inst_id), is_inst_id(true), token_only(false) {} // NOLINTNEXTLINE(google-explicit-constructor) - SemIRLocation(Parse::NodeLocation node_location) - : node_location(node_location), is_inst_id(false) {} + SemIRLocation(Parse::NodeId node_id) : SemIRLocation(node_id, false) {} + // NOLINTNEXTLINE(google-explicit-constructor) - SemIRLocation(Parse::NodeId node_id) - : SemIRLocation(Parse::NodeLocation(node_id)) {} + SemIRLocation(SemIR::LocationId loc_id) : SemIRLocation(loc_id, false) {} + + explicit SemIRLocation(SemIR::LocationId loc_id, bool token_only) + : loc_id(loc_id), is_inst_id(false), token_only(token_only) {} union { SemIR::InstId inst_id; - Parse::NodeLocation node_location; + SemIR::LocationId loc_id; }; bool is_inst_id; + bool token_only; }; +inline auto TokenOnly(SemIR::LocationId loc_id) -> SemIRLocation { + return SemIRLocation(loc_id, true); +} + // An integer value together with its type. The type is used to determine how to // format the value in diagnostics. struct TypedInt { diff --git a/toolchain/check/handle_alias.cpp b/toolchain/check/handle_alias.cpp index f4f38646cac7..89f8c767801f 100644 --- a/toolchain/check/handle_alias.cpp +++ b/toolchain/check/handle_alias.cpp @@ -48,20 +48,20 @@ auto HandleAlias(Context& context, Parse::AliasId /*node_id*/) -> bool { // TODO: Look into handling `false`, this doesn't do it right now because it // sees a value instruction instead of a builtin. alias_id = context.AddInst( - {name_context.node_id, + {name_context.loc_id, SemIR::BindAlias{context.insts().Get(expr_id).type_id(), bind_name_id, expr_id}}); } else if (auto inst = context.insts().TryGetAs(expr_id)) { // Pass through name references, albeit changing the name in use. alias_id = context.AddInst( - {name_context.node_id, + {name_context.loc_id, SemIR::BindAlias{inst->type_id, bind_name_id, inst->value_id}}); } else { CARBON_DIAGNOSTIC(AliasRequiresNameRef, Error, "Alias initializer must be a name reference."); context.emitter().Emit(expr_node, AliasRequiresNameRef); alias_id = - context.AddInst({name_context.node_id, + context.AddInst({name_context.loc_id, SemIR::BindAlias{SemIR::TypeId::Error, bind_name_id, SemIR::InstId::BuiltinError}}); } diff --git a/toolchain/check/handle_binding_pattern.cpp b/toolchain/check/handle_binding_pattern.cpp index 2fcbedf43362..67f54a2875b7 100644 --- a/toolchain/check/handle_binding_pattern.cpp +++ b/toolchain/check/handle_binding_pattern.cpp @@ -19,8 +19,9 @@ auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id, auto [name_node, name_id] = context.node_stack().PopNameWithNodeId(); // Create the appropriate kind of binding for this pattern. - auto make_bind_name = [&](SemIR::TypeId type_id, - SemIR::InstId value_id) -> SemIR::NodeIdAndInst { + auto make_bind_name = + [&](SemIR::TypeId type_id, + SemIR::InstId value_id) -> SemIR::LocationIdAndInst { // TODO: Eventually the name will need to support associations with other // scopes, but right now we don't support qualified names here. auto bind_name_id = context.bind_names().Add( diff --git a/toolchain/check/handle_expr_statement.cpp b/toolchain/check/handle_expr_statement.cpp index 38674c4946cb..468e32dbba0d 100644 --- a/toolchain/check/handle_expr_statement.cpp +++ b/toolchain/check/handle_expr_statement.cpp @@ -15,7 +15,7 @@ static auto HandleDiscardedExpr(Context& context, SemIR::InstId expr_id) // If we discard an initializing expression, convert it to a value or // reference so that it has something to initialize. auto expr = context.insts().Get(expr_id); - Convert(context, context.insts().GetNodeId(expr_id), expr_id, + Convert(context, context.insts().GetLocationId(expr_id), expr_id, {.kind = ConversionTarget::Discarded, .type_id = expr.type_id()}); // TODO: This will eventually need to do some "do not discard" analysis. diff --git a/toolchain/check/handle_index.cpp b/toolchain/check/handle_index.cpp index 7fd64ac35b7f..2b7a22d2291a 100644 --- a/toolchain/check/handle_index.cpp +++ b/toolchain/check/handle_index.cpp @@ -45,7 +45,7 @@ auto HandleIndexExpr(Context& context, Parse::IndexExprId node_id) -> bool { switch (operand_type_inst.kind()) { case SemIR::ArrayType::Kind: { auto array_type = operand_type_inst.As(); - auto index_node_id = context.insts().GetNodeId(index_inst_id); + auto index_node_id = context.insts().GetLocationId(index_inst_id); auto cast_index_id = ConvertToValueOfType( context, index_node_id, index_inst_id, context.GetBuiltinType(SemIR::BuiltinKind::IntType)); @@ -74,7 +74,7 @@ auto HandleIndexExpr(Context& context, Parse::IndexExprId node_id) -> bool { } case SemIR::TupleType::Kind: { SemIR::TypeId element_type_id = SemIR::TypeId::Error; - auto index_node_id = context.insts().GetNodeId(index_inst_id); + auto index_node_id = context.insts().GetLocationId(index_inst_id); index_inst_id = ConvertToValueOfType( context, index_node_id, index_inst_id, context.GetBuiltinType(SemIR::BuiltinKind::IntType)); diff --git a/toolchain/check/handle_let.cpp b/toolchain/check/handle_let.cpp index 29d3bd97851c..d875e3e4f0a1 100644 --- a/toolchain/check/handle_let.cpp +++ b/toolchain/check/handle_let.cpp @@ -28,7 +28,7 @@ auto HandleLetInitializer(Context& context, Parse::LetInitializerId node_id) static auto BuildAssociatedConstantDecl( Context& context, Parse::LetDeclId node_id, SemIR::InstId pattern_id, - SemIR::NodeIdAndInst pattern, SemIR::InterfaceId interface_id) -> void { + SemIR::LocationIdAndInst pattern, SemIR::InterfaceId interface_id) -> void { auto& interface_info = context.interfaces().Get(interface_id); auto binding_pattern = pattern.inst.TryAs(); @@ -36,7 +36,7 @@ static auto BuildAssociatedConstantDecl( CARBON_DIAGNOSTIC(ExpectedSymbolicBindingInAssociatedConstant, Error, "Pattern in associated constant declaration must be a " "single `:!` binding."); - context.emitter().Emit(pattern.node_id, + context.emitter().Emit(pattern.loc_id, ExpectedSymbolicBindingInAssociatedConstant); context.name_scopes().Get(interface_info.scope_id).has_error = true; return; @@ -55,7 +55,7 @@ static auto BuildAssociatedConstantDecl( // Add an associated entity name to the interface scope. auto assoc_id = BuildAssociatedEntity(context, interface_id, decl_id); auto name_context = - context.decl_name_stack().MakeUnqualifiedName(pattern.node_id, name_id); + context.decl_name_stack().MakeUnqualifiedName(pattern.loc_id, name_id); context.decl_name_stack().AddNameToLookup(name_context, assoc_id); } @@ -98,7 +98,7 @@ auto HandleLetDecl(Context& context, Parse::LetDeclId node_id) -> bool { } context.decl_state_stack().Pop(DeclState::Let); - auto pattern = context.insts().GetWithNodeId(pattern_id); + auto pattern = context.insts().GetWithLocationId(pattern_id); auto interface_scope = context.GetCurrentScopeAs(); if (value_id) { @@ -119,8 +119,7 @@ auto HandleLetDecl(Context& context, Parse::LetDeclId node_id) -> bool { CARBON_DIAGNOSTIC( ExpectedInitializerAfterLet, Error, "Expected `=`; `let` declaration must have an initializer."); - context.emitter().Emit(Parse::TokenOnly(node_id), - ExpectedInitializerAfterLet); + context.emitter().Emit(TokenOnly(node_id), ExpectedInitializerAfterLet); value_id = SemIR::InstId::BuiltinError; } diff --git a/toolchain/check/handle_namespace.cpp b/toolchain/check/handle_namespace.cpp index 8faa4e9b667d..b6dc0e9d0e53 100644 --- a/toolchain/check/handle_namespace.cpp +++ b/toolchain/check/handle_namespace.cpp @@ -37,10 +37,10 @@ auto HandleNamespace(Context& context, Parse::NamespaceId node_id) -> bool { // previous declaration. Otherwise, diagnose the issue. if (auto existing = context.insts().TryGetAs(existing_inst_id)) { - // When the name conflict is an imported namespace, fill the parse node + // When the name conflict is an imported namespace, fill the location ID // so that future diagnostics point at this declaration. if (existing->import_id.is_valid() && - !context.insts().GetNodeId(existing_inst_id).is_valid()) { + !context.insts().GetLocationId(existing_inst_id).is_valid()) { context.SetNamespaceNodeId(existing_inst_id, node_id); } } else { diff --git a/toolchain/check/handle_variable.cpp b/toolchain/check/handle_variable.cpp index 54227a5b8d0d..d04dd6628f84 100644 --- a/toolchain/check/handle_variable.cpp +++ b/toolchain/check/handle_variable.cpp @@ -55,7 +55,7 @@ auto HandleVariableDecl(Context& context, Parse::VariableDeclId node_id) // Form a corresponding name in the current context, and bind the name to // the variable. auto name_context = context.decl_name_stack().MakeUnqualifiedName( - context.insts().GetNodeId(value_id), + context.insts().GetLocationId(value_id), context.bind_names().Get(bind_name->bind_name_id).name_id); context.decl_name_stack().AddNameToLookup(name_context, value_id); value_id = bind_name->value_id; @@ -63,7 +63,7 @@ auto HandleVariableDecl(Context& context, Parse::VariableDeclId node_id) context.insts().TryGetAs(value_id)) { // Introduce the field name into the class. auto name_context = context.decl_name_stack().MakeUnqualifiedName( - context.insts().GetNodeId(value_id), field_decl->name_id); + context.insts().GetLocationId(value_id), field_decl->name_id); context.decl_name_stack().AddNameToLookup(name_context, value_id); } // TODO: Handle other kinds of pattern. diff --git a/toolchain/check/interface.cpp b/toolchain/check/interface.cpp index 875bcaf3d2e8..fa774ce81259 100644 --- a/toolchain/check/interface.cpp +++ b/toolchain/check/interface.cpp @@ -29,7 +29,7 @@ auto BuildAssociatedEntity(Context& context, SemIR::InterfaceId interface_id, // not the declaration itself. auto type_id = context.GetAssociatedEntityType( interface_id, context.insts().Get(decl_id).type_id()); - return context.AddInst({context.insts().GetNodeId(decl_id), + return context.AddInst({context.insts().GetLocationId(decl_id), SemIR::AssociatedEntity{type_id, index, decl_id}}); } diff --git a/toolchain/check/modifiers.cpp b/toolchain/check/modifiers.cpp index 254b34053eb6..44ce316a3ff7 100644 --- a/toolchain/check/modifiers.cpp +++ b/toolchain/check/modifiers.cpp @@ -11,17 +11,17 @@ namespace Carbon::Check { static auto ReportNotAllowed(Context& context, Parse::NodeId modifier_node, Lex::TokenKind decl_kind, llvm::StringRef context_string, - Parse::NodeId context_node) -> void { + SemIR::LocationId context_loc_id) -> void { CARBON_DIAGNOSTIC(ModifierNotAllowedOn, Error, "`{0}` not allowed on `{1}` declaration{2}.", Lex::TokenKind, Lex::TokenKind, std::string); auto diag = context.emitter().Build(modifier_node, ModifierNotAllowedOn, context.token_kind(modifier_node), decl_kind, context_string.str()); - if (context_node.is_valid()) { + if (context_loc_id.is_valid()) { CARBON_DIAGNOSTIC(ModifierNotInContext, Note, "Containing definition here."); - diag.Note(context_node, ModifierNotInContext); + diag.Note(context_loc_id, ModifierNotInContext); } diag.Emit(); } @@ -41,7 +41,7 @@ static auto ModifierOrderAsSet(ModifierOrder order) -> KeywordModifierSet { auto ForbidModifiersOnDecl(Context& context, KeywordModifierSet forbidden, Lex::TokenKind decl_kind, llvm::StringRef context_string, - Parse::NodeId context_node) -> void { + SemIR::LocationId context_loc_id) -> void { auto& s = context.decl_state_stack().innermost(); auto not_allowed = s.modifier_set & forbidden; if (!not_allowed) { @@ -53,7 +53,7 @@ auto ForbidModifiersOnDecl(Context& context, KeywordModifierSet forbidden, auto order = static_cast(order_index); if (!!(not_allowed & ModifierOrderAsSet(order))) { ReportNotAllowed(context, s.modifier_node_id(order), decl_kind, - context_string, context_node); + context_string, context_loc_id); s.set_modifier_node_id(order, Parse::NodeId::Invalid); } } @@ -121,12 +121,12 @@ auto CheckMethodModifiersOnFunction(Context& context, if (inheritance_kind == SemIR::Class::Final) { ForbidModifiersOnDecl(context, KeywordModifierSet::Virtual, decl_kind, " in a non-abstract non-base `class` definition", - context.insts().GetNodeId(target_id)); + context.insts().GetLocationId(target_id)); } if (inheritance_kind != SemIR::Class::Abstract) { ForbidModifiersOnDecl(context, KeywordModifierSet::Abstract, decl_kind, " in a non-abstract `class` definition", - context.insts().GetNodeId(target_id)); + context.insts().GetLocationId(target_id)); } return; } diff --git a/toolchain/check/modifiers.h b/toolchain/check/modifiers.h index f024936934b2..b8bc3b06d337 100644 --- a/toolchain/check/modifiers.h +++ b/toolchain/check/modifiers.h @@ -26,14 +26,13 @@ auto CheckMethodModifiersOnFunction(Context& context, SemIR::NameScopeId target_scope_id) -> void; // Like `LimitModifiersOnDecl`, except says which modifiers are forbidden, and a -// `context_string` (and optional `context_node`) specifying the context in +// `context_string` (and optional `context_loc_id`) specifying the context in // which those modifiers are forbidden. // TODO: Take another look at diagnostic phrasing for callers. -auto ForbidModifiersOnDecl(Context& context, KeywordModifierSet forbidden, - Lex::TokenKind decl_kind, - llvm::StringRef context_string, - Parse::NodeId context_node = Parse::NodeId::Invalid) - -> void; +auto ForbidModifiersOnDecl( + Context& context, KeywordModifierSet forbidden, Lex::TokenKind decl_kind, + llvm::StringRef context_string, + SemIR::LocationId context_loc_id = SemIR::LocationId::Invalid) -> void; // Reports a diagnostic (using `decl_kind`) if modifiers on this declaration are // not in `allowed`. Updates the declaration state in diff --git a/toolchain/check/pending_block.h b/toolchain/check/pending_block.h index a098864464cd..33f24e49a693 100644 --- a/toolchain/check/pending_block.h +++ b/toolchain/check/pending_block.h @@ -39,8 +39,8 @@ class PendingBlock { size_t size_; }; - auto AddInst(SemIR::NodeIdAndInst node_id_and_inst) -> SemIR::InstId { - auto inst_id = context_.AddInstInNoBlock(node_id_and_inst); + auto AddInst(SemIR::LocationIdAndInst loc_id_and_inst) -> SemIR::InstId { + auto inst_id = context_.AddInstInNoBlock(loc_id_and_inst); insts_.push_back(inst_id); return inst_id; } @@ -56,7 +56,7 @@ class PendingBlock { // Replace the instruction at target_id with the instructions in this block. // The new value for target_id should be value_id. auto MergeReplacing(SemIR::InstId target_id, SemIR::InstId value_id) -> void { - auto value = context_.insts().GetWithNodeId(value_id); + auto value = context_.insts().GetWithLocationId(value_id); // There are three cases here: @@ -64,7 +64,7 @@ class PendingBlock { // 1) The block is empty. Replace `target_id` with an empty splice // pointing at `value_id`. context_.ReplaceInstBeforeConstantUse( - target_id, {value.node_id, + target_id, {value.loc_id, SemIR::SpliceBlock{value.inst.type_id(), SemIR::InstBlockId::Empty, value_id}}); } else if (insts_.size() == 1 && insts_[0] == value_id) { @@ -75,7 +75,7 @@ class PendingBlock { // 3) Anything else: splice it into the IR, replacing `target_id`. context_.ReplaceInstBeforeConstantUse( target_id, - {value.node_id, + {value.loc_id, SemIR::SpliceBlock{value.inst.type_id(), context_.inst_blocks().Add(insts_), value_id}}); } diff --git a/toolchain/parse/tree_node_diagnostic_converter.h b/toolchain/parse/tree_node_diagnostic_converter.h index 546f3a4a487a..87f7c75393de 100644 --- a/toolchain/parse/tree_node_diagnostic_converter.h +++ b/toolchain/parse/tree_node_diagnostic_converter.h @@ -30,10 +30,6 @@ class NodeLocation { bool token_only_; }; -inline auto TokenOnly(NodeId node_id) -> NodeLocation { - return NodeLocation(node_id, true); -} - class NodeLocationConverter : public DiagnosticConverter { public: explicit NodeLocationConverter(const Lex::TokenizedBuffer* tokens, diff --git a/toolchain/sem_ir/BUILD b/toolchain/sem_ir/BUILD index ad633802315b..64f9aab705b5 100644 --- a/toolchain/sem_ir/BUILD +++ b/toolchain/sem_ir/BUILD @@ -36,6 +36,7 @@ cc_library( "//toolchain/base:index_base", "//toolchain/base:value_store", "//toolchain/diagnostics:diagnostic_emitter", + "//toolchain/parse:node_kind", "//toolchain/sem_ir:builtin_kind", ], ) @@ -92,6 +93,7 @@ cc_library( "file.h", "function.h", "impl.h", + "import_ir.h", "interface.h", "name.h", "name_scope.h", diff --git a/toolchain/sem_ir/constant.cpp b/toolchain/sem_ir/constant.cpp index 746d2a59f210..4ddf89da22f1 100644 --- a/toolchain/sem_ir/constant.cpp +++ b/toolchain/sem_ir/constant.cpp @@ -26,7 +26,7 @@ auto ConstantStore::GetOrAdd(Inst inst, bool is_symbolic) -> ConstantId { // Create the new inst and insert the new node. auto inst_id = constants_.getContext()->insts().AddInNoBlock( - NodeIdAndInst::Untyped(Parse::NodeId::Invalid, inst)); + LocationIdAndInst::Untyped(Parse::NodeId::Invalid, inst)); auto constant_id = is_symbolic ? SemIR::ConstantId::ForSymbolicConstant(inst_id) : SemIR::ConstantId::ForTemplateConstant(inst_id); diff --git a/toolchain/sem_ir/file.h b/toolchain/sem_ir/file.h index 038d2d5abd2f..a1da8130a96b 100644 --- a/toolchain/sem_ir/file.h +++ b/toolchain/sem_ir/file.h @@ -17,6 +17,7 @@ #include "toolchain/sem_ir/function.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/impl.h" +#include "toolchain/sem_ir/import_ir.h" #include "toolchain/sem_ir/inst.h" #include "toolchain/sem_ir/interface.h" #include "toolchain/sem_ir/name.h" @@ -40,15 +41,6 @@ struct BindNameInfo : public Printable { class File; -struct ImportIR : public Printable { - auto Print(llvm::raw_ostream& out) const -> void { out << node_id; } - - // The node ID for the import. - Parse::ImportDirectiveId node_id; - // The imported IR. - const File* sem_ir; -}; - // Provides semantic analysis on a Parse::Tree. class File : public Printable { public: @@ -149,6 +141,12 @@ class File : public Printable { auto import_irs() const -> const ValueStore& { return import_irs_; } + auto import_ir_insts() -> ValueStore& { + return import_ir_insts_; + } + auto import_ir_insts() const -> const ValueStore& { + return import_ir_insts_; + } auto names() const -> NameStoreWrapper { return NameStoreWrapper(&identifiers()); } @@ -225,6 +223,10 @@ class File : public Printable { // for references of builtins). ValueStore import_irs_; + // Related IR instructions. These are created for LocationIds for instructions + // that are import-related. + ValueStore import_ir_insts_; + // Storage for name scopes. NameScopeStore name_scopes_; diff --git a/toolchain/sem_ir/formatter.cpp b/toolchain/sem_ir/formatter.cpp index 1421adf6d222..a5f0cba34ff0 100644 --- a/toolchain/sem_ir/formatter.cpp +++ b/toolchain/sem_ir/formatter.cpp @@ -83,7 +83,8 @@ class InstNamer { insts[fn.return_slot_id.index] = { fn_scope, GetScopeInfo(fn_scope).insts.AllocateName( - *this, sem_ir.insts().GetNodeId(fn.return_slot_id), "return")}; + *this, sem_ir.insts().GetLocationId(fn.return_slot_id), + "return")}; } if (!fn.body_block_ids.empty()) { AddBlockLabel(fn_scope, fn.body_block_ids.front(), "entry", fn_loc); @@ -268,7 +269,7 @@ class InstNamer { return Name(allocated.insert({name, NameResult()}).first); } - auto AllocateName(const InstNamer& namer, Parse::NodeId node, + auto AllocateName(const InstNamer& namer, SemIR::LocationId loc_id, std::string name) -> Name { // The best (shortest) name for this instruction so far, and the current // name for it. @@ -307,8 +308,9 @@ class InstNamer { } // Append location information to try to disambiguate. - if (node.is_valid()) { - auto token = namer.parse_tree_.node_token(node); + // TODO: Consider handling inst_id cases. + if (loc_id.is_node_id()) { + auto token = namer.parse_tree_.node_token(loc_id.node_id()); llvm::raw_string_ostream(name) << ".loc" << namer.tokenized_buffer_.GetLineNumber(token); add_name(); @@ -344,29 +346,30 @@ class InstNamer { auto AddBlockLabel(ScopeId scope_id, InstBlockId block_id, std::string name = "", - Parse::NodeId node_id = Parse::NodeId::Invalid) -> void { + SemIR::LocationId loc_id = SemIR::LocationId::Invalid) + -> void { if (!block_id.is_valid() || labels[block_id.index].second) { return; } - if (!node_id.is_valid()) { + if (!loc_id.is_valid()) { if (const auto& block = sem_ir_.inst_blocks().Get(block_id); !block.empty()) { - node_id = sem_ir_.insts().GetNodeId(block.front()); + loc_id = sem_ir_.insts().GetLocationId(block.front()); } } labels[block_id.index] = { - scope_id, GetScopeInfo(scope_id).labels.AllocateName(*this, node_id, + scope_id, GetScopeInfo(scope_id).labels.AllocateName(*this, loc_id, std::move(name))}; } // Finds and adds a suitable block label for the given SemIR instruction that // represents some kind of branch. - auto AddBlockLabel(ScopeId scope_id, Parse::NodeId node_id, AnyBranch branch) - -> void { + auto AddBlockLabel(ScopeId scope_id, SemIR::LocationId loc_id, + AnyBranch branch) -> void { llvm::StringRef name; - switch (parse_tree_.node_kind(node_id)) { + switch (parse_tree_.node_kind(loc_id.node_id())) { case Parse::NodeKind::IfExprIf: switch (branch.kind) { case BranchIf::Kind: @@ -428,7 +431,7 @@ class InstNamer { break; } - AddBlockLabel(scope_id, branch.target_id, name.str(), node_id); + AddBlockLabel(scope_id, branch.target_id, name.str(), loc_id); } auto CollectNamesInBlock(ScopeId scope_id, InstBlockId block_id) -> void { @@ -451,7 +454,7 @@ class InstNamer { auto add_inst_name = [&](std::string name) { insts[inst_id.index] = { scope_id, scope.insts.AllocateName( - *this, sem_ir_.insts().GetNodeId(inst_id), name)}; + *this, sem_ir_.insts().GetLocationId(inst_id), name)}; }; auto add_inst_name_id = [&](NameId name_id, llvm::StringRef suffix = "") { add_inst_name( @@ -459,7 +462,8 @@ class InstNamer { }; if (auto branch = untyped_inst.TryAs()) { - AddBlockLabel(scope_id, sem_ir_.insts().GetNodeId(inst_id), *branch); + AddBlockLabel(scope_id, sem_ir_.insts().GetLocationId(inst_id), + *branch); } CARBON_KIND_SWITCH(untyped_inst) { diff --git a/toolchain/sem_ir/ids.h b/toolchain/sem_ir/ids.h index 9bb6577165bc..79ce0f1a9fd5 100644 --- a/toolchain/sem_ir/ids.h +++ b/toolchain/sem_ir/ids.h @@ -10,6 +10,7 @@ #include "toolchain/base/index_base.h" #include "toolchain/base/value_store.h" #include "toolchain/diagnostics/diagnostic_emitter.h" +#include "toolchain/parse/node_ids.h" #include "toolchain/sem_ir/builtin_kind.h" namespace Carbon::SemIR { @@ -21,6 +22,7 @@ struct BindNameInfo; struct Class; struct Function; struct ImportIR; +struct ImportIRInst; struct Interface; struct Impl; struct NameScope; @@ -481,6 +483,67 @@ struct ElementIndex : public IndexBase, public Printable { } }; +// The ID of an ImportIRInst. +struct ImportIRInstId : public IdBase, public Printable { + using ValueType = ImportIRInst; + + using IdBase::IdBase; +}; + +// A SemIR location used exclusively for diagnostic locations. +// +// Contents: +// - index > Invalid: A Parse::NodeId in the current IR. +// - index < Invalid: An ImportIRInstId. +// - index == Invalid: Can be used for either. +struct LocationId : public IdBase, public Printable { + // An explicitly invalid function ID. + static const LocationId Invalid; + + // NOLINTNEXTLINE(google-explicit-constructor) + constexpr LocationId(Parse::InvalidNodeId /*invalid*/) + : IdBase(InvalidIndex) {} + + // NOLINTNEXTLINE(google-explicit-constructor) + constexpr LocationId(Parse::NodeId node_id) : IdBase(node_id.index) { + CARBON_CHECK(node_id.is_valid() == is_valid()); + } + + // NOLINTNEXTLINE(google-explicit-constructor) + constexpr LocationId(ImportIRInstId inst_id) + : IdBase(InvalidIndex + ImportIRInstId::InvalidIndex - inst_id.index) { + CARBON_CHECK(inst_id.is_valid() == is_valid()); + } + + auto is_node_id() const -> bool { return index > InvalidIndex; } + auto is_import_ir_inst_id() const -> bool { return index < InvalidIndex; } + + // This is allowed to return an invalid NodeId, but should never be used for a + // valid InstId. + auto node_id() const -> Parse::NodeId { + CARBON_CHECK(is_node_id() || !is_valid()); + return Parse::NodeId(index); + } + + // This is allowed to return an invalid InstId, but should never be used for a + // valid NodeId. + auto import_ir_inst_id() const -> ImportIRInstId { + CARBON_CHECK(is_import_ir_inst_id() || !is_valid()); + return ImportIRInstId(InvalidIndex + ImportIRInstId::InvalidIndex - index); + } + + auto Print(llvm::raw_ostream& out) const -> void { + out << "loc_"; + if (is_node_id() || !is_valid()) { + out << node_id(); + } else { + out << import_ir_inst_id(); + } + } +}; + +constexpr LocationId LocationId::Invalid = LocationId(Parse::NodeId::Invalid); + } // namespace Carbon::SemIR // Support use of Id types as DenseMap/DenseSet keys. diff --git a/toolchain/sem_ir/import_ir.h b/toolchain/sem_ir/import_ir.h new file mode 100644 index 000000000000..dd36107f45f8 --- /dev/null +++ b/toolchain/sem_ir/import_ir.h @@ -0,0 +1,37 @@ +// 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 + +#ifndef CARBON_TOOLCHAIN_SEM_IR_IMPORT_IR_H_ +#define CARBON_TOOLCHAIN_SEM_IR_IMPORT_IR_H_ + +#include "llvm/ADT/FoldingSet.h" +#include "toolchain/sem_ir/ids.h" +#include "toolchain/sem_ir/inst.h" + +namespace Carbon::SemIR { + +// A reference to an imported IR. +struct ImportIR : public Printable { + auto Print(llvm::raw_ostream& out) const -> void { out << node_id; } + + // The node ID for the import. + Parse::ImportDirectiveId node_id; + // The imported IR. + const File* sem_ir; +}; + +// A reference to an instruction in an imported IR. Used for diagnostics with +// LocationId. +struct ImportIRInst : public Printable { + auto Print(llvm::raw_ostream& out) const -> void { + out << ir_id << ":" << inst_id; + } + + ImportIRId ir_id; + InstId inst_id; +}; + +} // namespace Carbon::SemIR + +#endif // CARBON_TOOLCHAIN_SEM_IR_IMPORT_IR_H_ diff --git a/toolchain/sem_ir/inst.h b/toolchain/sem_ir/inst.h index 3563b92ba6b8..3ad8f2c46ec3 100644 --- a/toolchain/sem_ir/inst.h +++ b/toolchain/sem_ir/inst.h @@ -288,15 +288,15 @@ inline auto operator<<(llvm::raw_ostream& out, TypedInst inst) return out; } -// Associates a NodeId and Inst in order to provide type-checking that the +// Associates a LocationId and Inst in order to provide type-checking that the // TypedNodeId corresponds to the InstT. -struct NodeIdAndInst { - // In cases where the NodeId is untyped or the InstT is unknown, the check - // can't be done at compile time. +struct LocationIdAndInst { + // In cases where the NodeId is untyped, an inst_id, or the InstT is unknown, + // the NodeId check can't be done at compile time. // TODO: Consider runtime validation that InstT::Kind::TypedNodeId // corresponds. - static auto Untyped(Parse::NodeId node_id, Inst inst) -> NodeIdAndInst { - return NodeIdAndInst(node_id, inst, /*is_untyped=*/true); + static auto Untyped(LocationId loc_id, Inst inst) -> LocationIdAndInst { + return LocationIdAndInst(loc_id, inst, /*is_untyped=*/true); } // For the common case, support construction as: @@ -304,22 +304,32 @@ struct NodeIdAndInst { template requires(Internal::HasNodeId) // NOLINTNEXTLINE(google-explicit-constructor) - NodeIdAndInst(decltype(InstT::Kind)::TypedNodeId node_id, InstT inst) - : node_id(node_id), inst(inst) {} + LocationIdAndInst(decltype(InstT::Kind)::TypedNodeId node_id, InstT inst) + : loc_id(node_id), inst(inst) {} // For cases with no parse node, support construction as: // context.AddInst({SemIR::MyInst{...}}); template requires(!Internal::HasNodeId) // NOLINTNEXTLINE(google-explicit-constructor) - NodeIdAndInst(InstT inst) : node_id(Parse::NodeId::Invalid), inst(inst) {} + LocationIdAndInst(InstT inst) : loc_id(Parse::NodeId::Invalid), inst(inst) {} - Parse::NodeId node_id; + // If TypedNodeId is Parse::NodeId, allow construction with a LocationId + // rather than requiring Untyped. + // TODO: This is somewhat historical due to fetching the NodeId from insts() + // for things like Temporary; should we require Untyped in these cases? + template + requires(std::same_as) + LocationIdAndInst(LocationId loc_id, InstT inst) + : loc_id(loc_id), inst(inst) {} + + LocationId loc_id; Inst inst; private: - explicit NodeIdAndInst(Parse::NodeId node_id, Inst inst, bool /*is_untyped*/) - : node_id(node_id), inst(inst) {} + explicit LocationIdAndInst(LocationId loc_id, Inst inst, bool /*is_untyped*/) + : loc_id(loc_id), inst(inst) {} }; // Provides a ValueStore wrapper for an API specific to instructions. @@ -330,17 +340,17 @@ class InstStore { // instruction block. Check::Context::AddInst or InstBlockStack::AddInst // should usually be used instead, to add the instruction to the current // block. - auto AddInNoBlock(NodeIdAndInst node_id_and_inst) -> InstId { - node_ids_.push_back(node_id_and_inst.node_id); - return values_.Add(node_id_and_inst.inst); + auto AddInNoBlock(LocationIdAndInst loc_id_and_inst) -> InstId { + loc_ids_.push_back(loc_id_and_inst.loc_id); + return values_.Add(loc_id_and_inst.inst); } // Returns the requested instruction. auto Get(InstId inst_id) const -> Inst { return values_.Get(inst_id); } - // Returns the requested instruction and its parse node. - auto GetWithNodeId(InstId inst_id) const -> NodeIdAndInst { - return NodeIdAndInst::Untyped(GetNodeId(inst_id), Get(inst_id)); + // Returns the requested instruction and its location ID. + auto GetWithLocationId(InstId inst_id) const -> LocationIdAndInst { + return LocationIdAndInst::Untyped(GetLocationId(inst_id), Get(inst_id)); } // Returns whether the requested instruction is the specified type. @@ -373,23 +383,26 @@ class InstStore { return TryGetAs(inst_id); } - auto GetNodeId(InstId inst_id) const -> Parse::NodeId { - return node_ids_[inst_id.index]; + auto GetLocationId(InstId inst_id) const -> LocationId { + CARBON_CHECK(inst_id.index >= 0) << inst_id.index; + CARBON_CHECK(inst_id.index < (int)loc_ids_.size()) + << inst_id.index << " " << loc_ids_.size(); + return loc_ids_[inst_id.index]; } - // Overwrites a given instruction and parse node with a new value. - auto Set(InstId inst_id, NodeIdAndInst node_id_and_inst) -> void { - values_.Get(inst_id) = node_id_and_inst.inst; - node_ids_[inst_id.index] = node_id_and_inst.node_id; + // Overwrites a given instruction and location ID with a new value. + auto Set(InstId inst_id, LocationIdAndInst loc_id_and_inst) -> void { + values_.Get(inst_id) = loc_id_and_inst.inst; + loc_ids_[inst_id.index] = loc_id_and_inst.loc_id; } - auto SetNodeId(InstId inst_id, Parse::NodeId node_id) -> void { - node_ids_[inst_id.index] = node_id; + auto SetLocationId(InstId inst_id, LocationId loc_id) -> void { + loc_ids_[inst_id.index] = loc_id; } // Reserves space. auto Reserve(size_t size) -> void { - node_ids_.reserve(size); + loc_ids_.reserve(size); values_.Reserve(size); } @@ -397,7 +410,7 @@ class InstStore { auto size() const -> int { return values_.size(); } private: - llvm::SmallVector node_ids_; + llvm::SmallVector loc_ids_; ValueStore values_; };