From 6fe1860a1d24ae1b1f655d70440e4fc65e6ceb18 Mon Sep 17 00:00:00 2001 From: Josh L Date: Fri, 9 Dec 2022 22:29:38 +0000 Subject: [PATCH 1/2] Move `numeric_literals` into `expressions/literals` and update --- docs/design/README.md | 23 ++- docs/design/expressions/literals.md | 211 ++++++++++++++++++++++++-- docs/design/numeric_literals.md | 226 ---------------------------- 3 files changed, 213 insertions(+), 247 deletions(-) delete mode 100644 docs/design/numeric_literals.md diff --git a/docs/design/README.md b/docs/design/README.md index 3a8d47c284a2d..c669d2d74f743 100644 --- a/docs/design/README.md +++ b/docs/design/README.md @@ -427,9 +427,9 @@ and [`while`](#while), and ### Integer types -The signed-integer type with bit width `N` may be written `iN` or -`Carbon.Int(N)`, as long as `N` is a positive multiple of 8. For example, `i32` -is equivalent to `Carbon.Int(32)`. Signed-integer +The signed-integer type with bit width `N` may be written `iN`, as long as `N` +is a positive multiple of 8. For example, `i32` is equivalent to +`Carbon.Int(32)`. Signed-integer [overflow](expressions/arithmetic.md#overflow-and-other-error-conditions) is a programming error: @@ -443,11 +443,11 @@ programming error: to a mathematically incorrect result, such as a two's complement result or zero. -The unsigned-integer types are written `uN` or `Carbon.UInt(N)`, with `N` a -positive multiple of 8. Unsigned integer types wrap around on overflow; we -strongly advise that they are not used except when those semantics are desired. -These types are intended for bit manipulation or modular arithmetic as often -found in [hashing](https://en.wikipedia.org/wiki/Hash_function), +The unsigned-integer types are written `uN`, with `N` a positive multiple of 8. +Unsigned integer types wrap around on overflow; we strongly advise that they are +not used except when those semantics are desired. These types are intended for +bit manipulation or modular arithmetic as often found in +[hashing](https://en.wikipedia.org/wiki/Hash_function), [cryptography](https://en.wikipedia.org/wiki/Cryptography), and [PRNG](https://en.wikipedia.org/wiki/Pseudorandom_number_generator) use cases. Values which can never be negative, like sizes, but for which wrapping does not @@ -499,7 +499,7 @@ represent that value. > References: > > - [Integer literal syntax](lexical_conventions/numeric_literals.md#integer-literals) -> - [Numeric Literal Semantics](numeric_literals.md) +> - [Numeric literal expressions](expressions/literals.md#numeric-literals) > - Proposal > [#143: Numeric literals](https://github.com/carbon-language/carbon-lang/pull/143) > - Proposal @@ -514,8 +514,7 @@ represent that value. Floating-point types in Carbon have IEEE-754 semantics, use the round-to-nearest rounding mode, and do not set any floating-point exception state. They are named with a _type literals_, consisting of `f` and the number of bits, which must be -a multiple of 8. The type literal `fN` results in the type `Carbon.Float(N)`. -These types will always be available: +a multiple of 8. These types will always be available: [`f16`](https://en.wikipedia.org/wiki/Half-precision_floating-point_format), [`f32`](https://en.wikipedia.org/wiki/Single-precision_floating-point_format), and @@ -565,7 +564,7 @@ selected. > References: > > - [Real-number literal syntax](lexical_conventions/numeric_literals.md#real-number-literals) -> - [Numeric Literal Semantics](numeric_literals.md) +> - [Numeric literal expressions](expressions/literals.md#numeric-literals) > - Proposal > [#143: Numeric literals](https://github.com/carbon-language/carbon-lang/pull/143) > - Proposal diff --git a/docs/design/expressions/literals.md b/docs/design/expressions/literals.md index 76c4fc291ae7c..9736c0ece6e22 100644 --- a/docs/design/expressions/literals.md +++ b/docs/design/expressions/literals.md @@ -6,29 +6,198 @@ Exceptions. See /LICENSE for license information. SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception --> +> **STATUS:** Up-to-date on 2022-Dec-9. + ## Table of contents -- [Overview](#overview) +- [Numeric literals](#numeric-literals) + - [Numeric literal syntax](#numeric-literal-syntax) + - [Defined Types](#defined-types) + - [Implicit conversions](#implicit-conversions) + - [Examples](#examples) + - [Alternatives Considered](#alternatives-considered) - [Numeric type literals](#numeric-type-literals) + - [Meaning](#meaning) - [Usage](#usage) - - [Alternatives considered](#alternatives-considered) + - [Alternatives considered](#alternatives-considered-1) +- [String literals](#string-literals) - [References](#references) -## Overview +## Numeric literals + +Numeric Literals are defined on Wikipedia +[here](). + +In Carbon, numeric literals have a type derived from their value. Two integer +literals have the same type if and only if they represent the same integer. Two +real number literals have the same type if and only if they represent the same +real number. + +That is: + +- For every integer, there is a type representing literals with that integer + value. +- For every rational number, there is a type representing literals with that + real value. +- The types for real numbers are distinct from the types for integers, even + for real numbers that represent integers. For example, `1 / 2` results in + `0`, due to integer arithmetic, whereas `1.0 / 2` results in `0.5`. This is + due to `1` having an integral type, while `1.0` has a real number type, even + though it represents the same numeric value. + +Primitive operators are available between numeric literals, and produce values +with numeric literal types. For example, the type of `1 + 2` is the same as the +type of `3`. + +Numeric types can provide conversions to support initialization from numeric +literals. Because the value of the literal is carried in the type, a type-level +decision can be made as to whether the conversion is valid. + +The integer types defined in the standard library permit conversion from integer +literal types whose values are representable in the integer type. The +floating-point types defined in the standard library permit conversion from +integer and rational literal types whose values are between the minimum and +maximum finite value representable in the floating-point type. + +### Numeric literal syntax + +Numeric literal syntax is covered in the +[numeric literal lexical conventions](../lexical_conventions/numeric_literals.md) +doc. Both Integer and Real-Number syntax is defined, with decimal, hexadecimal +and binary integer literals, and decimal and hexadecimal real number literals. + +### Defined Types + +The following types are defined in the Carbon prelude: + +- `Core.BigInt`, an arbitrary-precision integer type; +- `Core.Rational(T:! Type)`, a rational type, parameterized by a type used for + its numerator and denominator -- the exact constraints on `T` are not yet + decided; +- `Core.IntLiteral(N:! Core.BigInt)`, a type representing integer literals; + and +- `Core.FloatLiteral(X:! Core.Rational(Core.BigInt))`, a type representing + floating-point literals. + +All of these types are usable during compilation. `Core.BigInt` supports the +same operations as [`Core.Int(N)`](#meaning). `Core.Rational(T)` supports the +same operations as [`Core.Float(N)`](#meaning). + +The types `Core.IntLiteral(N)` and `Core.FloatLiteral(X)` also support primitive +integer and floating-point operations such as arithmetic and comparison, but +these operations are typically heterogeneous: for example, an addition between +`Core.IntLiteral(N)` and `Core.IntLiteral(M)` produces a value of type +`Core.IntLiteral(N + M)`. + +### Implicit conversions + +`Core.IntLiteral(N)` converts to any sufficiently large integer type, as if by: + +``` +impl forall [template N:! Core.BigInt, template M:! Core.BigInt] + Core.IntLiteral(N) as ImplicitAs(Core.Int(M)) + if N >= Core.Int(M).MinValue as Core.BigInt + and N <= Core.Int(M).MaxValue as Core.BigInt { + ... +} +impl forall [template N:! Core.BigInt, template M:! Core.BigInt] + Core.IntLiteral(N) as ImplicitAs(Core.UInt(M)) + if N >= Core.UInt(M).MinValue as Core.BigInt + and N <= Core.UInt(M).MaxValue as Core.BigInt { + ... +} +``` + +The above is for exposition purposes only; various parts of this syntax are not +yet decided. + +Similarly, `Core.IntLiteral(X)` and `Core.FloatLiteral(X)` convert to any +sufficiently large floating-point type, and produce the nearest representable +floating-point value. + +Conversions in which `X` lies exactly half-way between two values are rounded to +the value in which the mantissa is even, as defined in the IEEE 754 standard and +as was decided in +[proposal #866](https://github.com/carbon-language/carbon-lang/pull/866). + +Conversions in which `X` is outside the range of finite values of the +floating-point type are rejected rather than saturating to the finite range or +producing an infinity. + +### Examples + +```carbon +// This is OK: the initializer is of the integer literal type with value +// -2147483648 despite being written as a unary `-` applied to a literal. +var x: i32 = -2147483648; + +// This initializes y to 2^60. +var y: i64 = 1 << 60; + +// This forms a rational literal whose value is one third, and converts it to +// the nearest representable value of type `f64`. +var z: f64 = 1.0 / 3.0; + +// This is an error: 300 cannot be represented in type `i8`. +var c: i8 = 300; + +fn F[template T:! Type](v: T) { + var x: i32 = v * 2; +} + +// OK: x = 2_000_000_000. +F(1_000_000_000); + +// Error: 4_000_000_000 can't be represented in type `i32`. +F(2_000_000_000); + +// No storage required for the bound when it's of integer literal type. +struct Span(template T:! Type, template BoundT:! Type) { + var begin: T*; + var bound: BoundT; +} + +// Returns 1, because 1.3 can implicitly convert to f32, even though conversion +// to f64 might be a more exact match. +fn G() -> i32 { + match (1.3) { + case _: f32 => { return 1; } + case _: f64 => { return 2; } + } +} + +// Can only be called with a literal 0. +fn PassMeZero(_: Core.IntLiteral(0)); + +// Can only be called with integer literals in the given range. +fn ConvertToByte[template N:! Core.BigInt](_: Core.IntLiteral(N)) -> i8 + if N >= -128 and N <= 127 { + return N as i8; +} + +// Given any int literal, produces a literal whose value is one higher. +fn OneHigher(L: Core.IntLiteral(template _:! Core.BigInt)) -> auto { + return L + 1; +} +// Error: 256 can't be represented in type `i8`. +var v: i8 = OneHigher(255); +``` -This document is intended to cover all literal expressions, excluding numeric, -floats and strings, which are covered in the -[Lexical Conventions](../lexical_conventions/README.md) section. For now, the -document explains the numeric type literals. +### Alternatives Considered + +- [Use an ordinary integer or floating-point type for literals](/proposals/p0144.md#use-an-ordinary-integer-or-floating-point-type-for-literals) +- [Use same type for all literals](/proposals/p0144.md#use-same-type-for-all-literals) +- [Allow leading `-` in literal tokens](/proposals/p0144.md#allow-leading---in-literal-tokens) +- [Forbidding floating-point ties](/proposals/p0866.md#alternatives-considered) ## Numeric type literals Carbon has a simple keyword-like syntax of `iN`, `uN`, and `fN` for two's -complement integers, unsigned integers, and +complement signed integers, unsigned integers, and [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754) floating-point numbers, respectively. Here, `N` can be a positive multiple of 8, including the common power-of-two sizes (for example, `N = 8, 16, 32`). @@ -39,6 +208,15 @@ Examples of this syntax include: - `u32` - A 32-bit unsigned integer type - `f64` - A 64-bit IEEE-754 binary floating-point number type +### Meaning + +These type literals are aliases for parameterized types defined in the `Core` +package that is automatically imported by the prelude: + +- `iN` is an alias for `Core.Int(N)` +- `uN` is an alias for `Core.UInt(N)` +- `fN` is an alias for `Core.Float(N)` + ### Usage ```carbon @@ -64,9 +242,24 @@ as a 32-bit two's complement signed integer. `Main` then returns the output of - [Uppercase suffixes](/proposals/p2015.md#uppercase-suffixes) - [Additional bit sizes](/proposals/p2015.md#additional-bit-sizes) +## String literals + +String literal syntax is covered in the +[string literal lexical conventions](../lexical_conventions/string_literals.md). + +No design for string types has been through the proposal process yet. + ## References -- Issue +- Proposal + [#143: Numeric literals](https://github.com/carbon-language/carbon-lang/pull/143) +- Proposal + [#144: Numeric literal semantics](https://github.com/carbon-language/carbon-lang/pull/144) +- Question-for-leads issue [#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 [#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) diff --git a/docs/design/numeric_literals.md b/docs/design/numeric_literals.md deleted file mode 100644 index 71eb99d930aa2..0000000000000 --- a/docs/design/numeric_literals.md +++ /dev/null @@ -1,226 +0,0 @@ -# Numeric Literal Semantics - - - -> **STATUS:** Up-to-date on 23-Aug-2022. - - - -## Table of contents - -- [Overview](#overview) - - [TODO](#todo) - - [Numeric literal syntax](#numeric-literal-syntax) - - [Defined Types](#defined-types) - - [Implicit conversions](#implicit-conversions) -- [Examples](#examples) -- [Alternatives Considered](#alternatives-considered) -- [References](#references) - - - -## Overview - -Numeric Literals are defined on Wikipedia -[here](). - -In Carbon, numeric literals have a type derived from their value. Two integer -literals have the same type if and only if they represent the same integer. Two -real number literals have the same type if and only if they represent the same -real number. - -That is: - -- For every integer, there is a type representing literals with that integer - value. -- For every rational number, there is a type representing literals with that - real value. -- The types for real numbers are distinct from the types for integers, even - for real numbers that represent integers. For example, `1 / 2` results in - `0`, due to integer arithmetic, whereas `1.0 / 2` results in `0.5`. This is - due to `1` having an integral type, while `1.0` has a real number type, even - though it represents the same numeric value. - -Primitive operators are available between numeric literals, and produce values -with numeric literal types. For example, the type of `1 + 2` is the same as the -type of `3`. - -Numeric types can provide conversions to support initialization from numeric -literals. Because the value of the literal is carried in the type, a type-level -decision can be made as to whether the conversion is valid. - -The integer types defined in the standard library permit conversion from integer -literal types whose values are representable in the integer type. The -floating-point types defined in the standard library permit conversion from -integer and rational literal types whose values are between the minimum and -maximum finite value representable in the floating-point type. - -### TODO - -This document needs to be updated once we have resolved how to reference things -brought in by the prelude. `BigInt`, `Rational`, `IntLiteral`, and -`FloatLiteral` will likely be accessed through a package prefix like -`Carbon.BigInt` or `Core.BigInt`, and the [Defined Types](#defined-types) -section will need to be updated to reflect those. - -### Numeric literal syntax - -Numeric Literal syntax is covered in the -[numeric literal lexical conventions](lexical_conventions/numeric_literals.md) -doc. Both Integer and Real-Number syntax is defined, with decimal, hexadecimal -and binary integer literals, and decimal and hexadecimal real number literals. - -### Defined Types - -The following types are defined in the Carbon prelude: - -- An arbitrary-precision integer type. - - ``` - class BigInt; - ``` - -- A rational type, parameterized by a type used for its numerator and - denominator. - - ``` - class Rational(T:! Type); - ``` - - The exact constraints on `T` are not yet decided. - -- A type representing integer literals. - - ``` - class IntLiteral(N:! BigInt); - ``` - -- A type representing floating-point literals. - - ``` - class FloatLiteral(X:! Rational(BigInt)); - ``` - -All of these types are usable during compilation. `BigInt` supports the same -operations as `Int(n)`. `Rational(T)` supports the same operations as -`Float(n)`. - -The types `IntLiteral(n)` and `FloatLiteral(x)` also support primitive integer -and floating-point operations such as arithmetic and comparison, but these -operations are typically heterogeneous: for example, an addition between -`IntLiteral(n)` and `IntLiteral(m)` produces a value of type -`IntLiteral(n + m)`. - -### Implicit conversions - -`IntLiteral(n)` converts to any sufficiently large integer type, as if by: - -``` -impl forall [template N:! BigInt, template M:! BigInt] - IntLiteral(N) as ImplicitAs(Carbon.Int(M)) - if N >= Carbon.Int(M).MinValue as BigInt and N <= Carbon.Int(M).MaxValue as BigInt { - ... -} -impl forall [template N:! BigInt, template M:! BigInt] - IntLiteral(N) as ImplicitAs(Carbon.UInt(M)) - if N >= Carbon.UInt(M).MinValue as BigInt and N <= Carbon.UInt(M).MaxValue as BigInt { - ... -} -``` - -The above is for exposition purposes only; various parts of this syntax are not -yet decided. - -Similarly, `IntLiteral(x)` and `FloatLiteral(x)` convert to any sufficiently -large floating-point type, and produce the nearest representable floating-point -value. - -Conversions in which `x` lies exactly half-way between two values are rounded to -the value in which the mantissa is even, as defined in the IEEE 754 standard and -as was decided in -[proposal #866](https://github.com/carbon-language/carbon-lang/pull/866). - -Conversions in which `x` is outside the range of finite values of the -floating-point type are rejected rather than saturating to the finite range or -producing an infinity. - -## Examples - -```carbon -// This is OK: the initializer is of the integer literal type with value -// -2147483648 despite being written as a unary `-` applied to a literal. -var x: i32 = -2147483648; - -// This initializes y to 2^60. -var y: i64 = 1 << 60; - -// This forms a rational literal whose value is one third, and converts it to -// the nearest representable value of type `f64`. -var z: f64 = 1.0 / 3.0; - -// This is an error: 300 cannot be represented in type `i8`. -var c: i8 = 300; - -fn F[template T:! Type](v: T) { - var x: i32 = v * 2; -} - -// OK: x = 2_000_000_000. -F(1_000_000_000); - -// Error: 4_000_000_000 can't be represented in type `i32`. -F(2_000_000_000); - -// No storage required for the bound when it's of integer literal type. -struct Span(template T:! Type, template BoundT:! Type) { - var begin: T*; - var bound: BoundT; -} - -// Returns 1, because 1.3 can implicitly convert to f32, even though conversion -// to f64 might be a more exact match. -fn G() -> i32 { - match (1.3) { - case _: f32 => { return 1; } - case _: f64 => { return 2; } - } -} - -// Can only be called with a literal 0. -fn PassMeZero(_: IntLiteral(0)); - -// Can only be called with integer literals in the given range. -fn ConvertToByte[template N:! BigInt](_: IntLiteral(N)) -> i8 - if N >= -128 and N <= 127 { - return N as i8; -} - -// Given any int literal, produces a literal whose value is one higher. -fn OneHigher(L: IntLiteral(template _:! BigInt)) -> auto { - return L + 1; -} -// Error: 256 can't be represented in type `i8`. -var v: i8 = OneHigher(255); -``` - -## Alternatives Considered - -- [Use an ordinary integer or floating-point type for literals](/proposals/p0144.md#use-an-ordinary-integer-or-floating-point-type-for-literals) -- [Use same type for all literals](/proposals/p0144.md#use-same-type-for-all-literals) -- [Allow leading `-` in literal tokens](/proposals/p0144.md#allow-leading---in-literal-tokens) -- [Forbidding floating-point ties](/proposals/p0866.md/#alternatives-considered) - -## References - -> - Proposal -> [#143: Numeric literals](https://github.com/carbon-language/carbon-lang/pull/143) -> - Proposal -> [#144: Numeric literal semantics](https://github.com/carbon-language/carbon-lang/pull/144) -> - Proposal -> [#866: Allow ties in floating literals](https://github.com/carbon-language/carbon-lang/pull/866) -> - Issue -> [#1998: Make proposal for numeric type literal syntax](https://github.com/carbon-language/carbon-lang/issues/1998#issuecomment-1212644291) From 8b51abc920d027f90c48bba866c50aa70cddb9a8 Mon Sep 17 00:00:00 2001 From: Josh L Date: Fri, 9 Dec 2022 23:55:27 +0000 Subject: [PATCH 2/2] Address feedback --- docs/design/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/design/README.md b/docs/design/README.md index c669d2d74f743..09ee5d7335c2b 100644 --- a/docs/design/README.md +++ b/docs/design/README.md @@ -428,8 +428,8 @@ and [`while`](#while), and ### Integer types The signed-integer type with bit width `N` may be written `iN`, as long as `N` -is a positive multiple of 8. For example, `i32` is equivalent to -`Carbon.Int(32)`. Signed-integer +is a positive multiple of 8. For example, `i32` is a signed 32-bit integer. +Signed-integer [overflow](expressions/arithmetic.md#overflow-and-other-error-conditions) is a programming error: @@ -443,10 +443,10 @@ programming error: to a mathematically incorrect result, such as a two's complement result or zero. -The unsigned-integer types are written `uN`, with `N` a positive multiple of 8. -Unsigned integer types wrap around on overflow; we strongly advise that they are -not used except when those semantics are desired. These types are intended for -bit manipulation or modular arithmetic as often found in +The unsigned-integer types may be written `uN`, with `N` a positive multiple +of 8. Unsigned integer types wrap around on overflow; we strongly advise that +they are not used except when those semantics are desired. These types are +intended for bit manipulation or modular arithmetic as often found in [hashing](https://en.wikipedia.org/wiki/Hash_function), [cryptography](https://en.wikipedia.org/wiki/Cryptography), and [PRNG](https://en.wikipedia.org/wiki/Pseudorandom_number_generator) use cases.