Skip to content

Commit d01a02d

Browse files
jonmeowbricknerb
authored andcommitted
Move TokenOnly to LocIdForDiagnostics (carbon-language#5590)
This reclaims a bit inside `LocId`. I'm hopeful we don't actually need to store the token-only state. Note I'm looking at this in the context of desugaring; I was thinking about changing `ToImplicit` logic a little to push more towards `GetCanonicalLocId`, and the "desugaring" TODO there. Removing `ToTokenOnly` makes me feel a little more free to rename `ToImplicit`, since it eliminates consistency as a question.
1 parent 74af79e commit d01a02d

File tree

10 files changed

+49
-69
lines changed

10 files changed

+49
-69
lines changed

toolchain/check/diagnostic_emitter.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ auto DiagnosticEmitter::ConvertLoc(LocIdForDiagnostics loc_id,
1919
ContextFnT context_fn) const
2020
-> Diagnostics::ConvertedLoc {
2121
auto converted =
22-
ConvertLocImpl(static_cast<SemIR::LocId>(loc_id), context_fn);
22+
ConvertLocImpl(loc_id.loc_id(), loc_id.is_token_only(), context_fn);
2323

2424
// Use the token when possible, but -1 is the default value.
2525
auto last_offset = -1;
@@ -39,13 +39,11 @@ auto DiagnosticEmitter::ConvertLoc(LocIdForDiagnostics loc_id,
3939
return converted;
4040
}
4141

42-
auto DiagnosticEmitter::ConvertLocImpl(SemIR::LocId loc_id,
42+
auto DiagnosticEmitter::ConvertLocImpl(SemIR::LocId loc_id, bool is_token_only,
4343
ContextFnT context_fn) const
4444
-> Diagnostics::ConvertedLoc {
4545
llvm::SmallVector<SemIR::AbsoluteNodeId> absolute_node_ids =
4646
SemIR::GetAbsoluteNodeId(sem_ir_, loc_id);
47-
bool token_only =
48-
loc_id.kind() != SemIR::LocId::Kind::InstId && loc_id.is_token_only();
4947

5048
auto final_node_id = absolute_node_ids.pop_back_val();
5149
for (const auto& absolute_node_id : absolute_node_ids) {
@@ -55,12 +53,13 @@ auto DiagnosticEmitter::ConvertLocImpl(SemIR::LocId loc_id,
5553
continue;
5654
}
5755
// TODO: Include the name of the imported library in the diagnostic.
58-
auto diag_loc = ConvertLocInFile(absolute_node_id, token_only, context_fn);
56+
auto diag_loc =
57+
ConvertLocInFile(absolute_node_id, is_token_only, context_fn);
5958
CARBON_DIAGNOSTIC(InImport, LocationInfo, "in import");
6059
context_fn(diag_loc.loc, InImport);
6160
}
6261

63-
return ConvertLocInFile(final_node_id, token_only, context_fn);
62+
return ConvertLocInFile(final_node_id, is_token_only, context_fn);
6463
}
6564

6665
auto DiagnosticEmitter::ConvertLocInFile(SemIR::AbsoluteNodeId absolute_node_id,

toolchain/check/diagnostic_emitter.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ class DiagnosticEmitter : public DiagnosticEmitterBase {
4848

4949
private:
5050
// Implements `ConvertLoc`, but without `last_token_` applied.
51-
auto ConvertLocImpl(SemIR::LocId loc_id, ContextFnT context_fn) const
52-
-> Diagnostics::ConvertedLoc;
51+
auto ConvertLocImpl(SemIR::LocId loc_id, bool is_token_only,
52+
ContextFnT context_fn) const -> Diagnostics::ConvertedLoc;
5353

5454
// Converts a node_id corresponding to a specific sem_ir to a diagnostic
5555
// location.

toolchain/check/diagnostic_helpers.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,30 @@ namespace Carbon::Check {
1818
// explicitly construct a `LocId` from it first.
1919
class LocIdForDiagnostics {
2020
public:
21+
// Constructs a token-only location for a diagnostic.
22+
//
23+
// This means the displayed location will include only the location's specific
24+
// parse node, instead of also including its descendants.
25+
static auto TokenOnly(Parse::NodeId node_id) -> LocIdForDiagnostics {
26+
return LocIdForDiagnostics(SemIR::LocId(node_id), true);
27+
}
28+
2129
template <class LocT>
2230
requires std::constructible_from<SemIR::LocId, LocT>
2331
// NOLINTNEXTLINE(google-explicit-constructor)
24-
LocIdForDiagnostics(LocT loc_id) : loc_id_(SemIR::LocId(loc_id)) {}
32+
LocIdForDiagnostics(LocT loc_id)
33+
: LocIdForDiagnostics(SemIR::LocId(loc_id), false) {}
34+
35+
auto loc_id() const -> SemIR::LocId { return loc_id_; }
2536

26-
explicit operator SemIR::LocId() const { return loc_id_; }
37+
auto is_token_only() const -> bool { return is_token_only_; }
2738

2839
private:
40+
explicit LocIdForDiagnostics(SemIR::LocId loc_id, bool is_token_only)
41+
: loc_id_(loc_id), is_token_only_(is_token_only) {}
42+
2943
SemIR::LocId loc_id_;
44+
bool is_token_only_;
3045
};
3146

3247
// We define the emitter separately for dependencies, so only provide a base

toolchain/check/handle_binding_pattern.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ auto HandleParseNode(Context& context, Parse::AddrId node_id) -> bool {
369369
} else {
370370
CARBON_DIAGNOSTIC(AddrOnNonSelfParam, Error,
371371
"`addr` can only be applied to a `self` parameter");
372-
context.emitter().Emit(SemIR::LocId(node_id).ToTokenOnly(),
372+
context.emitter().Emit(LocIdForDiagnostics::TokenOnly(node_id),
373373
AddrOnNonSelfParam);
374374
context.node_stack().Push(node_id, param_pattern_id);
375375
}

toolchain/check/handle_function.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,7 @@ static auto BuildFunctionDecl(Context& context,
541541
SemIR::Function::VirtualModifier::Abstract) {
542542
CARBON_DIAGNOSTIC(DefinedAbstractFunction, Error,
543543
"definition of `abstract` function");
544-
context.emitter().Emit(SemIR::LocId(node_id).ToTokenOnly(),
544+
context.emitter().Emit(LocIdForDiagnostics::TokenOnly(node_id),
545545
DefinedAbstractFunction);
546546
}
547547

@@ -626,7 +626,7 @@ auto HandleParseNode(Context& context, Parse::FunctionDefinitionId node_id)
626626
CARBON_DIAGNOSTIC(
627627
MissingReturnStatement, Error,
628628
"missing `return` at end of function with declared return type");
629-
context.emitter().Emit(SemIR::LocId(node_id).ToTokenOnly(),
629+
context.emitter().Emit(LocIdForDiagnostics::TokenOnly(node_id),
630630
MissingReturnStatement);
631631
} else {
632632
AddReturnCleanupBlock(context, node_id);

toolchain/check/handle_let_and_var.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ auto HandleParseNode(Context& context, Parse::LetDeclId node_id) -> bool {
369369
CARBON_DIAGNOSTIC(
370370
ExpectedInitializerAfterLet, Error,
371371
"expected `=`; `let` declaration must have an initializer");
372-
context.emitter().Emit(SemIR::LocId(node_id).ToTokenOnly(),
372+
context.emitter().Emit(LocIdForDiagnostics::TokenOnly(node_id),
373373
ExpectedInitializerAfterLet);
374374
}
375375
return true;

toolchain/check/handle_name.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ auto HandleParseNode(Context& context, Parse::PointerMemberAccessExprId node_id)
5555
SemIR::TypeId);
5656

5757
auto builder =
58-
context.emitter().Build(SemIR::LocId(node_id).ToTokenOnly(),
58+
context.emitter().Build(LocIdForDiagnostics::TokenOnly(node_id),
5959
ArrowOperatorOfNonPointer, not_pointer_type_id);
6060
builder.Emit();
6161
};

toolchain/check/handle_operator.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -237,14 +237,15 @@ auto HandleParseNode(Context& context, Parse::PrefixOperatorAmpId node_id)
237237
case SemIR::ExprCategory::EphemeralRef:
238238
CARBON_DIAGNOSTIC(AddrOfEphemeralRef, Error,
239239
"cannot take the address of a temporary object");
240-
context.emitter().Emit(SemIR::LocId(node_id).ToTokenOnly(),
240+
context.emitter().Emit(LocIdForDiagnostics::TokenOnly(node_id),
241241
AddrOfEphemeralRef);
242242
value_id = SemIR::ErrorInst::InstId;
243243
break;
244244
default:
245245
CARBON_DIAGNOSTIC(AddrOfNonRef, Error,
246246
"cannot take the address of non-reference expression");
247-
context.emitter().Emit(SemIR::LocId(node_id).ToTokenOnly(), AddrOfNonRef);
247+
context.emitter().Emit(LocIdForDiagnostics::TokenOnly(node_id),
248+
AddrOfNonRef);
248249
value_id = SemIR::ErrorInst::InstId;
249250
break;
250251
}
@@ -327,15 +328,15 @@ auto HandleParseNode(Context& context, Parse::PrefixOperatorStarId node_id)
327328
SemIR::TypeId);
328329

329330
auto builder =
330-
context.emitter().Build(SemIR::LocId(node_id).ToTokenOnly(),
331+
context.emitter().Build(LocIdForDiagnostics::TokenOnly(node_id),
331332
DerefOfNonPointer, not_pointer_type_id);
332333

333334
// TODO: Check for any facet here, rather than only a type.
334335
if (not_pointer_type_id == SemIR::TypeType::TypeId) {
335336
CARBON_DIAGNOSTIC(
336337
DerefOfType, Note,
337338
"to form a pointer type, write the `*` after the pointee type");
338-
builder.Note(SemIR::LocId(node_id).ToTokenOnly(), DerefOfType);
339+
builder.Note(LocIdForDiagnostics::TokenOnly(node_id), DerefOfType);
339340
}
340341

341342
builder.Emit();

toolchain/sem_ir/ids.h

Lines changed: 7 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -835,7 +835,7 @@ struct ImportIRInstId : public IdBase<ImportIRInstId> {
835835
using ValueType = ImportIRInst;
836836

837837
// ImportIRInstId is restricted so that it can fit into LocId.
838-
static constexpr int32_t BitsWithNodeId = 29;
838+
static constexpr int BitsWithNodeId = 30;
839839

840840
// The maximum ID, non-inclusive.
841841
static constexpr int Max = (1 << BitsWithNodeId) - Parse::NodeId::Max - 2;
@@ -857,17 +857,17 @@ struct ImportIRInstId : public IdBase<ImportIRInstId> {
857857
// - NodeId: negative values starting after None; the 24 bit NodeId range.
858858
// - [-2, -2 - (1 << 24))
859859
// - ImportIRInstId: remaining negative values; after NodeId, fills out negative
860-
// values to 29 bits.
861-
// - [-2 - (1 << 24), -(1 << 29))
860+
// values to 30 bits.
861+
// - [-2 - (1 << 24), -(1 << 30))
862862
//
863-
// In addition, two bits are used for flags: `ImplicitBit` and `TokenOnlyBit`.
864-
// Note that these can only be used with negative, non-`InstId` values.
863+
// In addition, one bit is used for flags: `ImplicitBit`.
864+
// Note that this can only be used with negative, non-`InstId` values.
865865
//
866866
// Use `InstStore::GetCanonicalLocId()` to get a canonical `LocId` which will
867867
// not be backed by an `InstId`. Note that the canonical `LocId` may be `None`
868868
// even when the original `LocId` was not, so this operation needs to be done
869869
// before checking `has_value()`. Only canonical locations can be converted with
870-
// `ToImplicit()` or `ToTokenOnly()`.
870+
// `ToImplicit()`.
871871
struct LocId : public IdBase<LocId> {
872872
// The contained index kind.
873873
enum class Kind {
@@ -910,20 +910,6 @@ struct LocId : public IdBase<LocId> {
910910
return *this;
911911
}
912912

913-
// Forms an equivalent `LocId` for a token-only diagnostic location. Requires
914-
// a canonical location. See `InstStore::GetCanonicalLocId()`.
915-
//
916-
// TODO: Consider making this a part of check/ diagnostics instead, as a free
917-
// function operation on `LocIdForDiagnostics`?
918-
// https://github.com/carbon-language/carbon-lang/pull/5355#discussion_r2064113186
919-
auto ToTokenOnly() const -> LocId {
920-
CARBON_CHECK(kind() != Kind::InstId);
921-
if (has_value()) {
922-
return LocId(index & ~TokenOnlyBit);
923-
}
924-
return *this;
925-
}
926-
927913
// Returns the kind of the `LocId`.
928914
auto kind() const -> Kind {
929915
if (!has_value()) {
@@ -944,15 +930,6 @@ struct LocId : public IdBase<LocId> {
944930
return (kind() == Kind::NodeId) && (index & ImplicitBit) == 0;
945931
}
946932

947-
// Returns true if the location is token-only for diagnostics.
948-
//
949-
// This means the displayed location will include only the location's specific
950-
// parse node, instead of also including its descendants. As such, this can
951-
// only be true for locations backed by a `NodeId`.
952-
auto is_token_only() const -> bool {
953-
return kind() != Kind::InstId && (index & TokenOnlyBit) == 0;
954-
}
955-
956933
// Returns the equivalent `ImportIRInstId` when `kind()` matches or is `None`.
957934
// Note that the returned `ImportIRInstId` only identifies a location; it is
958935
// not correct to interpret it as the instruction from which another
@@ -987,18 +964,14 @@ struct LocId : public IdBase<LocId> {
987964
// for `NodeId`.
988965
static constexpr int32_t ImplicitBit = 1 << 30;
989966

990-
// See `is_token_only` for the use. This only applies for canonical locations
991-
// (i.e. those containing `NodeId` or `ImportIRInstId`).
992-
static constexpr int32_t TokenOnlyBit = 1 << 29;
993-
994967
// The value of the 0 index for each of `NodeId` and `ImportIRInstId`.
995968
static constexpr int32_t FirstNodeId = NoneIndex - 1;
996969
static constexpr int32_t FirstImportIRInstId =
997970
FirstNodeId - Parse::NodeId::Max;
998971

999972
auto index_without_flags() const -> int32_t {
1000973
CARBON_DCHECK(index < NoneIndex, "Only for NodeId and ImportIRInstId");
1001-
return index | ImplicitBit | TokenOnlyBit;
974+
return index | ImplicitBit;
1002975
}
1003976
};
1004977

toolchain/sem_ir/ids_test.cpp

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,37 +30,32 @@ TEST(IdsTest, LocIdValues) {
3030

3131
EXPECT_THAT(static_cast<LocId>(ImportIRInstId(0)).index, Eq(-2 - (1 << 24)));
3232
EXPECT_THAT(static_cast<LocId>(ImportIRInstId(ImportIRInstId::Max - 1)).index,
33-
Eq(-(1 << 29) + 1));
33+
Eq(-(1 << 30) + 1));
3434
}
3535

36-
// A standard parameterized test for (implicit, token_only, index).
36+
// A standard parameterized test for (implicit, index).
3737
class IdsTestWithParam
38-
: public testing::TestWithParam<std::tuple<bool, bool, int32_t>> {
38+
: public testing::TestWithParam<std::tuple<bool, int32_t>> {
3939
public:
4040
explicit IdsTestWithParam() {
4141
llvm::errs() << "implicit=" << is_implicit()
42-
<< ", token_only=" << is_token_only()
43-
<< ", index=" << std::get<2>(GetParam()) << "\n";
42+
<< ", index=" << std::get<1>(GetParam()) << "\n";
4443
}
4544

4645
// Returns IdT with its matching LocId form. Sets flags based on test
4746
// parameters.
4847
template <typename IdT>
4948
auto BuildIdAndLocId() -> std::pair<IdT, LocId> {
50-
auto [implicit, token_only, index] = GetParam();
49+
auto [implicit, index] = GetParam();
5150
IdT id(index);
5251
LocId loc_id(id);
5352
if (implicit) {
5453
loc_id = loc_id.ToImplicit();
5554
}
56-
if (token_only) {
57-
loc_id = loc_id.ToTokenOnly();
58-
}
5955
return {id, loc_id};
6056
}
6157

6258
auto is_implicit() -> bool { return std::get<0>(GetParam()); }
63-
auto is_token_only() -> bool { return std::get<1>(GetParam()); }
6459
};
6560

6661
// Returns a test case generator for edge-case values.
@@ -70,7 +65,7 @@ static auto GetValueRange(int32_t max) -> auto {
7065

7166
// Returns a test case generator for `IdsTestWithParam` uses.
7267
static auto CombineWithFlags(auto value_range) -> auto {
73-
return testing::Combine(testing::Bool(), testing::Bool(), value_range);
68+
return testing::Combine(testing::Bool(), value_range);
7469
}
7570

7671
class LocIdAsNoneTestWithParam : public IdsTestWithParam {};
@@ -102,23 +97,21 @@ TEST_P(LocIdAsImportIRInstIdTest, Test) {
10297
ASSERT_THAT(loc_id.kind(), Eq(LocId::Kind::ImportIRInstId));
10398
EXPECT_THAT(loc_id.import_ir_inst_id(), import_ir_inst_id);
10499
EXPECT_FALSE(loc_id.is_implicit());
105-
EXPECT_THAT(loc_id.is_token_only(), Eq(is_token_only()));
106100
}
107101

108102
class LocIdAsInstIdTest : public IdsTestWithParam {};
109103

110104
INSTANTIATE_TEST_SUITE_P(
111105
Test, LocIdAsInstIdTest,
112-
testing::Combine(testing::Values(false), testing::Values(false),
106+
testing::Combine(testing::Values(false),
113107
GetValueRange(std::numeric_limits<int32_t>::max())));
114108

115109
TEST_P(LocIdAsInstIdTest, Test) {
116110
auto [inst_id, loc_id] = BuildIdAndLocId<InstId>();
117111
EXPECT_TRUE(loc_id.has_value());
118112
ASSERT_THAT(loc_id.kind(), Eq(LocId::Kind::InstId));
119113
EXPECT_THAT(loc_id.inst_id(), inst_id);
120-
// Note that `is_implicit` and `is_token_only` are invalid to use with
121-
// `InstId`.
114+
// Note that `is_implicit` is invalid to use with `InstId`.
122115
}
123116

124117
class LocIdAsNodeIdTest : public IdsTestWithParam {};
@@ -132,7 +125,6 @@ TEST_P(LocIdAsNodeIdTest, Test) {
132125
ASSERT_THAT(loc_id.kind(), Eq(LocId::Kind::NodeId));
133126
EXPECT_THAT(loc_id.node_id(), node_id);
134127
EXPECT_THAT(loc_id.is_implicit(), Eq(is_implicit()));
135-
EXPECT_THAT(loc_id.is_token_only(), Eq(is_token_only()));
136128
}
137129

138130
} // namespace

0 commit comments

Comments
 (0)