summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorallisonhb <allisonhb@gmx.com>2016-12-07 20:44:54 -0500
committerallisonhb allisonhb@gmx.com <allisonhb@gmx.com>2016-12-13 20:29:26 -0500
commit8badcadbe51f4a02e495f462f5f2666a24d79cb0 (patch)
tree3f4cc473a81e71097e0f7e08a49ff1d4739feff9
parente60768b62151a160026985269a87fd5b63ee0ae8 (diff)
downloadscala-8badcadbe51f4a02e495f462f5f2666a24d79cb0.tar.gz
scala-8badcadbe51f4a02e495f462f5f2666a24d79cb0.tar.bz2
scala-8badcadbe51f4a02e495f462f5f2666a24d79cb0.zip
SI-4700 Show infix types with as few parentheses as needed.
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala30
-rw-r--r--test/files/run/t4700.check15
-rw-r--r--test/files/run/t4700.scala5
3 files changed, 41 insertions, 9 deletions
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index 54200dea8e..44e96163ea 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -2101,7 +2101,9 @@ trait Types
toBoolean(trivial)
}
- override def isShowAsInfixType: Boolean = sym.hasAnnotation(ShowAsInfixAnnotationClass)
+ /* It only makes sense to show 2-ary type constructors infix. */
+ override def isShowAsInfixType: Boolean =
+ sym.hasAnnotation(ShowAsInfixAnnotationClass) && hasLength(args, 2)
private[Types] def invalidateTypeRefCaches(): Unit = {
parentsCache = null
@@ -2328,6 +2330,22 @@ trait Types
case arg :: Nil => s"($arg,)"
case _ => args.mkString("(", ", ", ")")
}
+ private def infixTypeString: String = {
+ /* SLS 3.2.8: all infix types have the same precedence.
+ * In A op B op' C, op and op' need the same associativity.
+ * Therefore, if op is left associative, anything on its right
+ * needs to be parenthesized if it's an infix type, and vice versa. */
+ // we should only get here after `isShowInfixType` says we have 2 args
+ val l :: r :: Nil = args
+
+ val isRightAssoc = typeSymbol.decodedName endsWith ":"
+
+ val lstr = if (isRightAssoc && l.isShowAsInfixType) s"($l)" else l.toString
+
+ val rstr = if (!isRightAssoc && r.isShowAsInfixType) s"($r)" else r.toString
+
+ s"$lstr ${sym.decodedName} $rstr"
+ }
private def customToString = sym match {
case RepeatedParamClass | JavaRepeatedParamClass => args.head + "*"
case ByNameParamClass => "=> " + args.head
@@ -2351,14 +2369,8 @@ trait Types
xs.init.mkString("(", ", ", ")") + " => " + xs.last
}
}
- else if (isShowAsInfixType && args.length == 2)
- args(0) + " " + sym.decodedName + " " +
- (
- if (args(1).isShowAsInfixType)
- "(" + args(1) + ")"
- else
- args(1)
- )
+ else if (isShowAsInfixType)
+ infixTypeString
else if (isTupleTypeDirect(this))
tupleTypeString
else if (sym.isAliasType && prefixChain.exists(_.termSymbol.isSynthetic) && (this ne dealias))
diff --git a/test/files/run/t4700.check b/test/files/run/t4700.check
index 30f8124b85..40caf0fd36 100644
--- a/test/files/run/t4700.check
+++ b/test/files/run/t4700.check
@@ -29,4 +29,19 @@ defined type alias Mappy
scala> def foo: Int Mappy (Boolean && String) = ???
foo: Int Mappy (Boolean && String)
+scala> @showAsInfix class &:[L, R]
+defined class $amp$colon
+
+scala> def foo: Int &: String = ???
+foo: Int &: String
+
+scala> def foo: Int &: Boolean &: String = ???
+foo: Int &: Boolean &: String
+
+scala> def foo: (Int || String) &: Boolean = ???
+foo: (Int || String) &: Boolean
+
+scala> def foo: Int || (Boolean &: String) = ???
+foo: Int || (Boolean &: String)
+
scala> :quit
diff --git a/test/files/run/t4700.scala b/test/files/run/t4700.scala
index 6182656b18..77f0de3d38 100644
--- a/test/files/run/t4700.scala
+++ b/test/files/run/t4700.scala
@@ -13,6 +13,11 @@ object Test extends ReplTest {
|def foo: Int && (Boolean && String) = ???
|@showAsInfix type Mappy[T, U] = Map[T, U]
|def foo: Int Mappy (Boolean && String) = ???
+ |@showAsInfix class &:[L, R]
+ |def foo: Int &: String = ???
+ |def foo: Int &: Boolean &: String = ???
+ |def foo: (Int || String) &: Boolean = ???
+ |def foo: Int || (Boolean &: String) = ???
|""".stripMargin
}