Skip to content

Commit 1d24a1b

Browse files
authored
Merge pull request #2718 from dotty-staging/infix-prettyprint
SI-4700 Types with symbolic names print in infix by default
2 parents b7632b9 + a9032b0 commit 1d24a1b

File tree

2 files changed

+42
-0
lines changed

2 files changed

+42
-0
lines changed

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,28 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
124124
toTextTuple(args.init)
125125
("implicit " provided isImplicit) ~ argStr ~ " => " ~ argText(args.last)
126126
}
127+
128+
def isInfixType(tp: Type): Boolean = tp match {
129+
case AppliedType(tycon, args) =>
130+
args.length == 2 &&
131+
!Character.isUnicodeIdentifierStart(tycon.typeSymbol.name.toString.head)
132+
// TODO: Once we use the 2.12 stdlib, also check the @showAsInfix annotation
133+
case _ =>
134+
false
135+
}
136+
def toTextInfixType(op: Type, args: List[Type]): Text = {
137+
/* SLS 3.2.8: all infix types have the same precedence.
138+
* In A op B op' C, op and op' need the same associativity.
139+
* Therefore, if op is left associative, anything on its right
140+
* needs to be parenthesized if it's an infix type, and vice versa. */
141+
val l :: r :: Nil = args
142+
val isRightAssoc = op.typeSymbol.name.endsWith(":")
143+
val leftArg = if (isRightAssoc && isInfixType(l)) "(" ~ toText(l) ~ ")" else toText(l)
144+
val rightArg = if (!isRightAssoc && isInfixType(r)) "(" ~ toText(r) ~ ")" else toText(r)
145+
146+
leftArg ~ " " ~ toTextLocal(op) ~ " " ~ rightArg
147+
}
148+
127149
homogenize(tp) match {
128150
case x: ConstantType if homogenizedView =>
129151
return toText(x.widen)
@@ -132,6 +154,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
132154
if (tycon.isRepeatedParam) return toTextLocal(args.head) ~ "*"
133155
if (defn.isFunctionClass(cls)) return toTextFunction(args, cls.name.isImplicitFunction)
134156
if (defn.isTupleClass(cls)) return toTextTuple(args)
157+
if (isInfixType(tp)) return toTextInfixType(tycon, args)
135158
return (toTextLocal(tycon) ~ "[" ~ Text(args map argText, ", ") ~ "]").close
136159
case tp: TypeRef =>
137160
val hideType = !ctx.settings.debugAlias.value && (tp.symbol.isAliasPreferred)

tests/repl/infix-types.check

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
scala> class &&[T,U]
2+
defined class &&
3+
scala> def foo: Int && Boolean = ???
4+
def foo: Int && Boolean
5+
scala> def foo: Int && Boolean && String = ???
6+
def foo: Int && Boolean && String
7+
scala> def foo: Int && (Boolean && String) = ???
8+
def foo: Int && (Boolean && String)
9+
scala> class &:[L, R]
10+
defined class &:
11+
scala> def foo: Int &: String = ???
12+
def foo: Int &: String
13+
scala> def foo: Int &: Boolean &: String = ???
14+
def foo: Int &: Boolean &: String
15+
scala> def foo: (Int && String) &: Boolean = ???
16+
def foo: (Int && String) &: Boolean
17+
scala> def foo: Int && (Boolean &: String) = ???
18+
def foo: Int && (Boolean &: String)
19+
scala> :quit

0 commit comments

Comments
 (0)