Skip to content

Commit 0a05275

Browse files
authored
Merge pull request #3925 from dotty-staging/fix-3917
Fix #3917: Properly desugar `Ident`
2 parents e4c376e + 2d71030 commit 0a05275

File tree

9 files changed

+74
-71
lines changed

9 files changed

+74
-71
lines changed

compiler/sjs/backend/sjs/JSCodeGen.scala

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -793,7 +793,7 @@ class JSCodeGen()(implicit ctx: Context) {
793793
throw new FatalError(s"Assignment to static member ${sym.fullName} not supported")
794794
val genRhs = genExpr(rhs)
795795
val lhs = lhs0 match {
796-
case lhs: Ident => desugarIdent(lhs).getOrElse(lhs)
796+
case lhs: Ident => desugarIdent(lhs)
797797
case lhs => lhs
798798
}
799799
lhs match {
@@ -850,21 +850,6 @@ class JSCodeGen()(implicit ctx: Context) {
850850
}
851851
} // end of genStatOrExpr()
852852

853-
// !!! DUPLICATE code with DottyBackendInterface
854-
private def desugarIdent(i: Ident): Option[Select] = {
855-
i.tpe match {
856-
case TermRef(prefix: TermRef, name) =>
857-
Some(tpd.ref(prefix).select(i.symbol))
858-
case TermRef(prefix: ThisType, name) =>
859-
Some(tpd.This(prefix.cls).select(i.symbol))
860-
/*case TermRef(NoPrefix, name) =>
861-
if (i.symbol is Method) Some(This(i.symbol.topLevelClass).select(i.symbol)) // workaround #342 todo: remove after fixed
862-
else None*/
863-
case _ =>
864-
None
865-
}
866-
}
867-
868853
private def qualifierOf(fun: Tree): Tree = fun match {
869854
case fun: Ident =>
870855
fun.tpe match {
@@ -907,7 +892,7 @@ class JSCodeGen()(implicit ctx: Context) {
907892
val sym = tree.fun.symbol
908893

909894
val fun = tree.fun match {
910-
case fun: Ident => desugarIdent(fun).getOrElse(fun)
895+
case fun: Ident => desugarIdent(fun)
911896
case fun => fun
912897
}
913898

@@ -1571,7 +1556,7 @@ class JSCodeGen()(implicit ctx: Context) {
15711556
implicit val pos = tree.pos
15721557

15731558
val fun = tree.fun match {
1574-
case fun: Ident => desugarIdent(fun).get
1559+
case fun: Ident => desugarIdent(fun).asInstanceOf[Select]
15751560
case fun: Select => fun
15761561
}
15771562
val receiver = fun.qualifier

compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -444,16 +444,12 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
444444
def desugarIdent(i: Ident): Option[tpd.Select] = {
445445
var found = desugared.get(i.tpe)
446446
if (found == null) {
447-
i.tpe match {
448-
case TermRef(prefix: TermRef, _) =>
449-
found = tpd.ref(prefix).select(i.symbol)
450-
case TermRef(prefix: ThisType, _) =>
451-
found = tpd.This(prefix.cls).select(i.symbol)
452-
case TermRef(NoPrefix, _) =>
453-
if (i.symbol is Flags.Method) found = This(i.symbol.topLevelClass).select(i.symbol) // workaround #342 todo: remove after fixed
447+
tpd.desugarIdent(i) match {
448+
case sel: tpd.Select =>
449+
desugared.put(i.tpe, sel)
450+
found = sel
454451
case _ =>
455452
}
456-
if (found != null) desugared.put(i.tpe, found)
457453
}
458454
if (found == null) None else Some(found)
459455
}

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -826,14 +826,13 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
826826
*/
827827
def becomes(rhs: Tree)(implicit ctx: Context): Tree =
828828
if (tree.symbol is Method) {
829-
val setr = tree match {
830-
case Ident(_) =>
831-
val setter = tree.symbol.setter
832-
assert(setter.exists, tree.symbol.showLocated)
833-
ref(tree.symbol.setter)
834-
case Select(qual, _) => qual.select(tree.symbol.setter)
829+
val setter = tree.symbol.setter
830+
assert(setter.exists, tree.symbol.showLocated)
831+
val qual = tree match {
832+
case id: Ident => desugarIdentPrefix(id)
833+
case Select(qual, _) => qual
835834
}
836-
setr.appliedTo(rhs)
835+
qual.select(setter).appliedTo(rhs)
837836
}
838837
else Assign(tree, rhs)
839838

@@ -1012,5 +1011,22 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
10121011
val encoding = ctx.settings.encoding.value
10131012
if (file != null && file.exists) new SourceFile(file, Codec(encoding)) else NoSource
10141013
}
1014+
1015+
/** Desugar identifier into a select node. Return the tree itself if not possible */
1016+
def desugarIdent(tree: Ident)(implicit ctx: Context): Tree = {
1017+
val qual = desugarIdentPrefix(tree)
1018+
if (qual.isEmpty) tree
1019+
else qual.select(tree.symbol)
1020+
}
1021+
1022+
/** Recover identifier prefix (e.g. this) if it exists */
1023+
def desugarIdentPrefix(tree: Ident)(implicit ctx: Context): Tree = tree.tpe match {
1024+
case TermRef(prefix: TermRef, _) =>
1025+
ref(prefix)
1026+
case TermRef(prefix: ThisType, _) =>
1027+
This(prefix.cls)
1028+
case _ =>
1029+
EmptyTree
1030+
}
10151031
}
10161032

compiler/src/dotty/tools/dotc/transform/localopt/ConstantFold.scala

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import core.Symbols._
66
import core.Types._
77
import typer.ConstFold
88
import ast.Trees._
9-
import Simplify.desugarIdent
109

1110
/** Various constant folding.
1211
*
@@ -182,22 +181,19 @@ import Simplify.desugarIdent
182181
case _ => false
183182
}
184183
case t1: Ident =>
185-
desugarIdent(t1) match {
186-
case Some(t) =>
187-
val t2i = t2 match {
188-
case t2: Ident => desugarIdent(t2).getOrElse(t2)
189-
case _ => t2
190-
}
191-
isSimilar(t, t2i)
192-
case None => t1.symbol eq t2.symbol
184+
t2 match {
185+
case t2: Ident =>
186+
t1.symbol eq t2.symbol
187+
case _ => // Select
188+
isSimilar(t2, t1)
193189
}
194190
case t1: Select => t2 match {
195191
case t2: Select =>
196192
(t1.symbol eq t2.symbol) &&
197193
isSimilar(t1.qualifier, t2.qualifier)
198194
case t2: Ident => desugarIdent(t2) match {
199-
case Some(t2) => isSimilar(t1, t2)
200-
case None => false
195+
case t2: Select => isSimilar(t1, t2)
196+
case _ => false
201197
}
202198
case _ => false
203199
}

compiler/src/dotty/tools/dotc/transform/localopt/Devalify.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ class Devalify extends Optimisation {
194194
readingOnlyVals(qual)
195195

196196
case t: Ident if !t.symbol.is(Mutable | Method) && !t.symbol.info.dealias.isInstanceOf[ExprType] =>
197-
desugarIdent(t).forall(readingOnlyVals)
197+
desugarIdent(t) match { case s: Select => readingOnlyVals(s); case _ => true }
198198

199199
case t: This => true
200200
// null => false, or the following fails devalify:

compiler/src/dotty/tools/dotc/transform/localopt/DropNoEffects.scala

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,9 @@ class DropNoEffects(val simplifyPhase: Simplify) extends Optimisation {
100100
cpy.Block(bl)(stats2, expr2)
101101

102102
case t: Ident if !t.symbol.is(Method | Lazy) && !t.symbol.info.isInstanceOf[ExprType] || effectsDontEscape(t) =>
103-
desugarIdent(t) match {
104-
case Some(t) if !(t.qualifier.symbol.is(JavaDefined) && t.qualifier.symbol.is(Package)) => t
105-
case _ => EmptyTree
106-
}
103+
val prefix = desugarIdentPrefix(t)
104+
if (!prefix.isEmpty && !prefix.symbol.is(allOf(JavaDefined, Package))) t
105+
else EmptyTree
107106

108107
case app: Apply if app.fun.symbol.is(Label) && !app.tpe.finalResultType.derivesFrom(defn.UnitClass) =>
109108
// This is "the scary hack". It changes the return type to Unit, then

compiler/src/dotty/tools/dotc/transform/localopt/InlineCaseIntrinsics.scala

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import core.Flags._
1010
import core.TypeApplications.noBounds
1111
import ast.Trees._
1212
import transform.SymUtils._
13-
import Simplify.desugarIdent
1413
import dotty.tools.dotc.ast.tpd
1514

1615
/** Inline case class specific methods using desugarings assumptions.
@@ -109,10 +108,9 @@ class InlineCaseIntrinsics(val simplifyPhase: Simplify) extends Optimisation {
109108
def receiver(t: Tree): Type = t match {
110109
case t: Apply => receiver(t.fun)
111110
case t: TypeApply => receiver(t.fun)
112-
case t: Ident => desugarIdent(t) match {
113-
case Some(t) => receiver(t)
114-
case _ => NoType
115-
}
111+
case t: Ident =>
112+
val prefix = desugarIdentPrefix(t)
113+
prefix.tpe.widenDealias
116114
case t: Select => t.qualifier.tpe.widenDealias
117115
}
118116

compiler/src/dotty/tools/dotc/transform/localopt/Simplify.scala

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -149,29 +149,15 @@ class Simplify extends MiniPhase with IdentityDenotTransformer {
149149

150150
object Simplify {
151151
import tpd._
152-
// TODO: This function is duplicated in jvm/DottyBackendInterface.scala, let's factor these out!
153-
def desugarIdent(i: Ident)(implicit ctx: Context): Option[Select] = {
154-
i.tpe match {
155-
case TermRef(prefix: TermRef, _) =>
156-
Some(ref(prefix).select(i.symbol))
157-
case TermRef(prefix: ThisType, _) =>
158-
Some(This(prefix.cls).select(i.symbol))
159-
case _ => None
160-
}
161-
}
162152

163153
/** Is this tree mutable, or java.lang.System.{in, out, err}? These three
164154
* System members are the only static final fields that are mutable.
165155
* See https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.5.4
166156
*/
167-
@tailrec def isEffectivelyMutable(t: Tree)(implicit ctx: Context): Boolean = t match {
157+
def isEffectivelyMutable(t: Tree)(implicit ctx: Context): Boolean = t match {
168158
case _ if t.symbol.is(Mutable) => true
169-
case s: Select => s.symbol.owner == defn.SystemModule
170-
case i: Ident =>
171-
desugarIdent(i) match {
172-
case Some(ident) => isEffectivelyMutable(ident)
173-
case None => false
174-
}
159+
case _: Select | _: Ident =>
160+
t.symbol.owner == defn.SystemModule
175161
case _ => false
176162
}
177163

tests/pos/i3917.scala

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
class A {
2+
var a = false
3+
}
4+
5+
object B {
6+
var b = false
7+
}
8+
9+
class C {
10+
var c = false
11+
}
12+
13+
object C extends A {
14+
def test = {
15+
a = true
16+
C.a = true
17+
this.a = true
18+
C.this.a = true
19+
20+
import B._
21+
b = true
22+
23+
val c0 = new C
24+
import c0._
25+
c = true
26+
}
27+
}

0 commit comments

Comments
 (0)