Skip to content

Commit 2fc99ca

Browse files
committed
Use precedence levels properly when printing infix types
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 ```
1 parent 891eb23 commit 2fc99ca

File tree

2 files changed

+12
-4
lines changed

2 files changed

+12
-4
lines changed

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,15 +155,15 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
155155
case _ => false
156156
}
157157

158-
def toTextInfixType(op: Type, args: List[Type]): Text = {
158+
def toTextInfixType(op: Type, args: List[Type]): Text = changePrec(InfixPrec) {
159159
/* SLS 3.2.8: all infix types have the same precedence.
160160
* In A op B op' C, op and op' need the same associativity.
161161
* Therefore, if op is left associative, anything on its right
162162
* needs to be parenthesized if it's an infix type, and vice versa. */
163163
val l :: r :: Nil = args
164164
val isRightAssoc = op.typeSymbol.name.endsWith(":")
165-
val leftArg = if (isRightAssoc && isInfixType(l)) changePrec(GlobalPrec) { argText(l) } else argText(l)
166-
val rightArg = if (!isRightAssoc && isInfixType(r)) changePrec(GlobalPrec) { argText(r) } else argText(r)
165+
val leftArg = if (isRightAssoc) atPrec(OrPrec) { argText(l) } else argText(l)
166+
val rightArg = if (!isRightAssoc) atPrec(OrPrec) { argText(r) } else argText(r)
167167

168168
leftArg ~ " " ~ toTextLocal(op) ~ " " ~ rightArg
169169
}
@@ -174,7 +174,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
174174
if (tycon.isRepeatedParam) return toTextLocal(args.head) ~ "*"
175175
if (defn.isFunctionClass(cls)) return toTextFunction(args, cls.name.isImplicitFunction, cls.name.isErasedFunction)
176176
if (defn.isTupleClass(cls)) return toTextTuple(args)
177-
if (isInfixType(tp)) return atPrec(InfixPrec) { toTextInfixType(tycon, args) }
177+
if (isInfixType(tp)) return toTextInfixType(tycon, args)
178178
case EtaExpansion(tycon) =>
179179
return toText(tycon)
180180
case tp: RefinedType if defn.isFunctionType(tp) =>

compiler/test-resources/type-printer/infix

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,11 @@ scala> @scala.annotation.showAsInfix(false) class ||[T,U]
2525
// defined class ||
2626
scala> def foo: Int || Boolean = ???
2727
def foo: ||[Int, Boolean]
28+
scala> def foo: Int && (Boolean with String) = ???
29+
def foo: Int && Boolean & String
30+
scala> def foo: (Int && Boolean) with String = ???
31+
def foo: (Int && Boolean) & String
32+
scala> def foo: (Int && Boolean) & String = ???
33+
def foo: (Int && Boolean) & String
34+
scala> def foo: Int && (Boolean & String) = ???
35+
def foo: Int && Boolean & String

0 commit comments

Comments
 (0)