@@ -124,6 +124,28 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
124
124
toTextTuple(args.init)
125
125
(" implicit " provided isImplicit) ~ argStr ~ " => " ~ argText(args.last)
126
126
}
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
+
127
149
homogenize(tp) match {
128
150
case x : ConstantType if homogenizedView =>
129
151
return toText(x.widen)
@@ -132,6 +154,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
132
154
if (tycon.isRepeatedParam) return toTextLocal(args.head) ~ " *"
133
155
if (defn.isFunctionClass(cls)) return toTextFunction(args, cls.name.isImplicitFunction)
134
156
if (defn.isTupleClass(cls)) return toTextTuple(args)
157
+ if (isInfixType(tp)) return toTextInfixType(tycon, args)
135
158
return (toTextLocal(tycon) ~ " [" ~ Text (args map argText, " , " ) ~ " ]" ).close
136
159
case tp : TypeRef =>
137
160
val hideType = ! ctx.settings.debugAlias.value && (tp.symbol.isAliasPreferred)
0 commit comments