Add support for arithmetic operators:
- Unary `+`.
- Binary `+`, `-`, `*`, `/`, `%`.
Specify their behavior for integer and floating-point types. Signed integer overflow is a programming error, handled in various ways. Unsigned integer overflow is specified as wrapping around, intended for hashing / crypto / PRNG use cases.
Co-authored-by: jonmeow <46229924+jonmeow@users.noreply.github.com>
Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
Co-authored-by: josh11b <josh11b@users.noreply.github.com>
Provide an initial rough structure for the specification so we can add things
as they are decided.
Split the specification into a language and a library section. In the language
section, use one file per broad area of functionality. Divide the language up
based on the intended layering of the language design.
Roadmap updates for 2022. Key goals:
* Reach the point where the first draft of the core language design is complete, with some test programs and an approximate implementation in executable semantics.
* Go public, and improve public participation.
Co-authored-by: Jon Meow <46229924+jonmeow@users.noreply.github.com>
This proposal addresses the question of whether we should perform a fully top-down compilation (like in C), a mostly top-down compilation (like in C++), or whether we should allow information from later in the same source file to be used in earlier program constructs (like in Rust, Swift, Java, C#, Haskell, and so on).
The proposed direction is:
- Entities declared later in the same source file cannot be used earlier; top-down semantics apply everywhere.
- As an exception, class member function bodies are parsed as if they appeared after the class.
- Forward declarations can be used to separate interface from implementation and to allow entities to be used before they are defined.
- The behavior of the program is nonetheless required to be the same as if we had a globally-consistent rule: it's always a hard error to depend on any information that is not known or that is provided later.
Support for member access expressions with syntax `container.member`, covering cases such as:
* `object.field`
* `object.method(args)`
* `package.namespace.class.member`
* `object.(interface.member)`
* `object.(class.member)`
... and so on. Includes the rule for template name lookup as decided in #949.
Co-authored-by: josh11b <josh11b@users.noreply.github.com>
This is intended to be a more iterative edit to the chart:
- Adding `if` and struct literals, since it came up in arithmetic.
- Adding links to address a comment of mine about wanting references
- Rephrasing slightly to reduce the implication that it's only for operators (particularly since I don't think we want to call `if` an operator)
- Shifting operators below because similar
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Moves common script logic into utils.py (not a great name, but couldn't come up with better). This is in particular to make the buildifier.py script really trivial, allowing that pre-commit to be easily added. However, scripts have also been diverging on how we find bazel, so I'm trying to unify that.
The advantage of reimplementing buildifier's pre-commit is that (a) we can now run buildifier server-side, and (b) we can stop advising installing it manually. Then the only Linux-specific package manager is Cargo, which is only used for watchman, which is optional -- so stop highlighting Linux-specific package managers in the tool instructions.
This proposal introduces a conditional operator of the form:
```
if cond then value1 else value2
```
Co-authored-by: josh11b <josh11b@users.noreply.github.com>
Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
I was doing this for #851 initially, but I think #438 and #826 hadn't made it in (possibly intentionally due to #851? I don't recall).
Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Change the syntax for setting the associated constants and types in an interface implementation for a type from using `let` declarations as in:
```
class Vector(T:! Type) {
impl as Iterable {
let ElementType:! Type = T;
...
}
}
```
to using `where` clauses as in:
```
class Vector(T:! Type) {
impl as Iterable where .ElementType = T {
...
}
}
```
This is an attempt to simplify by removing redundancy, improve consistency by removing a use of `let` that was different than other examples, and better support forward declaration that a type implements an interface while retaining the information needed for type checking.
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Allowing interfaces to define default values for its associated entities. This:
- Helps with evolution by reducing the changes needed to add new members to an interface.
- Reduces boilerplate when some value is more common than others.
- Addresses the gap between the minimum necessary for a type to provide the desired functionality of an interface and the breadth of API that user's desire.
As an alternative, final values can be provided instead, which can't be overridden, but are more predictable for users and may avoid dynamic dispatch overhead in some cases.
Example:
```
// Interface parameter has a default of `Self`
interface Add(Right:! Type = Self) {
// `AddWith` *always* equals `Right`
final let AddWith:! Type = Right;
// `Result` has a default of `Self`
let Result:! Type = Self;
fn DoAdd[me: Self](right: Right) -> Result;
}
impl String as Add() {
// Right == AddWith == Result == Self == String
fn DoAdd[me: Self](right: Self) -> Self;
}
```
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This is a proposal to adopt interfaces as the single static open extension mechanism for things like selecting how operators are implemented for types.
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
There were some concerns about facet types leaking out of generic code in return types. Some initial fixes for this were done in [PR #900](https://github.com/carbon-language/carbon-lang/pull/900), but there remain concerns, for example when associated types are involved.
In particular, given an interface method with return type using an associated type, as in:
```
interface Deref {
let Result:! Type;
fn DoDeref[me: Self]() -> Result;
}
class IntHandle {
impl as Deref {
let Result:! Type = i32;
fn DoDeref[me: Self]() -> Result { ... }
}
}
```
Since `Result` has type `Type`, we had the problem that `IntHandle.DoDeref` would have to return `i32 as Type`, instead of the desired `i32`.
We also think we can simplify the model by eliminating the facet type concept and syntax.
This proposal removes facet types, introduces archetypes in their place, clarifies how associated types work outside of a generic function, and specifies how a generic `let` statement in a function body works.
Co-authored-by: Wolff Dobson <wolffg@users.noreply.github.com>
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Define initialization, assignment, comparison, and implicit conversion between data classes with different field orders and/or types.
Implements the decision made in #710 .
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Add support for marking impls as `final` to say they can't be specialized. This allows generic functions that see that the impl applies to determine the values for its associated types. For example this allows us to say that the implementation of the `Deref` interface for pointers can't be specialized. Otherwise, `*p` could have unknown type in a generic function.
Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
There are cases where an impl definition should apply to more than a single type and interface combination. The solution is to parameterize the impl definition, so it applies to a family of types, interfaces, or both. This includes:
- Declare an impl for a parameterized type, which may be external or declared out-of-line.
```
external impl [T:! Type] Vector(T) as Iterable { ... }
external impl Vector(T:! Type) as Iterable { ... }
```
- "Conditional conformance" where a parameterized type implements some interface if the parameter to the type satisfies some criteria, like implementing the same interface.
```
external impl [T:! Type] Pair(T, T) as Foo(T) { ... }
class Array(T:! Type, template N:! Int) {
impl [P:! Printable] Array(P, N) as Printable { ... }
impl Array(P:! Printable, N) as Printable { ... }
}
```
- "Blanket" impls where an interface is implemented for all types that implement another interface, or some other criteria beyond being a specific type.
```
external impl [T:! Ordered] T as PartiallyOrdered { ... }
```
- "Wildcard" impls where a family of interfaces are implemented for single type.
```
class BigInt {
external impl [T:! ImplicitAs(i32)] as AddTo(T) { ... }
external impl as AddTo(T:! ImplicitAs(i32)) { ... }
}
external impl [T:! ImplicitAs(i32)] BigInt as AddTo(T) { ... }
external impl BigInt as AddTo(T:! ImplicitAs(i32)) { ... }
```
In addition to a syntax for defining parameterized impls, we need rules for coherence:
- Orphan rules that ensure that impls are imported in any code that might use it.
- We need overlap rules that pick a specific impl when more than one impl declaration matches a specific query about whether a type implements an interface.
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Add an appendix with the rationale for and alternatives to coherence, along with an entry in the terminology and updates to the coherence discussion in the goals.
Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Implementations of interfaces are as public as the names used in their signature. No access control modifiers are allowed on `impl` declarations.
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Includes a variety of changes:
Int -> i32
this -> me
expand terminology doc and add links to it
fix text to reflect inline external impl introduced in Support external impl in class and adapter scopes. #905
no longer have plans for runtime type parameters
style updates like removing parentheticals and "we"
observe is a "declaration" not a "statement", since it can appear outside function bodies
many individual updates, clean-ups, and fixes
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This proposal describes `where` clauses that can add constraints on a type-of-type, for example define restrictions on its associated types. Example:
```
fn FindFirstPrime[T:! Container where .Element = i32]
(c: T) -> Optional(i32) {
// The elements of `c` have type `T.Element`, which is `i32`.
...
}
fn PrintContainer[T:! Container where .Element is Printable](c: T) {
// The type of the elements of `c` is not known, but we do know
// that type satisfies the `Printable` interface.
...
}
```
Some other constraints, such as `Sized` are defined as type-of-types directly, possibly parameterized.
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
This proposal provides an `as` expression for casting. This supports implicit conversions plus some safe and unsurprising conversions that we do not support implicitly:
* lossy but fully defined conversions to floating-point types
* conversion from `bool` to integer types
* conversion between adaptors and their adapted type, and more generally between compatible types
This facility can be extended by implementing the `As(TargetType)` interface for a type.
Co-authored-by: Geoff Romer <gromer@google.com>
Co-authored-by: josh11b <josh11b@users.noreply.github.com>