|
|
@@ -39,31 +39,32 @@ struct SpecificEvalInfo {
|
|
|
class EvalContext {
|
|
|
public:
|
|
|
explicit EvalContext(
|
|
|
- Context* context, SemIRLoc fallback_loc,
|
|
|
+ Context* context, SemIR::LocId fallback_loc_id,
|
|
|
SemIR::SpecificId specific_id = SemIR::SpecificId::None,
|
|
|
std::optional<SpecificEvalInfo> specific_eval_info = std::nullopt)
|
|
|
: context_(context),
|
|
|
- fallback_loc_(fallback_loc),
|
|
|
+ fallback_loc_id_(fallback_loc_id),
|
|
|
specific_id_(specific_id),
|
|
|
specific_eval_info_(specific_eval_info) {}
|
|
|
|
|
|
// Gets the location to use for diagnostics if a better location is
|
|
|
// unavailable.
|
|
|
// TODO: This is also sometimes unavailable.
|
|
|
- auto fallback_loc() const -> SemIRLoc { return fallback_loc_; }
|
|
|
+ auto fallback_loc_id() const -> SemIR::LocId { return fallback_loc_id_; }
|
|
|
|
|
|
// Returns a location to use to point at an instruction in a diagnostic, given
|
|
|
// a list of instructions that might have an attached location. This is the
|
|
|
// location of the first instruction in the list that has a location if there
|
|
|
// is one, and otherwise the fallback location.
|
|
|
- auto GetDiagnosticLoc(llvm::ArrayRef<SemIR::InstId> inst_ids) -> SemIRLoc {
|
|
|
+ auto GetDiagnosticLoc(llvm::ArrayRef<SemIR::InstId> inst_ids)
|
|
|
+ -> SemIR::LocId {
|
|
|
for (auto inst_id : inst_ids) {
|
|
|
if (inst_id.has_value() &&
|
|
|
context_->insts().GetLocId(inst_id).has_value()) {
|
|
|
return inst_id;
|
|
|
}
|
|
|
}
|
|
|
- return fallback_loc_;
|
|
|
+ return fallback_loc_id_;
|
|
|
}
|
|
|
|
|
|
// Gets the value of the specified compile-time binding in this context.
|
|
|
@@ -199,7 +200,7 @@ class EvalContext {
|
|
|
// The type-checking context in which we're performing evaluation.
|
|
|
Context* context_;
|
|
|
// The location to use for diagnostics when a better location isn't available.
|
|
|
- SemIRLoc fallback_loc_;
|
|
|
+ SemIR::LocId fallback_loc_id_;
|
|
|
// The specific that we are evaluating within.
|
|
|
SemIR::SpecificId specific_id_;
|
|
|
// If we are currently evaluating an eval block for `specific_id_`,
|
|
|
@@ -549,11 +550,11 @@ static auto GetConstantValue(EvalContext& eval_context,
|
|
|
.Get(specific.generic_id)
|
|
|
.decl_block_id.has_value()) {
|
|
|
ResolveSpecificDeclaration(eval_context.context(),
|
|
|
- eval_context.fallback_loc(), specific_id);
|
|
|
+ eval_context.fallback_loc_id(), specific_id);
|
|
|
}
|
|
|
return specific_id;
|
|
|
}
|
|
|
- return MakeSpecific(eval_context.context(), eval_context.fallback_loc(),
|
|
|
+ return MakeSpecific(eval_context.context(), eval_context.fallback_loc_id(),
|
|
|
specific.generic_id, args_id);
|
|
|
}
|
|
|
|
|
|
@@ -819,14 +820,14 @@ static auto PerformArrayIndex(EvalContext& eval_context, SemIR::ArrayIndex inst)
|
|
|
|
|
|
// Forms a constant int type as an evaluation result. Requires that width_id is
|
|
|
// constant.
|
|
|
-static auto MakeIntTypeResult(Context& context, SemIRLoc loc,
|
|
|
+static auto MakeIntTypeResult(Context& context, SemIR::LocId loc_id,
|
|
|
SemIR::IntKind int_kind, SemIR::InstId width_id,
|
|
|
Phase phase) -> SemIR::ConstantId {
|
|
|
auto result = SemIR::IntType{
|
|
|
.type_id = GetSingletonType(context, SemIR::TypeType::SingletonInstId),
|
|
|
.int_kind = int_kind,
|
|
|
.bit_width_id = width_id};
|
|
|
- if (!ValidateIntType(context, loc, result)) {
|
|
|
+ if (!ValidateIntType(context, loc_id, result)) {
|
|
|
return SemIR::ErrorInst::SingletonConstantId;
|
|
|
}
|
|
|
return MakeConstantResult(context, result, phase);
|
|
|
@@ -854,7 +855,7 @@ static auto PerformIntConvert(Context& context, SemIR::InstId arg_id,
|
|
|
|
|
|
// Performs a conversion between integer types, diagnosing if the value doesn't
|
|
|
// fit in the destination type.
|
|
|
-static auto PerformCheckedIntConvert(Context& context, SemIRLoc loc,
|
|
|
+static auto PerformCheckedIntConvert(Context& context, SemIR::LocId loc_id,
|
|
|
SemIR::InstId arg_id,
|
|
|
SemIR::TypeId dest_type_id)
|
|
|
-> SemIR::ConstantId {
|
|
|
@@ -872,7 +873,7 @@ static auto PerformCheckedIntConvert(Context& context, SemIRLoc loc,
|
|
|
NegativeIntInUnsignedType, Error,
|
|
|
"negative integer value {0} converted to unsigned type {1}", TypedInt,
|
|
|
SemIR::TypeId);
|
|
|
- context.emitter().Emit(loc, NegativeIntInUnsignedType,
|
|
|
+ context.emitter().Emit(loc_id, NegativeIntInUnsignedType,
|
|
|
{.type = arg.type_id, .value = arg_val},
|
|
|
dest_type_id);
|
|
|
}
|
|
|
@@ -882,7 +883,7 @@ static auto PerformCheckedIntConvert(Context& context, SemIRLoc loc,
|
|
|
CARBON_DIAGNOSTIC(IntTooLargeForType, Error,
|
|
|
"integer value {0} too large for type {1}", TypedInt,
|
|
|
SemIR::TypeId);
|
|
|
- context.emitter().Emit(loc, IntTooLargeForType,
|
|
|
+ context.emitter().Emit(loc_id, IntTooLargeForType,
|
|
|
{.type = arg.type_id, .value = arg_val},
|
|
|
dest_type_id);
|
|
|
}
|
|
|
@@ -893,9 +894,10 @@ static auto PerformCheckedIntConvert(Context& context, SemIRLoc loc,
|
|
|
}
|
|
|
|
|
|
// Issues a diagnostic for a compile-time division by zero.
|
|
|
-static auto DiagnoseDivisionByZero(Context& context, SemIRLoc loc) -> void {
|
|
|
+static auto DiagnoseDivisionByZero(Context& context, SemIR::LocId loc_id)
|
|
|
+ -> void {
|
|
|
CARBON_DIAGNOSTIC(CompileTimeDivisionByZero, Error, "division by zero");
|
|
|
- context.emitter().Emit(loc, CompileTimeDivisionByZero);
|
|
|
+ context.emitter().Emit(loc_id, CompileTimeDivisionByZero);
|
|
|
}
|
|
|
|
|
|
// Get an integer at a suitable bit-width: either `bit_width_id` if it has a
|
|
|
@@ -908,7 +910,7 @@ static auto GetIntAtSuitableWidth(Context& context, IntId int_id,
|
|
|
}
|
|
|
|
|
|
// Performs a builtin unary integer -> integer operation.
|
|
|
-static auto PerformBuiltinUnaryIntOp(Context& context, SemIRLoc loc,
|
|
|
+static auto PerformBuiltinUnaryIntOp(Context& context, SemIR::LocId loc_id,
|
|
|
SemIR::BuiltinFunctionKind builtin_kind,
|
|
|
SemIR::InstId arg_id)
|
|
|
-> SemIR::ConstantId {
|
|
|
@@ -923,7 +925,7 @@ static auto PerformBuiltinUnaryIntOp(Context& context, SemIRLoc loc,
|
|
|
if (bit_width_id.has_value()) {
|
|
|
CARBON_DIAGNOSTIC(CompileTimeIntegerNegateOverflow, Error,
|
|
|
"integer overflow in negation of {0}", TypedInt);
|
|
|
- context.emitter().Emit(loc, CompileTimeIntegerNegateOverflow,
|
|
|
+ context.emitter().Emit(loc_id, CompileTimeIntegerNegateOverflow,
|
|
|
{.type = op.type_id, .value = op_val});
|
|
|
} else {
|
|
|
// Widen the integer so we don't overflow into the sign bit.
|
|
|
@@ -1075,7 +1077,7 @@ static auto ComputeBinaryIntOpResult(SemIR::BuiltinFunctionKind builtin_kind,
|
|
|
}
|
|
|
|
|
|
// Performs a builtin integer bit shift operation.
|
|
|
-static auto PerformBuiltinIntShiftOp(Context& context, SemIRLoc loc,
|
|
|
+static auto PerformBuiltinIntShiftOp(Context& context, SemIR::LocId loc_id,
|
|
|
SemIR::BuiltinFunctionKind builtin_kind,
|
|
|
SemIR::InstId lhs_id, SemIR::InstId rhs_id)
|
|
|
-> SemIR::ConstantId {
|
|
|
@@ -1094,7 +1096,7 @@ static auto PerformBuiltinIntShiftOp(Context& context, SemIRLoc loc,
|
|
|
"shift distance >= type width of {0} in `{1} {2:<<|>>} {3}`", unsigned,
|
|
|
TypedInt, Diagnostics::BoolAsSelect, TypedInt);
|
|
|
context.emitter().Emit(
|
|
|
- loc, CompileTimeShiftOutOfRange, lhs_val.getBitWidth(),
|
|
|
+ loc_id, CompileTimeShiftOutOfRange, lhs_val.getBitWidth(),
|
|
|
{.type = lhs.type_id, .value = lhs_val},
|
|
|
builtin_kind == SemIR::BuiltinFunctionKind::IntLeftShift,
|
|
|
{.type = rhs.type_id, .value = rhs_orig_val});
|
|
|
@@ -1108,7 +1110,8 @@ static auto PerformBuiltinIntShiftOp(Context& context, SemIRLoc loc,
|
|
|
"shift distance negative in `{0} {1:<<|>>} {2}`",
|
|
|
TypedInt, Diagnostics::BoolAsSelect, TypedInt);
|
|
|
context.emitter().Emit(
|
|
|
- loc, CompileTimeShiftNegative, {.type = lhs.type_id, .value = lhs_val},
|
|
|
+ loc_id, CompileTimeShiftNegative,
|
|
|
+ {.type = lhs.type_id, .value = lhs_val},
|
|
|
builtin_kind == SemIR::BuiltinFunctionKind::IntLeftShift,
|
|
|
{.type = rhs.type_id, .value = rhs_orig_val});
|
|
|
// TODO: Is it useful to recover by returning 0 or -1?
|
|
|
@@ -1128,7 +1131,7 @@ static auto PerformBuiltinIntShiftOp(Context& context, SemIRLoc loc,
|
|
|
"integer whose width is greater than the "
|
|
|
"maximum supported width of {1}",
|
|
|
TypedInt, int);
|
|
|
- context.emitter().Emit(loc, CompileTimeUnsizedShiftOutOfRange,
|
|
|
+ context.emitter().Emit(loc_id, CompileTimeUnsizedShiftOutOfRange,
|
|
|
{.type = rhs.type_id, .value = rhs_orig_val},
|
|
|
IntStore::MaxIntWidth);
|
|
|
return SemIR::ErrorInst::SingletonConstantId;
|
|
|
@@ -1152,7 +1155,7 @@ static auto PerformBuiltinIntShiftOp(Context& context, SemIRLoc loc,
|
|
|
}
|
|
|
|
|
|
// Performs a homogeneous builtin binary integer -> integer operation.
|
|
|
-static auto PerformBuiltinBinaryIntOp(Context& context, SemIRLoc loc,
|
|
|
+static auto PerformBuiltinBinaryIntOp(Context& context, SemIR::LocId loc_id,
|
|
|
SemIR::BuiltinFunctionKind builtin_kind,
|
|
|
SemIR::InstId lhs_id,
|
|
|
SemIR::InstId rhs_id)
|
|
|
@@ -1174,7 +1177,7 @@ static auto PerformBuiltinBinaryIntOp(Context& context, SemIRLoc loc,
|
|
|
case SemIR::BuiltinFunctionKind::IntUDiv:
|
|
|
case SemIR::BuiltinFunctionKind::IntUMod:
|
|
|
if (rhs_val.isZero()) {
|
|
|
- DiagnoseDivisionByZero(context, loc);
|
|
|
+ DiagnoseDivisionByZero(context, loc_id);
|
|
|
return SemIR::ErrorInst::SingletonConstantId;
|
|
|
}
|
|
|
break;
|
|
|
@@ -1216,7 +1219,7 @@ static auto PerformBuiltinBinaryIntOp(Context& context, SemIRLoc loc,
|
|
|
CARBON_DIAGNOSTIC(CompileTimeIntegerOverflow, Error,
|
|
|
"integer overflow in calculation `{0} {1} {2}`", TypedInt,
|
|
|
Lex::TokenKind, TypedInt);
|
|
|
- context.emitter().Emit(loc, CompileTimeIntegerOverflow,
|
|
|
+ context.emitter().Emit(loc_id, CompileTimeIntegerOverflow,
|
|
|
{.type = type_id, .value = lhs_val}, result.op_token,
|
|
|
{.type = type_id, .value = rhs_val});
|
|
|
}
|
|
|
@@ -1366,8 +1369,8 @@ static auto PerformBuiltinBoolComparison(
|
|
|
}
|
|
|
|
|
|
// Returns a constant for a call to a builtin function.
|
|
|
-static auto MakeConstantForBuiltinCall(EvalContext& eval_context, SemIRLoc loc,
|
|
|
- SemIR::Call call,
|
|
|
+static auto MakeConstantForBuiltinCall(EvalContext& eval_context,
|
|
|
+ SemIR::LocId loc_id, SemIR::Call call,
|
|
|
SemIR::BuiltinFunctionKind builtin_kind,
|
|
|
llvm::ArrayRef<SemIR::InstId> arg_ids,
|
|
|
Phase phase) -> SemIR::ConstantId {
|
|
|
@@ -1403,7 +1406,7 @@ static auto MakeConstantForBuiltinCall(EvalContext& eval_context, SemIRLoc loc,
|
|
|
// say if it's referring to the left or the right side for the error.
|
|
|
// The `arg_id` instruction has no location in it for some reason.
|
|
|
context.emitter().Emit(
|
|
|
- loc, FacetTypeRequiredForTypeAndOperator,
|
|
|
+ loc_id, FacetTypeRequiredForTypeAndOperator,
|
|
|
context.types().GetTypeIdForTypeInstId(type_arg_id));
|
|
|
}
|
|
|
}
|
|
|
@@ -1430,12 +1433,12 @@ static auto MakeConstantForBuiltinCall(EvalContext& eval_context, SemIRLoc loc,
|
|
|
}
|
|
|
|
|
|
case SemIR::BuiltinFunctionKind::IntMakeTypeSigned: {
|
|
|
- return MakeIntTypeResult(context, loc, SemIR::IntKind::Signed, arg_ids[0],
|
|
|
- phase);
|
|
|
+ return MakeIntTypeResult(context, loc_id, SemIR::IntKind::Signed,
|
|
|
+ arg_ids[0], phase);
|
|
|
}
|
|
|
|
|
|
case SemIR::BuiltinFunctionKind::IntMakeTypeUnsigned: {
|
|
|
- return MakeIntTypeResult(context, loc, SemIR::IntKind::Unsigned,
|
|
|
+ return MakeIntTypeResult(context, loc_id, SemIR::IntKind::Unsigned,
|
|
|
arg_ids[0], phase);
|
|
|
}
|
|
|
|
|
|
@@ -1444,7 +1447,7 @@ static auto MakeConstantForBuiltinCall(EvalContext& eval_context, SemIRLoc loc,
|
|
|
if (phase != Phase::Concrete) {
|
|
|
break;
|
|
|
}
|
|
|
- if (!ValidateFloatBitWidth(context, loc, arg_ids[0])) {
|
|
|
+ if (!ValidateFloatBitWidth(context, loc_id, arg_ids[0])) {
|
|
|
return SemIR::ErrorInst::SingletonConstantId;
|
|
|
}
|
|
|
return context.constant_values().Get(
|
|
|
@@ -1466,7 +1469,8 @@ static auto MakeConstantForBuiltinCall(EvalContext& eval_context, SemIRLoc loc,
|
|
|
if (phase != Phase::Concrete) {
|
|
|
return MakeConstantResult(context, call, phase);
|
|
|
}
|
|
|
- return PerformCheckedIntConvert(context, loc, arg_ids[0], call.type_id);
|
|
|
+ return PerformCheckedIntConvert(context, loc_id, arg_ids[0],
|
|
|
+ call.type_id);
|
|
|
}
|
|
|
|
|
|
// Unary integer -> integer operations.
|
|
|
@@ -1476,7 +1480,8 @@ static auto MakeConstantForBuiltinCall(EvalContext& eval_context, SemIRLoc loc,
|
|
|
if (phase != Phase::Concrete) {
|
|
|
break;
|
|
|
}
|
|
|
- return PerformBuiltinUnaryIntOp(context, loc, builtin_kind, arg_ids[0]);
|
|
|
+ return PerformBuiltinUnaryIntOp(context, loc_id, builtin_kind,
|
|
|
+ arg_ids[0]);
|
|
|
}
|
|
|
|
|
|
// Homogeneous binary integer -> integer operations.
|
|
|
@@ -1496,8 +1501,8 @@ static auto MakeConstantForBuiltinCall(EvalContext& eval_context, SemIRLoc loc,
|
|
|
if (phase != Phase::Concrete) {
|
|
|
break;
|
|
|
}
|
|
|
- return PerformBuiltinBinaryIntOp(context, loc, builtin_kind, arg_ids[0],
|
|
|
- arg_ids[1]);
|
|
|
+ return PerformBuiltinBinaryIntOp(context, loc_id, builtin_kind,
|
|
|
+ arg_ids[0], arg_ids[1]);
|
|
|
}
|
|
|
|
|
|
// Bit shift operations.
|
|
|
@@ -1506,7 +1511,7 @@ static auto MakeConstantForBuiltinCall(EvalContext& eval_context, SemIRLoc loc,
|
|
|
if (phase != Phase::Concrete) {
|
|
|
break;
|
|
|
}
|
|
|
- return PerformBuiltinIntShiftOp(context, loc, builtin_kind, arg_ids[0],
|
|
|
+ return PerformBuiltinIntShiftOp(context, loc_id, builtin_kind, arg_ids[0],
|
|
|
arg_ids[1]);
|
|
|
}
|
|
|
|
|
|
@@ -1574,7 +1579,7 @@ static auto MakeConstantForBuiltinCall(EvalContext& eval_context, SemIRLoc loc,
|
|
|
}
|
|
|
|
|
|
// Makes a constant for a call instruction.
|
|
|
-static auto MakeConstantForCall(EvalContext& eval_context, SemIRLoc loc,
|
|
|
+static auto MakeConstantForCall(EvalContext& eval_context, SemIR::LocId loc_id,
|
|
|
SemIR::Call call) -> SemIR::ConstantId {
|
|
|
Phase phase = Phase::Concrete;
|
|
|
|
|
|
@@ -1630,7 +1635,7 @@ static auto MakeConstantForCall(EvalContext& eval_context, SemIRLoc loc,
|
|
|
CARBON_DIAGNOSTIC(CompTimeOnlyFunctionHere, Note,
|
|
|
"compile-time-only function declared here");
|
|
|
eval_context.emitter()
|
|
|
- .Build(loc, NonConstantCallToCompTimeOnlyFunction)
|
|
|
+ .Build(loc_id, NonConstantCallToCompTimeOnlyFunction)
|
|
|
.Note(eval_context.functions()
|
|
|
.Get(callee_function.function_id)
|
|
|
.latest_decl_id(),
|
|
|
@@ -1643,7 +1648,7 @@ static auto MakeConstantForCall(EvalContext& eval_context, SemIRLoc loc,
|
|
|
// Handle calls to builtins.
|
|
|
if (builtin_kind != SemIR::BuiltinFunctionKind::None) {
|
|
|
return MakeConstantForBuiltinCall(
|
|
|
- eval_context, loc, call, builtin_kind,
|
|
|
+ eval_context, loc_id, call, builtin_kind,
|
|
|
eval_context.inst_blocks().Get(call.args_id), phase);
|
|
|
}
|
|
|
|
|
|
@@ -1948,7 +1953,7 @@ auto TryEvalInstUnsafe(Context& context, SemIR::InstId inst_id,
|
|
|
return TryEvalInstInContext(eval_context, inst_id, inst);
|
|
|
}
|
|
|
|
|
|
-auto TryEvalBlockForSpecific(Context& context, SemIRLoc loc,
|
|
|
+auto TryEvalBlockForSpecific(Context& context, SemIR::LocId loc_id,
|
|
|
SemIR::SpecificId specific_id,
|
|
|
SemIR::GenericInstIndex::Region region)
|
|
|
-> SemIR::InstBlockId {
|
|
|
@@ -1959,7 +1964,7 @@ auto TryEvalBlockForSpecific(Context& context, SemIRLoc loc,
|
|
|
llvm::SmallVector<SemIR::InstId> result;
|
|
|
result.resize(eval_block.size(), SemIR::InstId::None);
|
|
|
|
|
|
- EvalContext eval_context(&context, loc, specific_id,
|
|
|
+ EvalContext eval_context(&context, loc_id, specific_id,
|
|
|
SpecificEvalInfo{
|
|
|
.region = region,
|
|
|
.values = result,
|
|
|
@@ -1969,7 +1974,7 @@ auto TryEvalBlockForSpecific(Context& context, SemIRLoc loc,
|
|
|
&context.emitter(), [&](auto& builder) {
|
|
|
CARBON_DIAGNOSTIC(ResolvingSpecificHere, Note, "in {0} used here",
|
|
|
SemIR::SpecificId);
|
|
|
- builder.Note(loc, ResolvingSpecificHere, specific_id);
|
|
|
+ builder.Note(loc_id, ResolvingSpecificHere, specific_id);
|
|
|
});
|
|
|
|
|
|
for (auto [i, inst_id] : llvm::enumerate(eval_block)) {
|