Skip to content

test symboo.defTree for symbols from Tasty #7036

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Aug 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion compiler/src/dotty/tools/dotc/core/Phases.scala
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ object Phases {
private[this] var myFlatClasses = false
private[this] var myRefChecked = false
private[this] var myLambdaLifted = false
private[this] var myPatternTranslated = false

private[this] var mySameMembersStartId = NoPhaseId
private[this] var mySameParentsStartId = NoPhaseId
Expand All @@ -372,7 +373,8 @@ object Phases {
final def erasedTypes: Boolean = myErasedTypes // Phase is after erasure
final def flatClasses: Boolean = myFlatClasses // Phase is after flatten
final def refChecked: Boolean = myRefChecked // Phase is after RefChecks
final def lambdaLifted: Boolean = myLambdaLifted // Phase is after LambdaLift
final def lambdaLifted: Boolean = myLambdaLifted // Phase is after LambdaLift
final def patternTranslated: Boolean = myPatternTranslated // Phase is after PatternMatcher

final def sameMembersStartId: Int = mySameMembersStartId
// id of first phase where all symbols are guaranteed to have the same members as in this phase
Expand All @@ -391,6 +393,7 @@ object Phases {
myFlatClasses = prev.getClass == classOf[Flatten] || prev.flatClasses
myRefChecked = prev.getClass == classOf[RefChecks] || prev.refChecked
myLambdaLifted = prev.getClass == classOf[LambdaLift] || prev.lambdaLifted
myPatternTranslated = prev.getClass == classOf[PatternMatcher] || prev.patternTranslated
mySameMembersStartId = if (changesMembers) id else prev.sameMembersStartId
mySameParentsStartId = if (changesParents) id else prev.sameParentsStartId
mySameBaseTypesStartId = if (changesBaseTypes) id else prev.sameBaseTypesStartId
Expand Down
5 changes: 5 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Symbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,11 @@ object Symbols {
d != null && d.flagsUNSAFE.is(Private)
}

/** Is the symbol a pattern bound symbol?
*/
final def isPatternBound(implicit ctx: Context): Boolean =
!isClass && this.is(Case, butNot = Enum | Module)

/** The symbol's signature if it is completed or a method, NotAMethod otherwise. */
final def signature(implicit ctx: Context): Signature =
if (lastDenot != null && (lastDenot.isCompleted || lastDenot.is(Method)))
Expand Down
6 changes: 6 additions & 0 deletions compiler/src/dotty/tools/dotc/plugins/Plugin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ sealed trait Plugin {
*
* Research plugin receives a phase plan and return a new phase plan, while
* non-research plugin returns a list of phases to be inserted.
*
*/
def isResearch: Boolean = isInstanceOf[ResearchPlugin]

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

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

/** A research plugin may customize the compilation pipeline freely
*
* @note Research plugins are only supported by nightly or snapshot build of the compiler.
*/
trait ResearchPlugin extends Plugin {
/** Research plugins should override this method to return the new phase plan
*
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ class ExpandSAMs extends MiniPhase {
def translateMatch(tree: Match, pfParam: Symbol, cases: List[CaseDef], defaultValue: Tree)(implicit ctx: Context) = {
val selector = tree.selector
val selectorTpe = selector.tpe.widen
val defaultSym = ctx.newSymbol(pfParam.owner, nme.WILDCARD, Synthetic, selectorTpe)
val defaultSym = ctx.newSymbol(pfParam.owner, nme.WILDCARD, Synthetic | Case, selectorTpe)
val defaultCase =
CaseDef(
Bind(defaultSym, Underscore(selectorTpe)),
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/LazyVals.scala
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ class LazyVals extends MiniPhase with IdentityDenotTransformer {
}

val retryCase = {
val caseSymbol = ctx.newSymbol(methodSymbol, nme.DEFAULT_EXCEPTION_NAME, Synthetic, defn.ThrowableType)
val caseSymbol = ctx.newSymbol(methodSymbol, nme.DEFAULT_EXCEPTION_NAME, Synthetic | Case, defn.ThrowableType)
val triggerRetry = setFlagState.appliedTo(thiz, offset, initState, fieldId)
CaseDef(
Bind(caseSymbol, ref(caseSymbol)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class NonLocalReturns extends MiniPhase {
*/
private def nonLocalReturnTry(body: Tree, key: TermSymbol, meth: Symbol)(implicit ctx: Context) = {
val keyDef = ValDef(key, New(defn.ObjectType, Nil))
val ex = ctx.newSymbol(meth, nme.ex, EmptyFlags, nonLocalReturnControl, coord = body.span)
val ex = ctx.newSymbol(meth, nme.ex, Case, nonLocalReturnControl, coord = body.span)
val pat = BindTyped(ex, nonLocalReturnControl)
val rhs = If(
ref(ex).select(nme.key).appliedToNone.select(nme.eq).appliedTo(ref(key)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
*
*/
def equalsBody(that: Tree)(implicit ctx: Context): Tree = {
val thatAsClazz = ctx.newSymbol(ctx.owner, nme.x_0, Synthetic, clazzType, coord = ctx.owner.span) // x$0
val thatAsClazz = ctx.newSymbol(ctx.owner, nme.x_0, Synthetic | Case, clazzType, coord = ctx.owner.span) // x$0
def wildcardAscription(tp: Type) = Typed(Underscore(tp), TypeTree(tp))
val pattern = Bind(thatAsClazz, wildcardAscription(AnnotatedType(clazzType, Annotation(defn.UncheckedAnnot)))) // x$0 @ (_: C @unchecked)
// compare primitive fields first, slow equality checks of non-primitive fields can be skipped when primitives differ
Expand Down
31 changes: 27 additions & 4 deletions compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ class TreeChecker extends Phase with SymTransformer {
class Checker(phasesToCheck: Seq[Phase]) extends ReTyper with Checking {

private[this] val nowDefinedSyms = new mutable.HashSet[Symbol]
private[this] val patBoundSyms = new mutable.HashSet[Symbol]
private[this] val everDefinedSyms = newMutableSymbolMap[untpd.Tree]

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

/** The following invariant holds:
*
* patBoundSyms.contains(sym) <=> sym.isPatternBound
*/
def withPatSyms[T](syms: List[Symbol])(op: => T)(implicit ctx: Context): T = {
nowDefinedSyms ++= syms
syms.foreach { sym =>
assert(
sym.isPatternBound,
"patBoundSyms.contains(sym) => sym.isPatternBound is broken." +
i" Pattern bound symbol $sym has incorrect flags: " + sym.flagsString + ", line " + sym.sourcePos.line
)
}
patBoundSyms ++= syms
val res = op
nowDefinedSyms --= syms
patBoundSyms --= syms
res
}

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

def assertDefined(tree: untpd.Tree)(implicit ctx: Context): Unit =
if (tree.symbol.maybeOwner.isTerm)
assert(nowDefinedSyms contains tree.symbol, i"undefined symbol ${tree.symbol} at line " + tree.sourcePos.line)
if (tree.symbol.maybeOwner.isTerm) {
val sym = tree.symbol
assert(
nowDefinedSyms.contains(sym) || patBoundSyms.contains(sym),
i"undefined symbol ${sym} at line " + tree.sourcePos.line
)

if (!ctx.phase.patternTranslated)
assert(
!sym.isPatternBound || patBoundSyms.contains(sym),
i"sym.isPatternBound => patBoundSyms.contains(sym) is broken, sym = $sym, line " + tree.sourcePos.line
)
}

/** assert Java classes are not used as objects */
def assertIdentNotJavaClass(tree: Tree)(implicit ctx: Context): Unit = tree match {
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Inliner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -784,7 +784,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
* scrutinee as RHS and type that corresponds to RHS.
*/
def newTermBinding(sym: TermSymbol, rhs: Tree): Unit = {
val copied = sym.copy(info = rhs.tpe.widenTermRefExpr, coord = sym.coord).asTerm
val copied = sym.copy(info = rhs.tpe.widenTermRefExpr, coord = sym.coord, flags = sym.flags &~ Case).asTerm
caseBindingMap += ((sym, ValDef(copied, constToLiteral(rhs)).withSpan(sym.span)))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ class BootstrappedOnlyCompilationTests extends ParallelTesting {
}

@Test def testPlugins: Unit = {
implicit val testGroup: TestGroup = TestGroup("testPlugins")
val pluginFile = "plugin.properties"

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

compileFilesInDir("tests/plugins/neg").checkExpectedErrors()
compileDir("tests/plugins/custom/analyzer", withCompilerOptions.and("-Yretain-trees")).checkCompile()
}
}

Expand Down
42 changes: 42 additions & 0 deletions sbt-dotty/sbt-test/sbt-dotty/analyzer-plugin/app/Hello.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package hello

import lib._

case class Student(name: String)

class M(val n: Int) {
val a = 30 * n
def this(c: Char) = this(c.toInt)

class B(x: Int) {
def this(c: Char) = this(c.toInt)
val b = x * a
def bar(i: Int) = i * x
}

def foo(i: Int) = i * n

def bar = {
class C(val s: String)
val c = new C("hello")
def qux = c.s
qux
}
}


object Test {
def testLib: Unit = {
val a: A = new A(30)
val b: a.B = new a.B(24)
a.foo(3)
b.bar(9)
}

def testHello: Unit = {
val a: M = new M(30)
val b: a.B = new a.B(24)
a.foo(3)
b.bar(9)
}
}
27 changes: 27 additions & 0 deletions sbt-dotty/sbt-test/sbt-dotty/analyzer-plugin/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
lazy val dottyVersion = sys.props("plugin.scalaVersion")

lazy val plugin = project
.in(file("plugin"))
.settings(
name := "init-checker",
version := "0.0.1",
organization := "ch.epfl.lamp",
scalaVersion := dottyVersion,

libraryDependencies ++= Seq(
"ch.epfl.lamp" %% "dotty-compiler" % scalaVersion.value % "provided"
)
)

lazy val lib = project
.in(file("lib"))
.settings(
scalaVersion := dottyVersion
)

lazy val app = project
.in(file("app"))
.settings(
scalaVersion := dottyVersion
)
.dependsOn(lib)
28 changes: 28 additions & 0 deletions sbt-dotty/sbt-test/sbt-dotty/analyzer-plugin/changes/plugin.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
lazy val dottyVersion = sys.props("plugin.scalaVersion")

lazy val plugin = project
.in(file("plugin"))
.settings(
name := "init-checker",
version := "0.0.1",
organization := "ch.epfl.lamp",
scalaVersion := dottyVersion,

libraryDependencies ++= Seq(
"ch.epfl.lamp" %% "dotty-compiler" % scalaVersion.value % "provided"
)
)

lazy val lib = project
.in(file("lib"))
.settings(
scalaVersion := dottyVersion
)

lazy val app = project
.in(file("app"))
.settings(
scalaVersion := dottyVersion,
addCompilerPlugin("ch.epfl.lamp" %% "init-checker" % "0.0.1")
)
.dependsOn(lib)
29 changes: 29 additions & 0 deletions sbt-dotty/sbt-test/sbt-dotty/analyzer-plugin/changes/retain.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
lazy val dottyVersion = sys.props("plugin.scalaVersion")

lazy val plugin = project
.in(file("plugin"))
.settings(
name := "init-checker",
version := "0.0.1",
organization := "ch.epfl.lamp",
scalaVersion := dottyVersion,

libraryDependencies ++= Seq(
"ch.epfl.lamp" %% "dotty-compiler" % scalaVersion.value % "provided"
)
)

lazy val lib = project
.in(file("lib"))
.settings(
scalaVersion := dottyVersion
)

lazy val app = project
.in(file("app"))
.settings(
scalaVersion := dottyVersion,
scalacOptions += "-Yretain-trees",
addCompilerPlugin("ch.epfl.lamp" %% "init-checker" % "0.0.1")
)
.dependsOn(lib)
17 changes: 17 additions & 0 deletions sbt-dotty/sbt-test/sbt-dotty/analyzer-plugin/lib/Lib.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package lib

class A(val n: Int) {
def this(c: Char) = this(c.toInt)

val a = 30 * n

class B(x: Int) {
def this(c: Char) = this(c.toInt)
val b = x * a
def bar(i: Int) = i * x
}

def foo(i: Int) = i * n
}

case class Product(name: String, price: Int)
Loading