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:
&
Besides being confusing in its own right, this loose approach with regard to precedence yields ambiguities with unboxed closure bounds:
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:
// Before After Note
// ~~~~~~ ~~~~~ ~~~~
&Object+Send &
&'a Object+'a &'a
Fn +Send Fn // (*)
Fn +Send Fn // (*) 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.