Skip to content

Commit 38e5259

Browse files
authored
Merge pull request #7036 from dotty-staging/test-defTree
test symboo.defTree for symbols from Tasty
2 parents ed5a4d1 + 1d7e79d commit 38e5259

File tree

25 files changed

+533
-10
lines changed

25 files changed

+533
-10
lines changed

compiler/src/dotty/tools/dotc/core/Phases.scala

+4-1
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ object Phases {
354354
private[this] var myFlatClasses = false
355355
private[this] var myRefChecked = false
356356
private[this] var myLambdaLifted = false
357+
private[this] var myPatternTranslated = false
357358

358359
private[this] var mySameMembersStartId = NoPhaseId
359360
private[this] var mySameParentsStartId = NoPhaseId
@@ -372,7 +373,8 @@ object Phases {
372373
final def erasedTypes: Boolean = myErasedTypes // Phase is after erasure
373374
final def flatClasses: Boolean = myFlatClasses // Phase is after flatten
374375
final def refChecked: Boolean = myRefChecked // Phase is after RefChecks
375-
final def lambdaLifted: Boolean = myLambdaLifted // Phase is after LambdaLift
376+
final def lambdaLifted: Boolean = myLambdaLifted // Phase is after LambdaLift
377+
final def patternTranslated: Boolean = myPatternTranslated // Phase is after PatternMatcher
376378

377379
final def sameMembersStartId: Int = mySameMembersStartId
378380
// id of first phase where all symbols are guaranteed to have the same members as in this phase
@@ -391,6 +393,7 @@ object Phases {
391393
myFlatClasses = prev.getClass == classOf[Flatten] || prev.flatClasses
392394
myRefChecked = prev.getClass == classOf[RefChecks] || prev.refChecked
393395
myLambdaLifted = prev.getClass == classOf[LambdaLift] || prev.lambdaLifted
396+
myPatternTranslated = prev.getClass == classOf[PatternMatcher] || prev.patternTranslated
394397
mySameMembersStartId = if (changesMembers) id else prev.sameMembersStartId
395398
mySameParentsStartId = if (changesParents) id else prev.sameParentsStartId
396399
mySameBaseTypesStartId = if (changesBaseTypes) id else prev.sameBaseTypesStartId

compiler/src/dotty/tools/dotc/core/Symbols.scala

+5
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,11 @@ object Symbols {
540540
d != null && d.flagsUNSAFE.is(Private)
541541
}
542542

543+
/** Is the symbol a pattern bound symbol?
544+
*/
545+
final def isPatternBound(implicit ctx: Context): Boolean =
546+
!isClass && this.is(Case, butNot = Enum | Module)
547+
543548
/** The symbol's signature if it is completed or a method, NotAMethod otherwise. */
544549
final def signature(implicit ctx: Context): Signature =
545550
if (lastDenot != null && (lastDenot.isCompleted || lastDenot.is(Method)))

compiler/src/dotty/tools/dotc/plugins/Plugin.scala

+6
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ sealed trait Plugin {
2828
*
2929
* Research plugin receives a phase plan and return a new phase plan, while
3030
* non-research plugin returns a list of phases to be inserted.
31+
*
3132
*/
3233
def isResearch: Boolean = isInstanceOf[ResearchPlugin]
3334

@@ -38,6 +39,7 @@ sealed trait Plugin {
3839
val optionsHelp: Option[String] = None
3940
}
4041

42+
/** A standard plugin can be inserted into the normal compilation pipeline */
4143
trait StandardPlugin extends Plugin {
4244
/** Non-research plugins should override this method to return the phases
4345
*
@@ -47,6 +49,10 @@ trait StandardPlugin extends Plugin {
4749
def init(options: List[String]): List[PluginPhase]
4850
}
4951

52+
/** A research plugin may customize the compilation pipeline freely
53+
*
54+
* @note Research plugins are only supported by nightly or snapshot build of the compiler.
55+
*/
5056
trait ResearchPlugin extends Plugin {
5157
/** Research plugins should override this method to return the new phase plan
5258
*

compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ class ExpandSAMs extends MiniPhase {
124124
def translateMatch(tree: Match, pfParam: Symbol, cases: List[CaseDef], defaultValue: Tree)(implicit ctx: Context) = {
125125
val selector = tree.selector
126126
val selectorTpe = selector.tpe.widen
127-
val defaultSym = ctx.newSymbol(pfParam.owner, nme.WILDCARD, Synthetic, selectorTpe)
127+
val defaultSym = ctx.newSymbol(pfParam.owner, nme.WILDCARD, Synthetic | Case, selectorTpe)
128128
val defaultCase =
129129
CaseDef(
130130
Bind(defaultSym, Underscore(selectorTpe)),

compiler/src/dotty/tools/dotc/transform/LazyVals.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
336336
}
337337

338338
val retryCase = {
339-
val caseSymbol = ctx.newSymbol(methodSymbol, nme.DEFAULT_EXCEPTION_NAME, Synthetic, defn.ThrowableType)
339+
val caseSymbol = ctx.newSymbol(methodSymbol, nme.DEFAULT_EXCEPTION_NAME, Synthetic | Case, defn.ThrowableType)
340340
val triggerRetry = setFlagState.appliedTo(thiz, offset, initState, fieldId)
341341
CaseDef(
342342
Bind(caseSymbol, ref(caseSymbol)),

compiler/src/dotty/tools/dotc/transform/NonLocalReturns.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class NonLocalReturns extends MiniPhase {
6969
*/
7070
private def nonLocalReturnTry(body: Tree, key: TermSymbol, meth: Symbol)(implicit ctx: Context) = {
7171
val keyDef = ValDef(key, New(defn.ObjectType, Nil))
72-
val ex = ctx.newSymbol(meth, nme.ex, EmptyFlags, nonLocalReturnControl, coord = body.span)
72+
val ex = ctx.newSymbol(meth, nme.ex, Case, nonLocalReturnControl, coord = body.span)
7373
val pat = BindTyped(ex, nonLocalReturnControl)
7474
val rhs = If(
7575
ref(ex).select(nme.key).appliedToNone.select(nme.eq).appliedTo(ref(key)),

compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
222222
*
223223
*/
224224
def equalsBody(that: Tree)(implicit ctx: Context): Tree = {
225-
val thatAsClazz = ctx.newSymbol(ctx.owner, nme.x_0, Synthetic, clazzType, coord = ctx.owner.span) // x$0
225+
val thatAsClazz = ctx.newSymbol(ctx.owner, nme.x_0, Synthetic | Case, clazzType, coord = ctx.owner.span) // x$0
226226
def wildcardAscription(tp: Type) = Typed(Underscore(tp), TypeTree(tp))
227227
val pattern = Bind(thatAsClazz, wildcardAscription(AnnotatedType(clazzType, Annotation(defn.UncheckedAnnot)))) // x$0 @ (_: C @unchecked)
228228
// compare primitive fields first, slow equality checks of non-primitive fields can be skipped when primitives differ

compiler/src/dotty/tools/dotc/transform/TreeChecker.scala

+27-4
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ class TreeChecker extends Phase with SymTransformer {
131131
class Checker(phasesToCheck: Seq[Phase]) extends ReTyper with Checking {
132132

133133
private[this] val nowDefinedSyms = new mutable.HashSet[Symbol]
134+
private[this] val patBoundSyms = new mutable.HashSet[Symbol]
134135
private[this] val everDefinedSyms = newMutableSymbolMap[untpd.Tree]
135136

136137
// don't check value classes after typer, as the constraint about constructors doesn't hold after transform
@@ -171,10 +172,21 @@ class TreeChecker extends Phase with SymTransformer {
171172
res
172173
}
173174

175+
/** The following invariant holds:
176+
*
177+
* patBoundSyms.contains(sym) <=> sym.isPatternBound
178+
*/
174179
def withPatSyms[T](syms: List[Symbol])(op: => T)(implicit ctx: Context): T = {
175-
nowDefinedSyms ++= syms
180+
syms.foreach { sym =>
181+
assert(
182+
sym.isPatternBound,
183+
"patBoundSyms.contains(sym) => sym.isPatternBound is broken." +
184+
i" Pattern bound symbol $sym has incorrect flags: " + sym.flagsString + ", line " + sym.sourcePos.line
185+
)
186+
}
187+
patBoundSyms ++= syms
176188
val res = op
177-
nowDefinedSyms --= syms
189+
patBoundSyms --= syms
178190
res
179191
}
180192

@@ -189,8 +201,19 @@ class TreeChecker extends Phase with SymTransformer {
189201
}
190202

191203
def assertDefined(tree: untpd.Tree)(implicit ctx: Context): Unit =
192-
if (tree.symbol.maybeOwner.isTerm)
193-
assert(nowDefinedSyms contains tree.symbol, i"undefined symbol ${tree.symbol} at line " + tree.sourcePos.line)
204+
if (tree.symbol.maybeOwner.isTerm) {
205+
val sym = tree.symbol
206+
assert(
207+
nowDefinedSyms.contains(sym) || patBoundSyms.contains(sym),
208+
i"undefined symbol ${sym} at line " + tree.sourcePos.line
209+
)
210+
211+
if (!ctx.phase.patternTranslated)
212+
assert(
213+
!sym.isPatternBound || patBoundSyms.contains(sym),
214+
i"sym.isPatternBound => patBoundSyms.contains(sym) is broken, sym = $sym, line " + tree.sourcePos.line
215+
)
216+
}
194217

195218
/** assert Java classes are not used as objects */
196219
def assertIdentNotJavaClass(tree: Tree)(implicit ctx: Context): Unit = tree match {

compiler/src/dotty/tools/dotc/typer/Inliner.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
784784
* scrutinee as RHS and type that corresponds to RHS.
785785
*/
786786
def newTermBinding(sym: TermSymbol, rhs: Tree): Unit = {
787-
val copied = sym.copy(info = rhs.tpe.widenTermRefExpr, coord = sym.coord).asTerm
787+
val copied = sym.copy(info = rhs.tpe.widenTermRefExpr, coord = sym.coord, flags = sym.flags &~ Case).asTerm
788788
caseBindingMap += ((sym, ValDef(copied, constToLiteral(rhs)).withSpan(sym.span)))
789789
}
790790

compiler/test/dotty/tools/dotc/BootstrappedOnlyCompilationTests.scala

+2
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ class BootstrappedOnlyCompilationTests extends ParallelTesting {
163163
}
164164

165165
@Test def testPlugins: Unit = {
166+
implicit val testGroup: TestGroup = TestGroup("testPlugins")
166167
val pluginFile = "plugin.properties"
167168

168169
// 1. hack with absolute path for -Xplugin
@@ -183,6 +184,7 @@ class BootstrappedOnlyCompilationTests extends ParallelTesting {
183184
}
184185

185186
compileFilesInDir("tests/plugins/neg").checkExpectedErrors()
187+
compileDir("tests/plugins/custom/analyzer", withCompilerOptions.and("-Yretain-trees")).checkCompile()
186188
}
187189
}
188190

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package hello
2+
3+
import lib._
4+
5+
case class Student(name: String)
6+
7+
class M(val n: Int) {
8+
val a = 30 * n
9+
def this(c: Char) = this(c.toInt)
10+
11+
class B(x: Int) {
12+
def this(c: Char) = this(c.toInt)
13+
val b = x * a
14+
def bar(i: Int) = i * x
15+
}
16+
17+
def foo(i: Int) = i * n
18+
19+
def bar = {
20+
class C(val s: String)
21+
val c = new C("hello")
22+
def qux = c.s
23+
qux
24+
}
25+
}
26+
27+
28+
object Test {
29+
def testLib: Unit = {
30+
val a: A = new A(30)
31+
val b: a.B = new a.B(24)
32+
a.foo(3)
33+
b.bar(9)
34+
}
35+
36+
def testHello: Unit = {
37+
val a: M = new M(30)
38+
val b: a.B = new a.B(24)
39+
a.foo(3)
40+
b.bar(9)
41+
}
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
lazy val dottyVersion = sys.props("plugin.scalaVersion")
2+
3+
lazy val plugin = project
4+
.in(file("plugin"))
5+
.settings(
6+
name := "init-checker",
7+
version := "0.0.1",
8+
organization := "ch.epfl.lamp",
9+
scalaVersion := dottyVersion,
10+
11+
libraryDependencies ++= Seq(
12+
"ch.epfl.lamp" %% "dotty-compiler" % scalaVersion.value % "provided"
13+
)
14+
)
15+
16+
lazy val lib = project
17+
.in(file("lib"))
18+
.settings(
19+
scalaVersion := dottyVersion
20+
)
21+
22+
lazy val app = project
23+
.in(file("app"))
24+
.settings(
25+
scalaVersion := dottyVersion
26+
)
27+
.dependsOn(lib)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
lazy val dottyVersion = sys.props("plugin.scalaVersion")
2+
3+
lazy val plugin = project
4+
.in(file("plugin"))
5+
.settings(
6+
name := "init-checker",
7+
version := "0.0.1",
8+
organization := "ch.epfl.lamp",
9+
scalaVersion := dottyVersion,
10+
11+
libraryDependencies ++= Seq(
12+
"ch.epfl.lamp" %% "dotty-compiler" % scalaVersion.value % "provided"
13+
)
14+
)
15+
16+
lazy val lib = project
17+
.in(file("lib"))
18+
.settings(
19+
scalaVersion := dottyVersion
20+
)
21+
22+
lazy val app = project
23+
.in(file("app"))
24+
.settings(
25+
scalaVersion := dottyVersion,
26+
addCompilerPlugin("ch.epfl.lamp" %% "init-checker" % "0.0.1")
27+
)
28+
.dependsOn(lib)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
lazy val dottyVersion = sys.props("plugin.scalaVersion")
2+
3+
lazy val plugin = project
4+
.in(file("plugin"))
5+
.settings(
6+
name := "init-checker",
7+
version := "0.0.1",
8+
organization := "ch.epfl.lamp",
9+
scalaVersion := dottyVersion,
10+
11+
libraryDependencies ++= Seq(
12+
"ch.epfl.lamp" %% "dotty-compiler" % scalaVersion.value % "provided"
13+
)
14+
)
15+
16+
lazy val lib = project
17+
.in(file("lib"))
18+
.settings(
19+
scalaVersion := dottyVersion
20+
)
21+
22+
lazy val app = project
23+
.in(file("app"))
24+
.settings(
25+
scalaVersion := dottyVersion,
26+
scalacOptions += "-Yretain-trees",
27+
addCompilerPlugin("ch.epfl.lamp" %% "init-checker" % "0.0.1")
28+
)
29+
.dependsOn(lib)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package lib
2+
3+
class A(val n: Int) {
4+
def this(c: Char) = this(c.toInt)
5+
6+
val a = 30 * n
7+
8+
class B(x: Int) {
9+
def this(c: Char) = this(c.toInt)
10+
val b = x * a
11+
def bar(i: Int) = i * x
12+
}
13+
14+
def foo(i: Int) = i * n
15+
}
16+
17+
case class Product(name: String, price: Int)

0 commit comments

Comments
 (0)