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

Skip to content

Commit ff38712

Browse files
committed
Simplify right-associative rewrite
Defer any rewriting from parser to typedApply. The application is typechecked in the normal way and evaluation order rejiggered after. In particular, there is no need to re-typecheck after re-inlining, for more precise types.
1 parent e884497 commit ff38712

File tree

9 files changed

+68
-82
lines changed

9 files changed

+68
-82
lines changed

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

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -867,26 +867,19 @@ self =>
867867
}
868868
}
869869
def mkNamed(args: List[Tree]) = if (isExpr) args map treeInfo.assignmentToMaybeNamedArg else args
870-
val arguments = right match {
870+
def arguments(arg: Tree) = arg match {
871871
case Parens(Nil) => Literal(Constant(())) :: Nil
872872
case Parens(args) => mkNamed(args)
873-
case _ => right :: Nil
873+
case _ => arg :: Nil
874874
}
875875
if (isExpr) {
876876
if (rightAssoc) {
877-
import symtab.Flags._
878-
val x = freshTermName(nme.RIGHT_ASSOC_OP_PREFIX)
879-
val liftedArg = atPos(left.pos) {
880-
ValDef(Modifiers(FINAL | SYNTHETIC | ARTIFACT), x, TypeTree(), stripParens(left))
881-
}
882-
Block(
883-
liftedArg :: Nil,
884-
Apply(mkSelection(right), List(Ident(x) setPos left.pos.focus)))
877+
Apply(mkSelection(right), arguments(left)).updateAttachment(RightAssociative)
885878
} else {
886-
Apply(mkSelection(left), arguments)
879+
Apply(mkSelection(left), arguments(right))
887880
}
888881
} else {
889-
Apply(Ident(op.encode), stripParens(left) :: arguments)
882+
Apply(Ident(op.encode), stripParens(left) :: arguments(right))
890883
}
891884
}
892885

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

Lines changed: 21 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,6 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
4646

4747
final val shortenImports = false
4848

49-
// All typechecked RHS of ValDefs for right-associative operator desugaring
50-
private val rightAssocValDefs = new mutable.AnyRefMap[Symbol, Tree]
51-
// Symbols of ValDefs for right-associative operator desugaring which are passed by name and have been inlined
52-
private val inlinedRightAssocValDefs = new mutable.HashSet[Symbol]
53-
5449
// For each class, we collect a mapping from constructor param accessors that are aliases of their superclass
5550
// param accessors. At the end of the typer phase, when this information is available all the way up the superclass
5651
// chain, this is used to determine which are true aliases, ones where the field can be elided from this class.
@@ -66,8 +61,6 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
6661
resetContexts()
6762
resetImplicits()
6863
resetDocComments()
69-
rightAssocValDefs.clear()
70-
inlinedRightAssocValDefs.clear()
7164
superConstructorCalls.clear()
7265
}
7366

@@ -2143,10 +2136,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
21432136
} else tpt1.tpe
21442137
transformedOrTyped(vdef.rhs, EXPRmode | BYVALmode, tpt2)
21452138
}
2146-
val vdef1 = treeCopy.ValDef(vdef, typedMods, sym.name, tpt1, checkDead(context, rhs1)) setType NoType
2147-
if (sym.isSynthetic && sym.name.startsWith(nme.RIGHT_ASSOC_OP_PREFIX))
2148-
rightAssocValDefs += ((sym, vdef1.rhs))
2149-
vdef1
2139+
treeCopy.ValDef(vdef, typedMods, sym.name, tpt1, checkDead(context, rhs1)) setType NoType
21502140
}
21512141

21522142
/** Analyze the super constructor call to record information used later to compute parameter aliases */
@@ -2559,13 +2549,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
25592549
if (result0.nonEmpty) checkPure(result0, supple = true)
25602550
}
25612551

2562-
// Remove ValDef for right-associative by-value operator desugaring which has been inlined into expr1
2563-
val statsTyped2 = statsTyped match {
2564-
case (vd: ValDef) :: Nil if inlinedRightAssocValDefs.remove(vd.symbol) => Nil
2565-
case _ => statsTyped
2566-
}
2567-
2568-
treeCopy.Block(block, statsTyped2, expr1)
2552+
treeCopy.Block(block, statsTyped, expr1)
25692553
.setType(if (treeInfo.isExprSafeToInline(block)) expr1.tpe else expr1.tpe.deconst)
25702554
} finally {
25712555
// enable escaping privates checking from the outside and recycle
@@ -3727,29 +3711,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
37273711
case _ => tp
37283712
}
37293713

3730-
// Inline RHS of ValDef for right-associative by-value operator desugaring.
3731-
// Remove the ValDef also if the argument is a constant-folded reference to it.
37323714
var (args2, pos2) = (args1, tree.pos)
3733-
args1 match {
3734-
case List(lit: Literal) =>
3735-
lit.attachments.get[OriginalTreeAttachment] match {
3736-
case Some(OriginalTreeAttachment(id: Ident)) if rightAssocValDefs.contains(id.symbol) =>
3737-
inlinedRightAssocValDefs += id.symbol
3738-
rightAssocValDefs.remove(id.symbol)
3739-
case _ =>
3740-
}
3741-
3742-
case List(id: Ident) if rightAssocValDefs.contains(id.symbol) =>
3743-
mt.params match {
3744-
case List(p) if p.isByNameParam =>
3745-
inlinedRightAssocValDefs += id.symbol
3746-
val rhs = rightAssocValDefs.remove(id.symbol).get
3747-
args2 = rhs.changeOwner(id.symbol -> context.owner) :: Nil
3748-
pos2 = wrappingPos(tree :: rhs :: Nil)
3749-
case _ =>
3750-
}
3751-
case _ =>
3752-
}
37533715

37543716
if (args.isEmpty && canTranslateEmptyListToNil && fun.symbol.isInitialized && currentRun.runDefinitions.isListApply(fun))
37553717
atPos(tree.pos)(gen.mkNil setType restpe)
@@ -4928,7 +4890,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
49284890
}
49294891
}
49304892

4931-
def typedApply(tree: Apply) = tree match {
4893+
def typedApply(tree: Apply): Tree = tree match {
49324894
case Apply(Block(stats, expr), args) =>
49334895
typed1(atPos(tree.pos)(Block(stats, Apply(expr, args) setPos tree.pos.makeTransparent)), mode, pt)
49344896
case Apply(fun, args) =>
@@ -4952,7 +4914,24 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
49524914
// The enclosing context may be case c @ C(_) => or val c @ C(_) = v.
49534915
tree1 modifyType (_.finalResultType)
49544916
tree1
4955-
case tree1 => tree1
4917+
case tree1 @ Apply(fun1, arg1 :: Nil) if tree.hasAttachment[RightAssociative.type] =>
4918+
fun1.tpe match {
4919+
// fix evaluation order of `x op_: y` if necessary to `{ val tmp = x ; y.op_:(tmp) }`
4920+
case MethodType(p :: Nil, _) if !tree1.isErroneous && !p.isByNameParam && (!treeInfo.isStableIdentifier(arg1, allowVolatile = false) || !treeInfo.isExprSafeToInline(arg1)) =>
4921+
import symtab.Flags._
4922+
val tmp = freshTermName(nme.RIGHT_ASSOC_OP_PREFIX)
4923+
val valSym = context.owner.newValue(tmp, arg1.pos.focus, FINAL | SYNTHETIC | ARTIFACT)
4924+
val rhs = arg1.changeOwner(context.owner -> valSym)
4925+
valSym.setInfo(rhs.tpe)
4926+
val liftedArg = atPos(arg1.pos) { ValDef(valSym, rhs) }
4927+
val blk = Block(
4928+
liftedArg :: Nil,
4929+
treeCopy.Apply(tree1, fun1, List(Ident(valSym) setPos arg1.pos.focus)).clearType()
4930+
)
4931+
typed(blk, mode, pt)
4932+
case _ => tree1
4933+
}
4934+
case tree1 => tree1
49564935
}
49574936
}
49584937

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,4 +121,7 @@ trait StdAttachments {
121121
class QualTypeSymAttachment(val sym: Symbol)
122122

123123
case object ConstructorNeedsFence extends PlainAttachment
124+
125+
/** Apply is right associative. */
126+
case object RightAssociative extends PlainAttachment
124127
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
6464
this.TypeParamVarargsAttachment
6565
this.KnownDirectSubclassesCalled
6666
this.ConstructorNeedsFence
67+
this.RightAssociative
6768
this.noPrint
6869
this.typeDebug
6970
// inaccessible: this.posAssigner

test/files/pos/t5073.scala

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
2+
trait Test {
3+
4+
trait T[A]
5+
6+
class C {
7+
def -:(x: AnyRef): T[x.type] = ???
8+
def +:(x: AnyRef)(i: Int): T[x.type] = ???
9+
}
10+
11+
val c = new C
12+
val x: AnyRef = ???
13+
14+
def ok: T[x.type] = c.-:(x)
15+
def no: T[x.type] = x -: c
16+
17+
def ok2: (Int => T[x.type]) = c.+:(x) _
18+
def no2: (Int => T[x.type]) = (x +: c) _
19+
def no3: (Int => T[x.type]) = (x +: c)(_)
20+
}

test/files/pos/tcpoly_ticket2096.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,19 @@ trait MBraceSeq[C[X] <: MBrace[C,X] with Seq[X],A] extends MBrace[C,A]
1111
case class MSequitor[A]( a_ : A* ) extends Seq[A] with MBrace[MSequitor,A]
1212
{
1313
override def nest( a : A ) = new MSequitor[A]( a )
14+
// temporary workaround
15+
override def flatten[T <: MSequitor[MSequitor[A]]]( bsq : T ) : MSequitor[A] = {
16+
bsq.foldLeft(new MSequitor[A]())(
17+
( acc : MSequitor[A], e : MSequitor[A] ) => ( acc ++ e ).asInstanceOf[MSequitor[A]]
18+
)
19+
}
20+
/*
1421
override def flatten[T <: MSequitor[MSequitor[A]]]( bsq : T ) : MSequitor[A] = {
1522
(new MSequitor[A]( ) /: bsq)( {
1623
( acc : MSequitor[A], e : MSequitor[A] ) => ( acc ++ e ).asInstanceOf[MSequitor[A]]
1724
} )
1825
}
26+
*/
1927
override def length = a_.length
2028
override def iterator = a_.iterator
2129
override def apply( n : Int ) = a_.apply( n )

test/files/run/t10751.check

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,14 @@
66
[12]()
77
};
88
[20:43]private[this] val n: [38]Int = [42:43]1;
9-
[51:60]{
10-
[53:60]<53:60><53:60>C.foo_:[[53]Nothing]([51]1)
11-
};
12-
[67:81]{
13-
[69:81]<69:81><69:81>C.foo_:[[75:78]<type: [75:78]scala.Any>]([67]1)
14-
};
15-
[89:98]{
16-
[89:98]<91:98><91:98>C.foo_:[[91]Nothing]([89:90][89]Test.this.n)
17-
};
18-
[105:119]{
19-
[105:119]<107:119><107:119>C.foo_:[[113:116]<type: [113:116]scala.Any>]([105:106][105]Test.this.n)
20-
};
21-
[127:136]{
22-
[129:136]<129:136><129:136>C.bar_:[[129]Nothing]([127]1)
23-
};
24-
[143:157]{
25-
[145:157]<145:157><145:157>C.bar_:[[151:154]<type: [151:154]scala.Any>]([143]1)
26-
};
27-
[165:174]{
28-
[165:166]final <synthetic> <artifact> val rassoc$7: [165]Int = [165:166][165]Test.this.n;
29-
[167:174]<167:174><167:174>C.bar_:[[167]Nothing]([165]rassoc$7)
30-
};
31-
[181:195]{
32-
[181:182]final <synthetic> <artifact> val rassoc$8: [181]Int = [181:182][181]Test.this.n;
33-
[183:195]<183:195><183:195>C.bar_:[[189:192]<type: [189:192]scala.Any>]([181]rassoc$8)
34-
}
9+
[51:60]<53:60><53:60>C.foo_:[[53]Nothing]([51:52]1);
10+
[67:81]<69:81><69:81>C.foo_:[[75:78]<type: [75:78]scala.Any>]([67:68]1);
11+
[89:98]<91:98><91:98>C.foo_:[[91]Nothing]([89:90][89]Test.this.n);
12+
[105:119]<107:119><107:119>C.foo_:[[113:116]<type: [113:116]scala.Any>]([105:106][105]Test.this.n);
13+
[127:136]<129:136><129:136>C.bar_:[[129]Nothing]([127:128]1);
14+
[143:157]<145:157><145:157>C.bar_:[[151:154]<type: [151:154]scala.Any>]([143:144]1);
15+
[165:174]<167:174><167:174>C.bar_:[[167]Nothing]([165:166][165]Test.this.n);
16+
[181:195]<183:195><183:195>C.bar_:[[189:192]<type: [189:192]scala.Any>]([181:182][181]Test.this.n)
3517
}
3618
}
3719

test/files/run/t4225e.check

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
t4225e.scala:12: warning: a pure expression does nothing in statement position; multiline expressions might require enclosing parentheses
22
def andThen_:(b : Bar) = { println("pre") ; b ; println("post") }
33
^
4+
foo
45
bar
56
foo
67
pre
@@ -11,9 +12,9 @@ bar
1112
pre
1213
post
1314

14-
bar
1515
foo
1616
pre
17+
bar
1718
post
1819

1920
foo

test/files/run/t4225e.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ object Test extends App {
2424

2525
println
2626

27-
// bar should be deferred but isn't due to scala/bug#10693
2827
mkBarString andThenByName_: mkFoo
2928

3029
println

0 commit comments

Comments
 (0)