@@ -130,7 +130,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
130
130
131
131
override def toText (tp : Type ): Text = controlled {
132
132
def toTextTuple (args : List [Type ]): Text =
133
- " (" ~ Text (args.map(argText), " , " ) ~ " )"
133
+ " (" ~ argsText (args) ~ " )"
134
134
135
135
def toTextFunction (args : List [Type ], isImplicit : Boolean , isErased : Boolean ): Text =
136
136
changePrec(GlobalPrec ) {
@@ -155,17 +155,24 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
155
155
case _ => false
156
156
}
157
157
158
- def toTextInfixType (op : Type , args : List [Type ]): Text = {
159
- /* SLS 3.2.8: all infix types have the same precedence.
160
- * In A op B op' C, op and op' need the same associativity.
161
- * Therefore, if op is left associative, anything on its right
162
- * needs to be parenthesized if it's an infix type, and vice versa. */
163
- val l :: r :: Nil = args
164
- val isRightAssoc = op.typeSymbol.name.endsWith(" :" )
165
- val leftArg = if (isRightAssoc && isInfixType(l)) " (" ~ argText(l) ~ " )" else argText(l)
166
- val rightArg = if (! isRightAssoc && isInfixType(r)) " (" ~ argText(r) ~ " )" else argText(r)
167
-
168
- leftArg ~ " " ~ simpleNameString(op.classSymbol) ~ " " ~ rightArg
158
+ def tyconName (tp : Type ): Name = tp.typeSymbol.name
159
+ def checkAssocMismatch (tp : Type , isRightAssoc : Boolean ) = tp match {
160
+ case AppliedType (tycon, _) => isInfixType(tp) && tyconName(tycon).endsWith(" :" ) != isRightAssoc
161
+ case AndType (_, _) => isRightAssoc
162
+ case OrType (_, _) => isRightAssoc
163
+ case _ => false
164
+ }
165
+
166
+ def toTextInfixType (opName : Name , l : Type , r : Type )(op : => Text ): Text = {
167
+ val isRightAssoc = opName.endsWith(" :" )
168
+ val opPrec = parsing.precedence(opName)
169
+
170
+ changePrec(opPrec) {
171
+ val leftPrec = if (isRightAssoc || checkAssocMismatch(l, isRightAssoc)) opPrec + 1 else opPrec
172
+ val rightPrec = if (! isRightAssoc || checkAssocMismatch(r, isRightAssoc)) opPrec + 1 else opPrec
173
+
174
+ atPrec(leftPrec) { argText(l) } ~ " " ~ op ~ " " ~ atPrec(rightPrec) { argText(r) }
175
+ }
169
176
}
170
177
171
178
homogenize(tp) match {
@@ -174,7 +181,20 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
174
181
if (tycon.isRepeatedParam) return toTextLocal(args.head) ~ " *"
175
182
if (defn.isFunctionClass(cls)) return toTextFunction(args, cls.name.isImplicitFunction, cls.name.isErasedFunction)
176
183
if (defn.isTupleClass(cls)) return toTextTuple(args)
177
- if (isInfixType(tp)) return toTextInfixType(tycon, args)
184
+ if (isInfixType(tp)) {
185
+ val l :: r :: Nil = args
186
+ val opName = tyconName(tycon)
187
+
188
+ return toTextInfixType(tyconName(tycon), l, r) { simpleNameString(tycon.typeSymbol) }
189
+ }
190
+
191
+ // Since RefinedPrinter, unlike PlainPrinter, can output right-associative type-operators, we must override handling
192
+ // of AndType and OrType to account for associativity
193
+ case AndType (tp1, tp2) =>
194
+ return toTextInfixType(tpnme.raw.AMP , tp1, tp2) { toText(tpnme.raw.AMP ) }
195
+ case OrType (tp1, tp2) =>
196
+ return toTextInfixType(tpnme.raw.BAR , tp1, tp2) { toText(tpnme.raw.BAR ) }
197
+
178
198
case EtaExpansion (tycon) =>
179
199
return toText(tycon)
180
200
case tp : RefinedType if defn.isFunctionType(tp) =>
@@ -201,7 +221,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
201
221
// (they don't need to because we keep the original type tree with
202
222
// the original annotation anyway. Therefore, there will always be
203
223
// one version of the annotation tree that has the correct positions).
204
- withoutPos(super .toText(tp))
224
+ return withoutPos(super .toText(tp))
205
225
case tp : SelectionProto =>
206
226
return " ?{ " ~ toText(tp.name) ~
207
227
(Str (" " ) provided ! tp.name.toSimpleName.last.isLetterOrDigit) ~
@@ -375,9 +395,9 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
375
395
case SingletonTypeTree (ref) =>
376
396
toTextLocal(ref) ~ " ." ~ keywordStr(" type" )
377
397
case AndTypeTree (l, r) =>
378
- changePrec(AndPrec ) { toText(l) ~ " & " ~ toText(r) }
398
+ changePrec(AndTypePrec ) { toText(l) ~ " & " ~ atPrec( AndTypePrec + 1 ) { toText(r) } }
379
399
case OrTypeTree (l, r) =>
380
- changePrec(OrPrec ) { toText(l) ~ " | " ~ toText(r) }
400
+ changePrec(OrTypePrec ) { toText(l) ~ " | " ~ atPrec( OrTypePrec + 1 ) { toText(r) } }
381
401
case RefinedTypeTree (tpt, refines) =>
382
402
toTextLocal(tpt) ~ " " ~ blockText(refines)
383
403
case AppliedTypeTree (tpt, args) =>
0 commit comments