Skip to content

Tune precedence of type operators #4920

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

Closed
wants to merge 11 commits into from

Conversation

Blaisorblade
Copy link
Contributor

@Blaisorblade Blaisorblade commented Aug 10, 2018

Change the precedence of type operators to comply with the spec.
Only the last two commits are new relative to #4072, they offer different options for cherry-picking or squashing; each of them passes tests.

  • we should choose;
  • update the Dotty syntax reference.

EDIT: just learned that our current precedence was already accepted as SIP-33!
https://docs.scala-lang.org/sips/priority-based-infix-type-precedence.html

`argText` uses `toTextGlobal` to change priority; instead, call `toText(arg)`
and leave the priority up to the caller.
- call-sites where `GlobalPrec` makes sense use now `argsText`.
- to ensure this is a refactoring, other call-sites now use `atPrec(GlobalPrec)`
  explicitly; all those calls will be corrected in subsequent commits.
Using `atPrec(GlobalPrec)` ensures that `argText(args.head)` never adds
parentheses around its output, but that's inappropriate for a function type
`T1 => T2`. The nested calls to `atPrec` make no sense, but `argText` hid that
before it was refactored.
Encapsulate the precedence rules in `parsing.precedence` while allowing for
different precedence between term- and type-level operators, as mandated by the
spec.

This is just a refactoring, the actual priority changes are separate.

* Add an `isType` flag to `parsing.precedence` and add
  constants for `AndTypePrec` and `OrTypePrec` (distinct from `OrPrec` and
  `AndPrec`, which is now unused and dropped).
* In the parser, consider `isType` to decide priority.
* In the pretty-printer, use `AndTypePrec` and `OrTypePrec` where appropriate.
While the operators should be associative, they aren't actually guaranteed to
be, so correct pretty-printing will help users.

* PrinterTests: Add first test for TypeTree printing.
* PrinterTests: disable colors, following ErrorMessagesTest.scala.
This way, printing an infix type need not inspect its arguments; that ensures we
don't need to handle *all* the possible forms of types that need to be wrapped
in parentheses.

I did this purely as a refactoring, based on how pretty-printers are supposed to
be written. But the new test case, combining infix type operators and builting
connectives, didn't work with the old code. It also doesn't work in Scala 2:

```scala
Welcome to Scala 2.12.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_172).
Type in expressions for evaluation. Or try :help.

scala> class &&[T,U]
defined class $amp$amp

scala> def foo: Int && Boolean = ???
foo: Int && Boolean

scala> def foo: Int && Boolean with String = ???
foo: Int && Boolean with String

scala> def foo: Int && (Boolean with String) = ???
foo: Int && Boolean with String

scala> def foo: (Int && Boolean) with String = ???
foo: Int && Boolean with String
```
* RefinedPrinter: Handle associativity mismatches for Type operators.
* Add Documentation/tutorial on how to use atPrec and changePrec correctly,
  since so much code got it wrong and it takes a while to get it.
* Extend tests for Type printing.
Refines 8b941d6: classSymbol is unnecessarily
aggressive here.
Unlike others (which here follow Scala 2 precedence), they should follow the
term-level precedence.
@Blaisorblade
Copy link
Contributor Author

SIP-33 mandates closing this, but #4072 is still in!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant