Skip to content

Transform/refchecks #163

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 35 commits into from
Oct 11, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
2020938
Code to handle overloaded unapply/unapplySeq methods
odersky Aug 3, 2014
168e4f1
Added version settings -migration, -source
odersky Aug 3, 2014
e25232d
Annotation decorators for symbols
odersky Aug 3, 2014
85044e4
Type#foreachPart
odersky Aug 3, 2014
9748c9b
Changed first phase normalization and improvements to TreeTransform
odersky Aug 3, 2014
f87153b
Detect cycles and protected legal ones with LazyRefs
odersky Aug 7, 2014
058729c
LazyRefs break cycles for unpickled types
odersky Aug 8, 2014
19b6a04
Re-enabled checkbounds tests
odersky Aug 8, 2014
9ec3a4f
prepareStats should span all statement transforms
odersky Aug 9, 2014
978a714
Initial version of RefChecks
odersky Aug 9, 2014
80ee8b1
Made Phase a trait
odersky Aug 9, 2014
bb1972b
Fixed fully qualified name of migration annotation
odersky Aug 9, 2014
9024f25
ParamAccessors are assumed to have definition
odersky Aug 9, 2014
57c6c85
Disentangle phases from treetransforms
odersky Aug 9, 2014
96cd350
Module vals are lazy
odersky Aug 9, 2014
80b866f
In refined printer, show only source modifier flags.
odersky Aug 9, 2014
bbf777a
Narrow assertion for Scope#enter
odersky Aug 9, 2014
c2cdd3a
More targeted eta-lifting
odersky Aug 10, 2014
f606a47
Add Product{1,2} supertrait to case classes
odersky Aug 10, 2014
d388e94
Fix Object's scope after ersure
odersky Aug 11, 2014
b89c4af
Add CaseAccessor flag for case accessors
odersky Aug 11, 2014
c7f817f
Added some more methods as infix tree operations:
odersky Aug 11, 2014
98d2583
New methods in Definitions
odersky Aug 11, 2014
ab63413
Sperate matchingDecl and mathingMember.
odersky Aug 11, 2014
ce53589
Add SyntheticMethods miniphase
odersky Aug 11, 2014
974f706
Avoid printing expanded names
odersky Aug 11, 2014
a3cc938
Use _1 intstead of get for accessing unary case class parameters
odersky Aug 11, 2014
81745e2
Fix a problem due to different type inference
odersky Aug 12, 2014
843f976
Two fixes in desugar
odersky Aug 12, 2014
472d711
Add matchesLoosely
odersky Aug 12, 2014
ab8ee53
mergeDenot should prefer concerete over deferred.
odersky Aug 12, 2014
deaa0d8
Package denotations are never transformed
odersky Aug 13, 2014
ece7656
Erasure should copy denotations only if they are changed.
odersky Aug 13, 2014
3558e07
Change access boundary of protected[this]
odersky Aug 13, 2014
34f73de
Fix and enable RefChecks
odersky Aug 13, 2014
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
10 changes: 5 additions & 5 deletions src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Contexts._
import Periods._
import Symbols._
import Scopes._
import typer.{FrontEnd, Typer, Mode, ImportInfo}
import typer.{FrontEnd, Typer, Mode, ImportInfo, RefChecks}
import reporting.ConsoleReporter
import dotty.tools.dotc.core.Phases.Phase
import dotty.tools.dotc.transform._
Expand All @@ -19,14 +19,14 @@ class Compiler {
def phases: List[List[Phase]] =
List(
List(new FrontEnd),
List(new Companions),
List(new FirstTransform, new SyntheticMethods),
List(new SuperAccessors),
// pickling and refchecks goes here
List(new ElimRepeated, new ElimLocals),
// pickling goes here
List(new RefChecks, new ElimRepeated, new ElimLocals),
List(new ExtensionMethods),
List(new TailRec),
List(new PatternMatcher,
new LazyValTranformContext().transformer,
// new LazyValTranformContext().transformer, // disabled, awaiting fixes
new Splitter),
List(new Nullarify,
new TypeTestsCasts,
Expand Down
4 changes: 2 additions & 2 deletions src/dotty/tools/dotc/ElimLocals.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import DenotTransformers.SymTransformer
import Phases.Phase
import Contexts.Context
import SymDenotations.SymDenotation
import TreeTransforms.TreeTransform
import TreeTransforms.MiniPhaseTransform
import Flags.Local

/** Widens all private[this] and protected[this] qualifiers to just private/protected */
class ElimLocals extends TreeTransform with SymTransformer { thisTransformer =>
class ElimLocals extends MiniPhaseTransform with SymTransformer { thisTransformer =>
override def name = "elimlocals"

def transformSym(ref: SymDenotation)(implicit ctx: Context) =
Expand Down
17 changes: 9 additions & 8 deletions src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -288,11 +288,9 @@ object desugar {
DefDef(synthetic, name, Nil, Nil, TypeTree(), rhs)
val isDefinedMeth = syntheticProperty(nme.isDefined, Literal(Constant(true)))
val productArityMeth = syntheticProperty(nme.productArity, Literal(Constant(arity)))
def selectorName(n: Int) =
if (arity == 1) nme.get else nme.selectorName(n)
val caseParams = constrVparamss.head.toArray
val productElemMeths = for (i <- 0 until arity) yield
syntheticProperty(selectorName(i), Select(This(EmptyTypeName), caseParams(i).name))
syntheticProperty(nme.selectorName(i), Select(This(EmptyTypeName), caseParams(i).name))
val copyMeths =
if (mods is Abstract) Nil
else {
Expand All @@ -312,12 +310,12 @@ object desugar {
def productConstr(n: Int) = {
val tycon = ref(defn.ProductNClass(n).typeRef)
val targs = constrVparamss.head map (_.tpt)
AppliedTypeTree(tycon, targs)
if (targs.isEmpty) tycon else AppliedTypeTree(tycon, targs)
}

// Case classes get a ProductN parent
var parents1 = parents
if ((mods is Case) && 2 <= arity && arity <= Definitions.MaxTupleArity)
if ((mods is Case) && arity <= Definitions.MaxTupleArity)
parents1 = parents1 :+ productConstr(arity)

// The thicket which is the desugared version of the companion object
Expand All @@ -326,7 +324,8 @@ object desugar {
moduleDef(
ModuleDef(
Modifiers(Synthetic), name.toTermName,
Template(emptyConstructor, parentTpt :: Nil, EmptyValDef, defs))).toList
Template(emptyConstructor, parentTpt :: Nil, EmptyValDef, defs)))
.withPos(cdef.pos).toList

// The companion object defifinitions, if a companion is needed, Nil otherwise.
// companion definitions include:
Expand All @@ -340,7 +339,8 @@ object desugar {
val companions =
if (mods is Case) {
val parent =
if (constrTparams.nonEmpty) anyRef // todo: also use anyRef if constructor has a dependent method type (or rule that out)!
if (constrTparams.nonEmpty || constrVparamss.length > 1) anyRef
// todo: also use anyRef if constructor has a dependent method type (or rule that out)!
else (constrVparamss :\ classTypeRef) ((vparams, restpe) => Function(vparams map (_.tpt), restpe))
val applyMeths =
if (mods is Abstract) Nil
Expand Down Expand Up @@ -388,8 +388,9 @@ object desugar {
val tparamAccessors = derivedTparams map { tdef =>
cpy.TypeDef(tdef, originalTparams.next.mods, tdef.name, tdef.rhs, tdef.tparams)
}
val caseAccessor = if (mods is Case) CaseAccessor else EmptyFlags
val vparamAccessors = derivedVparamss.flatten map { vdef =>
cpy.ValDef(vdef, originalVparams.next.mods, vdef.name, vdef.tpt, vdef.rhs)
cpy.ValDef(vdef, originalVparams.next.mods | caseAccessor, vdef.name, vdef.tpt, vdef.rhs)
}
cpy.TypeDef(cdef, mods, name,
cpy.Template(impl, constr, parents1, self1,
Expand Down
14 changes: 11 additions & 3 deletions src/dotty/tools/dotc/ast/TreeInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,19 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
/** The number of arguments in an application */
def numArgs(tree: Tree): Int = unsplice(tree) match {
case Apply(fn, args) => numArgs(fn) + args.length
case TypeApply(fn, args) => numArgs(fn)
case Block(stats, expr) => numArgs(expr)
case TypeApply(fn, _) => numArgs(fn)
case Block(_, expr) => numArgs(expr)
case _ => 0
}

/** The (last) list of arguments of an application */
def arguments(tree: Tree): List[Tree] = unsplice(tree) match {
case Apply(_, args) => args
case TypeApply(fn, _) => arguments(fn)
case Block(_, expr) => arguments(expr)
case _ => Nil
}

/** Is tree a self constructor call this(...)? I.e. a call to a constructor of the
* same object?
*/
Expand Down Expand Up @@ -253,7 +261,7 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
* is an abstract typoe declaration
*/
def lacksDefinition(mdef: MemberDef) = mdef match {
case mdef: ValOrDefDef => mdef.rhs.isEmpty && !mdef.name.isConstructorName
case mdef: ValOrDefDef => mdef.rhs.isEmpty && !mdef.name.isConstructorName && !mdef.mods.is(ParamAccessor)
case mdef: TypeDef => mdef.rhs.isEmpty || mdef.rhs.isInstanceOf[TypeBoundsTree]
case _ => false
}
Expand Down
24 changes: 15 additions & 9 deletions src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,21 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {

def appliedToTypeTrees(targs: List[Tree])(implicit ctx: Context): Tree =
if (targs.isEmpty) tree else TypeApply(tree, targs)

def isInstance(tp: Type)(implicit ctx: Context): Tree =
tree.select(defn.Any_isInstanceOf).appliedToType(tp)

def asInstance(tp: Type)(implicit ctx: Context): Tree =
tree.select(defn.Any_asInstanceOf).appliedToType(tp)

def ensureConforms(tp: Type)(implicit ctx: Context): Tree =
if (tree.tpe <:< tp) tree else asInstance(tp)

def and(that: Tree)(implicit ctx: Context): Tree =
tree.select(defn.Boolean_&&).appliedTo(that)

def or(that: Tree)(implicit ctx: Context): Tree =
tree.select(defn.Boolean_||).appliedTo(that)
}

implicit class ListOfTreeDecorator(val xs: List[tpd.Tree]) extends AnyVal {
Expand Down Expand Up @@ -648,15 +663,6 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {

def runtimeCall(name: TermName, args: List[Tree])(implicit ctx: Context): Tree = ???

def mkAnd(tree1: Tree, tree2: Tree)(implicit ctx: Context) =
tree1.select(defn.Boolean_and).appliedTo(tree2)

def mkAsInstanceOf(tree: Tree, pt: Type)(implicit ctx: Context): Tree =
tree.select(defn.Any_asInstanceOf).appliedToType(pt)

def ensureConforms(tree: Tree, pt: Type)(implicit ctx: Context): Tree =
if (tree.tpe <:< pt) tree else mkAsInstanceOf(tree, pt)

// ensure that constructors are fully applied?
// ensure that normal methods are fully applied?

Expand Down
1 change: 1 addition & 0 deletions src/dotty/tools/dotc/config/Printers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ object Printers {
val completions = noPrinter
val gadts = noPrinter
val hk = noPrinter
val variances = noPrinter
val incremental = noPrinter
val config = noPrinter
val transforms = noPrinter
Expand Down
3 changes: 2 additions & 1 deletion src/dotty/tools/dotc/config/ScalaSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ class ScalaSettings extends Settings.SettingGroup {
val logFreeTerms = BooleanSetting("-Xlog-free-terms", "Print a message when reification creates a free term.")
val logFreeTypes = BooleanSetting("-Xlog-free-types", "Print a message when reification resorts to generating a free type.")
val maxClassfileName = IntSetting("-Xmax-classfile-name", "Maximum filename length for generated classes", 255, 72 to 255)
val Xmigration28 = BooleanSetting("-Xmigration", "Warn about constructs whose behavior may have changed between 2.7 and 2.8.")
val Xmigration = VersionSetting("-Xmigration", "Warn about constructs whose behavior may have changed since version.")
val Xsource = VersionSetting("-Xsource", "Treat compiler input as Scala source for the specified version.")
val Xnojline = BooleanSetting("-Xnojline", "Do not use JLine for editing.")
val Xverify = BooleanSetting("-Xverify", "Verify generic signatures in generated bytecode (asm backend only.)")
val plugin = MultiStringSetting("-Xplugin", "file", "Load one or more plugins from files.")
Expand Down
183 changes: 183 additions & 0 deletions src/dotty/tools/dotc/config/ScalaVersion.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/* @author James Iry
*/
package dotty.tools.dotc.config

import scala.util.{Try, Success, Failure}

/**
* Represents a single Scala version in a manner that
* supports easy comparison and sorting.
*/
sealed abstract class ScalaVersion extends Ordered[ScalaVersion] {
def unparse: String
}

/**
* A scala version that sorts higher than all actual versions
*/
case object NoScalaVersion extends ScalaVersion {
def unparse = "none"

def compare(that: ScalaVersion): Int = that match {
case NoScalaVersion => 0
case _ => 1
}
}

/**
* A specific Scala version, not one of the magic min/max versions. An SpecificScalaVersion
* may or may not be a released version - i.e. this same class is used to represent
* final, release candidate, milestone, and development builds. The build argument is used
* to segregate builds
*/
case class SpecificScalaVersion(major: Int, minor: Int, rev: Int, build: ScalaBuild) extends ScalaVersion {
def unparse = s"${major}.${minor}.${rev}.${build.unparse}"

def compare(that: ScalaVersion): Int = that match {
case SpecificScalaVersion(thatMajor, thatMinor, thatRev, thatBuild) =>
// this could be done more cleanly by importing scala.math.Ordering.Implicits, but we have to do these
// comparisons a lot so I'm using brute force direct style code
if (major < thatMajor) -1
else if (major > thatMajor) 1
else if (minor < thatMinor) -1
else if (minor > thatMinor) 1
else if (rev < thatRev) -1
else if (rev > thatRev) 1
else build compare thatBuild
case AnyScalaVersion => 1
case NoScalaVersion => -1
}
}

/**
* A Scala version that sorts lower than all actual versions
*/
case object AnyScalaVersion extends ScalaVersion {
def unparse = "any"

def compare(that: ScalaVersion): Int = that match {
case AnyScalaVersion => 0
case _ => -1
}
}

/**
* Methods for parsing ScalaVersions
*/
object ScalaVersion {
private val dot = "\\."
private val dash = "\\-"
private def not(s:String) = s"[^${s}]"
private val R = s"((${not(dot)}*)(${dot}(${not(dot)}*)(${dot}(${not(dash)}*)(${dash}(.*))?)?)?)".r

def parse(versionString : String): Try[ScalaVersion] = {
def failure = Failure(new NumberFormatException(
s"There was a problem parsing ${versionString}. " +
"Versions should be in the form major[.minor[.revision]] " +
"where each part is a positive number, as in 2.10.1. " +
"The minor and revision parts are optional."
))

def toInt(s: String) = s match {
case null | "" => 0
case _ => s.toInt
}

def isInt(s: String) = Try(toInt(s)).isSuccess

import ScalaBuild._

def toBuild(s: String) = s match {
case null | "FINAL" => Final
case s if (s.toUpperCase.startsWith("RC") && isInt(s.substring(2))) => RC(toInt(s.substring(2)))
case s if (s.toUpperCase.startsWith("M") && isInt(s.substring(1))) => Milestone(toInt(s.substring(1)))
case _ => Development(s)
}

try versionString match {
case "" | "any" => Success(AnyScalaVersion)
case "none" => Success(NoScalaVersion)
case R(_, majorS, _, minorS, _, revS, _, buildS) =>
Success(SpecificScalaVersion(toInt(majorS), toInt(minorS), toInt(revS), toBuild(buildS)))
case _ => failure
} catch {
case e: NumberFormatException => failure
}
}

/**
* The version of the compiler running now
*/
val current = parse(util.Properties.versionNumberString).get
}

/**
* Represents the data after the dash in major.minor.rev-build
*/
abstract class ScalaBuild extends Ordered[ScalaBuild] {
/**
* Return a version of this build information that can be parsed back into the
* same ScalaBuild
*/
def unparse: String
}

object ScalaBuild {

/** A development, test, nightly, snapshot or other "unofficial" build
*/
case class Development(id: String) extends ScalaBuild {
def unparse = s"-${id}"

def compare(that: ScalaBuild) = that match {
// sorting two development builds based on id is reasonably valid for two versions created with the same schema
// otherwise it's not correct, but since it's impossible to put a total ordering on development build versions
// this is a pragmatic compromise
case Development(thatId) => id compare thatId
// assume a development build is newer than anything else, that's not really true, but good luck
// mapping development build versions to other build types
case _ => 1
}
}

/** A final build
*/
case object Final extends ScalaBuild {
def unparse = ""

def compare(that: ScalaBuild) = that match {
case Final => 0
// a final is newer than anything other than a development build or another final
case Development(_) => -1
case _ => 1
}
}

/** A candidate for final release
*/
case class RC(n: Int) extends ScalaBuild {
def unparse = s"-RC${n}"

def compare(that: ScalaBuild) = that match {
// compare two rcs based on their RC numbers
case RC(thatN) => n - thatN
// an rc is older than anything other than a milestone or another rc
case Milestone(_) => 1
case _ => -1
}
}

/** An intermediate release
*/
case class Milestone(n: Int) extends ScalaBuild {
def unparse = s"-M${n}"

def compare(that: ScalaBuild) = that match {
// compare two milestones based on their milestone numbers
case Milestone(thatN) => n - thatN
// a milestone is older than anything other than another milestone
case _ => -1

}
}
}
Loading