Implement Core.CharLiteral operations from #6710 and #7314 (#7316)

Adds support for arithmetic and comparison operators on
`Core.CharLiteral`s, as well as conversions between `CharLiteral` and
integer types.

Make some minor tweaks to fix skill issues encountered while making this
change.

Assisted-by: Gemini via Antigravity
This commit is contained in:
Richard Smith
2026-06-11 16:45:39 +00:00
committed by GitHub
parent a914dba888
commit 25e72882fc
49 changed files with 2411 additions and 355 deletions
+87 -5
View File
@@ -461,11 +461,76 @@ constexpr BuiltinInfo MaybeUnformedMakeType = {
constexpr BuiltinInfo FormMakeType = {"form.make_type",
ValidateSignature<auto()->Type>};
// Converts between char types, with a diagnostic if the value doesn't fit.
constexpr BuiltinInfo CharConvertChecked = {
"char.convert_checked",
// Converts a character literal to a character type, with a diagnostic if the
// value doesn't fit.
constexpr BuiltinInfo CharLiteralConvertChar = {
"char_literal.convert_char",
ValidateSignature<auto(CharLiteral)->CharCompatible>};
// Converts a character literal to a sized integer type, with a diagnostic if
// the value doesn't fit.
constexpr BuiltinInfo CharLiteralConvertInt = {
"char_literal.convert_int",
ValidateSignature<auto(CharLiteral)->AnySizedInt>};
// Converts an integer type to a character literal, with a diagnostic if the
// value is not a valid Unicode code point.
constexpr BuiltinInfo IntConvertCharLiteral = {
"int.convert_char_literal", ValidateSignature<auto(AnyInt)->CharLiteral>};
// Determines if two character literals are equal.
constexpr BuiltinInfo CharLiteralEq = {
"char_literal.eq", ValidateSignature<auto(CharLiteral, CharLiteral)->Bool>};
// Determines if two character literals are not equal.
constexpr BuiltinInfo CharLiteralNeq = {
"char_literal.neq",
ValidateSignature<auto(CharLiteral, CharLiteral)->Bool>};
// Determines if one character literal is less than another.
constexpr BuiltinInfo CharLiteralLess = {
"char_literal.less",
ValidateSignature<auto(CharLiteral, CharLiteral)->Bool>};
// Determines if one character literal is less than or equal to another.
constexpr BuiltinInfo CharLiteralLessEq = {
"char_literal.less_eq",
ValidateSignature<auto(CharLiteral, CharLiteral)->Bool>};
// Determines if one character literal is greater than another.
constexpr BuiltinInfo CharLiteralGreater = {
"char_literal.greater",
ValidateSignature<auto(CharLiteral, CharLiteral)->Bool>};
// Determines if one character literal is greater than or equal to another.
constexpr BuiltinInfo CharLiteralGreaterEq = {
"char_literal.greater_eq",
ValidateSignature<auto(CharLiteral, CharLiteral)->Bool>};
// Adds an integer to a character literal, with a diagnostic on overflow or
// if the result is not a valid Unicode code point.
constexpr BuiltinInfo CharLiteralAdd = {
"char_literal.add",
ValidateSignature<auto(CharLiteral, AnyInt)->CharLiteral>};
// Adds a character literal to an integer, with a diagnostic on overflow or
// if the result is not a valid Unicode code point.
constexpr BuiltinInfo IntAddCharLiteral = {
"int.add_char_literal",
ValidateSignature<auto(AnyInt, CharLiteral)->CharLiteral>};
// Subtracts an integer from a character literal, with a diagnostic on
// overflow or if the result is not a valid Unicode code point.
constexpr BuiltinInfo CharLiteralSubInt = {
"char_literal.sub_int",
ValidateSignature<auto(CharLiteral, AnyInt)->CharLiteral>};
// Subtracts one character literal from another, returning the distance as
// an integer.
constexpr BuiltinInfo CharLiteralSubChar = {
"char_literal.sub_char",
ValidateSignature<auto(CharLiteral, CharLiteral)->AnyInt>};
// Converts from an integer type to a char-compatible type (u8/adapted Char).
constexpr BuiltinInfo IntConvertChar = {
"int.convert_char", ValidateSignature<auto(AnyInt)->CharCompatible>};
@@ -812,7 +877,8 @@ static auto IsLiteralType(const File& sem_ir, TypeId type_id) -> bool {
// Unwrap adapters.
type_id = sem_ir.types().GetTransitiveAdaptedType(type_id);
auto type_inst_id = sem_ir.types().GetAsInst(type_id);
return type_inst_id.IsOneOf<IntLiteralType, FloatLiteralType>();
return type_inst_id
.IsOneOf<IntLiteralType, FloatLiteralType, CharLiteralType>();
}
// Determines whether a builtin call involves an integer or floating-point
@@ -856,13 +922,29 @@ auto BuiltinFunctionKind::IsCompTimeOnly(const File& sem_ir,
llvm::ArrayRef<InstId> arg_ids,
TypeId return_type_id) const -> bool {
switch (*this) {
case CharConvertChecked:
case FloatConvertChecked:
case IntConvertChecked:
case IntConvertFloatChecked:
// Checked conversions are compile-time only.
return true;
case CharLiteralAdd:
case CharLiteralConvertChar:
case CharLiteralConvertInt:
case CharLiteralEq:
case CharLiteralGreater:
case CharLiteralGreaterEq:
case CharLiteralLess:
case CharLiteralLessEq:
case CharLiteralNeq:
case CharLiteralSubChar:
case CharLiteralSubInt:
case IntAddCharLiteral:
case IntConvertCharLiteral:
// These operations always involve a literal type.
// See AnyLiteralTypes comment for explanation.
return true;
case FloatConvert:
case FloatConvertInt:
case IntConvert: