Files
carbon-lang/toolchain/check/diagnostic_helpers.h
T
Jon Ross-Perkins 89a6818424 Move TokenOnly to LocIdForDiagnostics (#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.
2025-06-03 01:14:54 +00:00

158 lines
5.7 KiB
C++

// 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_CHECK_DIAGNOSTIC_HELPERS_H_
#define CARBON_TOOLCHAIN_CHECK_DIAGNOSTIC_HELPERS_H_
#include <concepts>
#include "llvm/ADT/APSInt.h"
#include "toolchain/parse/node_ids.h"
#include "toolchain/sem_ir/ids.h"
namespace Carbon::Check {
// The `DiagnosticEmitterBase` is templated on this type so that
// diagnostics can be passed an `InstId` as a location, without having to
// explicitly construct a `LocId` from it first.
class LocIdForDiagnostics {
public:
// Constructs a token-only location for a diagnostic.
//
// This means the displayed location will include only the location's specific
// parse node, instead of also including its descendants.
static auto TokenOnly(Parse::NodeId node_id) -> LocIdForDiagnostics {
return LocIdForDiagnostics(SemIR::LocId(node_id), true);
}
template <class LocT>
requires std::constructible_from<SemIR::LocId, LocT>
// NOLINTNEXTLINE(google-explicit-constructor)
LocIdForDiagnostics(LocT loc_id)
: LocIdForDiagnostics(SemIR::LocId(loc_id), false) {}
auto loc_id() const -> SemIR::LocId { return loc_id_; }
auto is_token_only() const -> bool { return is_token_only_; }
private:
explicit LocIdForDiagnostics(SemIR::LocId loc_id, bool is_token_only)
: loc_id_(loc_id), is_token_only_(is_token_only) {}
SemIR::LocId loc_id_;
bool is_token_only_;
};
// We define the emitter separately for dependencies, so only provide a base
// here.
using DiagnosticEmitterBase = Diagnostics::Emitter<LocIdForDiagnostics>;
using DiagnosticBuilder = DiagnosticEmitterBase::Builder;
// A function that forms a diagnostic for some kind of problem. The
// DiagnosticBuilder is returned rather than emitted so that the caller
// can add contextual notes as appropriate.
using MakeDiagnosticBuilderFn = llvm::function_ref<auto()->DiagnosticBuilder>;
// An expression with a constant value, for rendering in a diagnostic. The
// diagnostic rendering will include enclosing "`"s.
struct InstIdAsConstant {
using DiagnosticType = Diagnostics::TypeInfo<std::string>;
// NOLINTNEXTLINE(google-explicit-constructor)
InstIdAsConstant(SemIR::InstId inst_id) : inst_id(inst_id) {}
SemIR::InstId inst_id;
};
// An expression whose type should be rendered in a diagnostic. The diagnostic
// rendering will include enclosing "`"s, and may also include extra information
// about the type if it might otherwise be ambiguous or context-dependent, such
// as the targets of aliases used in the type.
//
// TODO: Include such additional information where relevant. For example:
// "`StdString` (aka `Cpp.std.basic_string(Char)`)".
//
// This should be used instead of `TypeId` as a diagnostic argument wherever
// possible, because we should eventually be able to produce a sugared type name
// in this case, whereas a `TypeId` will render as a canonical type.
struct TypeOfInstId {
using DiagnosticType = Diagnostics::TypeInfo<std::string>;
// NOLINTNEXTLINE(google-explicit-constructor)
TypeOfInstId(SemIR::InstId inst_id) : inst_id(inst_id) {}
SemIR::InstId inst_id;
};
// A type expression, for rendering in a diagnostic. The diagnostic rendering
// will include enclosing "`"s, and may also include extra information about the
// type if it would otherwise be ambiguous.
//
// TODO: Include such additional information where relevant.
//
// This should be used when the source expression used to construct a type is
// available.
//
// Note that this is currently an alias for InstIdAsConstant. However, using
// InstIdAsType is clearer when defining CARBON_DIAGNOSTICs, and we may wish to
// distinguish type arguments in diagnostics from more general constants in some
// way in the future.
using InstIdAsType = InstIdAsConstant;
// A type expression, for rendering in a diagnostic as a raw type. When
// formatting as a raw type in a diagnostic, the type will be formatted as a
// simple Carbon expression, without enclosing "`"s. Once we start including
// extra information about types, such annotations will also not be included for
// raw types.
//
// This is intended for cases where the type is part of a larger syntactic
// construct in a diagnostic, such as "redefinition of `impl {0} as {1}`".
struct InstIdAsRawType {
using DiagnosticType = Diagnostics::TypeInfo<std::string>;
// NOLINTNEXTLINE(google-explicit-constructor)
InstIdAsRawType(SemIR::InstId inst_id) : inst_id(inst_id) {}
SemIR::InstId inst_id;
};
// A type value for rendering in a diagnostic without enclosing "`"s. See
// `InstIdAsRawType` for details on raw type formatting.
//
// As with `TypeId`, this should be avoided as a diagnostic argument where
// possible, because it can't be formatted with syntactic sugar such as aliases
// that describe how the type was written.
struct TypeIdAsRawType {
using DiagnosticType = Diagnostics::TypeInfo<std::string>;
// NOLINTNEXTLINE(google-explicit-constructor)
TypeIdAsRawType(SemIR::TypeId type_id) : type_id(type_id) {}
SemIR::TypeId type_id;
};
// An integer value together with its type. The type is used to determine how to
// format the value in diagnostics.
struct TypedInt {
using DiagnosticType = Diagnostics::TypeInfo<llvm::APSInt>;
SemIR::TypeId type;
llvm::APInt value;
};
struct SpecificInterfaceIdAsRawType {
using DiagnosticType = Diagnostics::TypeInfo<std::string>;
// NOLINTNEXTLINE(google-explicit-constructor)
SpecificInterfaceIdAsRawType(SemIR::SpecificInterfaceId specific_interface_id)
: specific_interface_id(specific_interface_id) {}
SemIR::SpecificInterfaceId specific_interface_id;
};
} // namespace Carbon::Check
#endif // CARBON_TOOLCHAIN_CHECK_DIAGNOSTIC_HELPERS_H_