From d01e1d2d0612549db57ee5e62c1059d243371ffe Mon Sep 17 00:00:00 2001 From: josh11b <15258583+josh11b@users.noreply.github.com> Date: Mon, 1 Jun 2026 12:34:35 -0700 Subject: [PATCH] Update design docs for proposal #6710: `char` redesign (#7281) Note that #7266 has already updated the toolchain for `char`, but not `Core.CharLiteral`. Assisted-by: Gemini via Antigravity --------- Co-authored-by: Josh L Co-authored-by: Geoff Romer --- docs/design/README.md | 2 +- docs/design/expressions/arithmetic.md | 32 ++++++++- docs/design/expressions/as_expressions.md | 5 +- .../expressions/comparison_operators.md | 7 +- .../expressions/implicit_conversions.md | 18 ++++- docs/design/expressions/literals.md | 31 +++++++++ docs/design/interoperability/README.md | 22 +++++- docs/design/lexical_conventions/README.md | 1 + .../lexical_conventions/character_literals.md | 68 +++++++++++++++++++ 9 files changed, 175 insertions(+), 11 deletions(-) create mode 100644 docs/design/lexical_conventions/character_literals.md diff --git a/docs/design/README.md b/docs/design/README.md index f821da3ccede..2b740c67e0c9 100644 --- a/docs/design/README.md +++ b/docs/design/README.md @@ -3609,7 +3609,7 @@ provided by `` or ``. The basic C and C++ integer types like namespace given an `import Cpp;` declaration, with names like `Cpp.int`, `Cpp.char`, and `Cpp.unsigned_long`. C++ types are considered different if C++ considers them different, so C++ overloads are resolved the same way. Carbon -[conventions for implicit conversions between integer types](expressions/implicit_conversions.md#data-types) +[conventions for implicit conversions between integer types](expressions/implicit_conversions.md#numeric-types) apply here, allowing them whenever the numerical value for all inputs may be preserved by the conversion. diff --git a/docs/design/expressions/arithmetic.md b/docs/design/expressions/arithmetic.md index f750f6cb2ac0..8d5f49ee3491 100644 --- a/docs/design/expressions/arithmetic.md +++ b/docs/design/expressions/arithmetic.md @@ -17,6 +17,8 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - [Overflow and other error conditions](#overflow-and-other-error-conditions) - [Floating-point types](#floating-point-types) - [Strings](#strings) + - [Character types](#character-types) + - [Overflow Semantics](#overflow-semantics) - [Extensibility](#extensibility) - [Alternatives considered](#alternatives-considered) - [References](#references) @@ -104,8 +106,8 @@ converted as follows: - If one type is `iN` and the other type is `uM`, and `M` < `N`, the `uM` operand is converted to `iN`. - If one type is `fN` and the other type is `iM` or `uM`, and there is an - [implicit conversion](implicit_conversions.md#data-types) from the integer - type to `fN`, then the integer operand is converted to `fN`. + [implicit conversion](implicit_conversions.md#numeric-types) from the + integer type to `fN`, then the integer operand is converted to `fN`. More broadly, if one operand is of built-in type and the other operand can be implicitly converted to that type, then it is, unless that behavior is @@ -185,6 +187,30 @@ Because floating-point arithmetic follows IEEE 754 rules: overflow results in `+` for concatenation. See [#457](https://github.com/carbon-language/carbon-lang/issues/457). +### Character types + +Character types (`char` and `Core.CharLiteral`) support arithmetic operations +aligned with the concept of "characters" rather than raw integers. Operations +with `Core.CharLiteral` and compile-time constants produce compile-time integer +or `Core.CharLiteral` results. Operations with a `char` or a runtime integer +argument produce `char` results. + +- **Addition:** The sum of a character and an integer produces a character. +- **Subtraction:** + - The difference of two characters produces an `i32`. This is preferred + even for `char` to be consistent with the range needed to represent the + difference of two `Core.CharLiteral` values. + - A character minus an integer produces a character, much like adding a + character to a negative integer. + +#### Overflow Semantics + +Arithmetic operations on `char` and `Core.CharLiteral` use error overflow +semantics [similar to signed integers](#overflow-and-other-error-conditions). +For example, `(('a' as char) + 500)` is invalid code because it causes `char` +overflow. That's why conversions are to signed values (for example, +`char as i16`). + ## Extensibility Arithmetic operators can be provided for user-defined types by implementing the @@ -289,3 +315,5 @@ to give the semantics described above. [#1083: Arithmetic](https://github.com/carbon-language/carbon-lang/pull/1083) - Proposal [#1178: Rework operator interfaces](https://github.com/carbon-language/carbon-lang/pull/1178) +- Proposal + [#6710: `char` redesign](https://github.com/carbon-language/carbon-lang/pull/6710) diff --git a/docs/design/expressions/as_expressions.md b/docs/design/expressions/as_expressions.md index 68150652baf9..3be0bd43d866 100644 --- a/docs/design/expressions/as_expressions.md +++ b/docs/design/expressions/as_expressions.md @@ -128,8 +128,9 @@ var e: i32 as GetType(); ### Data types -In addition to the [implicit conversions](implicit_conversions.md#data-types), -the following numeric conversions are supported by `as`: +In addition to the +[implicit conversions](implicit_conversions.md#numeric-types), the following +numeric conversions are supported by `as`: - `iN`, `uN`, or `fN` -> `fM`, for any `N` and `M`. Values that cannot be exactly represented are suitably rounded to one of the two nearest diff --git a/docs/design/expressions/comparison_operators.md b/docs/design/expressions/comparison_operators.md index d4397f243d55..6a52f72b943c 100644 --- a/docs/design/expressions/comparison_operators.md +++ b/docs/design/expressions/comparison_operators.md @@ -112,7 +112,7 @@ if (m > 1 == n > 1) { ### Built-in comparisons and implicit conversions -Built-in comparisons are permitted in three cases: +Built-in comparisons are permitted in the following cases: 1. When both operands are of standard Carbon integer types (`Int(n)` or `Unsigned(n)`). @@ -120,6 +120,7 @@ Built-in comparisons are permitted in three cases: 3. When one operand is of floating-point type and the other is of integer type, if all values of the integer type can be exactly represented in the floating-point type. +4. When both operands are of type `char` or `Core.CharLiteral`. In each case, the result is the mathematically-correct answer. This applies even when comparing `Int(n)` with `Unsigned(m)`. @@ -225,7 +226,7 @@ We permit the following comparisons involving constants: - Any two constants can be compared, even if there is no type that can represent both. -As described in [implicit conversions](implicit_conversions.md#data-types), +As described in [implicit conversions](implicit_conversions.md#numeric-types), integer constants can be implicitly converted to any integer or floating-point type that can represent their value, and floating-point constants can be implicitly converted to any floating-point type that can represent their value. @@ -526,3 +527,5 @@ in general. That decision is left to a future proposal. [#1178: Rework operator interfaces](https://github.com/carbon-language/carbon-lang/pull/1178) - Issue [#710: Default comparison for data classes](https://github.com/carbon-language/carbon-lang/issues/710) +- Proposal + [#6710: `char` redesign](https://github.com/carbon-language/carbon-lang/pull/6710) diff --git a/docs/design/expressions/implicit_conversions.md b/docs/design/expressions/implicit_conversions.md index 8593102b7041..ada4c0c976d9 100644 --- a/docs/design/expressions/implicit_conversions.md +++ b/docs/design/expressions/implicit_conversions.md @@ -16,7 +16,8 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - [Semantics-preserving](#semantics-preserving) - [Examples](#examples) - [Built-in types](#built-in-types) - - [Data types](#data-types) + - [Numeric types](#numeric-types) + - [Character types](#character-types) - [Same type](#same-type) - [Pointer conversions](#pointer-conversions) - [Facet types](#facet-types) @@ -98,7 +99,7 @@ salient part of a `StringView`'s value. ## Built-in types -### Data types +### Numeric types The following implicit numeric conversions are available: @@ -156,6 +157,17 @@ var a: u32 = ^0; var b: u32 = a & ^4; ``` +### Character types + +A character constant can be implicitly converted to any non-literal character +type in which that value can be exactly represented. For now the only +non-literal character type is `char`, which represents a single UTF-8 code unit +in a single byte, and so implicit conversion from `Core.CharLiteral` to `char` +is only valid for values in the range `0x00`..`0x7F`. + +No other implicit conversions (such as converting `char` to/from integer types +or `Core.CharLiteral` to integers) are permitted. + ### Same type The following conversion is available for every type `T`: @@ -244,3 +256,5 @@ types. [#820: Implicit conversions](https://github.com/carbon-language/carbon-lang/pull/820). - Proposal [#866: Allow ties in floating literals](https://github.com/carbon-language/carbon-lang/pull/866). +- Proposal + [#6710: `char` redesign](https://github.com/carbon-language/carbon-lang/pull/6710) diff --git a/docs/design/expressions/literals.md b/docs/design/expressions/literals.md index 4a5b65664004..e224e3a467df 100644 --- a/docs/design/expressions/literals.md +++ b/docs/design/expressions/literals.md @@ -23,6 +23,8 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - [Usage](#usage) - [Alternatives considered](#alternatives-considered-1) - [String literals](#string-literals) +- [Character literals](#character-literals) +- [Character type literals](#character-type-literals) - [References](#references) @@ -249,6 +251,31 @@ String literal syntax is covered in the No design for string types has been through the proposal process yet. +## Character literals + +Character literals are defined in the +[character literals lexical conventions](../lexical_conventions/character_literals.md). + +In Carbon, character literals have the type `Core.CharLiteral`, which represents +a single Unicode code point. This type supports addition and subtraction, see +[arithmetic](arithmetic.md#character-types). For example, `'a' + 1` results in a +`Core.CharLiteral` with value `'b'`. Operations that result in invalid Unicode +code points (such as `'a' + 0xFFFFFF`) are compile-time errors. + +A `Core.CharLiteral` will implicitly convert to `char` if its value is in the +range `0x00`..`0x7F`, see +[implicit conversions](implicit_conversions.md#character-types). + +## Character type literals + +Carbon defines `char` as a type literal, which is the same type as `Core.Char`, +an adapter for `u8`. + +- `char` notionally represents a single UTF-8 code unit. +- It can contain invalid UTF-8 code units, as long as it remains 8 bits. No + runtime validation is guaranteed. +- Carbon's string types use `char` for elements. + ## References - Proposal @@ -259,7 +286,11 @@ No design for string types has been through the proposal process yet. [#543: pick names for fixed-size integer types](https://github.com/carbon-language/carbon-lang/issues/543) - Proposal [#866: Allow ties in floating literals](https://github.com/carbon-language/carbon-lang/pull/866) +- Proposal + [#1964: Character Literals](https://github.com/carbon-language/carbon-lang/pull/1964) - Proposal [#2015: Numeric type literal syntax](https://github.com/carbon-language/carbon-lang/pull/2015) - Question-for-leads issue [#2113: Structure, scope, and naming of the prelude and syntax aliases](https://github.com/carbon-language/carbon-lang/issues/2113) +- Proposal + [#6710: `char` redesign](https://github.com/carbon-language/carbon-lang/pull/6710) diff --git a/docs/design/interoperability/README.md b/docs/design/interoperability/README.md index ff1dbfe41245..960ba6d469fe 100644 --- a/docs/design/interoperability/README.md +++ b/docs/design/interoperability/README.md @@ -28,7 +28,10 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - [TODO: Struct literals](#todo-struct-literals) - [TODO: Accessing C++ classes, structs, and members](#todo-accessing-c-classes-structs-and-members) - [TODO: Accessing global variables](#todo-accessing-global-variables) -- [TODO: Bi-directional type mapping: primitives and core types](#todo-bi-directional-type-mapping-primitives-and-core-types) +- [Bi-directional type mapping: primitives and core types](#bi-directional-type-mapping-primitives-and-core-types) + - [TODO: Integers](#todo-integers) + - [Character types](#character-types) + - [References](#references) - [TODO: Advanced type mapping: pointers, references, and `const`](#todo-advanced-type-mapping-pointers-references-and-const) - [TODO: Bi-directional type mapping: standard library types](#todo-bi-directional-type-mapping-standard-library-types) - [TODO: The operator interoperability model](#todo-the-operator-interoperability-model) @@ -206,7 +209,22 @@ fn Run() { ## TODO: Accessing global variables -## TODO: Bi-directional type mapping: primitives and core types +## Bi-directional type mapping: primitives and core types + +### TODO: Integers + +### Character types + +Carbon's `char` type transparently maps to C++'s `char` type. Carbon's `char` +type is always unsigned. When compiling C++ using Carbon's toolchain, C++ `char` +is treated as `unsigned` by default (`-funsigned-char`). When interoperating +with a signed C++ `char` type (`-fno-unsigned-char`), Carbon will maintain +interoperability, though bits will be interpreted differently in each language. + +#### References + +- Proposal + [#6710: `char` redesign](https://github.com/carbon-language/carbon-lang/pull/6710) ## TODO: Advanced type mapping: pointers, references, and `const` diff --git a/docs/design/lexical_conventions/README.md b/docs/design/lexical_conventions/README.md index 6bfac20c1d07..70165a1650cd 100644 --- a/docs/design/lexical_conventions/README.md +++ b/docs/design/lexical_conventions/README.md @@ -28,6 +28,7 @@ A _lexical element_ is one of the following: - a [numeric literal](numeric_literals.md) - a [string literal](string_literals.md) + - a [character literal](character_literals.md) - a [comment](comments.md) - a [symbolic token](symbolic_tokens.md) diff --git a/docs/design/lexical_conventions/character_literals.md b/docs/design/lexical_conventions/character_literals.md new file mode 100644 index 000000000000..377392df1e3c --- /dev/null +++ b/docs/design/lexical_conventions/character_literals.md @@ -0,0 +1,68 @@ +# Character literals + + + + + +## Table of contents + +- [Overview](#overview) +- [Details](#details) + - [Escape Sequences](#escape-sequences) +- [References](#references) + + + +## Overview + +A character literal represents a single Unicode code point at compile time. +Character literals are delimited by single quotes (`'`), for example `'a'`. + +```carbon +var a: char = 'a'; +var newline: char = '\n'; +``` + +## Details + +A character literal consists of a sequence of characters enclosed in single +quotes (`'`). + +- The contents must represent precisely one Unicode code point. +- Hex escape sequences (`\xHH`) are supported but limited to values up to + `0x7F` (where the UTF-8 code unit and Unicode code point values are + identical). Values `0x80` and above are disallowed in character literals to + avoid ambiguity between arbitrary byte values and Unicode code points. +- Grapheme clusters (sequences of multiple code points representing a single + visual character) are **not** supported in character literals. + +### Escape Sequences + +Character literals support the same escape sequences as +[string literals](string_literals.md#escape-sequences): + +| Escape | Meaning | +| ------------- | ------------------------------------------------------------------- | +| `\t` | U+0009 CHARACTER TABULATION | +| `\n` | U+000A LINE FEED | +| `\r` | U+000D CARRIAGE RETURN | +| `\"` | U+0022 QUOTATION MARK (`"`) | +| `\'` | U+0027 APOSTROPHE (`'`) | +| `\\` | U+005C REVERSE SOLIDUS (`\`) | +| `\0` | Code unit with value 0 | +| `\xHH` | Code unit with hexadecimal value HH16(limited to ≤ `7F`) | +| `\u{HHHH...}` | Unicode code point U+HHHH... | + +Hexadecimal digits (`H`) in `\x` or `\u` escape sequences must use uppercase +letters (for example, `\x0A`, not `\x0a`). + +## References + +- Proposal + [#1964: Character Literals](https://github.com/carbon-language/carbon-lang/pull/1964) +- Proposal + [#6710: `char` redesign](https://github.com/carbon-language/carbon-lang/pull/6710)