diff --git a/text/0000-precedence-of-plus.md b/text/0000-precedence-of-plus.md new file mode 100644 index 00000000000..84b52654158 --- /dev/null +++ b/text/0000-precedence-of-plus.md @@ -0,0 +1,92 @@ +- Start Date: (fill me in with today's date, YYYY-MM-DD) +- RFC PR: (leave this empty) +- Rust Issue: (leave this empty) + +# Summary + +Change the precedence of `+` (object bounds) in type grammar so that +it is similar to the precedence in the expression grammars. + +# Motivation + +Currently `+` in types has a much higher precedence than it does in expressions. +This means that for example one can write a type like the following: + +``` +&Object+Send +``` + +Whereas if that were an expression, parentheses would be required: + +```rust +&(Object+Send) +```` + +Besides being confusing in its own right, this loose approach with +regard to precedence yields ambiguities with unboxed closure bounds: + +```rust +fn foo(f: F) + where F: FnOnce(&int) -> &Object + Send +{ } +``` + +In this example, it is unclear whether `F` returns an object which is +`Send`, or whether `F` itself is `Send`. + +# Detailed design + +This RFC proposes that the precedence of `+` be made lower than unary +type operators. In addition, the grammar is segregated such that in +"open-ended" contexts (e.g., after `->`), parentheses are required to +use a `+`, whereas in others (e.g., inside `<>`), parentheses are not. +Here are some examples: + +```rust +// Before After Note +// ~~~~~~ ~~~~~ ~~~~ + &Object+Send &(Object+Send) + &'a Object+'a &'a (Object+'a) + Box Box + foo::(...) foo::(...) + Fn() -> Object+Send Fn() -> (Object+Send) // (*) + Fn() -> &Object+Send Fn() -> &(Object+Send) + +// (*) Must yield a type error, as return type must be `Sized`. +``` + +More fully, the type grammar is as follows (EBNF notation): + + TYPE = PATH + | '&' [LIFETIME] TYPE + | '&' [LIFETIME] 'mut' TYPE + | '*' 'const' TYPE + | '*' 'mut' TYPE + | ... + | '(' SUM ')' + SUM = TYPE { '+' TYPE } + PATH = IDS '<' SUM { ',' SUM } '>' + | IDS '(' SUM { ',' SUM } ')' '->' TYPE + IDS = ['::'] ID { '::' ID } + +Where clauses would use the following grammar: + + WHERE_CLAUSE = PATH { '+' PATH } + +One property of this grammar is that the `TYPE` nonterminal does not +require a terminator as it has no "open-ended" expansions. `SUM`, in +contrast, can be extended any number of times via the `+` token. Hence +is why `SUM` must be enclosed in parens to make it into a `TYPE`. + +# Drawbacks + +Common types like `&'a Foo+'a` become slightly longer (`&'a (Foo+'a)`). + +# Alternatives + +We could live with the inconsistency between the type/expression +grammars and disambiguate where clauses in an ad-hoc way. + +# Unresolved questions + +None.