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

Skip to content

Commit 6e754c2

Browse files
som-snyttlrytz
authored andcommitted
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 1a699f4 commit 6e754c2

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
@@ -860,26 +860,19 @@ self =>
860860
}
861861
}
862862
def mkNamed(args: List[Tree]) = if (isExpr) args map treeInfo.assignmentToMaybeNamedArg else args
863-
val arguments = right match {
863+
def arguments(arg: Tree) = arg match {
864864
case Parens(Nil) => literalUnit :: Nil
865865
case Parens(args) => mkNamed(args)
866-
case _ => right :: Nil
866+
case _ => arg :: Nil
867867
}
868868
if (isExpr) {
869869
if (rightAssoc) {
870-
import symtab.Flags._
871-
val x = freshTermName(nme.RIGHT_ASSOC_OP_PREFIX)
872-
val liftedArg = atPos(left.pos) {
873-
ValDef(Modifiers(FINAL | SYNTHETIC | ARTIFACT), x, TypeTree(), stripParens(left))
874-
}
875-
Block(
876-
liftedArg :: Nil,
877-
Apply(mkSelection(right), List(Ident(x) setPos left.pos.focus)))
870+
Apply(mkSelection(right), arguments(left)).updateAttachment(RightAssociative)
878871
} else {
879-
Apply(mkSelection(left), arguments)
872+
Apply(mkSelection(left), arguments(right))
880873
}
881874
} else {
882-
Apply(Ident(op.encode), stripParens(left) :: arguments)
875+
Apply(Ident(op.encode), stripParens(left) :: arguments(right))
883876
}
884877
}
885878

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

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

4848
final val shortenImports = false
4949

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

@@ -2164,10 +2157,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
21642157
} else tpt1.tpe
21652158
transformedOrTyped(vdef.rhs, EXPRmode | BYVALmode, tpt2)
21662159
}
2167-
val vdef1 = treeCopy.ValDef(vdef, typedMods, sym.name, tpt1, checkDead(context, rhs1)) setType NoType
2168-
if (sym.isSynthetic && sym.name.startsWith(nme.RIGHT_ASSOC_OP_PREFIX))
2169-
rightAssocValDefs += ((sym, vdef1.rhs))
2170-
vdef1
2160+
treeCopy.ValDef(vdef, typedMods, sym.name, tpt1, checkDead(context, rhs1)) setType NoType
21712161
}
21722162

21732163
/** Analyze the super constructor call to record information used later to compute parameter aliases */
@@ -2587,13 +2577,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
25872577
if (isMultiline && settings.warnByNameImplicit) checkImplicitlyAdaptedBlockResult(expr1)
25882578
}
25892579

2590-
// Remove ValDef for right-associative by-value operator desugaring which has been inlined into expr1
2591-
val statsTyped2 = statsTyped match {
2592-
case (vd: ValDef) :: Nil if inlinedRightAssocValDefs.remove(vd.symbol) => Nil
2593-
case _ => statsTyped
2594-
}
2595-
2596-
treeCopy.Block(block, statsTyped2, expr1)
2580+
treeCopy.Block(block, statsTyped, expr1)
25972581
.setType(if (treeInfo.isExprSafeToInline(block)) expr1.tpe else expr1.tpe.deconst)
25982582
} finally {
25992583
// enable escaping privates checking from the outside and recycle
@@ -3778,29 +3762,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
37783762
case _ => tp
37793763
}
37803764

3781-
// Inline RHS of ValDef for right-associative by-value operator desugaring.
3782-
// Remove the ValDef also if the argument is a constant-folded reference to it.
37833765
var (args2, pos2) = (args1, tree.pos)
3784-
args1 match {
3785-
case List(lit: Literal) =>
3786-
lit.attachments.get[OriginalTreeAttachment] match {
3787-
case Some(OriginalTreeAttachment(id: Ident)) if rightAssocValDefs.contains(id.symbol) =>
3788-
inlinedRightAssocValDefs += id.symbol
3789-
rightAssocValDefs.remove(id.symbol)
3790-
case _ =>
3791-
}
3792-
3793-
case List(id: Ident) if rightAssocValDefs.contains(id.symbol) =>
3794-
mt.params match {
3795-
case List(p) if p.isByNameParam =>
3796-
inlinedRightAssocValDefs += id.symbol
3797-
val rhs = rightAssocValDefs.remove(id.symbol).get
3798-
args2 = rhs.changeOwner(id.symbol -> context.owner) :: Nil
3799-
pos2 = wrappingPos(tree :: rhs :: Nil)
3800-
case _ =>
3801-
}
3802-
case _ =>
3803-
}
38043766

38053767
if (args.isEmpty && canTranslateEmptyListToNil && fun.symbol.isInitialized && currentRun.runDefinitions.isListApply(fun))
38063768
atPos(tree.pos)(gen.mkNil setType restpe)
@@ -5028,7 +4990,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
50284990
}
50294991
}
50304992

5031-
def typedApply(tree: Apply) = tree match {
4993+
def typedApply(tree: Apply): Tree = tree match {
50324994
case Apply(Block(stats, expr), args) =>
50334995
typed1(atPos(tree.pos)(Block(stats, Apply(expr, args) setPos tree.pos.makeTransparent)), mode, pt)
50344996
case Apply(fun, args) =>
@@ -5052,7 +5014,24 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
50525014
// The enclosing context may be case c @ C(_) => or val c @ C(_) = v.
50535015
tree1 modifyType (_.finalResultType)
50545016
tree1
5055-
case tree1 => tree1
5017+
case tree1 @ Apply(fun1, arg1 :: Nil) if tree.hasAttachment[RightAssociative.type] =>
5018+
fun1.tpe match {
5019+
// fix evaluation order of `x op_: y` if necessary to `{ val tmp = x ; y.op_:(tmp) }`
5020+
case MethodType(p :: Nil, _) if !tree1.isErroneous && !p.isByNameParam && (!treeInfo.isStableIdentifier(arg1, allowVolatile = false) || !treeInfo.isExprSafeToInline(arg1)) =>
5021+
import symtab.Flags._
5022+
val tmp = freshTermName(nme.RIGHT_ASSOC_OP_PREFIX)
5023+
val valSym = context.owner.newValue(tmp, arg1.pos.focus, FINAL | SYNTHETIC | ARTIFACT)
5024+
val rhs = arg1.changeOwner(context.owner -> valSym)
5025+
valSym.setInfo(rhs.tpe)
5026+
val liftedArg = atPos(arg1.pos) { ValDef(valSym, rhs) }
5027+
val blk = Block(
5028+
liftedArg :: Nil,
5029+
treeCopy.Apply(tree1, fun1, List(Ident(valSym) setPos arg1.pos.focus)).clearType()
5030+
)
5031+
typed(blk, mode, pt)
5032+
case _ => tree1
5033+
}
5034+
case tree1 => tree1
50565035
}
50575036
}
50585037

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

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

121121
case object ConstructorNeedsFence extends PlainAttachment
122+
123+
/** Apply is right associative. */
124+
case object RightAssociative extends PlainAttachment
122125
}

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)