Skip to content

Commit 661a3c3

Browse files
authored
Reflect "Numeric literal semantics #144" in the design docs (#2092)
This PR aims to complete issue #1997.
1 parent dcc80f5 commit 661a3c3

File tree

2 files changed

+230
-2
lines changed

2 files changed

+230
-2
lines changed

docs/design/README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,8 @@ represent that value.
476476

477477
> References:
478478
>
479-
> - [Integer literals](lexical_conventions/numeric_literals.md#integer-literals)
479+
> - [Integer literal syntax](lexical_conventions/numeric_literals.md#integer-literals)
480+
> - [Numeric Literal Semantics](numeric_literals.md)
480481
> - Proposal
481482
> [#143: Numeric literals](https://github.com/carbon-language/carbon-lang/pull/143)
482483
> - Proposal
@@ -521,7 +522,8 @@ selected.
521522

522523
> References:
523524
>
524-
> - [Real-number literals](lexical_conventions/numeric_literals.md#real-number-literals)
525+
> - [Real-number literal syntax](lexical_conventions/numeric_literals.md#real-number-literals)
526+
> - [Numeric Literal Semantics](numeric_literals.md)
525527
> - Proposal
526528
> [#143: Numeric literals](https://github.com/carbon-language/carbon-lang/pull/143)
527529
> - Proposal

docs/design/numeric_literals.md

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
# Numeric Literal Semantics
2+
3+
<!--
4+
Part of the Carbon Language project, under the Apache License v2.0 with LLVM
5+
Exceptions. See /LICENSE for license information.
6+
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
-->
8+
9+
> **STATUS:** Up-to-date on 23-Aug-2022.
10+
11+
<!-- toc -->
12+
13+
## Table of contents
14+
15+
- [Overview](#overview)
16+
- [TODO](#todo)
17+
- [Numeric literal syntax](#numeric-literal-syntax)
18+
- [Defined Types](#defined-types)
19+
- [Implicit conversions](#implicit-conversions)
20+
- [Examples](#examples)
21+
- [Alternatives Considered](#alternatives-considered)
22+
- [References](#references)
23+
24+
<!-- tocstop -->
25+
26+
## Overview
27+
28+
Numeric Literals are defined on Wikipedia
29+
[here](<https://en.wikipedia.org/wiki/Literal_(computer_programming)>).
30+
31+
In Carbon, numeric literals have a type derived from their value. Two integer
32+
literals have the same type if and only if they represent the same integer. Two
33+
real number literals have the same type if and only if they represent the same
34+
real number.
35+
36+
That is:
37+
38+
- For every integer, there is a type representing literals with that integer
39+
value.
40+
- For every rational number, there is a type representing literals with that
41+
real value.
42+
- The types for real numbers are distinct from the types for integers, even
43+
for real numbers that represent integers. For example, `1 / 2` results in
44+
`0`, due to integer arithmetic, whereas `1.0 / 2` results in `0.5`. This is
45+
due to `1` having an integral type, while `1.0` has a real number type, even
46+
though it represents the same numeric value.
47+
48+
Primitive operators are available between numeric literals, and produce values
49+
with numeric literal types. For example, the type of `1 + 2` is the same as the
50+
type of `3`.
51+
52+
Numeric types can provide conversions to support initialization from numeric
53+
literals. Because the value of the literal is carried in the type, a type-level
54+
decision can be made as to whether the conversion is valid.
55+
56+
The integer types defined in the standard library permit conversion from integer
57+
literal types whose values are representable in the integer type. The
58+
floating-point types defined in the standard library permit conversion from
59+
integer and rational literal types whose values are between the minimum and
60+
maximum finite value representable in the floating-point type.
61+
62+
### TODO
63+
64+
This document needs to be updated once we have resolved how to reference things
65+
brought in by the prelude. `BigInt`, `Rational`, `IntLiteral`, and
66+
`FloatLiteral` will likely be accessed through a package prefix like
67+
`Carbon.BigInt` or `Core.BigInt`, and the [Defined Types](#defined-types)
68+
section will need to be updated to reflect those.
69+
70+
### Numeric literal syntax
71+
72+
Numeric Literal syntax is covered in the
73+
[numeric literal lexical conventions](lexical_conventions/numeric_literals.md)
74+
doc. Both Integer and Real-Number syntax is defined, with decimal, hexadecimal
75+
and binary integer literals, and decimal and hexadecimal real number literals.
76+
77+
### Defined Types
78+
79+
The following types are defined in the Carbon prelude:
80+
81+
- An arbitrary-precision integer type.
82+
83+
```
84+
class BigInt;
85+
```
86+
87+
- A rational type, parameterized by a type used for its numerator and
88+
denominator.
89+
90+
```
91+
class Rational(T:! Type);
92+
```
93+
94+
The exact constraints on `T` are not yet decided.
95+
96+
- A type representing integer literals.
97+
98+
```
99+
class IntLiteral(N:! BigInt);
100+
```
101+
102+
- A type representing floating-point literals.
103+
104+
```
105+
class FloatLiteral(X:! Rational(BigInt));
106+
```
107+
108+
All of these types are usable during compilation. `BigInt` supports the same
109+
operations as `Int(n)`. `Rational(T)` supports the same operations as
110+
`Float(n)`.
111+
112+
The types `IntLiteral(n)` and `FloatLiteral(x)` also support primitive integer
113+
and floating-point operations such as arithmetic and comparison, but these
114+
operations are typically heterogeneous: for example, an addition between
115+
`IntLiteral(n)` and `IntLiteral(m)` produces a value of type
116+
`IntLiteral(n + m)`.
117+
118+
### Implicit conversions
119+
120+
`IntLiteral(n)` converts to any sufficiently large integer type, as if by:
121+
122+
```
123+
impl forall [template N:! BigInt, template M:! BigInt]
124+
IntLiteral(N) as ImplicitAs(Carbon.Int(M))
125+
if N >= Carbon.Int(M).MinValue as BigInt and N <= Carbon.Int(M).MaxValue as BigInt {
126+
...
127+
}
128+
impl forall [template N:! BigInt, template M:! BigInt]
129+
IntLiteral(N) as ImplicitAs(Carbon.UInt(M))
130+
if N >= Carbon.UInt(M).MinValue as BigInt and N <= Carbon.UInt(M).MaxValue as BigInt {
131+
...
132+
}
133+
```
134+
135+
The above is for exposition purposes only; various parts of this syntax are not
136+
yet decided.
137+
138+
Similarly, `IntLiteral(x)` and `FloatLiteral(x)` convert to any sufficiently
139+
large floating-point type, and produce the nearest representable floating-point
140+
value.
141+
142+
Conversions in which `x` lies exactly half-way between two values are rounded to
143+
the value in which the mantissa is even, as defined in the IEEE 754 standard and
144+
as was decided in
145+
[proposal #866](https://github.com/carbon-language/carbon-lang/pull/866).
146+
147+
Conversions in which `x` is outside the range of finite values of the
148+
floating-point type are rejected rather than saturating to the finite range or
149+
producing an infinity.
150+
151+
## Examples
152+
153+
```carbon
154+
// This is OK: the initializer is of the integer literal type with value
155+
// -2147483648 despite being written as a unary `-` applied to a literal.
156+
var x: i32 = -2147483648;
157+
158+
// This initializes y to 2^60.
159+
var y: i64 = 1 << 60;
160+
161+
// This forms a rational literal whose value is one third, and converts it to
162+
// the nearest representable value of type `f64`.
163+
var z: f64 = 1.0 / 3.0;
164+
165+
// This is an error: 300 cannot be represented in type `i8`.
166+
var c: i8 = 300;
167+
168+
fn F[template T:! Type](v: T) {
169+
var x: i32 = v * 2;
170+
}
171+
172+
// OK: x = 2_000_000_000.
173+
F(1_000_000_000);
174+
175+
// Error: 4_000_000_000 can't be represented in type `i32`.
176+
F(2_000_000_000);
177+
178+
// No storage required for the bound when it's of integer literal type.
179+
struct Span(template T:! Type, template BoundT:! Type) {
180+
var begin: T*;
181+
var bound: BoundT;
182+
}
183+
184+
// Returns 1, because 1.3 can implicitly convert to f32, even though conversion
185+
// to f64 might be a more exact match.
186+
fn G() -> i32 {
187+
match (1.3) {
188+
case _: f32 => { return 1; }
189+
case _: f64 => { return 2; }
190+
}
191+
}
192+
193+
// Can only be called with a literal 0.
194+
fn PassMeZero(_: IntLiteral(0));
195+
196+
// Can only be called with integer literals in the given range.
197+
fn ConvertToByte[template N:! BigInt](_: IntLiteral(N)) -> i8
198+
if N >= -128 and N <= 127 {
199+
return N as i8;
200+
}
201+
202+
// Given any int literal, produces a literal whose value is one higher.
203+
fn OneHigher(L: IntLiteral(template _:! BigInt)) -> auto {
204+
return L + 1;
205+
}
206+
// Error: 256 can't be represented in type `i8`.
207+
var v: i8 = OneHigher(255);
208+
```
209+
210+
## Alternatives Considered
211+
212+
- [Use an ordinary integer or floating-point type for literals](/proposals/p0144.md#use-an-ordinary-integer-or-floating-point-type-for-literals)
213+
- [Use same type for all literals](/proposals/p0144.md#use-same-type-for-all-literals)
214+
- [Allow leading `-` in literal tokens](/proposals/p0144.md#allow-leading---in-literal-tokens)
215+
- [Forbidding floating-point ties](/proposals/p0866.md/#alternatives-considered)
216+
217+
## References
218+
219+
> - Proposal
220+
> [#143: Numeric literals](https://github.com/carbon-language/carbon-lang/pull/143)
221+
> - Proposal
222+
> [#144: Numeric literal semantics](https://github.com/carbon-language/carbon-lang/pull/144)
223+
> - Proposal
224+
> [#866: Allow ties in floating literals](https://github.com/carbon-language/carbon-lang/pull/866)
225+
> - Issue
226+
> [#1998: Make proposal for numeric type literal syntax](https://github.com/carbon-language/carbon-lang/issues/1998#issuecomment-1212644291)

0 commit comments

Comments
 (0)