Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Numeric literal semantics #144

Merged
merged 14 commits into from
Sep 24, 2021
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 0 additions & 57 deletions proposals/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,60 +23,3 @@ request:
- `p####.md` will contain the main proposal text.
- `p####` may be present as an optional subdirectory for related files (for
example, images).

## Proposal list

<!-- proposals -->
<!-- Generated by ./scripts/update_proposal_list.py -->

- [0024 - Generics goals](p0024.md)
- [0029 - Linear, rebase, and pull-request GitHub workflow](p0029.md)
- [0042 - Create code review guidelines](p0042.md)
- [0044 - Proposal tracking](p0044.md)
- [0051 - Goals](p0051.md)
- [0063 - Criteria for Carbon to go public](p0063.md)
- [0074 - Change comment/decision timelines in proposal process](p0074.md)
- [0083 - In-progress design overview](p0083.md)
- [0107 - Code and name organization](p0107.md)
- [0113 - Add a C++ style guide](p0113.md)
- [0120 - Add idiomatic code performance and developer-facing docs to goals](p0120.md)
- [0142 - Unicode source files](p0142.md)
- [0143 - Numeric literals](p0143.md)
- [0144 - Numeric literal semantics](p0144.md)
- [0149 - Change documentation style guide](p0149.md)
- [0157 - Design direction for sum types](p0157.md)
- [0162 - Basic Syntax](p0162.md)
- [0175 - C++ interoperability goals](p0175.md)
- [0179 - Create a toolchain team.](p0179.md)
- [0196 - Language-level safety strategy](p0196.md)
- [0198 - Comments](p0198.md)
- [0199 - String literals](p0199.md)
- [0253 - 2021 Roadmap](p0253.md)
- [0257 - Initialization of memory and variables](p0257.md)
- [0285 - if/else](p0285.md)
- [0301 - Principle: Errors are values](p0301.md)
- [0339 - `var` statement](p0339.md)
- [0340 - while loops](p0340.md)
- [0353 - `for` loops](p0353.md)
- [0415 - Syntax: `return`](p0415.md)
- [0426 - Governance & evolution revamp](p0426.md)
- [0438 - Functions](p0438.md)
- [0444 - GitHub Discussions](p0444.md)
- [0447 - Generics terminology](p0447.md)
- [0524 - Generics overview](p0524.md)
- [0538 - `return` with no argument](p0538.md)
- [0540 - Remove `Void`](p0540.md)
- [0553 - Generics details part 1](p0553.md)
- [0555 - Operator precedence](p0555.md)
- [0561 - Basic classes: use cases, struct literals, struct types, and future work](p0561.md)
- [0601 - Operator tokens](p0601.md)
- [0618 - var ordering](p0618.md)
- [0623 - Require braces](p0623.md)
- [0646 - Low context-sensitivity principle](p0646.md)
- [0676 - `:!` generic syntax](p0676.md)
- [0680 - And, or, not](p0680.md)
- [0722 - Nominal classes and methods](p0722.md)
- [0731 - Generics details 2: adapters, associated types, parameterized interfaces](p0731.md)
- [0777 - Inheritance](p0777.md)

<!-- endproposals -->
76 changes: 49 additions & 27 deletions proposals/p0144.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,8 @@ That is:

- For every integer, there is a type representing literals with that integer
value.
- For every dyadic or decadic rational number, there is a type representing
literals with that real value. Dyadic and decadic rational numbers are those
real numbers that can be written as a finite digit sequence in base 2 or 10,
respectively.
- 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. `var x: i32 = 1.0;` is invalid.

Expand Down Expand Up @@ -113,7 +111,7 @@ The following types are defined in the Carbon prelude:
class BigInt;
```

- A rational type, parameterized by its numerator and denominator types.
- A rational type, parameterized by a type used for its numerator and denominator.

```
class Rational(T:! Type);
Expand All @@ -130,14 +128,14 @@ The following types are defined in the Carbon prelude:
- A type representing floating-point literals.

```
class FloatLiteral(N:! Rational(BigInt));
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(n)` also support primitive integer
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
Expand All @@ -148,25 +146,29 @@ operations are typically heterogeneous: for example, an addition between
`IntLiteral(n)` converts to any sufficiently large integer type, as if by:

```
impl [template N:! BigInt, template M:! u32]
impl [template N:! BigInt, template M:! BigInt]
IntLiteral(N) as ImplicitAs(Int(M))
if N >= M.MinValue as BigInt and N <= M.MaxValue as BigInt {
if N >= Int(M).MinValue as BigInt and N <= Int(M).MaxValue as BigInt {
...
}
impl [template N:! BigInt, template M:! u32]
impl [template N:! BigInt, template M:! BigInt]
IntLiteral(N) as ImplicitAs(Unsigned(M))
if N >= M.MinValue as BigInt and N <= M.MaxValue as BigInt {
if N >= Int(M).MinValue as BigInt and N <= Int(M).MaxValue as BigInt {
...
}
```

The above is for exposition purposes only; various parts of this syntax are not
yet decided.

Similarly, `FloatLiteral(n)` converts to any sufficiently large integer or
floating-point type, except that conversions in which `n` lies exactly half-way
between two values are rejected, as
[previously decided](https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/lexical_conventions/numeric_literals.md#ties).
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
rejected, as
[previously decided](/docs/design/lexical_conventions/numeric_literals.md#ties).
Conversions in which `x` is outside the range of finite values of the
floating-point type are also represented, rather than saturating to the finite
range or producing an infinity.

### Examples

Expand All @@ -189,11 +191,11 @@ fn f[template T:! Type](v: T) {
var x: i32 = v * 2;
}

// OK: x = 2'000'000'000.
f(1'000'000'000);
// 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);
// 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) {
Expand Down Expand Up @@ -239,9 +241,9 @@ Advantages:

Disadvantages:

- Surprising results when the result of applying an operator to a literal
would result in overflow. Even if we diagnose this, a diagnostic that
`-2147483648` is invalid because it overflows is surprising.
- Surprising behavior when applying an operator to a literal would result in
overflow. Even if we diagnose this, a diagnostic that `-2147483648` is
invalid because it overflows is surprising.
- Creates additional literal syntax that users will need to understand.
- May select types that don't match the programmer's expectations.
- Whatever types we pick are privileged.
Expand All @@ -253,9 +255,31 @@ Advantages:

- Only introduces two new types, not an unbounded parameterized family of
types.
- Writing a function that takes any integer literal can be done with more
obvious syntax and less syntactic overhead. Instead of:
```
fn OneHigher(L: IntLiteral(template _:! BigInt));
```
we could write
```
fn OneHigher(template L:! Integer);
```
However, this problem could be solved for `IntLiteral` by adding an
`AnyIntLiteral` interface if we think it's pressing. Also, with this
zygoloid marked this conversation as resolved.
Show resolved Hide resolved
proposal, a function taking any integer expression that can be evaluated to
a constant can be written as
```
fn F(template N:! BigInt);
```
and such a function would accept all integer literals, as well as
non-literal constants.

Disadvantages:

- Our mechanism for specifying the behavior of operations such as arithmetic
is based on interface implementations, which are looked up by type.
Supporting `impl` selection based on values would introduce substantial
complexity.
- If we introduce an arbitrary-precision integer type, it would be
inconsistent to support it only during compilation.
- Such a type would be expensive, and programs may use it accidentally. For
Expand All @@ -265,12 +289,10 @@ Disadvantages:
value `123`; as such, `x` is effectively immutable. The arbitrary-precision
integer type introduced in this proposal can only be used explicitly by
programs naming it.
- Our mechanism for specifying the behavior of operations such as arithmetic
is based on interface implementations, which are looked up by type.
Supporting `impl` selection based on values would introduce substantial
complexity.

We could treat a leading `-` as part of a literal.
We could treat a leading `-` character as part of a numeric literal token, so
that -- for example -- `-123` would be a single `-123` token rather than a unary
negation applied to a literal `123`.

Advantages:

Expand Down