Enable rumdl markdown line-length enforcement and reflowing (#7667)

This should handle over-long lines. I had tried to make the normalize
method work, but it doesn't seem promising and so let's at least enable
this version.

Assisted-by: Antigravity with Gemini
This commit is contained in:
Chandler Carruth
2026-08-27 00:13:39 +00:00
committed by GitHub
parent 197cae22f1
commit ba0011bca8
59 changed files with 430 additions and 393 deletions
+2 -1
View File
@@ -62,7 +62,8 @@ project uses Bazelisk.
You can run the Carbon driver or command line directly via Bazel:
- `bazelisk run //toolchain -- compile --phase=parse toolchain/parse/testdata/basics/empty.carbon`
- `bazelisk run //toolchain -- compile --phase=parse
toolchain/parse/testdata/basics/empty.carbon`
## Advanced configurations
+20 -19
View File
@@ -70,19 +70,19 @@ CARBON_SEM_IR_BUILTIN_FUNCTION_KIND(IntConvertFloat)
Inside
[builtin_function_kind.cpp](../../../toolchain/sem_ir/builtin_function_kind.cpp):
1. **Define Parameter Constraints**: If the parameter requires novel constraints
(e.g. "must be a float type"), define a template constraint struct checking
the matching `SemIR` type instruction (such as `FloatType` or
`FloatLiteralType`). Use pre-established semantic helpers:
1. **Define Parameter Constraints**: If the parameter requires novel
constraints (e.g. "must be a float type"), define a template constraint
struct checking the matching `SemIR` type instruction (such as `FloatType`
or `FloatLiteralType`). Use pre-established semantic helpers:
- `TypeParam<I, T>`: Ensures different parameters resolve to identical type
structures (e.g., generic constraint matching).
- `TypeParam<I, T>`: Ensures different parameters resolve to identical
type structures (e.g., generic constraint matching).
- `AnyInt`, `AnyFloat`, `AnySizedInt`, `AnySizedFloat`, `CharCompatible`,
`StdInitializerList`, `NoReturn`.
2. **Map Literal Name & Register Constraint Signature**: Declare a `BuiltinInfo`
constant inside `namespace BuiltinFunctionInfo` matching the macro-defined
name:
2. **Map Literal Name & Register Constraint Signature**: Declare a
`BuiltinInfo` constant inside `namespace BuiltinFunctionInfo` matching the
macro-defined name:
```cpp
// toolchain/sem_ir/builtin_function_kind.cpp
@@ -127,7 +127,8 @@ execute compile-time computations:
```
- Extract inputs safely from local value stores (e.g.
`context.ints().Get(arg.int_id)` or `context.floats().Get(arg.float_id)`).
`context.ints().Get(arg.int_id)` or
`context.floats().Get(arg.float_id)`).
- Leverage high-precision LLVM mathematical structures (`llvm::APInt`,
`llvm::APFloat`, `llvm::APSInt`) to handle custom bits and signedness
safely.
@@ -142,8 +143,8 @@ execute compile-time computations:
CARBON_DIAGNOSTIC_KIND(IntTooLargeForFloatType)
```
- Emplace localized diagnostic formatting messages where they are caught in
`eval.cpp`:
- Emplace localized diagnostic formatting messages where they are caught
in `eval.cpp`:
```cpp
CARBON_DIAGNOSTIC(IntTooLargeForFloatType, Error,
@@ -152,8 +153,8 @@ execute compile-time computations:
context.emitter().Emit(loc_id, IntTooLargeForFloatType, val, dest_type_id);
```
- Return `SemIR::ErrorInst::ConstantId` to gracefully abort invalid constant
generation rather than crashing the compiler.
- Return `SemIR::ErrorInst::ConstantId` to gracefully abort invalid
constant generation rather than crashing the compiler.
3. **Fast-Path Range Limits**:
- Before evaluating expensive math operations on giant exponents (e.g.
@@ -244,11 +245,11 @@ Create validation splits under
`toolchain/check/testdata/builtins/char_literal/convert.carbon`.
- **Minimal Prelude & Direct Call Isolation**: Builtin tests must **not** test
the prelude library or operators. They must use the minimal primitive
prelude
(`// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/primitives.carbon`)
or a smaller prelude, and explicitly declare and call the builtin functions
under test directly (e.g., `fn Add(a: f64, b: f64) -> f64 = "float.add";`).
This isolates the testing of compiler builtins from the library prelude.
prelude (`// INCLUDE-FILE:
toolchain/testing/testdata/min_prelude/primitives.carbon`) or a smaller
prelude, and explicitly declare and call the builtin functions under test
directly (e.g., `fn Add(a: f64, b: f64) -> f64 = "float.add";`). This
isolates the testing of compiler builtins from the library prelude.
- **Min-Prelude Limitations**: Standard operators (like `+`, `-`, `/`, `<`,
etc.) are **not** available in minimized preludes because the core operators
library isn't imported. To write tests with a minimal footprint, call
+4 -4
View File
@@ -215,8 +215,8 @@ interoperable code, adhere strictly to these rules:
be mentioned if it wouldn't otherwise be clear:
- _Situation-only_: `"redeclaration of X"` (implies that redeclaration is
not permitted).
- _Rule-inclusion_:
``"`self` declared in invalid context; can only be declared in implicit parameter list"``.
- _Rule-inclusion_: ``"`self` declared in invalid context; can only be
declared in implicit parameter list"``.
- **Wording Choice ("cannot" vs "allowed")**: Explicitly avoid `"allowed"`,
`"legal"`, `"permitted"`, `"valid"`, and related passive wording. You may
use `"cannot"` if needed, but try to use phrasing that does not require it:
@@ -228,8 +228,8 @@ interoperable code, adhere strictly to these rules:
- **Developer Intent Hints**: It is acceptable for a diagnostic to guess at
the developer's intent and provide a hint _after_ explaining the situation
and the rule, but never as a substitute for that:
- _Correct_:
``"cannot implicitly convert `i32` to `String`; add `as String` for explicit conversion"``
- _Correct_: ``"cannot implicitly convert `i32` to `String`; add `as
String` for explicit conversion"``
- _Incorrect_: ``"add `as String` to convert `i32` to `String`"`` (Lacks
the core violation message).
- **Structure for Tooling API**: Try to structure diagnostics such that
+3 -3
View File
@@ -53,9 +53,9 @@ filename.
`error_handling.md`, `one_way.md`).
- **Living design**: If the proposal updates design documentation, include
those changes in the PR if possible. If deferred, add "TODO" comments
pointing to the proposal (e.g.,
`> **TODO:** Document ... adopted in [p######](/proposals/p######-title.md)`).
For pervasive changes, file a GitHub issue instead of adding many TODOs.
pointing to the proposal (e.g., `> **TODO:** Document ... adopted in
[p######](/proposals/p######-title.md)`). For pervasive changes, file a
GitHub issue instead of adding many TODOs.
## Alternatives considered and leads decisions
@@ -110,7 +110,8 @@ gh pr diff 1234 | python3 .agents/skills/summarize_testdata_changes/scripts/pars
`// CHECK`), along with diagnostic output changes where relevant
- Diagnostic Changes: Changes to diagnostic output (lines prefixed with
`// CHECK:STDERR`) with no corresponding changes to test inputs
- [Output Type] Changes: Changes to STDOUT (lines prefixed with `// CHECK:STDOUT`)
- [Output Type] Changes: Changes to STDOUT (lines prefixed with `//
CHECK:STDOUT`)
- Create one section for each relevant kind of test. For example,
parser tests should typically be in a "Parse Tree Changes" section,
check tests should typically be in a "SemIR Changes" section, and
@@ -49,8 +49,8 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- **Test everything**: `bazelisk test //...`
- **Test specific target**: `bazelisk test //toolchain/testing:file_test`
- **Test specific file**:
`bazelisk test //toolchain/testing:file_test --test_arg=--file_tests=<path_to_carbon_file>`
- **Test specific file**: `bazelisk test //toolchain/testing:file_test
--test_arg=--file_tests=<path_to_carbon_file>`
- **Build toolchain**: `bazelisk build //toolchain/...`
### Updating test data
+2 -2
View File
@@ -32,7 +32,7 @@ repos:
# Run markdown linting early so that doc style and table-of-contents see the
# linted state.
- repo: https://github.com/rvben/rumdl-pre-commit
rev: v0.2.22
rev: v0.2.58
hooks:
- id: rumdl
args: [--fix]
@@ -51,7 +51,7 @@ repos:
# Re-run markdown linting to fix any issues caused by doc style and TOC. This
# is very fast, so it shouldn't be problematic to run twice.
- repo: https://github.com/rvben/rumdl-pre-commit
rev: v0.2.30
rev: v0.2.58
hooks:
- id: rumdl
args: [--fix]
+15 -1
View File
@@ -15,7 +15,6 @@ respect-gitignore = true
# Disable rules that produce the most noise initially. Some of these might make
# sense to re-enable.
disable = [
"MD013", # Line length exceeded
"MD033", # Inline HTML - commonly used in real-world markdown
"MD036", # Emphasis used instead of heading
"MD040", # Code blocks should have a language specified
@@ -25,6 +24,21 @@ disable = [
"MD028", # Blank line inside blockquote
]
# Line wrapping
[MD013]
reflow = true
# Note that we might want to use the "normalize" reflow mode to have more
# consistent line wrapping, however this mode is currently deeply incompatible
# with inline HTML that we use reasonably often. For now, we go with the default
# mode that doesn't try to normalize wrapping.
reflow-mode = "default"
ignore-link-urls = false
code-blocks = false
code-spans = false
atomic-spans = false
headings = false
stern = true
# Heading style
[MD003]
style = "atx"
+16 -16
View File
@@ -250,21 +250,21 @@ below. We also emphasize two additional requirements for contributors operating
or using AI-based tools:
1. **Contributions should not become extractive of the project and community**:
the value added should outweigh the overhead of landing the contribution. The
overhead of landing contributions ranges from code review, to discussions,
distractions from the current project priorities, or growing maintenance
burden without growing maintainers.
the value added should outweigh the overhead of landing the contribution.
The overhead of landing contributions ranges from code review, to
discussions, distractions from the current project priorities, or growing
maintenance burden without growing maintainers.
2. **Each PR should be transparent about the tooling used** in proportion to how
much of the PR was produced by the tool and whether the tool is a standard
one for the project. For example, formatting with the standard tools is
reasonable to assume without further comment. But if a PR is largely derived
from running a specific Python script, regular expression, or AI-based tool
over the codebase, we ask that its commit message is transparent about this
and include a description of how the tool was used to formulate the change.
For PRs largely derived from AI-based tooling, we suggest following the
pattern established by the Fedora Project to mark commits with
`Assisted-by: ...`.
2. **Each PR should be transparent about the tooling used** in proportion to
how much of the PR was produced by the tool and whether the tool is a
standard one for the project. For example, formatting with the standard
tools is reasonable to assume without further comment. But if a PR is
largely derived from running a specific Python script, regular expression,
or AI-based tool over the codebase, we ask that its commit message is
transparent about this and include a description of how the tool was used to
formulate the change. For PRs largely derived from AI-based tooling, we
suggest following the pattern established by the Fedora Project to mark
commits with `Assisted-by: ...`.
Our policies and practices here are inspired by and aim to be roughly compatible
with several other open source projects:
@@ -405,8 +405,8 @@ respectful, and don't drown out other discussion.
Changes to Carbon documentation follow the
[Google developer documentation style guide](https://developers.google.com/style).
Markdown files should additionally use [rumdl](https://github.com/rvben/rumdl) for
formatting, which we automate with
Markdown files should additionally use [rumdl](https://github.com/rvben/rumdl)
for formatting, which we automate with
[prek](/docs/project/contribution_tools.md#running-prek).
Other style points to be aware of are:
+5 -5
View File
@@ -354,9 +354,9 @@ var résultat: String = "Succès";
```
Comments start with two slashes `//` and go to the end of the line. A comment
may be the only content on its line, or it may follow other content as a trailing
comment. Full-line comments are preferred for documentation, while trailing
comments mark or annotate a specific line.
may be the only content on its line, or it may follow other content as a
trailing comment. Full-line comments are preferred for documentation, while
trailing comments mark or annotate a specific line.
```carbon
// Compute an approximation of π.
@@ -1204,8 +1204,8 @@ they are used.
> [#162: Basic Syntax](https://github.com/carbon-language/carbon-lang/pull/162)
> - Proposal
> [#257: Initialization of memory and variables](https://github.com/carbon-language/carbon-lang/pull/257)
> - Proposal
> [#339: Add `var <type> <identifier> [ = <value> ];` syntax for variables](https://github.com/carbon-language/carbon-lang/pull/339)
> - Proposal [#339: Add `var <type> <identifier> [ = <value> ];` syntax for
> variables](https://github.com/carbon-language/carbon-lang/pull/339)
> - Proposal
> [#618: var ordering](https://github.com/carbon-language/carbon-lang/pull/618)
> - Proposal
+10 -9
View File
@@ -1711,11 +1711,12 @@ class SongByTitle {
}
```
An adapter can also preserve the API and interface implementations of the original
type using `extend adapt`. For details on how an extending adapter implements
interfaces that are implemented for the adapted type, as well as applications of adapters to generics, see
[Adapting types](/docs/design/generics/details.md#adapting-types) in the generics
design.
An adapter can also preserve the API and interface implementations of the
original type using `extend adapt`. For details on how an extending adapter
implements interfaces that are implemented for the adapted type, as well as
applications of adapters to generics, see
[Adapting types](/docs/design/generics/details.md#adapting-types) in the
generics design.
**Comparison with other languages:** This is similar to the Rust idiom called
"newtype", which is used to implement traits on types while avoiding
@@ -1736,10 +1737,10 @@ checks, like `ValidDate` with the same data layout as `Date`. Or to record the
units associated with a value, such as `Seconds` versus `Milliseconds` or `Feet`
versus `Meters`.
> **Future work:** We should have some way of restricting the casts between a type
> and an adapter to address this use case. One possibility would be to add the
> keyword `private` before `adapt`, so you might write
> `extend private adapt Date;`.
> **Future work:** We should have some way of restricting the casts between a
> type and an adapter to address this use case. One possibility would be to add
> the keyword `private` before `adapt`, so you might write `extend private adapt
> Date;`.
Haskell has a [`newtype` feature](https://wiki.haskell.org/Newtype) as well.
Haskell's feature doesn't directly support reusing implementations either, but
+9 -9
View File
@@ -52,15 +52,15 @@ A named function definition or declaration has one of the following syntactic
forms (where items in square brackets are optional and independent):
- `fn` _name_ [_implicit-parameters_] [_tuple-pattern_] `=>` _expression_ `;`
- `fn` _name_ [_implicit-parameters_] [_tuple-pattern_] [`->` _return-form_] `{`
_statements_ `}`
- `fn` _name_ [_implicit-parameters_] [_tuple-pattern_] [`->` _return-form_]
`{` _statements_ `}`
- `fn` _name_ [_implicit-parameters_] _tuple-pattern_ [`->` _return-form_] `;`
A lambda expression has one of the following syntactic forms:
- `fn` [_implicit-parameters_] [_tuple-pattern_] `=>` _expression_
- `fn` [_implicit-parameters_] [_tuple-pattern_] [`->` _return-form_] `{` _statements_
`}`
- `fn` [_implicit-parameters_] [_tuple-pattern_] [`->` _return-form_] `{`
_statements_ `}`
Named function definitions are distinguished from lambdas by the presence of a
name after the `fn` keyword. If a statement or declaration begins with `fn`, a
@@ -758,14 +758,14 @@ parameters. This checking proceeds as follows:
- If the parameter is a `template` binding, the argument expression is
converted to have the same type as the binding and template constant
expression phase.
- If the parameter is a checked generic binding, the argument expression is
converted to have the same type as the binding and symbolic constant
- If the parameter is a checked generic binding, the argument expression
is converted to have the same type as the binding and symbolic constant
expression phase.
- Otherwise, the parameter is pattern-matched against the argument.
If a parameter is a compile-time binding, its corresponding converted argument
expression is evaluated, and its value is added to the list of deduced
argument values before any later parameters are processed.
If a parameter is a compile-time binding, its corresponding converted
argument expression is evaluated, and its value is added to the list of
deduced argument values before any later parameters are processed.
The result of the call expression depends on the callee:
+3 -2
View File
@@ -46,8 +46,9 @@ These last two cases are highlighted as concerns in Rust in
Since Carbon is bundling interface implementations into types, for the
convenience and expressiveness that provides, we satisfy those use cases by
giving the user control over the type of a value. This means having facilities
for defining new [compatible types](/docs/design/classes.md#compatible-types) with
different interface implementations, and casting between those types as needed.
for defining new [compatible types](/docs/design/classes.md#compatible-types)
with different interface implementations, and casting between those types as
needed.
## The "Hashtable Problem"
@@ -31,9 +31,9 @@ This document explains the rationale for choosing to make
## Rewrite constraints
Rewrite constraints are [`where` clauses](details.md#where-constraints) of the
form `.AssociatedConstant = Value`. Given a checked generic binding `T: A where .B = C`,
references to `T.(A.B)` are rewritten to `C`. This appendix describes the
precise rules governing them.
form `.AssociatedConstant = Value`. Given a checked generic binding `T: A where
.B = C`, references to `T.(A.B)` are rewritten to `C`. This appendix describes
the precise rules governing them.
## Combining constraints with `&`
+22 -18
View File
@@ -1123,7 +1123,8 @@ instead.
### Constraints that don't depend on `.Self`
> **TODO:** Link to section explaining when identifying a facet type happens when
> **TODO:** Link to section explaining when identifying a facet type happens
> when
> [#5168: Forward `impl` declaration of an incomplete interface](/proposals/p005168-forward-impl-declaration-of-an-incomplete-interface.md)
> is applied to these docs.
@@ -1139,11 +1140,11 @@ constraint N(T: type) {
}
```
When the above named constraint is identified as part of a facet type as
`C impls N(.Self)`, the resulting requirement `Z where .Z1 = {}` is only
When the above named constraint is identified as part of a facet type as `C
impls N(.Self)`, the resulting requirement `Z where .Z1 = {}` is only
constraining `C`, and not `.Self` from the top-level top-level facet type. So we
require that `C impls (Z where .Z1 = {})` is already true in order to successfully
identify.
require that `C impls (Z where .Z1 = {})` is already true in order to
successfully identify.
```carbon
interface Z(V: type) {
@@ -1799,9 +1800,10 @@ be detected in function overloading.
Since interfaces may only be implemented for a type once, and we limit where
implementations may be added to a type, there is a need to allow the user to
switch the type of a value to access different interface implementations. Carbon
therefore provides [adapters](/docs/design/classes.md#adapters) as a way to create new types
[compatible with](/docs/design/classes.md#compatible-types) existing types with different
APIs, in particular with different interface implementations:
therefore provides [adapters](/docs/design/classes.md#adapters) as a way to
create new types [compatible with](/docs/design/classes.md#compatible-types)
existing types with different APIs, in particular with different interface
implementations:
```carbon
interface Printable {
@@ -2675,9 +2677,9 @@ member of another. The `where` operator is not associative, so a type expression
using multiple must use round parens `(`...`)` to specify grouping.
The scope of a facet type formed by a `where` declaration
[extends](/docs/design/expressions/member_access.md#extend) the scope of its first
operand, and the resulting facet type is complete if that scope it extends is
complete.
[extends](/docs/design/expressions/member_access.md#extend) the scope of its
first operand, and the resulting facet type is complete if that scope it extends
is complete.
> **Comparison with other languages:** Both Swift and Rust use `where` clauses
> on declarations instead of in the expression syntax. These happen after the
@@ -2863,7 +2865,8 @@ constraint ContainerIsSlice {
The `.Self` construct follows these rules:
- A checked binding `X` introduces a checked generic binding `.Self: type`, where
- A checked binding `X` introduces a checked generic binding `.Self: type`,
where
references to `.Self` are resolved to `X`. This allows you to use `.Self` as
an interface parameter as in `X: I(.Self)`.
@@ -3967,11 +3970,11 @@ fn DownCast[T: type](p: T*, generic U: type where .Self extends T) -> U*;
Given a type `U`, define the facet type `CompatibleWith(U)` as follows:
> `CompatibleWith(U)` is a facet type whose values are facets `T` such that
> `T as type` and `U as type` are
> [compatible types](/docs/design/classes.md#compatible-types). That is values of `T` and
> `U` as types can be cast back and forth without any change in representation
> (for example `T` is an [adapter](#adapting-types) for `U`).
> `CompatibleWith(U)` is a facet type whose values are facets `T` such that `T
> as type` and `U as type` are
> [compatible types](/docs/design/classes.md#compatible-types). That is values
> of `T` and `U` as types can be cast back and forth without any change in
> representation (for example `T` is an [adapter](#adapting-types) for `U`).
`CompatibleWith` determines an equivalence relationship between types.
Specifically, given two types `T1` and `T2`, they are equivalent if
@@ -4819,7 +4822,8 @@ difference.
#### Prioritization rule
> **TODO:** Document the changes to prioritization adopted in
> [#5337: Interface extension and `final impl` update](/proposals/p005337-interface-extension-and-final-impl-update.md) and
> [#5337: Interface extension and `final impl` update](/proposals/p005337-interface-extension-and-final-impl-update.md)
> and
> [#7493: Disallow impl in match_first twice](/proposals/p007493-disallow-impl-in-match-first-twice.md).
Since at most one library can contain `impl` definitions with a given type
+6 -5
View File
@@ -142,8 +142,8 @@ fn SortVector(generic T: Comparable, a: Vector(T)*) { ... }
```
The syntax above uses the `generic` keyword to indicate that the parameter named
`T` is a _checked generic_ parameter. The `template` keyword may be added instead to
make it a _template generic_.
`T` is a _checked generic_ parameter. The `template` keyword may be added
instead to make it a _template generic_.
Given an `i32` vector `iv`, `SortVector(i32, &iv)` is equivalent to
`SortInt32Vector(&iv)`. Similarly for a `String` vector `sv`,
@@ -527,9 +527,10 @@ cast from `T` to `CDCover`.
### Adapting types
Carbon has a mechanism called [adapting types](/docs/design/classes.md#adapters)
to create new types that are [compatible](/docs/design/classes.md#compatible-types) with
existing types but with different interface implementations. This could be used
to add or replace implementations, or define implementations for reuse.
to create new types that are
[compatible](/docs/design/classes.md#compatible-types) with existing types but
with different interface implementations. This could be used to add or replace
implementations, or define implementations for reuse.
In this example, we have multiple ways of sorting a collection of `Song` values.
+11 -9
View File
@@ -551,14 +551,16 @@ make it clear that the data representation of the value is not changing, just
its type as reflected in the API available to manipulate the value.
Casting is indicated explicitly by way of some syntax in the source code. You
might use a cast to switch between [type adaptations](/docs/design/classes.md#adapters), or to
be explicit where an implicit conversion would otherwise occur. For now, we are
saying "`x as y`" is the provisional syntax in Carbon for casting the value `x`
to the type `y`. Note that outside of generics, the term "casting" includes any
explicit type change, including those that change the data representation.
might use a cast to switch between
[type adaptations](/docs/design/classes.md#adapters), or to be explicit where an
implicit conversion would otherwise occur. For now, we are saying "`x as y`" is
the provisional syntax in Carbon for casting the value `x` to the type `y`. Note
that outside of generics, the term "casting" includes any explicit type change,
including those that change the data representation.
In contexts where an expression of one type is provided and a different type is
required, an [implicit conversion](/docs/design/expressions/implicit_conversions.md) is
required, an
[implicit conversion](/docs/design/expressions/implicit_conversions.md) is
performed if it is considered safe to do so. Such an implicit conversion, if
permitted, always has the same meaning as an explicit cast.
@@ -824,9 +826,9 @@ express, for example:
element type.
- An interface may define an associated facet that needs to be constrained to
implement some interfaces.
- This type must be [compatible](/docs/design/classes.md#compatible-types) with another type. You
might use this to define alternate implementations of a single interfaces,
such as sorting order, for a single type.
- This type must be [compatible](/docs/design/classes.md#compatible-types)
with another type. You might use this to define alternate implementations of
a single interfaces, such as sorting order, for a single type.
Note that type constraints can be a restriction on one facet parameter or
associated facet, or can define a relationship between multiple facets.
+2 -2
View File
@@ -860,8 +860,8 @@ Evaluation of the last line involves 6 function calls:
1. Call `MakeA`.
2. Call `A.(Core.ImplicitAsPrimitive(C)).Convert`, to convert the `A` object to
a `C` value, as part of type conversion.
3. Call `A.(Core.Copy).Op` to copy the `C` value into the storage for `cd.0`, as
part of category conversion.
3. Call `A.(Core.Copy).Op` to copy the `C` value into the storage for `cd.0`,
as part of category conversion.
4. Call `MakeB`.
5. Call `B.(Core.ImplicitAsPrimitive(D)).Convert`.
6. Call `B.(Core.Copy).Op`.
+19 -17
View File
@@ -26,10 +26,10 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
## Overview
One of Carbon's core goals is [practical safety]. This is referring to _[code
safety]_
as opposed to the larger space of [systems safety]. The largest aspect of code safety
at the language level is [memory safety], but this also applies to other aspects
of code safety such as avoiding undefined behavior in other forms.
safety]_ as opposed to the larger space of [systems safety]. The largest aspect
of code safety at the language level is [memory safety], but this also applies
to other aspects of code safety such as avoiding undefined behavior in other
forms.
[practical safety]:
/docs/project/goals.md#practical-safety-and-testing-mechanisms
@@ -45,9 +45,9 @@ guarantees. Our safety strategy has to address how C++ code fits into it, and
provide an incremental path from where the code is at today towards increasing
levels of safety.
Ultimately, Carbon will both provide a [memory-safe language], _and_ provide a language
that is a target for mechanical migration from C++ and optimizes even further for
interop with unsafe C++ with minimal friction.
Ultimately, Carbon will both provide a [memory-safe language], _and_ provide a
language that is a target for mechanical migration from C++ and optimizes even
further for interop with unsafe C++ with minimal friction.
[memory-safe language]: /docs/design/safety/terminology.md#memory-safe-language
@@ -55,9 +55,9 @@ interop with unsafe C++ with minimal friction.
Carbon will have both _safe_ and _unsafe_ code. Safe code provides limits on the
potential behavior of the program even in the face of bugs in order to prevent
[safety bugs] from becoming [vulnerabilities]. Unsafe code is any code or operation
which lacks limits or guarantees on behavior, and as a consequence may have undefined
behavior or be a safety bug.
[safety bugs] from becoming [vulnerabilities]. Unsafe code is any code or
operation which lacks limits or guarantees on behavior, and as a consequence may
have undefined behavior or be a safety bug.
[safety bugs]: /docs/design/safety/terminology.md#safety-bugs
[vulnerabilities]:
@@ -128,8 +128,8 @@ expressivity is available at that finer granularity through explicitly marking
Carbon will use a hybrid of different techniques to achieve memory safety in its
safe code, largely broken down by the categories of memory safety:
- [Type safety]: compile-time enforcement, the same as other statically typed languages
with generic type systems.
- [Type safety]: compile-time enforcement, the same as other statically typed
languages with generic type systems.
- [Initialization safety]: hybrid of run-time and compile-time enforcement.
- [Spatial safety]: run-time enforcement.
- [Temporal safety]: compile-time enforcement through its type system.
@@ -161,7 +161,8 @@ also involve a temporal memory safety violation. For example, despite both Go
and non-strict-concurrency Swift only providing temporal safety, the rate of
memory safety vulnerabilities in software written in both matches the expected
low rate for memory-safe languages. As a consequence, Carbon has some
flexibility while still being a [memory-safe language] according to our definition:
flexibility while still being a [memory-safe language] according to our
definition:
- Carbon might choose to _not_ prevent data race bugs that are not
_themselves_ also temporal safety bugs, even though the data race may lead
@@ -173,8 +174,8 @@ flexibility while still being a [memory-safe language] according to our definiti
free.
Despite having this flexibility, preventing data race bugs remains _highly
valuable_ for correctness, debugging, and achieving [fearless concurrency]. If Carbon
can, it should work to prevent data races as well.
valuable_ for correctness, debugging, and achieving [fearless concurrency]. If
Carbon can, it should work to prevent data races as well.
[fearless concurrency]: https://doc.rust-lang.org/book/ch16-00-concurrency.html
@@ -220,8 +221,9 @@ run-time enforcement components of our
[memory safety model](#memory-safety-model) above. This means, for example, that
bounds checking is enabled in the release build. There is [evidence] that the
cost of these hardening steps is low. Following the specific guidance of our top
priority for [performance control], Carbon will provide ways to write unsafe code
that disables the run-time enforcement, enabling the control of any overhead incurred.
priority for [performance control], Carbon will provide ways to write unsafe
code that disables the run-time enforcement, enabling the control of any
overhead incurred.
[evidence]: https://chandlerc.blog/posts/2024/11/story-time-bounds-checking/
[performance control]: /docs/project/goals.md#performance-critical-software
+6 -6
View File
@@ -1044,10 +1044,10 @@ applied to phases uses the ordering "runtime" < "symbolic" < "template"):
`(<T1, C, P1, V1>, <T2, C, P2, V2>, ... <TN, C, PN, VN>)` can be converted
to a primitive extended type
`<(T1, T2, ..., TN), C, min(P1, P2, ..., PN), (V1, V2, ... VN)>`.
- An expression of struct extended type
`{.a = <Ta, C, Pa, Va>, .b = <Tb, C, Pb, Vb>, ... .z = <Tz, C, Pz, Vz>}` can
be converted to a primitive extended type
`<{.a = Ta, .b = Tb, ... .z = Tz}, C, min(Pa, Pb, ... Pz), {.a = Va, .b = Vb, ... .z = Vz}>`.
- An expression of struct extended type `{.a = <Ta, C, Pa, Va>, .b = <Tb, C,
Pb, Vb>, ... .z = <Tz, C, Pz, Vz>}` can be converted to a primitive extended
type `<{.a = Ta, .b = Tb, ... .z = Tz}, C, min(Pa, Pb, ... Pz), {.a = Va,
.b = Vb, ... .z = Vz}>`.
When `C` is "value", composition forms a value representation of the aggregate
from value representations of the elements. When `C` is "initializing", it
@@ -1169,8 +1169,8 @@ alternatives considered section of [P2006]:
### Pointer syntax
The type of a pointer to a type `T` is written with a postfix `*` as in `T*`.
Dereferencing a pointer is a [_reference expression_] and is written with a prefix
`*` as in `*p`:
Dereferencing a pointer is a [_reference expression_] and is written with a
prefix `*` as in `*p`:
```carbon
var i: i32 = 42;
+9 -9
View File
@@ -210,8 +210,8 @@ To use it:
A typical commit workflow looks like:
1. `git commit` to try committing files. This automatically executes `prek run`,
which may fail and leave files modified for cleanup.
1. `git commit` to try committing files. This automatically executes `prek
run`, which may fail and leave files modified for cleanup.
2. `git add .` to add the automatic modifications done by hooks.
3. `git commit` again.
@@ -235,16 +235,16 @@ considering if they fit your workflow.
- **WARNING**: Bugs in `rs-git-fsmonitor` and/or Watchman can result in
`prek` deleting files. If you see files being deleted, disable
`rs-git-fsmonitor` with `git config --unset core.fsmonitor`.
- [rumdl](https://github.com/rvben/rumdl): A Markdown formatter, which we use for
formatting Markdown files. If you want to format files directly or use it in
your editor, you can install it:
- [rumdl](https://github.com/rvben/rumdl): A Markdown formatter, which we use
for formatting Markdown files. If you want to format files directly or use
it in your editor, you can install it:
- With `cargo` (preferred): `cargo install --locked rumdl`
- With `brew` (on macOS): `brew install rumdl`
- For Vim/Neovim, it is recommended to connect using its built-in Language
Server Protocol (LSP) capabilities (by way of `rumdl server`). It is supported
by [Mason](https://github.com/williamboman/mason.nvim) (as `rumdl`) and
can be configured by way of `nvim-lspconfig` or formatting plugins like
`conform.nvim`. For more details, see the
Server Protocol (LSP) capabilities (by way of `rumdl server`). It is
supported by [Mason](https://github.com/williamboman/mason.nvim) (as
`rumdl`) and can be configured by way of `nvim-lspconfig` or formatting
plugins like `conform.nvim`. For more details, see the
[rumdl editor integration documentation](https://github.com/rvben/rumdl#editor-integration).
- [vim-prettier](https://github.com/prettier/vim-prettier): A vim integration
for [Prettier](https://prettier.io/), which we use for formatting.
+2 -2
View File
@@ -37,8 +37,8 @@ documentation.
- Links to issues and to complete proposals should use the text `#nnnn`, where
`nnnn` is the issue number, optionally followed by the proposal title, and
should link to the issue or pull request on GitHub. For example,
`[#123: widget painting](https://github.com/carbon-language/carbon-lang/pull/123)`.
should link to the issue or pull request on GitHub. For example, `[#123:
widget painting](https://github.com/carbon-language/carbon-lang/pull/123)`.
- Links to specific sections of a proposal should link to the repository copy
of the proposal file, using the section title or other appropriate link
text. For example,
@@ -73,12 +73,14 @@ in order to maintain the same behaviour.
## Alternatives considered
This rule was originally stated that any two files could be concatenated in some
order without changing the meaning of the code. However this creates (at least) two problems:
order without changing the meaning of the code. However this creates (at least)
two problems:
- Under separate compilation, `impl` declarations in an impl file are not
visible to other Carbon files. Concatenating them into another file would make
them visible, and could change the meaning of code that can now find them.
visible to other Carbon files. Concatenating them into another file would
make them visible, and could change the meaning of code that can now find
them.
- Packages introduce a named scope, so the symbols within the package are
qualified by the package name. Concatenating the contents of one package into
another would change the name by which any moved entities would be found. This
would necessitate changes to the code to resolve name lookups.
qualified by the package name. Concatenating the contents of one package
into another would change the name by which any moved entities would be
found. This would necessitate changes to the code to resolve name lookups.
+3 -3
View File
@@ -93,9 +93,9 @@ split up pull requests:
right": not too big, not too small. You don't want to separate a pattern of
tightly related changes into separate requests when they're easier to review
as a set or batch, and you don't want to bundle unrelated changes together.
Typically you should try to keep the pull request as small as you can without
breaking apart tightly coupled changes. However, listen to your code reviewer
if they ask to split things up or combine them.
Typically you should try to keep the pull request as small as you can
without breaking apart tightly coupled changes. However, listen to your code
reviewer if they ask to split things up or combine them.
While the default is to squash pull requests into a single commit, _during_ the
review you typically want to leave the development history undisturbed until the
@@ -39,12 +39,12 @@ This achieves two goals:
1. Replaces the term `master`. This term, while only used in isolation in Git,
[was used](https://mail.gnome.org/archives/desktop-devel-list/2019-May/msg00066.html)
in immediately preceding and related systems as part of extremely problematic
"master/slave" terminology. That background associates the term with
unacceptable historical and cultural meanings. The intent of those using or
adopting the term isn't relevant to this association. The less overtly
problematic term being isolated from the rest doesn't erase its history, and
doesn't completely avoid painful associations.
in immediately preceding and related systems as part of extremely
problematic "master/slave" terminology. That background associates the term
with unacceptable historical and cultural meanings. The intent of those
using or adopting the term isn't relevant to this association. The less
overtly problematic term being isolated from the rest doesn't erase its
history, and doesn't completely avoid painful associations.
2. It directly anchors and reinforces contributors on the trunk-based workflow.
+4 -4
View File
@@ -667,13 +667,13 @@ may create them for bucketing work, they are non-essential):
1. Create the PR, for example #456, naming the proposal p0456.md.
2. Update the labels of #456 when progressing a proposal.
1. Don't bother putting the status in p0456.md: people should rely on the PR
labels since it's in the same place.
1. Don't bother putting the status in p0456.md: people should rely on the
PR labels since it's in the same place.
3. When a decision is made, add it as a comment to #456.
1. This does not replace the Discourse Forum topic announcing a decision.
2. Comments on the decision should go in Discourse Forums.
3. The author is asked to link to the decision in p0456.md before the commit
is approved.
3. The author is asked to link to the decision in p0456.md before the
commit is approved.
4. If declined/deferred proposals are committed, it would be best to add a
status in p0456.md before committing.
@@ -757,13 +757,13 @@ approaches looks like:
- Alternative: `library "Boost/Random.Uniform" namespace Boost;`
- Specifying namespaces:
- Proposal: `package BoostRandom namespace Distributions;`
- Alternative:
`library "Boost/Random.Uniform" namespace Boost.Random.Distributions;`
- Alternative: `library "Boost/Random.Uniform" namespace
Boost.Random.Distributions;`
- Combined:
- Proposal:
`package BoostRandom library "Uniform" namespace Distributions;`
- Alternative:
`library "Boost/Random.Uniform" namespace Boost.Random.Distributions;`
- Alternative: `library "Boost/Random.Uniform" namespace
Boost.Random.Distributions;`
- `import` changes:
- Trivial:
- Proposal: `import BoostRandom;`
+12 -11
View File
@@ -107,9 +107,10 @@ The choice to require NFC is really four choices:
same glyph, such as with pre-combined diacritics versus with diacritics
expressed as separate combining characters, or with combining characters
in a different order, would be considered different characters.
- If we use a canonical normalization form, all ways of encoding diacritics
are considered to form the same character, but ligatures such as `ffi` are
considered distinct from the character sequence that they decompose into.
- If we use a canonical normalization form, all ways of encoding
diacritics are considered to form the same character, but ligatures such
as `ffi` are considered distinct from the character sequence that they
decompose into.
- If we use a compatibility normalization form, ligatures are considered
equivalent to the character sequence that they decompose into.
@@ -124,19 +125,19 @@ The choice to require NFC is really four choices:
See also the discussion of [homoglyphs](#homoglyphs) below.
2. Composition: we use a composed normalization form rather than a decomposed
normalization form. For example, `ō` is encoded as U+014D (LATIN SMALL LETTER
O WITH MACRON) in a composed form and as U+006F (LATIN SMALL LETTER O),
U+0304 (COMBINING MACRON) in a decomposed form. The composed form results in
smaller representations whenever the two differ, but the decomposed form is a
little easier for algorithmic processing (for example, typo correction and
homoglyph detection).
normalization form. For example, `ō` is encoded as U+014D (LATIN SMALL
LETTER O WITH MACRON) in a composed form and as U+006F (LATIN SMALL LETTER
O), U+0304 (COMBINING MACRON) in a decomposed form. The composed form
results in smaller representations whenever the two differ, but the
decomposed form is a little easier for algorithmic processing (for example,
typo correction and homoglyph detection).
3. We require source files to be in our chosen form, rather than converting to
that form as necessary.
4. We require that the entire contents of the file be normalized, rather than
restricting our attention to only identifiers, or only identifiers and string
literals.
restricting our attention to only identifiers, or only identifiers and
string literals.
### Characters in identifiers and whitespace
+3 -3
View File
@@ -463,9 +463,9 @@ The proposal does not include declarations for uninitialized variables, leaving
that to a later proposal.
In this proposal, assignment is a statement. It could instead be an expression
as it is in C and C++. The arguments against assignment-as-an-expression
include (1) it complicates reasoning about the ordering of side-effects and (2) it
can cause confusion between `=` and `==`
as it is in C and C++. The arguments against assignment-as-an-expression include
(1) it complicates reasoning about the ordering of side-effects and (2) it can
cause confusion between `=` and `==`
[(SEI CERT C Coding Standard)](https://wiki.sei.cmu.edu/confluence/display/c/EXP45-C.+Do+not+perform+assignments+in+selection+statements)
[Visual Studio Warning](https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-4-c4706?view=vs-2019).
@@ -555,9 +555,10 @@ fn ReturnVarWithControlFlow() -> Point {
We propose a set of restrictions to give simple and understandable behavior
which remains reasonably expressive.
1. Once a `returned var` is in scope, another `returned var` cannot be declared.
2. Any `return` with a `returned var` in scope must be `return var;` and returns
the declared `returned var`.
1. Once a `returned var` is in scope, another `returned var` cannot be
declared.
2. Any `return` with a `returned var` in scope must be `return var;` and
returns the declared `returned var`.
3. If control flow exits the scope of a `returned var` in any way other than a
`return var;`, it ends the lifetime of the declared `returned var` exactly
like it would end the lifetime of a `var` declaration.
+9 -9
View File
@@ -286,12 +286,12 @@ Disadvantages:
expectations, for example in some important bit-manipulation cases.
- Give integer types a range of values rather than simply a bit-width. For
example, we can say that negation on `i32` produces a type that can
represent [-2<sup>31</sup>+1, 2<sup>31</sup>], which still fits in 32 bits.
However, this would add significant complexity to the type system, and with
this approach, division would still increase the bit width: for example,
`a / b`, where `a` and `b` are `iN`s, has 2<sup>`N`</sup>+1 distinct possible
values. This is especially surprising because integer division is usually
expected to make a number smaller!
represent [-2<sup>31</sup>+1, 2<sup>31</sup>], which still fits in 32
bits. However, this would add significant complexity to the type system,
and with this approach, division would still increase the bit width: for
example, `a / b`, where `a` and `b` are `iN`s, has 2<sup>`N`</sup>+1
distinct possible values. This is especially surprising because integer
division is usually expected to make a number smaller!
- Refactoring code becomes more challenging, as the appropriate intermediate
type must be determined. Mitigating this, the type system would inform the
programmer when they make a mistake.
@@ -379,9 +379,9 @@ cases are:
difference of such unsigned quantities, and it's generally preferable for
such subtractions to produce a negative result rather than a subtle bug.
Moreover, while a restriction to non-negative values is common, supporting
only the case of a range restriction to [0, 2<sup>N</sup>-1], but not any other
range, does not do a good job of addressing the general desire to capture intent
and to make invalid states unrepresentable.
only the case of a range restriction to [0, 2<sup>N</sup>-1], but not any
other range, does not do a good job of addressing the general desire to
capture intent and to make invalid states unrepresentable.
- Ability to reduce storage size. Spending a sign bit every time a number is
stored, even when it's known to be non-negative is wasteful. This is an
important concern, and one we should address, but it's thought to be better
+19 -20
View File
@@ -84,28 +84,27 @@ the code, in support of these goals:
> Summary of options for implicit parameters / arrays ambiguity discussed so
> far:
>
> 1. Just make it work as-is: `impl [a; b]` parses as an array type,
> `impl [a, b]` parses as an implicit parameter. Theoretically this is
> unambiguous given that a `;` is required inside the `[`...`]` in the former
> and disallowed in the latter. Concerns: it's likely to be visually
> ambiguous.
> 1. Just make it work as-is: `impl [a; b]` parses as an array type, `impl [a,
> b]` parses as an implicit parameter. Theoretically this is unambiguous
> given that a `;` is required inside the `[`...`]` in the former and
> disallowed in the latter. Concerns: it's likely to be visually ambiguous.
> 2. Add mandatory parentheses: `impl [T:! Type] (Vector(T) as Container)`.
> Concerns: it's hard to avoid requiring them in cases that don't start with
> a `[` if we want an unambiguous grammar. Requiring them always would impose
> a small ergonomic hit.
> 3. Add an introducer keyword for implicit parameters:
> `impl where [T:! Type] Vector(T) as Container`. Unambiguous. Concerns:
> still some visual ambiguity due to reuse of `[`...`]`, concern over whether
> we'd uniformly use this syntax (`fn F where [T:! Type](x: T)`) or have
> non-uniform syntax for implicit parameters.
> 4. Use a different syntax for array types in general:
> `impl Array(T) as Container` or `impl Array[N] as Container`. Concerns: may
> want a first-class syntax here, especially if (per @geoffromer 's variadics
> work, we want some special behavior for a deduced bound), and there's a
> strong convention to use `[`...`]` for this. The latter syntax is messy
> because of our types-as-expressions approach, but we could imagine
> providing a `impl Type as Indexable where .Result = Type` to construct
> array types. `T[]` might be a special case of some kind.
> a `[` if we want an unambiguous grammar. Requiring them always would
> impose a small ergonomic hit.
> 3. Add an introducer keyword for implicit parameters: `impl where [T:! Type]
> Vector(T) as Container`. Unambiguous. Concerns: still some visual
> ambiguity due to reuse of `[`...`]`, concern over whether we'd uniformly
> use this syntax (`fn F where [T:! Type](x: T)`) or have non-uniform syntax
> for implicit parameters.
> 4. Use a different syntax for array types in general: `impl Array(T) as
> Container` or `impl Array[N] as Container`. Concerns: may want a
> first-class syntax here, especially if (per @geoffromer 's variadics work,
> we want some special behavior for a deduced bound), and there's a strong
> convention to use `[`...`]` for this. The latter syntax is messy because
> of our types-as-expressions approach, but we could imagine providing a
> `impl Type as Indexable where .Result = Type` to construct array types.
> `T[]` might be a special case of some kind.
> 5. Use a different syntax for implicit parameters in general:
> `impl<T:! Type> Vector(T) as Container`. Concerns: we don't have many
> delimiter options unless we start using multi-character delimiters; `()`,
@@ -542,8 +542,8 @@ class MyIntContainer {
Mixins are currently in early design stages. This section highlights possible
uses speculating on the final design. Some may include:
- Improved semantics for views compared to getter methods: no direct side effect
from using the view
- Improved semantics for views compared to getter methods: no direct side
effect from using the view
- Facilitate code reuse, compared to reimplementing an interface
- Direct access to `self`, limiting needs for pointers and address resolution
@@ -624,8 +624,8 @@ author chooses between value and reference).
For reference, range-based `for` loops in C++ requires:
- `begin()` and `end()` methods or free functions, and
- the type returned supports pre-increment `++`, indirection `*`, and inequality
`!=` operations
- the type returned supports pre-increment `++`, indirection `*`, and
inequality `!=` operations
See [range-based for statement](https://eel.is/c++draft/stmt.iter#stmt.ranged)
for more details.
@@ -799,8 +799,8 @@ This would work similarly to [Python generator functions](#python).
This has the following advantages:
- Removes the need for an `Optional`, and the associated overheads, copies, and
unwrapping.
- Removes the need for an `Optional`, and the associated overheads, copies,
and unwrapping.
- No boundary checks needed at the `for` level
- Compatible with R-value containers
@@ -850,13 +850,13 @@ value, or [inverting control](#inversion-of-control).
The iterator approach was considered but proved to have key limitations that a
cursor approach does not have:
- It requires implementing 2 interfaces instead of 1, and is more complex due to
having the iteration logic separated from the container itself
- It requires implementing 2 interfaces instead of 1, and is more complex due
to having the iteration logic separated from the container itself
- More difficult to harden or troubleshoot, compared to a cursor that allows
bounds checking in debug & hardened build modes
- Can pose problems with ranges that consumes their input (See Barry Revzins
"take(5)" presentation from C++Now 2023), when compared to a combined `Next()`
approach.
"take(5)" presentation from C++Now 2023), when compared to a combined
`Next()` approach.
- Higher overhead
- Proves to be difficult to support for R-values
@@ -103,8 +103,8 @@ provide a `main` function that is used as the entry point.
In the `Main` package, the package declaration does not explicitly specify a
package name. The package declaration syntax becomes:
- `package` _Foo_ [`library "`_Bar_`"`] \(`api` | `impl`) `;`, unchanged from #107,
for a file that is part of a package other than the `Main` package.
- `package` _Foo_ [`library "`_Bar_`"`] \(`api` | `impl`) `;`, unchanged from
#107, for a file that is part of a package other than the `Main` package.
- `library "`_Bar_`"` (`api` | `impl`) `;` for a library that is part of the
`Main` package.
- Omitted entirely for an `impl` file in the `Main` package that is not part
@@ -43,8 +43,8 @@ Statements need some system for separation. There are two main options for this:
1. Require semicolons to terminate statements.
2. Automatically determine where statements terminate.
- Some languages, such as Python, define a syntax where a newline terminates
statements.
- Some languages, such as Python, define a syntax where a newline
terminates statements.
- Other languages, such as Javascript, require semicolons but define rules
for semicolon insertion.
@@ -56,9 +56,10 @@ evaluation. We executed on this really well, but with mixed results.
https://github.com/carbon-language/carbon-lang/blob/840cb1bed7cf9bd57e000cb4a61e986c383d3038/docs/project/roadmap.md
On getting ready for evaluation, we made fantastic progress on getting the
language (design) ready. We have [milestone definitions], and closed the most critical
gaps in the design from the start of the year. The remaining gaps are either lower
risk, almost finished, or really need interop to effectively explore.
language (design) ready. We have [milestone definitions], and closed the most
critical gaps in the design from the start of the year. The remaining gaps are
either lower risk, almost finished, or really need interop to effectively
explore.
[milestone definitions]: /docs/project/milestones.md
@@ -239,8 +239,8 @@ How does this arise?
operator is applied.
- If it is a reference expression, the "member binding to reference"
(`BindToRef`) operator is applied.
- If it is a value expression, the "member binding to value" (`BindToValue`)
operator is applied.
- If it is a value expression, the "member binding to value"
(`BindToValue`) operator is applied.
3. The result of the member binding has a type that implements the call
interface.
@@ -281,10 +281,10 @@ on advantages and disadvantages for each option.
Disadvantages:
- Prevents placing `export name` next to the import that is expected to add
the name.
- Means `export import` and `export name` will be in different sections: no
single place to look for re-exports.
- Prevents placing `export name` next to the import that is expected to
add the name.
- Means `export import` and `export name` will be in different sections:
no single place to look for re-exports.
3. No ordering for `export name`
@@ -189,10 +189,11 @@ From this, we derive that we want:
- We should try to avoid special syntax.
- Everything else should be written as idiomatic types with descriptive names.
[^1]:
"[chandlerc] Prioritize: slices first, then [resizable storage], then compile-time
sized storage, then everything else is vastly less common. Between those three,
the difference in frequency between the first two is the biggest." from [open discussion on 2024-12-05](https://docs.google.com/document/d/1Iut5f2TQBrtBNIduF4vJYOKfw7MbS8xH_J01_Q4e6Rk/edit?resourcekey=0-mc_vh5UzrzXfU4kO-3tOjA&tab=t.0)
[^1]: "[chandlerc] Prioritize: slices first, then [resizable storage], then
compile-time sized storage, then everything else is vastly less common.
Between those three, the difference in frequency between the first two is
the biggest." from
[open discussion on 2024-12-05](https://docs.google.com/document/d/1Iut5f2TQBrtBNIduF4vJYOKfw7MbS8xH_J01_Q4e6Rk/edit?resourcekey=0-mc_vh5UzrzXfU4kO-3tOjA&tab=t.0)
[^2]:
Slices are included with fundamental types for simplicity, since they will
@@ -116,7 +116,8 @@ Such a name lookup only finds names that were declared prior to the lookup, in
line with the
[information accumulation principle](/docs/project/principles/information_accumulation.md).
If the name is first declared after the point at which it is looked up, the
later declaration of the name is rejected by to the poisoning rule [described earlier](#background].
later declaration of the name is rejected by to the poisoning rule [described
earlier](#background].
```carbon
base class A {
@@ -859,28 +859,28 @@ we found a number of problems with that approach:
- There are multiple possible semantics you might want, and having a single
`impl` does not provide the affordances for choosing between those options,
where one `impl` per interface would. For example, in
`impl forall [T:! type] C(T) as I & J where .(I.x) = i32 and .(J.y) = .(I.x)`,
if there is a specialization of `C(T)` for `I`, will `J.y` have the value
`i32` or the `I.x` from the specialization? In practice, the semantics of
rewrites mean that `.(I.x)` is replaced with `i32` at an early stage in the
compiler (to support things like `.(J.y) = .(I.x).D`), and so only the first
option is consistent. This is a particular concern for the "Independent
impls" option above. If this `impl` is split into two, then the different
possible meanings have different spellings:
where one `impl` per interface would. For example, in `impl forall [T:!
type] C(T) as I & J where .(I.x) = i32 and .(J.y) = .(I.x)`, if there is a
specialization of `C(T)` for `I`, will `J.y` have the value `i32` or the
`I.x` from the specialization? In practice, the semantics of rewrites mean
that `.(I.x)` is replaced with `i32` at an early stage in the compiler (to
support things like `.(J.y) = .(I.x).D`), and so only the first option is
consistent. This is a particular concern for the "Independent impls" option
above. If this `impl` is split into two, then the different possible
meanings have different spellings:
- `impl forall [T:! type] C(T) as J where .(J.y) = i32` means `J.y` will
be `i32` independent of any specialization of `C(T)` for `I`
- `impl forall [T:! type where C(T) impls I] C(T) as J where .(J.y) = .(I.x)`
means `J.y` matches `I.x` even if `C(T)` is specialized
- `impl forall [T:! type where C(T) impls I] C(T) as J where .(J.y) =
.(I.x)` means `J.y` matches `I.x` even if `C(T)` is specialized
- `impl forall [T:! type where C(T) impls (I where .x = i32)] C(T) as J where .(J.y) = .(I.x)`
means this impl won't be used unless `I.x` is `i32`. Note this last form
approximates the "Constrained impls" approach above, but with an
explicit ordering to determine the semantics, and the existing language
rules preventing the code from declaring cycles that would make it
ambiguous.
- `impl forall [T:! type where C(T) impls (I where .x = i32)] C(T) as J
where .(J.y) = .(I.x)` means this impl won't be used unless `I.x` is
`i32`. Note this last form approximates the "Constrained impls" approach
above, but with an explicit ordering to determine the semantics, and the
existing language rules preventing the code from declaring cycles that
would make it ambiguous.
- If an interface `J` extends `I` but they are defined in distinct libraries,
there is no guarantee that an implementation of `J` belongs in the same
@@ -114,23 +114,17 @@ However the [problems](#problem) discussed above result from this situation. We
can gain the benefit of access to the codebase while reducing its impact on
developers and users by moving it into a separate git repository.
[^5]:
https://discord.com/channels/655572317891461132/998959756045713438/1225116234199203860
[^5]: https://discord.com/channels/655572317891461132/998959756045713438/1225116234199203860
[^6]:
https://discord.com/channels/655572317891461132/998959756045713438/1237143981150830673
[^6]: https://discord.com/channels/655572317891461132/998959756045713438/1237143981150830673
[^7]:
https://discord.com/channels/655572317891461132/709488742942900284/1250577021474443376
[^7]: https://discord.com/channels/655572317891461132/709488742942900284/1250577021474443376
[^8]:
https://discord.com/channels/655572317891461132/748959784815951963/1255669935439482993
[^8]: https://discord.com/channels/655572317891461132/748959784815951963/1255669935439482993
[^9]:
https://discord.com/channels/655572317891461132/655578254970716160/1302033729761443963
[^9]: https://discord.com/channels/655572317891461132/655578254970716160/1302033729761443963
[^10]:
https://discord.com/channels/655572317891461132/941071822756143115/1349523309682753606
[^10]: https://discord.com/channels/655572317891461132/941071822756143115/1349523309682753606
## Alternatives considered
@@ -115,7 +115,8 @@ include: `__cplusplus`, `__FILE__`, `__LINE__`, `__DATE__`, `__TIME__` etc.
See the Swift
[implementation](https://github.com/swiftlang/swift/blob/main/lib/ClangImporter/ImportMacro.cpp)
and [documentation](https://developer.apple.com/documentation/swift/using-imported-c-macros-in-swift).
and
[documentation](https://developer.apple.com/documentation/swift/using-imported-c-macros-in-swift).
Swift supports importing object-like C macros as global constants. Macros that
use integer, floating-point and string literals are supported. Also simple
@@ -231,10 +232,10 @@ imported. For example, the following macro wont have a Carbon equivalent:
### Implementation
1. _Name lookup_: When a C++ macro name is encountered in Carbon it is looked-up
before any other name. Following the C++ rules, this allows the macro to be
found in case there is a non-macro with the same name (for example named
variable).
1. _Name lookup_: When a C++ macro name is encountered in Carbon it is
looked-up before any other name. Following the C++ rules, this allows the
macro to be found in case there is a non-macro with the same name (for
example named variable).
2. _Macro import_: If a macro is found, it is imported as a constant to Carbon,
by parsing the tokens of the replacement list to a constant expression and
+7 -7
View File
@@ -327,13 +327,13 @@ The comment notes that three options were proposed:
2. `char` models a UTF-8 code unit, although it may not necessarily be valid,
and may appear in a sequence that is not a valid UTF-8 encoding.
As with the first option, `char` can represent an integer in [0, 255], although
it is not an integer type. Higher-level abstractions would likely (eventually)
be provided to represent different views of the code unit sequence as (for example)
a sequence of code points or a sequence of graphemes, but the fundamental model
exposes the encoding. Functions taking `char` or `char` sequences would assume
UTF-8 encoding, and would need to consider how to handle invalid `char`s and
invalid `char` sequences.
As with the first option, `char` can represent an integer in [0, 255],
although it is not an integer type. Higher-level abstractions would likely
(eventually) be provided to represent different views of the code unit
sequence as (for example) a sequence of code points or a sequence of
graphemes, but the fundamental model exposes the encoding. Functions taking
`char` or `char` sequences would assume UTF-8 encoding, and would need to
consider how to handle invalid `char`s and invalid `char` sequences.
3. Use a foundation that enforces Unicode string validity, for some definition
of "Unicode string validity".
+2 -2
View File
@@ -191,8 +191,8 @@ will have to be inside `F` since it uses the name `C` which is introduced inside
the scope of `F`. Thus if `F` is generic, all users of the `impl` will share a
consistent view of any generic bindings used by the `impl` declaration.
3. A name is introduced in a scope nested within the scope containing the `impl`
declaration.
3. A name is introduced in a scope nested within the scope containing the
`impl` declaration.
```carbon
fn F() {
@@ -71,8 +71,9 @@ literals was defined as producing `i32`, with the rationale:
> two `Core.CharLiteral` values.
`CharLiteral` values are in the range [0, 0x10FFFF], so the smallest fixed-width
power-of-two-sized type their differences fit within is indeed `i32`. However, we
did not consider using a literal type, nor the layering impact of this choice.
power-of-two-sized type their differences fit within is indeed `i32`. However,
we did not consider using a literal type, nor the layering impact of this
choice.
## Proposal
+8 -4
View File
@@ -512,15 +512,19 @@ file_test infrastructure; see
There are several supported ways to run Carbon on a given test file. For
example, with `toolchain/parse/testdata/basics/empty.carbon`:
- `bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/parse/testdata/basics/empty.carbon`
- `bazel test //toolchain/testing:file_test
--test_arg=--file_tests=toolchain/parse/testdata/basics/empty.carbon`
- Executes an individual test.
- `bazel run //toolchain -- compile --phase=parse --dump-parse-tree toolchain/parse/testdata/basics/empty.carbon`
- `bazel run //toolchain -- compile --phase=parse --dump-parse-tree
toolchain/parse/testdata/basics/empty.carbon`
- Explicitly runs `carbon` with the provided arguments.
- `bazel-bin/toolchain/carbon compile --phase=parse --dump-parse-tree toolchain/parse/testdata/basics/empty.carbon`
- `bazel-bin/toolchain/carbon compile --phase=parse --dump-parse-tree
toolchain/parse/testdata/basics/empty.carbon`
- Similar to the previous command, but without using `bazel run`. This can
be useful with a debugger or other tool that needs to directly run the
binary.
- `bazel run //toolchain -- -v compile --phase=check toolchain/check/testdata/basics/run.carbon`
- `bazel run //toolchain -- -v compile --phase=check
toolchain/check/testdata/basics/run.carbon`
- Runs using `-v` for verbose log output, and running through the `check`
phase.
+21 -19
View File
@@ -128,14 +128,15 @@ instead we call it directly. Otherwise, we generate a thunk as follows.
On the C++ side, we have two `clang::FunctionDecl`s:
- The original callee.
- The thunk with a simplified ABI, which is defined to call the original callee.
- The thunk with a simplified ABI, which is defined to call the original
callee.
On the Carbon side, we have two `SemIR::Function`s:
- The function representing the original C++ function signature. This is marked
as `SpecialFunctionKind::HasCppThunk`. Attempts to call this function generate
a call through the thunk instead. This is returned when Carbon invokes C++
overload resolution.
- The function representing the original C++ function signature. This is
marked as `SpecialFunctionKind::HasCppThunk`. Attempts to call this function
generate a call through the thunk instead. This is returned when Carbon
invokes C++ overload resolution.
- The function representing the C++ thunk. This is the target of SemIR `call`
instructions, and is marked as `SpecialFunctionKind::CppThunk`. This has the
same symbol name as the C++ thunk.
@@ -164,16 +165,16 @@ When C++ code calls into Carbon, we always generate a thunk on each side.
On the Carbon side, we have two `SemIR::Function`s:
- The original callee.
- The thunk with a simplified ABI, which is defined to call the original callee.
This is marked as `SpecialFunctionKind::CppThunk`.
- The thunk with a simplified ABI, which is defined to call the original
callee. This is marked as `SpecialFunctionKind::CppThunk`.
On the C++ side, we have two `clang::FunctionDecl`s:
- A C++ function representing the original Carbon function signature. This
function is defined in the C++ AST with a body that calls the thunk; from
Clang's perspective this is a normal C++ function.
- A C++ function representing the Carbon thunk. This has the same symbol name as
the Carbon thunk.
- A C++ function representing the Carbon thunk. This has the same symbol name
as the Carbon thunk.
`Context::clang_decls` can be used to map between the corresponding C++ and
Carbon functions above. `Function::cpp_thunk_callee` can be used to map from the
@@ -211,8 +212,8 @@ class Derived {
This is implemented by combining three other kinds of thunk, as follows:
- A declaration of the C++ function in the base class is imported into Carbon as
a member of the derived class. This function is marked as being a
- A declaration of the C++ function in the base class is imported into Carbon
as a member of the derived class. This function is marked as being a
[signature adaptation thunk](#signature-adaptation-thunks) for the Carbon
overrider.
- The signature adaptation thunk is [exported to C++](#c-calling-carbon). This
@@ -220,9 +221,9 @@ This is implemented by combining three other kinds of thunk, as follows:
adaptation thunk, and a C++-side definition.
- The Carbon-side thunk's call to the signature adaptation thunk is inlined in
SemIR.
- The C++-side function definition uses the exact signature of the original C++
function. We know to do this because it is a thunk generated for a signature
adaptation thunk whose signature is itself imported from C++.
- The C++-side function definition uses the exact signature of the original
C++ function. We know to do this because it is a thunk generated for a
signature adaptation thunk whose signature is itself imported from C++.
In `clang_decls`, the signature adaptation thunk corresponds to the C++ virtual
override function.
@@ -240,8 +241,8 @@ We are concerned with two vtables:
used for constant evaluation on the Carbon side.
- The C++-side vtable representation. In this case, because the vptr was
originally introduced by a C++ class, this will be used for code generation.
This is generated by Clang based on our exporting a suitable set of overriding
functions when we export the Carbon class to C++.
This is generated by Clang based on our exporting a suitable set of
overriding functions when we export the Carbon class to C++.
The Carbon-side vtable contains the signature adaptation thunk. The C++-side
vtable contains the corresponding C++ virtual override function.
@@ -293,6 +294,7 @@ We can't synthesize the definition of the C++-side virtual overrider until the
enclosing class is complete in the C++ AST. Therefore we split the
responsibility for generating the thunks in two:
- When we complete the Carbon class, we generate the signature adaptation thunk.
- When we form a corresponding complete C++ class type, we generate the C++-side
virtual overrider thunk.
- When we complete the Carbon class, we generate the signature adaptation
thunk.
- When we form a corresponding complete C++ class type, we generate the
C++-side virtual overrider thunk.
+6 -6
View File
@@ -264,12 +264,12 @@ if %equal then br !if.then else br !if.else
## Parser-driven pattern block pushing
In order to produce correct pattern blocks, we need to ensure that a new pattern
block is pushed onto the stack at the start of every full-pattern, and popped
at the end. We attempt to do this precisely rather than speculatively, by leveraging
the parser to precisely mark the nodes immediately before full-patterns, and
pushing the pattern block stack when we handle those nodes. We then rely on
signals from both the parser and the node stack to determine when to pop from
the pattern block stack.
block is pushed onto the stack at the start of every full-pattern, and popped at
the end. We attempt to do this precisely rather than speculatively, by
leveraging the parser to precisely mark the nodes immediately before
full-patterns, and pushing the pattern block stack when we handle those nodes.
We then rely on signals from both the parser and the node stack to determine
when to pop from the pattern block stack.
In the case of `let` and `var` decls, this is fairly straightforward: the
beginning is marked by the `LetIntroducer` or `VarIntroducer` node, and the end
+3 -3
View File
@@ -97,9 +97,9 @@ complexity in the number of specifics for that generic.
We define two fingerprints for each specific:
1. `specific_fingerprint`: Includes all specific-dependent information.
2. `common_fingerprint`: Includes the same except for `specific_id` information,
as `specific_id`s can only be determined to be equivalent after building an
equivalence SCC.
2. `common_fingerprint`: Includes the same except for `specific_id`
information, as `specific_id`s can only be determined to be equivalent after
building an equivalence SCC.
Two specific functions are equivalent if their `specific_fingerprint`s are equal
and are not equivalent if their `common_fingerprint`s differs. If the
+2 -1
View File
@@ -176,7 +176,8 @@ support for debugging the toolchain tests. To set that up:
A typical debug session looks like:
1. `bazel build -c dbg --features=-lldb_flags --features=gdb_flags //toolchain/testing:file_test`
1. `bazel build -c dbg --features=-lldb_flags --features=gdb_flags
//toolchain/testing:file_test`
2. Open a `.carbon` testdata file to debug. This must be the active file in VS
Code.
3. Go to the "Run and debug" panel in VS Code.
+6 -7
View File
@@ -279,16 +279,15 @@ Carbon's diagnostic style aims to balance these concerns. Our style is:
- `"redeclaration of X"` describes the situation and implies that
redeclarations are not permitted.
- ``"`self` declared in invalid context; can only be declared in implicit parameter list"``
describes the language rule.
- ``"`self` declared in invalid context; can only be declared in implicit
parameter list"`` describes the language rule.
- It's OK for a diagnostic to guess at the developer's intent and provide
a hint after explaining the situation and the rule, but not as a
substitute for that. For example,
``"add `as String` to convert `i32` to `String`"`` is not sufficient as
an error message, but
``"cannot implicitly convert `i32` to `String`; add `as String` for explicit conversion"``
could be acceptable.
substitute for that. For example, ``"add `as String` to convert `i32` to
`String`"`` is not sufficient as an error message, but ``"cannot
implicitly convert `i32` to `String`; add `as String` for explicit
conversion"`` could be acceptable.
- Use "cannot" if needed, but try to use phrasing that doesn't require it.
Avoid "allowed", "legal", "permitted", "valid", and related wording. For
+4 -3
View File
@@ -15,9 +15,10 @@ This extension is currently experimental, and being developed alongside Carbon.
1. Download and install a `carbon`
[release](https://github.com/carbon-language/carbon-lang/releases).
- By default, the extension will look for `carbon` under `./bazel-bin`. This
is for developers actively working on Carbon and running VS Code inside a
[carbon-lang](https://github.com/carbon-language/carbon-lang) clone.
- By default, the extension will look for `carbon` under `./bazel-bin`.
This is for developers actively working on Carbon and running VS Code
inside a [carbon-lang](https://github.com/carbon-language/carbon-lang)
clone.
2. Install the
[Carbon Language extension](https://marketplace.visualstudio.com/items?itemName=carbon-lang.carbon-vscode).
3. Configure the installed path to `carbon`.
+2 -2
View File
@@ -52,8 +52,8 @@ This installs `vsce` and `ovsx` to `/usr/local/bin`. Ensure that
2. Go to
https://marketplace.visualstudio.com/manage/publishers/carbon-lang
- We use `infra-role@carbon-lang.dev` for publishing; the GitHub
account `CarbonInfraBot` can also be used for login. Contact leads
if you require access.
account `CarbonInfraBot` can also be used for login. Contact
leads if you require access.
3. Next to the extension name, click the "..." and select "Update".
4. Select the `carbon.vsix` file.
3. Build and publish to the Open VSX Registry by following the