mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Support parse/check/lower for char (#5901)
toolchain/check/testdata/builtins/char/basics.carbon and toolchain/lower/testdata/builtins/char.carbon are probably the most interesting tests here. The parse tests is required because this adds a new node kind, and we need coverage of it; but the attached info is minor. There's a fair amount of test churn here because I'm adding the Core.Char and Core.CharLiteral types as new singletons. My intent here is that `CharId` is always a unicode code point, even when the type is a `Char` and thus must be a single UTF-8 code unit (single byte). This mainly means the stored value of a `CharValue` can be printed internally without knowing the type. --------- Co-authored-by: josh11b <15258583+josh11b@users.noreply.github.com> Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This commit is contained in:
co-authored by
josh11b
Richard Smith
parent
9c7e0f6bd5
commit
37d5046ceb
@@ -9,6 +9,7 @@
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
#include "llvm/Support/ConvertUTF.h"
|
||||
#include "toolchain/base/canonical_value_store.h"
|
||||
#include "toolchain/base/kind_switch.h"
|
||||
#include "toolchain/check/action.h"
|
||||
@@ -951,6 +952,28 @@ static auto PerformArrayIndex(EvalContext& eval_context, SemIR::ArrayIndex inst)
|
||||
return eval_context.GetConstantValue(elements[index_val.getZExtValue()]);
|
||||
}
|
||||
|
||||
// Performs a conversion between character types, diagnosing if the value
|
||||
// doesn't fit in the destination type.
|
||||
static auto PerformCheckedCharConvert(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::InstId arg_id,
|
||||
SemIR::TypeId dest_type_id)
|
||||
-> SemIR::ConstantId {
|
||||
auto arg = context.insts().GetAs<SemIR::CharLiteralValue>(arg_id);
|
||||
|
||||
// Values over 0x80 require multiple code units in UTF-8.
|
||||
if (arg.value.index >= 0x80) {
|
||||
CARBON_DIAGNOSTIC(CharTooLargeForType, Error,
|
||||
"character value {0} too large for type {1}",
|
||||
SemIR::CharId, SemIR::TypeId);
|
||||
context.emitter().Emit(loc_id, CharTooLargeForType, arg.value,
|
||||
dest_type_id);
|
||||
return SemIR::ErrorInst::ConstantId;
|
||||
}
|
||||
|
||||
llvm::APInt int_val(8, arg.value.index, /*isSigned=*/false);
|
||||
return MakeIntResult(context, dest_type_id, /*is_signed=*/false, int_val);
|
||||
}
|
||||
|
||||
// Forms a constant int type as an evaluation result. Requires that width_id is
|
||||
// constant.
|
||||
static auto MakeIntTypeResult(Context& context, SemIR::LocId loc_id,
|
||||
@@ -1590,6 +1613,10 @@ static auto MakeConstantForBuiltinCall(EvalContext& eval_context,
|
||||
return MakeFacetTypeResult(eval_context.context(), combined_info, phase);
|
||||
}
|
||||
|
||||
case SemIR::BuiltinFunctionKind::CharLiteralMakeType: {
|
||||
return context.constant_values().Get(SemIR::CharLiteralType::TypeInstId);
|
||||
}
|
||||
|
||||
case SemIR::BuiltinFunctionKind::IntLiteralMakeType: {
|
||||
return context.constant_values().Get(SemIR::IntLiteralType::TypeInstId);
|
||||
}
|
||||
@@ -1619,6 +1646,15 @@ static auto MakeConstantForBuiltinCall(EvalContext& eval_context,
|
||||
return context.constant_values().Get(SemIR::BoolType::TypeInstId);
|
||||
}
|
||||
|
||||
// Character conversions.
|
||||
case SemIR::BuiltinFunctionKind::CharConvertChecked: {
|
||||
if (phase != Phase::Concrete) {
|
||||
return MakeConstantResult(context, call, phase);
|
||||
}
|
||||
return PerformCheckedCharConvert(context, loc_id, arg_ids[0],
|
||||
call.type_id);
|
||||
}
|
||||
|
||||
// Integer conversions.
|
||||
case SemIR::BuiltinFunctionKind::IntConvert: {
|
||||
if (phase != Phase::Concrete) {
|
||||
|
||||
Reference in New Issue
Block a user