Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b6afeeb

Browse files
committed
Move right-associative rewrite into typer
Parser marks application as right-associative. Typer identifies subexpressions to pre-compute in order to preserve left-to-right evaluation.
1 parent a9078fb commit b6afeeb

File tree

25 files changed

+402
-169
lines changed

25 files changed

+402
-169
lines changed

src/compiler/scala/tools/nsc/ast/parser/Parsers.scala

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -930,7 +930,7 @@ self =>
930930
case _ => t
931931
}
932932

933-
/** Create tree representing (unencoded) binary operation expression or pattern. */
933+
/** Create tree representing (unencoded) binary operation expression or pattern. Pos set by caller. */
934934
def makeBinop(isExpr: Boolean, left: Tree, op: TermName, right: Tree, opPos: Position, targs: List[Tree] = Nil): Tree = {
935935
require(isExpr || targs.isEmpty || targs.exists(_.isErroneous),
936936
s"Incompatible args to makeBinop: !isExpr but targs=$targs")
@@ -941,42 +941,35 @@ self =>
941941
val pos = (opPos union t.pos) makeTransparentIf rightAssoc
942942
val sel = atPos(pos)(Select(stripParens(t), op.encode))
943943
if (targs.isEmpty) sel
944-
else {
945-
/* if it's right-associative, `targs` are between `op` and `t` so make the pos transparent */
944+
else
945+
// if it's right-associative, (deprecated) `targs` are between `op` and `t` so make the pos transparent
946946
atPos((pos union targs.last.pos) makeTransparentIf rightAssoc) {
947947
TypeApply(sel, targs)
948948
}
949-
}
950949
}
951950
def mkNamed(args: List[Tree]) = if (!isExpr) args else
952951
args.map(treeInfo.assignmentToMaybeNamedArg(_))
953952
.tap(res => if (currentRun.isScala3 && args.lengthCompare(1) == 0 && (args.head ne res.head))
954953
deprecationWarning(args.head.pos.point, "named argument is deprecated for infix syntax", since="2.13.16"))
955954
var isMultiarg = false
956-
val arguments = right match {
955+
def arguments(arg: Tree) = arg match {
957956
case Parens(Nil) => literalUnit :: Nil
958957
case Parens(args @ (_ :: Nil)) => mkNamed(args)
959958
case Parens(args) => isMultiarg = true ; mkNamed(args)
960-
case _ => right :: Nil
959+
case _ => arg :: Nil
961960
}
962961
def mkApply(fun: Tree, args: List[Tree]) = {
963962
val apply = Apply(fun, args).updateAttachment(InfixAttachment)
964963
if (isMultiarg) apply.updateAttachment(MultiargInfixAttachment)
965964
apply
966965
}
967-
if (isExpr) {
968-
if (rightAssoc) {
969-
import symtab.Flags._
970-
val x = freshTermName(nme.RIGHT_ASSOC_OP_PREFIX)
971-
val liftedArg = atPos(left.pos) {
972-
ValDef(Modifiers(FINAL | SYNTHETIC | ARTIFACT), x, TypeTree(), stripParens(left))
973-
}
974-
val apply = mkApply(mkSelection(right), List(Ident(x) setPos left.pos.focus))
975-
Block(liftedArg :: Nil, apply)
976-
} else
977-
mkApply(mkSelection(left), arguments)
978-
} else
979-
mkApply(Ident(op.encode), stripParens(left) :: arguments)
966+
if (isExpr)
967+
if (rightAssoc)
968+
mkApply(mkSelection(right), arguments(left)).updateAttachment(RightAssociative)
969+
else
970+
mkApply(mkSelection(left), arguments(right))
971+
else
972+
mkApply(Ident(op.encode), stripParens(left) :: arguments(right))
980973
}
981974

982975
/** Is current ident a `*`, and is it followed by a `)` or `, )`? */
@@ -1014,10 +1007,9 @@ self =>
10141007
}
10151008

10161009
def checkHeadAssoc(leftAssoc: Boolean) = checkAssoc(opHead.offset, opHead.operator, leftAssoc)
1017-
def checkAssoc(offset: Offset, op: Name, leftAssoc: Boolean) = (
1010+
def checkAssoc(offset: Offset, op: Name, leftAssoc: Boolean) =
10181011
if (nme.isLeftAssoc(op) != leftAssoc)
10191012
syntaxError(offset, "left- and right-associative operators with same precedence may not be mixed", skipIt = false)
1020-
)
10211013

10221014
def finishPostfixOp(start: Int, base: List[OpInfo], opinfo: OpInfo): Tree = {
10231015
if (opinfo.targs.nonEmpty)
@@ -1047,7 +1039,7 @@ self =>
10471039

10481040
def reduceStack(isExpr: Boolean, base: List[OpInfo], top: Tree): Tree = {
10491041
val opPrecedence = if (isIdent) Precedence(in.name.toString) else Precedence(0)
1050-
val leftAssoc = !isIdent || (nme isLeftAssoc in.name)
1042+
val leftAssoc = !isIdent || nme.isLeftAssoc(in.name)
10511043

10521044
reduceStack(isExpr, base, top, opPrecedence, leftAssoc)
10531045
}

src/compiler/scala/tools/nsc/typechecker/Typers.scala

Lines changed: 110 additions & 90 deletions
Large diffs are not rendered by default.

src/partest/scala/tools/partest/TestState.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
package scala.tools.partest
1414

15+
import scala.tools.nsc.util._
16+
1517
sealed abstract class TestState {
1618
def testFile: java.io.File
1719
def what: String
@@ -67,7 +69,7 @@ object TestState {
6769
}
6870
case class Crash(testFile: java.io.File, caught: Throwable, transcript: Array[String]) extends TestState {
6971
def what = "crash"
70-
def reason = s"caught $caught_s - ${caught.getMessage}"
72+
def reason = s"caught $caught_s - ${caught.getMessage}: ${caught.stackTracePrefixString(_ => true)}"
7173
override def shortStatus = "?!"
7274

7375
private def caught_s = (caught.getClass.getName split '.').last

src/reflect/scala/reflect/internal/StdAttachments.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,4 +183,9 @@ trait StdAttachments {
183183
case object DiscardedExpr extends PlainAttachment
184184
/** Anonymous parameter of `if (_)` may be inferred as Boolean. */
185185
case object BooleanParameterType extends PlainAttachment
186+
187+
/** Apply is right associative. */
188+
case object RightAssociative extends PlainAttachment
189+
/** Arg to right associative infix application is candidate for rewriting. */
190+
case object RightAssociativeArg extends PlainAttachment
186191
}

src/reflect/scala/reflect/internal/Types.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ import scala.util.chaining._
7171
// [tparams]result where result is a (Nullary)MethodType or ClassInfoType
7272
7373
// The remaining types are not used after phase `typer`.
74-
case OverloadedType(pre, tparams, alts) =>
74+
case OverloadedType(pre, alts) =>
7575
// all alternatives of an overloaded ident
7676
case AntiPolyType(pre, targs) =>
7777
// rarely used, disappears when combined with a PolyType

src/reflect/scala/reflect/internal/util/package.scala

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,14 @@
1010
* additional information regarding copyright ownership.
1111
*/
1212

13-
package scala
14-
package reflect
15-
package internal
16-
17-
import scala.language.existentials // scala/bug#6541
13+
package scala.reflect.internal
1814

1915
package object util {
2016

2117
// An allocation-avoiding reusable instance of the so-common List(Nil).
2218
val ListOfNil: List[List[Nothing]] = Nil :: Nil
2319
val SomeOfNil: Option[List[Nothing]] = Some(Nil)
2420

25-
def andFalse(body: Unit): Boolean = false
26-
2721
// Shorten a name like Symbols$FooSymbol to FooSymbol.
2822
private def shortenName(name: String): String = {
2923
if (name == "") return ""
@@ -45,7 +39,7 @@ package object util {
4539
if (isModule)
4640
(name split '$' filterNot (_ == "")).last + "$"
4741
else if (isAnon)
48-
clazz.getSuperclass :: clazz.getInterfaces.toList map (c => shortClass(c)) mkString " with "
42+
clazz.getInterfaces.toList.prepended(clazz.getSuperclass).map(shortClass).mkString(" with ")
4943
else
5044
shortenName(name)
5145
}

src/reflect/scala/reflect/runtime/JavaUniverseForce.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
9191
this.DiscardedValue
9292
this.DiscardedExpr
9393
this.BooleanParameterType
94+
this.RightAssociative
95+
this.RightAssociativeArg
9496
this.noPrint
9597
this.typeDebug
9698
// inaccessible: this.posAssigner

test/files/pos/t11467.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//> using options -Werror -Wunused
2+
3+
//import language.existentials
4+
5+
trait OtherType[T]
6+
case class Existensialism(field: OtherType[_])
7+
8+
class C {
9+
def f(clazz: Class[_]) = clazz.getSuperclass :: clazz.getInterfaces.toList
10+
}

test/files/pos/t1980.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// regression test from LazyListTest
2+
//
3+
class L { val ll: LazyList[Nothing] = LazyList.empty #::: ll }
4+
5+
class M {
6+
def arg: LazyList[Int] = LazyList.empty[Int]
7+
def ll: LazyList[Int] = arg #::: ll
8+
}
9+
10+
/* was
11+
private[this] val ll: scala.collection.immutable.LazyList[Nothing] = {
12+
final <synthetic> <artifact> val rassoc$1: scala.collection.immutable.LazyList[A] = LazyList.empty;
13+
immutable.this.LazyList.toDeferrer[Nothing](L.this.ll).#:::[Nothing](rassoc$1[Nothing])
14+
};
15+
*/

test/files/pos/t4518.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
import language.existentials
3+
4+
class Broke {
5+
6+
val tempval = new AnyRef {val roleA = new AnyRef with Bar}.roleA
7+
8+
new AnyRef {} -: tempval // when not assigning to anything, no problem
9+
val broke_val = new AnyRef {} -: tempval // type mismatch error only when assigning
10+
11+
trait Foo[AnyRef] { }
12+
13+
trait Bar extends Foo[AnyRef] {
14+
def -:(core: AnyRef): this.type with Foo[core.type] = throw new Exception()
15+
}
16+
}

0 commit comments

Comments
 (0)