aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Petrashko <dark@d-d.me>2014-05-09 11:16:57 +0200
committerDmitry Petrashko <dark@d-d.me>2014-05-09 11:16:57 +0200
commit8a4186ff782efefb98686aa35bf7f5dd1418210d (patch)
treeb82a383068ef0eadff6948a0cfcdd4459aaf5d10
parentc5c400c6f53e2d15fb311df63f87bb62e39c858c (diff)
parente83df26f7a6bc583599e0b50bdb2f806cbf314f7 (diff)
downloaddotty-8a4186ff782efefb98686aa35bf7f5dd1418210d.tar.gz
dotty-8a4186ff782efefb98686aa35bf7f5dd1418210d.tar.bz2
dotty-8a4186ff782efefb98686aa35bf7f5dd1418210d.zip
Merge pull request #128 from dotty-staging/fix/erasure-2
Fix/erasure 2
-rw-r--r--src/dotty/annotation/internal/Repeated.scala5
-rw-r--r--src/dotty/tools/dotc/Compiler.scala4
-rw-r--r--src/dotty/tools/dotc/Main.scala2
-rw-r--r--src/dotty/tools/dotc/Run.scala6
-rw-r--r--src/dotty/tools/dotc/ast/Desugar.scala4
-rw-r--r--src/dotty/tools/dotc/ast/Trees.scala11
-rw-r--r--src/dotty/tools/dotc/ast/tpd.scala29
-rw-r--r--src/dotty/tools/dotc/config/Config.scala6
-rw-r--r--src/dotty/tools/dotc/config/PathResolver.scala2
-rw-r--r--src/dotty/tools/dotc/core/Constraint.scala167
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala137
-rw-r--r--src/dotty/tools/dotc/core/Denotations.scala2
-rw-r--r--src/dotty/tools/dotc/core/Phases.scala6
-rw-r--r--src/dotty/tools/dotc/core/StdNames.scala2
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala5
-rw-r--r--src/dotty/tools/dotc/core/TypeApplications.scala42
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala167
-rw-r--r--src/dotty/tools/dotc/core/TyperState.scala15
-rw-r--r--src/dotty/tools/dotc/core/Types.scala26
-rw-r--r--src/dotty/tools/dotc/core/pickling/ClassfileParser.scala6
-rw-r--r--src/dotty/tools/dotc/core/transform/Erasure.scala6
-rw-r--r--src/dotty/tools/dotc/printing/PlainPrinter.scala2
-rw-r--r--src/dotty/tools/dotc/transform/Erasure.scala11
-rw-r--r--src/dotty/tools/dotc/transform/InterceptedMethods.scala20
-rw-r--r--src/dotty/tools/dotc/transform/LazyVals.scala2
-rw-r--r--src/dotty/tools/dotc/transform/TailRec.scala7
-rw-r--r--src/dotty/tools/dotc/transform/TreeChecker.scala76
-rw-r--r--src/dotty/tools/dotc/transform/TreeTransform.scala61
-rw-r--r--src/dotty/tools/dotc/transform/TypeTestsCasts.scala8
-rw-r--r--src/dotty/tools/dotc/typer/Checking.scala10
-rw-r--r--src/dotty/tools/dotc/typer/EtaExpansion.scala1
-rw-r--r--src/dotty/tools/dotc/typer/Implicits.scala7
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala140
-rw-r--r--src/dotty/tools/dotc/typer/ProtoTypes.scala21
-rw-r--r--src/dotty/tools/dotc/typer/ReTyper.scala6
-rw-r--r--src/dotty/tools/dotc/typer/TypeAssigner.scala11
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala10
-rw-r--r--test/dotc/comptest.scala2
-rw-r--r--test/dotc/tests.scala19
-rw-r--r--test/test/CompilerTest.scala16
-rw-r--r--test/test/transform/LazyValsTest.scala23
-rw-r--r--tests/neg/tailcall/tailrec-2.scala2
-rw-r--r--tests/pending/pos/t1164.scala (renamed from tests/pos/t1164.scala)0
43 files changed, 742 insertions, 363 deletions
diff --git a/src/dotty/annotation/internal/Repeated.scala b/src/dotty/annotation/internal/Repeated.scala
new file mode 100644
index 000000000..94e9df858
--- /dev/null
+++ b/src/dotty/annotation/internal/Repeated.scala
@@ -0,0 +1,5 @@
+package dotty.annotation.internal
+
+import scala.annotation.Annotation
+
+final class Repeated() extends Annotation \ No newline at end of file
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala
index 36af6a438..a4a8fbbc8 100644
--- a/src/dotty/tools/dotc/Compiler.scala
+++ b/src/dotty/tools/dotc/Compiler.scala
@@ -21,7 +21,6 @@ class Compiler {
List(
List(new FrontEnd),
List(new LazyValsCreateCompanionObjects,
- /* new Constructors, */
new TailRec), //force separataion between lazyVals and LVCreateCO
List(new PatternMatcher,
new LazyValTranformContext().transformer,
@@ -30,7 +29,8 @@ class Compiler {
new TypeTestsCasts,
new InterceptedMethods),
List(new Erasure),
- List(new UncurryTreeTransform, new CollectEntryPoints)
+ List(new UncurryTreeTransform
+ /* , new Constructors */)
)
var runId = 1
diff --git a/src/dotty/tools/dotc/Main.scala b/src/dotty/tools/dotc/Main.scala
index 72f29fe6e..0b136d72f 100644
--- a/src/dotty/tools/dotc/Main.scala
+++ b/src/dotty/tools/dotc/Main.scala
@@ -9,8 +9,6 @@ import core.Contexts.Context
import reporting.Reporter
/* To do:
-s * - Revise the way classes are inherited - when not followed by [...] or (...),
- * assume the unparameterized type and forward type parameters as we do now for the synthetic head class.
*/
object Main extends Driver {
def resident(compiler: Compiler): Reporter = unsupported("resident") /*loop { line =>
diff --git a/src/dotty/tools/dotc/Run.scala b/src/dotty/tools/dotc/Run.scala
index 247fa4336..a639b20cd 100644
--- a/src/dotty/tools/dotc/Run.scala
+++ b/src/dotty/tools/dotc/Run.scala
@@ -42,8 +42,10 @@ class Run(comp: Compiler)(implicit ctx: Context) {
phase.runOn(units)
def foreachUnit(op: Context => Unit)(implicit ctx: Context): Unit =
for (unit <- units) op(ctx.fresh.setPhase(phase.next).setCompilationUnit(unit))
- if (ctx.settings.Xprint.value.containsPhase(phase)) foreachUnit(printTree)
- if (ctx.settings.Ycheck.value.containsPhase(phase)) foreachUnit(TreeChecker.check)
+ if (ctx.settings.Xprint.value.containsPhase(phase))
+ foreachUnit(printTree)
+ if (ctx.settings.Ycheck.value.containsPhase(phase) && !ctx.reporter.hasErrors)
+ foreachUnit(TreeChecker.check)
}
}
}
diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala
index 8d891b9d9..513dee2ff 100644
--- a/src/dotty/tools/dotc/ast/Desugar.scala
+++ b/src/dotty/tools/dotc/ast/Desugar.scala
@@ -751,7 +751,9 @@ object desugar {
makeBinop(l, op, r)
case PostfixOp(t, op) =>
if ((ctx.mode is Mode.Type) && op == nme.raw.STAR)
- AppliedTypeTree(ref(defn.RepeatedParamType), t)
+ Annotated(
+ New(ref(defn.RepeatedAnnot.typeRef), Nil :: Nil),
+ AppliedTypeTree(ref(defn.SeqClass.typeRef), t))
else {
assert(ctx.mode.isExpr, ctx.mode)
Select(t, op)
diff --git a/src/dotty/tools/dotc/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala
index 2ae494d55..e11bdeefc 100644
--- a/src/dotty/tools/dotc/ast/Trees.scala
+++ b/src/dotty/tools/dotc/ast/Trees.scala
@@ -180,6 +180,8 @@ object Trees {
def tokenPos: Seq[(Token, Position)] = ???
}
+ private var nextId = 0
+
/** Trees take a parameter indicating what the type of their `tpe` field
* is. Two choices: `Type` or `Untyped`.
* Untyped trees have type `Tree[Untyped]`.
@@ -204,6 +206,15 @@ object Trees {
if (Stats.enabled) ntrees += 1
+ /** A unique identifier for this tree. Used for debugging, and potentially
+ * tracking presentation compiler interactions
+ */
+ val uniqueId = {
+ nextId += 1
+ //assert(nextId != 214, this)
+ nextId
+ }
+
/** The type constructor at the root of the tree */
type ThisTree[T >: Untyped] <: Tree[T]
diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala
index e9775f1dc..3b240ad2c 100644
--- a/src/dotty/tools/dotc/ast/tpd.scala
+++ b/src/dotty/tools/dotc/ast/tpd.scala
@@ -210,8 +210,24 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def TypeDef(sym: TypeSymbol)(implicit ctx: Context): TypeDef =
ta.assignType(untpd.TypeDef(Modifiers(sym), sym.name, TypeTree(sym.info)), sym)
- def ClassDef(cls: ClassSymbol, constr: DefDef, body: List[Tree])(implicit ctx: Context): TypeDef = {
- val parents = cls.info.parents map (TypeTree(_))
+ def ClassDef(cls: ClassSymbol, constr: DefDef, body: List[Tree], superArgs: List[Tree] = Nil)(implicit ctx: Context): TypeDef = {
+ val firstParent :: otherParents = cls.info.parents
+ val superRef =
+ if (cls is Trait) TypeTree(firstParent)
+ else {
+ def isApplicable(ctpe: Type): Boolean = ctpe match {
+ case ctpe: PolyType =>
+ isApplicable(ctpe.instantiate(firstParent.argTypes))
+ case ctpe: MethodType =>
+ (superArgs corresponds ctpe.paramTypes)(_.tpe <:< _)
+ case _ =>
+ false
+ }
+ val constr = firstParent.decl(nme.CONSTRUCTOR).suchThat(constr => isApplicable(constr.info))
+ New(firstParent, constr.symbol.asTerm, superArgs)
+ }
+ val parents = superRef :: otherParents.map(TypeTree(_))
+
val selfType =
if (cls.classInfo.selfInfo ne NoType) ValDef(ctx.newSelfSym(cls))
else EmptyValDef
@@ -260,10 +276,13 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
// ------ Creating typed equivalents of trees that exist only in untyped form -------
- /** new C(args) */
- def New(tp: Type, args: List[Tree])(implicit ctx: Context): Apply = {
+ /** new C(args), calling the primary constructor of C */
+ def New(tp: Type, args: List[Tree])(implicit ctx: Context): Apply =
+ New(tp, tp.typeSymbol.primaryConstructor.asTerm, args)
+
+ /** new C(args), calling given constructor `constr` of C */
+ def New(tp: Type, constr: TermSymbol, args: List[Tree])(implicit ctx: Context): Apply = {
val targs = tp.argTypes
- val constr = tp.typeSymbol.primaryConstructor.asTerm
Apply(
Select(
New(tp withoutArgs targs),
diff --git a/src/dotty/tools/dotc/config/Config.scala b/src/dotty/tools/dotc/config/Config.scala
index e77b10bfb..c247699da 100644
--- a/src/dotty/tools/dotc/config/Config.scala
+++ b/src/dotty/tools/dotc/config/Config.scala
@@ -37,4 +37,10 @@ object Config {
/** The recursion depth for showing a summarized string */
final val summarizeDepth = 2
+
+ /** Track dependencies for constraint propagation satisfiability checking
+ * If turned off, constraint checking is simpler but potentially slower
+ * for large constraints.
+ */
+ final val trackConstrDeps = true
} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/config/PathResolver.scala b/src/dotty/tools/dotc/config/PathResolver.scala
index 34678ae2b..f9f698e72 100644
--- a/src/dotty/tools/dotc/config/PathResolver.scala
+++ b/src/dotty/tools/dotc/config/PathResolver.scala
@@ -148,7 +148,7 @@ object PathResolver {
println(Defaults)
}
else {
- implicit val ctx = (new ContextBase).initialCtx
+ implicit val ctx: Context = (new ContextBase).initialCtx // Dotty deviation: implicits need explicit type
val ArgsSummary(sstate, rest, errors) =
ctx.settings.processArguments(args.toList, true)
errors.foreach(println)
diff --git a/src/dotty/tools/dotc/core/Constraint.scala b/src/dotty/tools/dotc/core/Constraint.scala
index 64fb8764e..339dbb64a 100644
--- a/src/dotty/tools/dotc/core/Constraint.scala
+++ b/src/dotty/tools/dotc/core/Constraint.scala
@@ -10,6 +10,55 @@ import printing.Texts._
import config.Config
import config.Printers._
+object Constraint {
+
+ /** The type of `Constraint#myMap` */
+ type ParamInfo = SimpleMap[PolyType, Array[Type]]
+
+ /** The type of `Constraint#dependents */
+ type DependentMap = SimpleMap[PolyType, Array[Set[PolyParam]]]
+
+ /** The type of functions that include or exclude a `PolyParam` in or from a set*/
+ private type DepDelta = (Set[PolyParam], PolyParam) => Set[PolyParam]
+
+ private val addDep: DepDelta = (_ + _)
+ private val removeDep: DepDelta = (_ - _)
+
+ private val NoTypeBounds = new TypeBounds(WildcardType, WildcardType){}
+
+ /** An accumulator that changes dependencies on `param`.
+ * @param param The parameter to which changed dependencies refer.
+ * @param ofVariance Include `PolyParams` occurring at this variance in the dependencies.
+ * @param delta The dependency change to perform (add or remove).
+ */
+ private class ChangeDependencies(param: PolyParam, ofVariance: Int, delta: DepDelta)(implicit ctx: Context)
+ extends TypeAccumulator[DependentMap] {
+ def apply(deps: DependentMap, tp: Type): DependentMap = tp match {
+ case tp @ PolyParam(pt, n) if
+ this.variance == 0 || this.variance == ofVariance =>
+ val oldDeps = deps(pt)
+ val original = safeSelect(oldDeps, n)
+ val changed = delta(original, param)
+ if (original eq changed) deps
+ else {
+ val newDeps =
+ if (oldDeps == null) new Array[Set[PolyParam]](pt.paramBounds.length)
+ else oldDeps.clone
+ newDeps(n) = changed
+ deps.updated(pt, newDeps)
+ }
+ case _ => foldOver(deps, tp)
+ }
+ }
+
+ /** `deps(n)`, except that `Set()` is returned if `deps` or `deps(n)` are null */
+ private def safeSelect(deps: Array[Set[PolyParam]], n: Int) : Set[PolyParam] =
+ if (deps == null || deps(n) == null) Set()
+ else deps(n)
+}
+
+import Constraint._
+
/** Constraint over undetermined type parameters
* @param myMap a map from PolyType to arrays.
* Each array contains twice the number of entries as there a type parameters
@@ -18,8 +67,20 @@ import config.Printers._
* track the corresponding parameters, or is left empty (filled with nulls).
* An instantiated type parameter is represented by having its instance type in
* the corresponding array entry.
+ * @param dependents a map from PolyTypes to arrays of Sets of PolyParams.
+ * The i'th set in an array corresponding to polytype `pt` contains
+ * those dependent `PolyParam`s `dp` that have `PolyParam(pt, i)` in their bounds in
+ * significant position. A position is significant if solving the
+ * constraint for `(pt, i)` with a type higher than its lower bound
+ * would lead to a constraint for `dp` that was not looser than
+ * the existing constraint. Specifically, it means that all poly params
+ * appearing covariantly in the lower bound and contravariantly in the
+ * upper bound, as well as all poly params appearing nonvariantly are
+ * significant.
+ * The `dependents` map is maintained and queried only of `Config.trackConstrDeps` is set.
*/
-class Constraint(val myMap: SimpleMap[PolyType, Array[Type]]) extends Showable {
+class Constraint(private val myMap: ParamInfo,
+ private val dependents: DependentMap) extends Showable {
/** Does the constraint's domain contain the type parameters of `pt`? */
def contains(pt: PolyType): Boolean = myMap(pt) != null
@@ -66,16 +127,88 @@ class Constraint(val myMap: SimpleMap[PolyType, Array[Type]]) extends Showable {
def typeVarOfParam(param: PolyParam): Type = {
val entries = myMap(param.binder)
if (entries == null) NoType
- else typeVar(entries, param.paramNum)
+ else {
+ val tvar = typeVar(entries, param.paramNum)
+ if (tvar != null) tvar else NoType
+ }
+ }
+
+ /** Change dependencies in map `deps` to reflect new parameter bounds.
+ * @param deps The map to change
+ * @param pt the polytype that contains the parameters which might have new bounds
+ * @param entries the entries for the parameters which might have new bounds
+ * @param delta the change operation, one of `addDep` or `removeDep`.
+ * @param cmpEntries the comparison entries or `null` if no such entries exist.
+ * As an optimization, only bounds that differ between `entries`
+ * and `cmpEntries` will record their dependencies.
+ */
+ def changeDependencies(deps: DependentMap, pt: PolyType, entries: Array[Type], delta: DepDelta, cmpEntries: Array[Type])(implicit ctx: Context): DependentMap = {
+ val limit = paramCount(entries)
+ def loop(deps: DependentMap, n: Int): DependentMap = {
+ if (n >= limit) deps
+ else {
+ val newDeps = entries(n) match {
+ case bounds @ TypeBounds(lo, hi) =>
+ val cmpBounds =
+ if (cmpEntries == null) NoTypeBounds
+ else cmpEntries(n) match {
+ case bounds: TypeBounds => bounds
+ case _ => NoTypeBounds
+ }
+ if (cmpBounds eq bounds) deps
+ else {
+ val param = PolyParam(pt, n)
+ val deps1 =
+ if (cmpBounds.lo eq lo) deps
+ else new ChangeDependencies(param, 1, delta).apply(deps, lo)
+ val deps2 =
+ if (cmpBounds.hi eq hi) deps1
+ else new ChangeDependencies(param, -1, delta).apply(deps1, hi)
+ deps2
+ }
+ case _ =>
+ deps
+ }
+ loop(newDeps, n + 1)
+ }
+ }
+ if (Config.trackConstrDeps) loop(deps, 0) else deps
}
+ /** Change dependencies to reflect all changes between the bounds in `oldMap` and `newMap`.
+ */
+ def diffDependencies(deps: DependentMap, oldMap: ParamInfo, newMap: ParamInfo)(implicit ctx: Context): DependentMap =
+ if (Config.trackConstrDeps) {
+ var d = deps
+ oldMap foreachBinding { (poly, entries) =>
+ val newEntries = newMap(poly)
+ if (newEntries ne entries) d = changeDependencies(d, poly, entries, removeDep, newEntries)
+ }
+ newMap foreachBinding { (poly, entries) =>
+ val oldEntries = oldMap(poly)
+ if (oldEntries ne entries) d = changeDependencies(d, poly, entries, addDep, oldEntries)
+ }
+ d
+ } else deps
+
+ /** The set of parameters that depend directly on `param`
+ * according to what's stored in `dependents`.
+ */
+ def dependentParams(param: PolyParam): Set[PolyParam] =
+ safeSelect(dependents(param.binder), param.paramNum)
+
/** A new constraint which is derived from this constraint by adding or replacing
* the entries corresponding to `pt` with `entries`.
*/
private def updateEntries(pt: PolyType, entries: Array[Type])(implicit ctx: Context) : Constraint = {
- val res = new Constraint(myMap.updated(pt, entries))
+ val res = new Constraint(
+ myMap.updated(pt, entries),
+ changeDependencies(dependents, pt, entries, addDep, myMap(pt)))
+
+ //assert(res.domainPolys.filter(pt =>
+ // pt.resultType.resultType.widen.classSymbol.name.toString == "Ensuring").length < 2) //DEBUG
if (Config.checkConstraintsNonCyclic) checkNonCyclic(pt, entries)
- ctx.runInfo.recordConstraintSize(res)
+ ctx.runInfo.recordConstraintSize(res, res.myMap.size)
res
}
@@ -114,7 +247,10 @@ class Constraint(val myMap: SimpleMap[PolyType, Array[Type]]) extends Showable {
updateEntries(poly, myMap(poly) map op)
/** A new constraint with all entries coming from `pt` removed. */
- def remove(pt: PolyType) = new Constraint(myMap remove pt)
+ def remove(pt: PolyType)(implicit ctx: Context) =
+ new Constraint(
+ myMap remove pt,
+ changeDependencies(dependents, pt, myMap(pt), removeDep, null))
/** Is entry associated with `pt` removable?
* @param removedParam The index of a parameter which is still present in the
@@ -185,7 +321,10 @@ class Constraint(val myMap: SimpleMap[PolyType, Array[Type]]) extends Showable {
val pt = param.binder
val constr1 = if (isRemovable(pt, param.paramNum)) remove(pt) else updated(param, tp)
- val result = new Constraint(constr1.myMap mapValues subst)
+ val substMap = constr1.myMap mapValues subst
+ val result = new Constraint(
+ substMap,
+ diffDependencies(constr1.dependents, constr1.myMap, substMap))
if (Config.checkConstraintsNonCyclic) result.checkNonCyclic()
result
}
@@ -243,6 +382,16 @@ class Constraint(val myMap: SimpleMap[PolyType, Array[Type]]) extends Showable {
if isBounds(entries(n))
} yield PolyParam(poly, n)
+ /** Check whether predicate holds for all parameters in constraint
+ */
+ def forallParams(p: PolyParam => Boolean): Boolean = {
+ myMap.foreachBinding { (poly, entries) =>
+ for (i <- 0 until paramCount(entries))
+ if (isBounds(entries(i)) && !p(PolyParam(poly, i))) return false
+ }
+ true
+ }
+
/** Perform operation `op` on all typevars, or only on uninstantiated
* typevars, depending on whether `uninstOnly` is set or not.
*/
@@ -299,9 +448,9 @@ class Constraint(val myMap: SimpleMap[PolyType, Array[Type]]) extends Showable {
trait ConstraintRunInfo { self: RunInfo =>
private var maxSize = 0
private var maxConstraint: Constraint = _
- def recordConstraintSize(c: Constraint) =
- if (c.myMap.size > maxSize) {
- maxSize = c.myMap.size
+ def recordConstraintSize(c: Constraint, size: Int) =
+ if (size > maxSize) {
+ maxSize = size
maxConstraint = c
}
def printMaxConstraint()(implicit ctx: Context) =
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index 9497438f2..6f34efc8b 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -30,6 +30,9 @@ class Definitions {
private def newCompleteClassSymbol(owner: Symbol, name: TypeName, flags: FlagSet, parents: List[TypeRef], decls: Scope = newScope) =
ctx.newCompleteClassSymbol(owner, name, flags | Permanent, parents, decls).entered
+ private def newTopClassSymbol(name: TypeName, flags: FlagSet, parents: List[TypeRef]) =
+ completeClass(newCompleteClassSymbol(ScalaPackageClass, name, flags, parents))
+
private def newTypeParam(cls: ClassSymbol, name: TypeName, flags: FlagSet, scope: MutableScope) =
scope.enter(newSymbol(cls, name, flags | TypeParamCreationFlags, TypeBounds.empty))
@@ -74,7 +77,7 @@ class Definitions {
newPolyMethod(cls, name, 1, resultTypeFn, flags)
private def newT1EmptyParamsMethod(cls: ClassSymbol, name: TermName, resultTypeFn: PolyType => Type, flags: FlagSet) =
- newPolyMethod(cls, name, 1, pt => MethodType(Nil, Nil, resultTypeFn(pt)), flags)
+ newPolyMethod(cls, name, 1, pt => MethodType(Nil, resultTypeFn(pt)), flags)
private def mkArityArray(name: String, arity: Int, countFrom: Int): Array[ClassSymbol] = {
val arr = new Array[ClassSymbol](arity + 1)
@@ -82,6 +85,12 @@ class Definitions {
arr
}
+ private def completeClass(cls: ClassSymbol): ClassSymbol = {
+ ensureConstructor(cls, EmptyScope)
+ if (cls.linkedClass.exists) cls.linkedClass.info = NoType
+ cls
+ }
+
lazy val RootClass: ClassSymbol = ctx.newPackageSymbol(
NoSymbol, nme.ROOT, (root, rootcls) => ctx.rootLoader(root)).moduleClass.asClass
lazy val RootPackage: TermSymbol = ctx.newSymbol(
@@ -95,58 +104,67 @@ class Definitions {
lazy val JavaPackageVal = ctx.requiredPackage("java")
lazy val JavaLangPackageVal = ctx.requiredPackage("java.lang")
- lazy val ObjectClass = ctx.requiredClass("java.lang.Object")
- lazy val AnyRefAlias: TypeSymbol = newAliasType(tpnme.AnyRef, ObjectType)
-
- lazy val Object_## = newMethod(ObjectClass, nme.HASHHASH, ExprType(IntType), Final)
- lazy val Object_== = newMethod(ObjectClass, nme.EQ, methOfAny(BooleanType), Final)
- lazy val Object_!= = newMethod(ObjectClass, nme.NE, methOfAny(BooleanType), Final)
- lazy val Object_eq = newMethod(ObjectClass, nme.eq, methOfAnyRef(BooleanType), Final)
- lazy val Object_ne = newMethod(ObjectClass, nme.ne, methOfAnyRef(BooleanType), Final)
- lazy val Object_isInstanceOf = newT1ParameterlessMethod(ObjectClass, nme.isInstanceOf_Ob, _ => BooleanType, Final | Synthetic)
- lazy val Object_asInstanceOf = newT1ParameterlessMethod(ObjectClass, nme.asInstanceOf_Ob, PolyParam(_, 0), Final | Synthetic)
- lazy val Object_synchronized = newPolyMethod(ObjectClass, nme.synchronized_, 1,
- pt => MethodType(List(PolyParam(pt, 0)), PolyParam(pt, 0)), Final)
-
- def Object_getClass = objMethod(nme.getClass_)
- def Object_clone = objMethod(nme.clone_)
- def Object_finalize = objMethod(nme.finalize_)
- def Object_notify = objMethod(nme.notify_)
- def Object_notifyAll = objMethod(nme.notifyAll_)
- def Object_equals = objMethod(nme.equals_)
- def Object_hashCode = objMethod(nme.hashCode_)
- def Object_toString = objMethod(nme.toString_)
- private def objMethod(name: PreName) = ObjectClass.requiredMethod(name)
-
- lazy val AnyClass: ClassSymbol = {
- val cls = newCompleteClassSymbol(ScalaPackageClass, tpnme.Any, Abstract, Nil)
- ensureConstructor(cls, EmptyScope)
- cls
- }
-
- lazy val AnyValClass: ClassSymbol = ctx.requiredClass("scala.AnyVal")
+ /** Note: We cannot have same named methods defined in Object and Any (and AnyVal, for that matter)
+ * because after erasure the Any and AnyVal references get remapped to the Object methods
+ * which would result in a double binding assertion failure.
+ * Instead we do the following:
+ *
+ * - Have some methods exist only in Any, and remap them with the Erasure denotation
+ * transformer to be owned by Object.
+ * - Have other methods exist only in Object.
+ * To achieve this, we synthesize all Any and Object methods; Object methods no longer get
+ * loaded from a classfile.
+ *
+ * There's a remaining question about `getClass`. In Scala2.x `getClass` was handled by compiler magic.
+ * This is deemed too cumersome for Dotty and therefore right now `getClass` gets no special treatment;
+ * it's just a method on `Any` which returns the raw type `java.lang.Class`. An alternative
+ * way to get better `getClass` typing would be to treat `getClass` as a method of a generic
+ * decorator which gets remapped in a later phase to Object#getClass. Then we could give it
+ * the right type without changing the typechecker:
+ *
+ * implicit class AnyGetClass[T](val x: T) extends AnyVal {
+ * def getClass: java.lang.Class[T] = ???
+ * }
+ */
+ lazy val AnyClass: ClassSymbol = completeClass(newCompleteClassSymbol(ScalaPackageClass, tpnme.Any, Abstract, Nil))
+ lazy val AnyValClass: ClassSymbol = completeClass(newCompleteClassSymbol(ScalaPackageClass, tpnme.AnyVal, Abstract, List(AnyClass.typeRef)))
- lazy val AnyVal_getClass = AnyValClass.requiredMethod(nme.getClass_)
lazy val Any_== = newMethod(AnyClass, nme.EQ, methOfAny(BooleanType), Final)
lazy val Any_!= = newMethod(AnyClass, nme.NE, methOfAny(BooleanType), Final)
lazy val Any_equals = newMethod(AnyClass, nme.equals_, methOfAny(BooleanType))
- lazy val Any_hashCode = newMethod(AnyClass, nme.hashCode_, ExprType(IntType))
- lazy val Any_toString = newMethod(AnyClass, nme.toString_, ExprType(StringType))
+ lazy val Any_hashCode = newMethod(AnyClass, nme.hashCode_, MethodType(Nil, IntType))
+ lazy val Any_toString = newMethod(AnyClass, nme.toString_, MethodType(Nil, StringType))
lazy val Any_## = newMethod(AnyClass, nme.HASHHASH, ExprType(IntType), Final)
-
- // Any_getClass requires special handling. The return type is determined on
- // a per-call-site basis as if the function being called were actually:
- //
- // // Assuming `target.getClass()`
- // def getClass[T](target: T): Class[_ <: T]
- //
- // Since getClass is not actually a polymorphic method, this requires compiler
- // participation. At the "Any" level, the return type is Class[_] as it is in
- // java.lang.Object. Java also special cases the return type.
- lazy val Any_getClass = newMethod(AnyClass, nme.getClass_, ExprType(Object_getClass.info.resultType), Deferred)
+ lazy val Any_getClass = newMethod(AnyClass, nme.getClass_, MethodType(Nil, ClassClass.typeRef), Final)
lazy val Any_isInstanceOf = newT1ParameterlessMethod(AnyClass, nme.isInstanceOf_, _ => BooleanType, Final)
lazy val Any_asInstanceOf = newT1ParameterlessMethod(AnyClass, nme.asInstanceOf_, PolyParam(_, 0), Final)
+ def AnyMethods = List(Any_==, Any_!=, Any_equals, Any_hashCode,
+ Any_toString, Any_##, Any_getClass, Any_isInstanceOf, Any_asInstanceOf)
+
+ lazy val ObjectClass: ClassSymbol = {
+ val cls = ctx.requiredClass("java.lang.Object")
+ assert(!cls.isCompleted, "race for completing java.lang.Object")
+ cls.info = ClassInfo(cls.owner.thisType, cls, AnyClass.typeRef :: Nil, newScope)
+ completeClass(cls)
+ }
+ lazy val AnyRefAlias: TypeSymbol = newAliasType(tpnme.AnyRef, ObjectType)
+
+ lazy val Object_eq = newMethod(ObjectClass, nme.eq, methOfAnyRef(BooleanType), Final)
+ lazy val Object_ne = newMethod(ObjectClass, nme.ne, methOfAnyRef(BooleanType), Final)
+ lazy val Object_synchronized = newPolyMethod(ObjectClass, nme.synchronized_, 1,
+ pt => MethodType(List(PolyParam(pt, 0)), PolyParam(pt, 0)), Final)
+ lazy val Object_clone = newMethod(ObjectClass, nme.clone_, MethodType(Nil, ObjectType), Protected)
+ lazy val Object_finalize = newMethod(ObjectClass, nme.finalize_, MethodType(Nil, UnitType), Protected)
+ lazy val Object_notify = newMethod(ObjectClass, nme.notify_, MethodType(Nil, UnitType))
+ lazy val Object_notifyAll = newMethod(ObjectClass, nme.notifyAll_, MethodType(Nil, UnitType))
+ lazy val Object_wait = newMethod(ObjectClass, nme.wait_, MethodType(Nil, UnitType))
+ lazy val Object_waitL = newMethod(ObjectClass, nme.wait_, MethodType(LongType :: Nil, UnitType))
+ lazy val Object_waitLI = newMethod(ObjectClass, nme.wait_, MethodType(LongType :: IntType :: Nil, UnitType))
+
+ def ObjectMethods = List(Object_eq, Object_ne, Object_synchronized, Object_clone,
+ Object_finalize, Object_notify, Object_notifyAll, Object_wait, Object_waitL, Object_waitLI)
+
lazy val NotNullClass = ctx.requiredClass("scala.NotNull")
lazy val NothingClass: ClassSymbol = newCompleteClassSymbol(
@@ -160,6 +178,7 @@ class Definitions {
lazy val BoxesRunTimeClass = BoxesRunTimeModule.moduleClass
lazy val DottyPredefModule = ctx.requiredModule("dotty.DottyPredef")
lazy val NilModule = ctx.requiredModule("scala.collection.immutable.Nil")
+ lazy val PredefConformsClass = ctx.requiredClass("scala.Predef." + tpnme.Conforms)
// lazy val FunctionClass: ClassSymbol = ctx.requiredClass("scala.Function")
lazy val SingletonClass: ClassSymbol =
@@ -265,6 +284,7 @@ class Definitions {
// Annotation classes
lazy val AliasAnnot = ctx.requiredClass("dotty.annotation.internal.Alias")
lazy val ChildAnnot = ctx.requiredClass("dotty.annotation.internal.Child")
+ lazy val RepeatedAnnot = ctx.requiredClass("dotty.annotation.internal.Repeated")
lazy val InvariantBetweenClass = ctx.requiredClass("dotty.annotation.internal.InvariantBetween")
lazy val CovariantBetweenClass = ctx.requiredClass("dotty.annotation.internal.CovariantBetween")
lazy val ContravariantBetweenClass = ctx.requiredClass("dotty.annotation.internal.ContravariantBetween")
@@ -380,8 +400,8 @@ class Definitions {
lazy val PhantomClasses = Set[Symbol](AnyClass, AnyValClass, NullClass, NothingClass)
- lazy val asInstanceOfMethods = Set[Symbol](Any_asInstanceOf, Object_asInstanceOf)
- lazy val isInstanceOfMethods = Set[Symbol](Any_isInstanceOf, Object_isInstanceOf)
+ lazy val asInstanceOfMethods = Set[Symbol](Any_asInstanceOf)
+ lazy val isInstanceOfMethods = Set[Symbol](Any_isInstanceOf)
lazy val typeTestsOrCasts = asInstanceOfMethods ++ isInstanceOfMethods
lazy val RootImports = List[Symbol](JavaLangPackageVal, ScalaPackageVal, ScalaPredefModule, DottyPredefModule)
@@ -518,11 +538,11 @@ class Definitions {
/** Lists core classes that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */
lazy val syntheticCoreClasses = List(
+ AnyClass,
AnyRefAlias,
RepeatedParamClass,
JavaRepeatedParamClass,
ByNameParamClass2x,
- AnyClass,
AnyValClass,
NullClass,
NothingClass,
@@ -531,26 +551,7 @@ class Definitions {
EmptyPackageVal)
/** Lists core methods that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */
- lazy val syntheticCoreMethods = List(
- Any_==,
- Any_!=,
- Any_equals,
- Any_hashCode,
- Any_toString,
- Any_getClass,
- Any_isInstanceOf,
- Any_asInstanceOf,
- Any_##,
- Object_eq,
- Object_ne,
- Object_==,
- Object_!=,
- Object_##,
- Object_synchronized,
- Object_isInstanceOf,
- Object_asInstanceOf,
- String_+
- )
+ lazy val syntheticCoreMethods = AnyMethods ++ ObjectMethods ++ List(String_+)
private[this] var _isInitialized = false
def isInitialized = _isInitialized
diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala
index e5f5e6f87..9eab2bd04 100644
--- a/src/dotty/tools/dotc/core/Denotations.scala
+++ b/src/dotty/tools/dotc/core/Denotations.scala
@@ -600,7 +600,7 @@ object Denotations {
case denot: SymDenotation => s"in ${denot.owner}"
case _ => ""
}
- def msg = s"stale symbol; $this#${symbol.id} $ownerMsg, defined in run ${myValidFor.runId}, is referred to in run ${ctx.runId}"
+ def msg = s"stale symbol; $this#${symbol.id} $ownerMsg, defined in ${myValidFor}, is referred to in run ${ctx.period}"
throw new StaleSymbol(msg)
}
diff --git a/src/dotty/tools/dotc/core/Phases.scala b/src/dotty/tools/dotc/core/Phases.scala
index f76b83db6..251cd3876 100644
--- a/src/dotty/tools/dotc/core/Phases.scala
+++ b/src/dotty/tools/dotc/core/Phases.scala
@@ -36,6 +36,8 @@ trait Phases {
def atPhaseNotLaterThanTyper[T](op: Context => T): T =
atPhaseNotLaterThan(base.typerPhase)(op)
+
+ def isAfterTyper: Boolean = base.isAfterTyper(phase)
}
object Phases {
@@ -177,9 +179,11 @@ object Phases {
def refchecksPhase = refChecksCache.phase
def erasurePhase = erasureCache.phase
def flattenPhase = flattenCache.phase
+
+ def isAfterTyper(phase: Phase): Boolean = phase.id > typerPhase.id
}
- final val typerName = "typer"
+ final val typerName = "frontend"
final val refChecksName = "refchecks"
final val erasureName = "erasure"
final val flattenName = "flatten"
diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala
index cb4272f7a..593feb909 100644
--- a/src/dotty/tools/dotc/core/StdNames.scala
+++ b/src/dotty/tools/dotc/core/StdNames.scala
@@ -331,7 +331,6 @@ object StdNames {
val asType: N = "asType"
val asClass: N = "asClass"
val asInstanceOf_ : N = "asInstanceOf"
- val asInstanceOf_Ob : N = "$asInstanceOf"
val assert_ : N = "assert"
val assume_ : N = "assume"
val box: N = "box"
@@ -388,7 +387,6 @@ object StdNames {
val isDefinedAt: N = "isDefinedAt"
val isEmpty: N = "isEmpty"
val isInstanceOf_ : N = "isInstanceOf"
- val isInstanceOf_Ob : N = "$isInstanceOf"
val java: N = "java"
val keepUnions: N = "keepUnions"
val key: N = "key"
diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala
index 9cf06ec47..c7e7dc50d 100644
--- a/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -46,8 +46,9 @@ trait SymDenotations { this: Context =>
case ClassInfo(_, _, _, _, selfInfo) => selfInfo == denot.symbol
case _ => false
}
- stillValid(owner) && owner.isClass && (
- (owner.decls.lookupAll(denot.name) contains denot.symbol)
+ stillValid(owner) && (
+ !owner.isClass
+ || (owner.decls.lookupAll(denot.name) contains denot.symbol)
|| isSelfSym
)
} catch {
diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala
index 4b251f183..c4845a249 100644
--- a/src/dotty/tools/dotc/core/TypeApplications.scala
+++ b/src/dotty/tools/dotc/core/TypeApplications.scala
@@ -111,7 +111,7 @@ class TypeApplications(val self: Type) extends AnyVal {
/** Encode the type resulting from applying this type to given arguments */
final def appliedTo(args: List[Type])(implicit ctx: Context): Type = /*>|>*/ track("appliedTo") /*<|<*/ {
- def recur(tp: Type, tparams: List[TypeSymbol], args: List[Type]): Type = args match {
+ def matchParams(tp: Type, tparams: List[TypeSymbol], args: List[Type]): Type = args match {
case arg :: args1 =>
if (tparams.isEmpty) {
println(s"applied type mismatch: $self $args, typeParams = $typeParams, tsym = ${self.typeSymbol.debugString}") // !!! DEBUG
@@ -119,32 +119,46 @@ class TypeApplications(val self: Type) extends AnyVal {
}
val tparam = tparams.head
val tp1 = RefinedType(tp, tparam.name, arg.toBounds(tparam))
- recur(tp1, tparams.tail, args1)
+ matchParams(tp1, tparams.tail, args1)
case nil => tp
}
- def safeTypeParams(tsym: Symbol) =
- if (tsym.isClass || !self.typeSymbol.isCompleting) typeParams
- else {
- ctx.warning("encountered F-bounded higher-kinded type parameters; assuming they are invariant")
- defn.hkTrait(args map alwaysZero).typeParams
- }
-
- if (args.isEmpty || !canHaveTypeParams) self
- else self match {
+ /** Instantiate type `tp` with `args`.
+ * @param original The original type for which we compute the type parameters
+ * This makes a difference for refinement types, because
+ * refinements bind type parameters and thereby remove them
+ * from `typeParams`.
+ */
+ def instantiate(tp: Type, original: Type): Type = tp match {
case tp: TypeRef =>
val tsym = tp.symbol
if (tsym.isAliasType) tp.underlying.appliedTo(args)
- else recur(tp, safeTypeParams(tsym), args)
+ else {
+ val safeTypeParams =
+ if (tsym.isClass || !tp.typeSymbol.isCompleting) original.typeParams
+ else {
+ ctx.warning("encountered F-bounded higher-kinded type parameters; assuming they are invariant")
+ defn.hkTrait(args map alwaysZero).typeParams
+ }
+ matchParams(tp, safeTypeParams, args)
+ }
+ case tp: RefinedType =>
+ tp.derivedRefinedType(
+ instantiate(tp.parent, original),
+ tp.refinedName,
+ tp.refinedInfo)
case tp: TypeProxy =>
- tp.underlying.appliedTo(args)
+ instantiate(tp.underlying, original)
case AndType(l, r) =>
l.appliedTo(args) & r
case tp: PolyType =>
tp.instantiate(args)
case ErrorType =>
- self
+ tp
}
+
+ if (args.isEmpty || !canHaveTypeParams) self
+ else instantiate(self, self)
}
final def appliedTo(arg: Type)(implicit ctx: Context): Type = appliedTo(arg :: Nil)
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index cab09826b..6174f0915 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -32,6 +32,11 @@ class TypeComparer(initctx: Context) extends DotClass {
*/
protected var ignoreConstraint = false
+ /** Compare a solution of the constraint instead of the constrained parameters.
+ * The solution maps every parameter to its lower bound.
+ */
+ protected var solvedConstraint = false
+
private var needsGc = false
/** Is a subtype check in course? In that case we may not
@@ -79,14 +84,89 @@ class TypeComparer(initctx: Context) extends DotClass {
myAnyType
}
+ /** Map that approximates each param in constraint by its lower bound.
+ * Currently only used for diagnostics.
+ */
+ val approxParams = new TypeMap {
+ def apply(tp: Type): Type = tp.stripTypeVar match {
+ case tp: PolyParam if constraint contains tp =>
+ this(constraint.bounds(tp).lo)
+ case tp =>
+ mapOver(tp)
+ }
+ }
+
+ /** If `param` is contained in constraint, test whether its
+ * bounds are non-empty. Otherwise return `true`.
+ */
+ private def checkBounds(param: PolyParam): Boolean = constraint.at(param) match {
+ case TypeBounds(lo, hi) =>
+ if (Stats.monitored) Stats.record("checkBounds")
+ isSubType(lo, hi)
+ case _ => true
+ }
+
+ /** Test validity of constraint for parameter `changed` and of all
+ * parameters that depend on it.
+ */
+ private def propagate(changed: PolyParam): Boolean =
+ if (Config.trackConstrDeps)
+ checkBounds(changed) &&
+ propagate(constraint.dependentParams(changed) - changed, Set(changed))
+ else
+ constraint forallParams checkBounds
+
+ /** Ensure validity of constraints for parameters `params` and of all
+ * parameters that depend on them and that have not been tested
+ * now or before. If `trackConstrDeps` is not set, do this for all
+ * parameters in the constraint.
+ * @param seen the set of parameters that have been tested before.
+ */
+ private def propagate(params: Set[PolyParam], seen: Set[PolyParam]): Boolean =
+ params.isEmpty ||
+ (params forall checkBounds) && {
+ val seen1 = seen ++ params
+ val nextParams = (Set[PolyParam]() /: params) { (ps, p) =>
+ ps ++ (constraint.dependentParams(p) -- seen1)
+ }
+ propagate(nextParams, seen1)
+ }
+
+ /** Check whether the lower bounds of all parameters in this
+ * constraint are a solution to the constraint.
+ * As an optimization, when `trackConstrDeps` is set, we
+ * only test that the solutions satisfy the constraints `changed`
+ * and all parameters that depend on it.
+ */
+ def isSatisfiable(changed: PolyParam): Boolean = {
+ val saved = solvedConstraint
+ solvedConstraint = true
+ try
+ if (Config.trackConstrDeps) propagate(changed)
+ else
+ constraint.forallParams { param =>
+ checkBounds(param) || {
+ val TypeBounds(lo, hi) = constraint.bounds(param)
+ ctx.log(i"sub fail $lo <:< $hi")
+ ctx.log(i"approximated = ${approxParams(lo)} <:< ${approxParams(hi)}")
+ false
+ }
+ }
+ finally solvedConstraint = saved
+ }
+
/** Update constraint for `param` to `bounds`, check that
* new constraint is still satisfiable.
*/
private def updateConstraint(param: PolyParam, bounds: TypeBounds): Boolean = {
val saved = constraint
constraint = constraint.updated(param, bounds)
- isSubType(bounds.lo, bounds.hi) ||
- { constraint = saved; false } // don't leave the constraint in unsatisfiable state
+ if (propagate(param)) {
+ if (isSatisfiable(param)) return true
+ ctx.log(i"SAT $constraint produced by $param $bounds is not satisfiable")
+ }
+ constraint = saved // don't leave the constraint in unsatisfiable state
+ false
}
private def addConstraint1(param: PolyParam, bound: Type, fromBelow: Boolean): Boolean = {
@@ -101,7 +181,7 @@ class TypeComparer(initctx: Context) extends DotClass {
finally ignoreConstraint = saved
val res =
(param == bound) || (oldBounds eq newBounds) || updateConstraint(param, newBounds)
- constr.println(s"add constraint $param ${if (fromBelow) ">:" else "<:"} $bound = $res")
+ constr.println(s"added1 constraint $param ${if (fromBelow) ">:" else "<:"} $bound = $res")
if (res) constr.println(constraint.show)
res
}
@@ -127,7 +207,8 @@ class TypeComparer(initctx: Context) extends DotClass {
def addConstraint(param: PolyParam, bound0: Type, fromBelow: Boolean): Boolean = {
assert(!frozenConstraint)
val bound = bound0.dealias.stripTypeVar
- constr.println(s"adding ${param.show} ${if (fromBelow) ">:>" else "<:<"} ${bound.show} (${bound.getClass}) to ${constraint.show}")
+ def description = s"${param.show} ${if (fromBelow) ">:>" else "<:<"} ${bound.show} (${bound.getClass}) to ${constraint.show}"
+ constr.println(s"adding $description")
val res = bound match {
case bound: PolyParam if constraint contains bound =>
val TypeBounds(lo, hi) = constraint.bounds(bound)
@@ -150,12 +231,12 @@ class TypeComparer(initctx: Context) extends DotClass {
case bound => // !!! remove to keep the originals
addConstraint1(param, bound, fromBelow)
}
- constr.println(s"added ${param.show} ${if (fromBelow) ">:>" else "<:<"} ${bound.show} = ${constraint.show}")
+ constr.println(s"added $description = ${constraint.show}")
res
}
def isConstrained(param: PolyParam): Boolean =
- !frozenConstraint && (constraint contains param)
+ !frozenConstraint && !solvedConstraint && (constraint contains param)
/** Solve constraint set for given type parameter `param`.
* If `fromBelow` is true the parameter is approximated by its lower bound,
@@ -280,7 +361,7 @@ class TypeComparer(initctx: Context) extends DotClass {
tp2 match {
case tp2: NamedType =>
def compareNamed = {
- implicit val ctx = this.ctx
+ implicit val ctx: Context = this.ctx // Dotty deviation: implicits need explicit type
tp1 match {
case tp1: NamedType =>
val sym1 = tp1.symbol
@@ -305,13 +386,15 @@ class TypeComparer(initctx: Context) extends DotClass {
case tp2: ProtoType =>
isMatchedByProto(tp2, tp1)
case tp2: PolyParam =>
- def comparePolyParam = {
- tp2 == tp1 ||
- isSubTypeWhenFrozen(tp1, bounds(tp2).lo) || {
- if (isConstrained(tp2)) addConstraint(tp2, tp1.widen, fromBelow = true)
- else (ctx.mode is Mode.TypevarsMissContext) || secondTry(tp1, tp2)
- }
- }
+ def comparePolyParam =
+ tp2 == tp1 || {
+ if (solvedConstraint && (constraint contains tp2)) isSubType(tp1, bounds(tp2).lo)
+ else
+ isSubTypeWhenFrozen(tp1, bounds(tp2).lo) || {
+ if (isConstrained(tp2)) addConstraint(tp2, tp1.widen, fromBelow = true)
+ else (ctx.mode is Mode.TypevarsMissContext) || secondTry(tp1, tp2)
+ }
+ }
comparePolyParam
case tp2: BoundType =>
tp2 == tp1 || secondTry(tp1, tp2)
@@ -345,23 +428,25 @@ class TypeComparer(initctx: Context) extends DotClass {
case OrType(tp11, tp12) =>
isSubType(tp11, tp2) && isSubType(tp12, tp2)
case tp1: PolyParam =>
- def comparePolyParam = {
- tp1 == tp2 ||
- isSubTypeWhenFrozen(bounds(tp1).hi, tp2) || {
- if (isConstrained(tp1))
- addConstraint(tp1, tp2, fromBelow = false) && {
- if ((!frozenConstraint) &&
- (tp2 isRef defn.NothingClass) &&
- state.isGlobalCommittable) {
- def msg = s"!!! instantiated to Nothing: $tp1, constraint = ${constraint.show}"
- if (Config.flagInstantiationToNothing) assert(false, msg)
- else ctx.log(msg)
- }
- true
+ def comparePolyParam =
+ tp1 == tp2 || {
+ if (solvedConstraint && (constraint contains tp1)) isSubType(bounds(tp1).lo, tp2)
+ else
+ isSubTypeWhenFrozen(bounds(tp1).hi, tp2) || {
+ if (isConstrained(tp1))
+ addConstraint(tp1, tp2, fromBelow = false) && {
+ if ((!frozenConstraint) &&
+ (tp2 isRef defn.NothingClass) &&
+ state.isGlobalCommittable) {
+ def msg = s"!!! instantiated to Nothing: $tp1, constraint = ${constraint.show}"
+ if (Config.flagInstantiationToNothing) assert(false, msg)
+ else ctx.log(msg)
+ }
+ true
+ }
+ else (ctx.mode is Mode.TypevarsMissContext) || thirdTry(tp1, tp2)
}
- else (ctx.mode is Mode.TypevarsMissContext) || thirdTry(tp1, tp2)
}
- }
comparePolyParam
case tp1: BoundType =>
tp1 == tp2 || thirdTry(tp1, tp2)
@@ -590,7 +675,7 @@ class TypeComparer(initctx: Context) extends DotClass {
/** Defer constraining type variables when compared against prototypes */
def isMatchedByProto(proto: ProtoType, tp: Type) = tp.stripTypeVar match {
- case tp: PolyParam if constraint contains tp => true
+ case tp: PolyParam if !solvedConstraint && (constraint contains tp) => true
case _ => proto.isMatchedBy(tp)
}
@@ -612,6 +697,12 @@ class TypeComparer(initctx: Context) extends DotClass {
i < tparams.length && tparams(i).name == name2
}
+ /** Is type `tp` a TypeRef referring to a higher-kinded parameter? */
+ private def isHKRef(tp: Type) = tp match {
+ case TypeRef(_, name) => name.isHkParamName
+ case _ => false
+ }
+
/** Can type `tp` be constrained from above by adding a constraint to
* a typevar that it refers to? In that case we have to be careful not
* to approximate with the lower bound of a type in `thirdTry`. Instead,
@@ -619,7 +710,7 @@ class TypeComparer(initctx: Context) extends DotClass {
* type variable with (the corresponding type in) `tp2` instead.
*/
def isCappable(tp: Type): Boolean = tp match {
- case tp: PolyParam => constraint contains tp
+ case tp: PolyParam => !solvedConstraint && (constraint contains tp)
case tp: TypeProxy => isCappable(tp.underlying)
case tp: AndOrType => isCappable(tp.tp1) || isCappable(tp.tp2)
case _ => false
@@ -656,7 +747,7 @@ class TypeComparer(initctx: Context) extends DotClass {
v == 0 || tparam.variance == v
}
hk.println(s"isSubTypeHK: args1 = $args1, hk-bounds = $hkBounds $boundsOK $variancesOK")
- boundsOK && variancesOK
+ boundsOK && variancesOK || fourthTry(tp1, tp2)
}
def trySetType(tr: NamedType, bounds: TypeBounds): Boolean =
@@ -895,7 +986,11 @@ class TypeComparer(initctx: Context) extends DotClass {
else {
val t2 = distributeAnd(tp2, tp1)
if (t2.exists) t2
- else AndType(tp1, tp2)
+ else {
+ if (isHKRef(tp1)) tp2
+ else if (isHKRef(tp2)) tp1
+ else AndType(tp1, tp2)
+ }
}
}
@@ -915,7 +1010,11 @@ class TypeComparer(initctx: Context) extends DotClass {
else {
val t2 = distributeOr(tp2, tp1)
if (t2.exists) t2
- else OrType(tp1, tp2)
+ else {
+ if (isHKRef(tp1)) tp1
+ else if (isHKRef(tp2)) tp2
+ else OrType(tp1, tp2)
+ }
}
}
diff --git a/src/dotty/tools/dotc/core/TyperState.scala b/src/dotty/tools/dotc/core/TyperState.scala
index 6e17767d2..59c934e0d 100644
--- a/src/dotty/tools/dotc/core/TyperState.scala
+++ b/src/dotty/tools/dotc/core/TyperState.scala
@@ -14,7 +14,7 @@ import collection.mutable
class TyperState(val reporter: Reporter) extends DotClass with Showable {
/** The current constraint set */
- def constraint: Constraint = new Constraint(SimpleMap.Empty)
+ def constraint: Constraint = new Constraint(SimpleMap.Empty, SimpleMap.Empty)
def constraint_=(c: Constraint): Unit = {}
/** The uninstantiated variables */
@@ -27,6 +27,9 @@ class TyperState(val reporter: Reporter) extends DotClass with Showable {
*/
def instType(tvar: TypeVar): Type = constraint.at(tvar.origin) match {
case _: TypeBounds => NoType
+ case tp: PolyParam =>
+ var tvar1 = constraint.typeVarOfParam(tp)
+ if (tvar1.exists) tvar1 else tp
case tp => tp
}
@@ -35,6 +38,9 @@ class TyperState(val reporter: Reporter) extends DotClass with Showable {
*/
def fresh(isCommittable: Boolean): TyperState = this
+ /** A fresh type state with the same constraint as this one and the given reporter */
+ def withReporter(reporter: Reporter) = new TyperState(reporter)
+
/** Commit state so that it gets propagated to enclosing context */
def commit()(implicit ctx: Context): Unit = unsupported("commit")
@@ -42,7 +48,7 @@ class TyperState(val reporter: Reporter) extends DotClass with Showable {
* type variable instantiation cannot be retracted anymore. Then, remove
* no-longer needed constraint entries.
*/
- def gc(): Unit = ()
+ def gc()(implicit ctx: Context): Unit = ()
/** Is it allowed to commit this state? */
def isCommittable: Boolean = false
@@ -64,6 +70,9 @@ extends TyperState(reporter) {
override def fresh(isCommittable: Boolean): TyperState =
new MutableTyperState(this, new StoreReporter, isCommittable)
+ override def withReporter(reporter: Reporter) =
+ new MutableTyperState(this, reporter, isCommittable)
+
override val isGlobalCommittable =
isCommittable &&
(!previous.isInstanceOf[MutableTyperState] || previous.isGlobalCommittable)
@@ -87,7 +96,7 @@ extends TyperState(reporter) {
reporter.flush()
}
- override def gc(): Unit = {
+ override def gc()(implicit ctx: Context): Unit = {
val toCollect = new mutable.ListBuffer[PolyType]
constraint foreachTypeVar { tvar =>
if (!tvar.inst.exists) {
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 5ce13ad55..088a2e3af 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -597,7 +597,7 @@ object Types {
final def objToAny(implicit ctx: Context) =
if ((this isRef defn.ObjectClass) && !ctx.phase.erasedTypes) defn.AnyType else this
- /** If this is repeated parameter type, its underlying type,
+ /** If this is repeated parameter type, its underlying Seq type,
* else the type itself.
*/
def underlyingIfRepeated(implicit ctx: Context): Type = this match {
@@ -1314,11 +1314,12 @@ object Types {
unique(new NonMemberTermRef(prefix, name, sym))
def withSymAndName(prefix: Type, sym: TermSymbol, name: TermName)(implicit ctx: Context): TermRef =
- if (prefix eq NoPrefix) withNonMemberSym(prefix, name, sym)
- else {
- if (sym.defRunId != NoRunId && sym.isCompleted) withSig(prefix, name, sym.signature)
- else apply(prefix, name)
- } withSym (sym, Signature.NotAMethod)
+ if (prefix eq NoPrefix)
+ withNonMemberSym(prefix, name, sym)
+ else if (sym.defRunId != NoRunId && sym.isCompleted)
+ withSig(prefix, name, sym.signature) withSym (sym, sym.signature)
+ else
+ apply(prefix, name) withSym (sym, Signature.NotAMethod)
def withSig(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef =
unique(withSig(prefix, sym.name, sym.signature).withSym(sym, sym.signature))
@@ -1663,9 +1664,15 @@ object Types {
def apply(paramTypes: List[Type], resultType: Type)(implicit ctx: Context): MethodType =
apply(nme.syntheticParamNames(paramTypes.length), paramTypes, resultType)
def fromSymbols(params: List[Symbol], resultType: Type)(implicit ctx: Context) = {
+ def paramInfo(param: Symbol): Type = param.info match {
+ case AnnotatedType(annot, tp) if annot matches defn.RepeatedAnnot =>
+ tp.translateParameterized(defn.SeqClass, defn.RepeatedParamClass)
+ case tp =>
+ tp
+ }
def transformResult(mt: MethodType) =
resultType.subst(params, (0 until params.length).toList map (MethodParam(mt, _)))
- apply(params map (_.name.asTermName), params map (_.info))(transformResult _)
+ apply(params map (_.name.asTermName), params map paramInfo)(transformResult _)
}
}
@@ -2112,11 +2119,12 @@ object Types {
override def toString =
if (lo eq hi) s"TypeAlias($lo)" else s"TypeBounds($lo, $hi)"
+
+ override def computeHash = unsupported("computeHash")
}
class CachedTypeBounds(lo: Type, hi: Type, hc: Int) extends TypeBounds(lo, hi) {
myHash = hc
- override def computeHash = unsupported("computeHash")
}
final class CoTypeBounds(lo: Type, hi: Type, hc: Int) extends CachedTypeBounds(lo, hi, hc) {
@@ -2269,7 +2277,7 @@ object Types {
/** Map this function over given type */
def mapOver(tp: Type): Type = {
- implicit val ctx = this.ctx
+ implicit val ctx: Context = this.ctx // Dotty deviation: implicits need explicit type
tp match {
case tp: NamedType =>
if (stopAtStatic && tp.symbol.isStatic) tp
diff --git a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
index f5942dac2..0ed301732 100644
--- a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
+++ b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
@@ -891,8 +891,10 @@ class ClassfileParser(
def getType(index: Int)(implicit ctx: Context): Type =
sigToType(getExternalName(index))
- def getSuperClass(index: Int)(implicit ctx: Context): Symbol =
- if (index == 0) defn.AnyClass else getClassSymbol(index)
+ def getSuperClass(index: Int)(implicit ctx: Context): Symbol = {
+ assert(index != 0, "attempt to parse java.lang.Object from classfile")
+ getClassSymbol(index)
+ }
def getConstant(index: Int)(implicit ctx: Context): Constant = {
if (index <= 0 || len <= index) errorBadIndex(index)
diff --git a/src/dotty/tools/dotc/core/transform/Erasure.scala b/src/dotty/tools/dotc/core/transform/Erasure.scala
index 9fb580ae8..f2e3355fb 100644
--- a/src/dotty/tools/dotc/core/transform/Erasure.scala
+++ b/src/dotty/tools/dotc/core/transform/Erasure.scala
@@ -61,8 +61,8 @@ object Erasure {
*/
def transformInfo(sym: Symbol, tp: Type)(implicit ctx: Context): Type = {
val erase = erasureFn(sym is JavaDefined, isSemi = true, sym.isConstructor, wildcardOK = false)
- if ((sym eq defn.Object_asInstanceOf) ||
- (sym eq defn.Object_isInstanceOf) ||
+ if ((sym eq defn.Any_asInstanceOf) ||
+ (sym eq defn.Any_isInstanceOf) ||
(sym.owner eq defn.ArrayClass) && (sym.isType || sym.isConstructor)) sym.info
else if (sym.isAbstractType) TypeAlias(WildcardType)
else erase(tp)
@@ -124,7 +124,7 @@ class Erasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wildcard
else this(parent)
case tp: TermRef =>
val sym = tp.symbol
- if (sym.owner is Package) sym.termRef
+ if (sym.exists && (sym.owner is Package)) sym.termRef
else tp.derivedSelect(this(tp.prefix))
case _: ThisType | _: ConstantType =>
tp
diff --git a/src/dotty/tools/dotc/printing/PlainPrinter.scala b/src/dotty/tools/dotc/printing/PlainPrinter.scala
index f10aa7225..308470885 100644
--- a/src/dotty/tools/dotc/printing/PlainPrinter.scala
+++ b/src/dotty/tools/dotc/printing/PlainPrinter.scala
@@ -143,7 +143,7 @@ class PlainPrinter(_ctx: Context) extends Printer {
toTextLocal(tpe) ~ " " ~ toText(annot)
case tp: TypeVar =>
val suffix = if (tp.isInstantiated) "'" else "?"
- toTextLocal(tp.stripTypeVar) ~ suffix // debug for now, so that we can see where the TypeVars are.
+ toTextLocal(tp.instanceOpt orElse tp.origin) ~ suffix // debug for now, so that we can see where the TypeVars are.
case _ =>
tp.fallbackToText(this)
}
diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala
index 791df341a..e6d012d68 100644
--- a/src/dotty/tools/dotc/transform/Erasure.scala
+++ b/src/dotty/tools/dotc/transform/Erasure.scala
@@ -33,7 +33,10 @@ class Erasure extends Phase with DenotTransformer {
def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = ref match {
case ref: SymDenotation =>
assert(ctx.phase == this, s"transforming $ref at ${ctx.phase}")
- ref.copySymDenotation(info = transformInfo(ref.symbol, ref.info))
+ val owner = ref.owner
+ ref.copySymDenotation(
+ owner = if (owner eq defn.AnyClass) defn.ObjectClass else owner,
+ info = transformInfo(ref.symbol, ref.info))
case ref =>
ref.derivedSingleDenotation(ref.symbol, erasure(ref.info))
}
@@ -136,7 +139,7 @@ object Erasure {
cast(runtimeCall(nme.toObjectArray, tree :: Nil), pt)
case _ =>
ctx.log(s"casting from ${tree.showSummary}: ${tree.tpe.show} to ${pt.show}")
- TypeApply(Select(tree, defn.Object_asInstanceOf), TypeTree(pt) :: Nil)
+ TypeApply(Select(tree, defn.Any_asInstanceOf), TypeTree(pt) :: Nil)
}
/** Adaptation of an expression `e` to an expected type `PT`, applying the following
@@ -195,7 +198,7 @@ object Erasure {
*/
override def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = {
val sym = tree.symbol
- assert(sym.exists)
+ assert(sym.exists, tree.show)
def select(qual: Tree, sym: Symbol): Tree =
untpd.cpy.Select(tree, qual, sym.name) withType qual.tpe.select(sym)
@@ -242,6 +245,8 @@ object Erasure {
case mt: MethodType =>
val args1 = args.zipWithConserve(mt.paramTypes)(typedExpr)
untpd.cpy.Apply(tree, fun1, args1) withType mt.resultType
+ case _ =>
+ throw new MatchError(i"tree $tree has uxpected type of function ${fun1.tpe.widen}, was ${fun.typeOpt.widen}")
}
}
diff --git a/src/dotty/tools/dotc/transform/InterceptedMethods.scala b/src/dotty/tools/dotc/transform/InterceptedMethods.scala
index d5a4377d0..f5fed6fda 100644
--- a/src/dotty/tools/dotc/transform/InterceptedMethods.scala
+++ b/src/dotty/tools/dotc/transform/InterceptedMethods.scala
@@ -28,6 +28,10 @@ import dotty.tools.dotc.core.Denotations.SingleDenotation
import dotty.tools.dotc.core.SymDenotations.SymDenotation
import StdNames._
+// @DarkDimius The getClass scheme changed. We no longer can have
+// two different methods in Any and Object. The tests pass but I
+// am not sure Intercepted methods treats getClass right now.
+// Please check and delete comment when done.
/** Replace member references as follows:
*
* - `x == y` for == in class Any becomes `x equals y` with equals in class Object.
@@ -50,12 +54,10 @@ class InterceptedMethods extends TreeTransform {
/** perform context-dependant initialization */
override def init(implicit ctx: Context, info: TransformerInfo): Unit = {
- getClassMethods = Set(defn.Any_getClass, defn.AnyVal_getClass)
- poundPoundMethods = Set(defn.Any_##, defn.Object_##)
+ poundPoundMethods = Set(defn.Any_##)
Any_comparisons = Set(defn.Any_==, defn.Any_!=)
- interceptedMethods = getClassMethods ++ poundPoundMethods ++ Any_comparisons
- primitiveGetClassMethods = Set[Symbol](defn.Any_getClass, defn.AnyVal_getClass) ++
- defn.ScalaValueClasses.map(x => x.requiredMethod(nme.getClass_))
+ interceptedMethods = poundPoundMethods ++ Any_comparisons
+ primitiveGetClassMethods = Set[Symbol]() ++ defn.ScalaValueClasses.map(x => x.requiredMethod(nme.getClass_))
}
// this should be removed if we have guarantee that ## will get Apply node
@@ -97,7 +99,7 @@ class InterceptedMethods extends TreeTransform {
override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree = {
def unknown = {
- assert(false, s"The symbol '${tree.fun.symbol}' was interecepted but didn't match any cases, " +
+ assert(false, s"The symbol '${tree.fun.symbol.showLocated}' was intercepted but didn't match any cases, " +
s"that means the intercepted methods set doesn't match the code")
tree
}
@@ -109,9 +111,9 @@ class InterceptedMethods extends TreeTransform {
PoundPoundValue(qual)
} else if (Any_comparisons contains tree.fun.symbol.asTerm) {
if (tree.fun.symbol eq defn.Any_==) {
- Apply(Select(qual, defn.Object_equals.termRef), tree.args)
+ Apply(Select(qual, defn.Any_equals), tree.args)
} else if (tree.fun.symbol eq defn.Any_!=) {
- Select(Apply(Select(qual, defn.Object_equals.termRef), tree.args), defn.Boolean_!.termRef)
+ Select(Apply(Select(qual, defn.Any_equals), tree.args), defn.Boolean_!)
} else unknown
} /* else if (isPrimitiveValueClass(qual.tpe.typeSymbol)) {
// todo: this is needed to support value classes
@@ -128,7 +130,7 @@ class InterceptedMethods extends TreeTransform {
// we get a primitive form of _getClass trying to target a boxed value
// so we need replace that method name with Object_getClass to get correct behavior.
// See SI-5568.
- Apply(Select(qual, defn.Object_getClass.termRef), Nil)
+ Apply(Select(qual, defn.Any_getClass), Nil)
} else {
unknown
}
diff --git a/src/dotty/tools/dotc/transform/LazyVals.scala b/src/dotty/tools/dotc/transform/LazyVals.scala
index 9e5ddffa4..527c7e228 100644
--- a/src/dotty/tools/dotc/transform/LazyVals.scala
+++ b/src/dotty/tools/dotc/transform/LazyVals.scala
@@ -54,7 +54,7 @@ class LazyValTranformContext {
val infoTransformerNewDefinitions = mutable.Map.empty[ClassSymbol, ListBuffer[Symbol]]
- def addSym(owner: ClassSymbol, sym: Symbol) {
+ def addSym(owner: ClassSymbol, sym: Symbol) = {
infoTransformerNewDefinitions.get(owner) match {
case Some(x) => x += sym
case None => infoTransformerNewDefinitions.put(owner, ListBuffer(sym))
diff --git a/src/dotty/tools/dotc/transform/TailRec.scala b/src/dotty/tools/dotc/transform/TailRec.scala
index b0d5c6438..cd0643a6e 100644
--- a/src/dotty/tools/dotc/transform/TailRec.scala
+++ b/src/dotty/tools/dotc/transform/TailRec.scala
@@ -129,7 +129,7 @@ class TailRec extends TreeTransform with DenotTransformer {
Block(
List(res),
vparamss0.foldLeft(Apply(call, List(This(owner))))
- {case (call, args) => Apply(call, args.map(x=> Ident(x.symbol.termRef)))}
+ {(call, args) => Apply(call, args.map(x => Ident(x.symbol.termRef)))}
)
}
else {
@@ -213,7 +213,8 @@ class TailRec extends TreeTransform with DenotTransformer {
val methodWithTargs = if (targs.nonEmpty) TypeApply(method, targs) else method
if (methodWithTargs.tpe.widen.isParameterless) methodWithTargs
else argumentss.foldLeft(methodWithTargs) {
- case (method, args) => Apply(method, args)
+ // case (method, args) => Apply(method, args) // Dotty deviation no auto-detupling yet. Interesting that one can do it in Scala2!
+ (method, args) => Apply(method, args)
}
}
def fail(reason: String) = {
@@ -229,7 +230,7 @@ class TailRec extends TreeTransform with DenotTransformer {
val recv = noTailTransform(reciever)
if (recv.tpe.widen.isParameterless) method
else argumentss.foldLeft(Apply(method, List(recv))) {
- case (method, args) => Apply(method, args)
+ (method, args) => Apply(method, args) // Dotty deviation no auto-detupling yet.
}
}
diff --git a/src/dotty/tools/dotc/transform/TreeChecker.scala b/src/dotty/tools/dotc/transform/TreeChecker.scala
index f52c5bc1c..e9970e1f8 100644
--- a/src/dotty/tools/dotc/transform/TreeChecker.scala
+++ b/src/dotty/tools/dotc/transform/TreeChecker.scala
@@ -8,14 +8,17 @@ import core.SymDenotations._
import core.Contexts._
import core.Symbols._
import core.Types._
+import core.Flags._
import core.Constants._
import core.StdNames._
import core.Decorators._
import core.transform.Erasure.isUnboundedGeneric
import typer._
import typer.ErrorReporting._
+import reporting.ThrowingReporter
import ast.Trees._
import ast.{tpd, untpd}
+import java.lang.AssertionError
/** This transform eliminates patterns. Right now it's a dummy.
* Awaiting the real pattern matcher.
@@ -25,38 +28,69 @@ class TreeChecker {
def check(ctx: Context) = {
println(s"checking ${ctx.compilationUnit} after phase ${ctx.phase.prev}")
- Checker.typedExpr(ctx.compilationUnit.tpdTree)(ctx)
+ val checkingCtx = ctx.fresh
+ .setTyperState(ctx.typerState.withReporter(new ThrowingReporter(ctx.typerState.reporter)))
+ Checker.typedExpr(ctx.compilationUnit.tpdTree)(checkingCtx)
}
object Checker extends ReTyper {
- override def typed(tree: untpd.Tree, pt: Type)(implicit ctx: Context) =
- if (tree.isEmpty) tree.asInstanceOf[Tree]
- else {
- assert(tree.hasType, tree.show)
- val tree1 = super.typed(tree, pt)
- def sameType(tp1: Type, tp2: Type) =
- (tp1 eq tp2) || // accept NoType / NoType
- (tp1 =:= tp2)
- def divergenceMsg =
- s"""Types differ
- |Original type : ${tree.typeOpt.show}
- |After checking: ${tree1.tpe.show}
- |Original tree : ${tree.show}
- |After checking: ${tree1.show}
- """.stripMargin
- assert(sameType(tree1.tpe, tree.typeOpt), divergenceMsg)
- tree1
- }
+ override def typed(tree: untpd.Tree, pt: Type)(implicit ctx: Context) = try {
+ tree match {
+ case _: untpd.UnApply =>
+ // can't recheck patterns
+ tree.asInstanceOf[tpd.Tree]
+ case _: untpd.TypedSplice | _: untpd.Thicket | _: EmptyValDef[_] =>
+ super.typed(tree)
+ case _ if tree.isType =>
+ promote(tree)
+ case _ =>
+ val tree1 = super.typed(tree, pt)
+ def sameType(tp1: Type, tp2: Type) =
+ (tp1 eq tp2) || // accept NoType / NoType
+ (tp1 =:= tp2)
+ def divergenceMsg =
+ s"""Types differ
+ |Original type : ${tree.typeOpt.show}
+ |After checking: ${tree1.tpe.show}
+ |Original tree : ${tree.show}
+ |After checking: ${tree1.show}
+ """.stripMargin
+ assert(sameType(tree1.tpe, tree.typeOpt), divergenceMsg)
+ tree1
+ }
+ } catch {
+ case ex: Throwable =>
+ println(i"exception while checking $tree of class ${tree.getClass} # ${tree.uniqueId}")
+ throw ex
+ }
override def typedIdent(tree: untpd.Ident, pt: Type)(implicit ctx: Context): Tree = {
- assert(tree.isTerm, tree.show)
+ assert(tree.isTerm || ctx.phase.prev.id <= ctx.typerPhase.id, tree.show + " at " + ctx.phase)
super.typedIdent(tree, pt)
}
override def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = {
- assert(tree.isTerm, tree.show)
+ assert(tree.isTerm || ctx.phase.prev.id <= ctx.typerPhase.id, tree.show + " at " + ctx.phase)
super.typedSelect(tree, pt)
}
+
+ /** Check that all defined symbols have legal owners.
+ * An owner is legal if it is either the same as the context's owner
+ * or there's an owner chain of valdefs starting at the context's owner and
+ * reaching up to the symbol's owner. The reason for this relaxed matching
+ * is that we should be able to pull out an expression as an initializer
+ * of a helper value without having to do a change owner traversal of the expression.
+ */
+ override def index(trees: List[untpd.Tree])(implicit ctx: Context): Context = {
+ def ownerMatches(symOwner: Symbol, ctxOwner: Symbol): Boolean =
+ symOwner == ctxOwner ||
+ ctxOwner.isTerm && !(ctxOwner is Method | Lazy | Mutable) &&
+ ownerMatches(symOwner, ctxOwner.owner)
+ for (tree <- trees if tree.isDef)
+ assert(ownerMatches(tree.symbol.owner, ctx.owner),
+ i"bad owner; $tree has owner ${tree.symbol.owner}, expected was ${ctx.owner}")
+ super.index(trees)
+ }
}
}
diff --git a/src/dotty/tools/dotc/transform/TreeTransform.scala b/src/dotty/tools/dotc/transform/TreeTransform.scala
index c0ce68e95..1bce0de66 100644
--- a/src/dotty/tools/dotc/transform/TreeTransform.scala
+++ b/src/dotty/tools/dotc/transform/TreeTransform.scala
@@ -886,32 +886,33 @@ object TreeTransforms {
final private[TreeTransforms] def transformNamed(tree: NameTree, info: TransformerInfo, cur: Int)(implicit ctx: Context): Tree =
tree match {
case tree: Ident =>
- implicit val mutatedInfo = mutateTransformers(info, prepForIdent, info.nx.nxPrepIdent, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForIdent, info.nx.nxPrepIdent, tree, cur)
+ // Dotty deviation: implicits need explicit type
if (mutatedInfo eq null) tree
else goIdent(tree, mutatedInfo.nx.nxTransIdent(cur))
case tree: Select =>
- implicit val mutatedInfo = mutateTransformers(info, prepForSelect, info.nx.nxPrepSelect, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForSelect, info.nx.nxPrepSelect, tree, cur)
if (mutatedInfo eq null) tree
else {
val qual = transform(tree.qualifier, mutatedInfo, cur)
goSelect(cpy.Select(tree, qual, tree.name), mutatedInfo.nx.nxTransSelect(cur))
}
case tree: SelectFromTypeTree =>
- implicit val mutatedInfo = mutateTransformers(info, prepForSelectFromTypeTree, info.nx.nxPrepSelectFromTypeTree, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForSelectFromTypeTree, info.nx.nxPrepSelectFromTypeTree, tree, cur)
if (mutatedInfo eq null) tree
else {
val qual = transform(tree.qualifier, mutatedInfo, cur)
goSelectFromTypeTree(cpy.SelectFromTypeTree(tree, qual, tree.name), mutatedInfo.nx.nxTransSelectFromTypeTree(cur))
}
case tree: Bind =>
- implicit val mutatedInfo = mutateTransformers(info, prepForBind, info.nx.nxPrepBind, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForBind, info.nx.nxPrepBind, tree, cur)
if (mutatedInfo eq null) tree
else {
val body = transform(tree.body, mutatedInfo, mutatedInfo.nx.nxTransBind(cur))
goBind(cpy.Bind(tree, tree.name, body), cur)
}
case tree: ValDef if !tree.isEmpty => // As a result of discussing with Martin: emptyValDefs shouldn't be copied // NAME
- implicit val mutatedInfo = mutateTransformers(info, prepForValDef, info.nx.nxPrepValDef, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForValDef, info.nx.nxPrepValDef, tree, cur)
if (mutatedInfo eq null) tree
else {
val nestedCtx = if (tree.symbol.exists) localContext(tree.symbol) else ctx
@@ -920,7 +921,7 @@ object TreeTransforms {
goValDef(cpy.ValDef(tree, tree.mods, tree.name, tpt, rhs), mutatedInfo.nx.nxTransValDef(cur))
}
case tree: DefDef =>
- implicit val mutatedInfo = mutateTransformers(info, prepForDefDef, info.nx.nxPrepDefDef, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForDefDef, info.nx.nxPrepDefDef, tree, cur)
if (mutatedInfo eq null) tree
else {
val nestedCtx = localContext(tree.symbol)
@@ -931,7 +932,7 @@ object TreeTransforms {
goDefDef(cpy.DefDef(tree, tree.mods, tree.name, tparams, vparams, tpt, rhs), mutatedInfo.nx.nxTransDefDef(cur))
}
case tree: TypeDef =>
- implicit val mutatedInfo = mutateTransformers(info, prepForTypeDef, info.nx.nxPrepTypeDef, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForTypeDef, info.nx.nxPrepTypeDef, tree, cur)
if (mutatedInfo eq null) tree
else {
val rhs = transform(tree.rhs, mutatedInfo, cur)(localContext(tree.symbol))
@@ -944,18 +945,18 @@ object TreeTransforms {
final private[TreeTransforms] def transformUnnamed(tree: Tree, info: TransformerInfo, cur: Int)(implicit ctx: Context): Tree =
tree match {
case tree: This =>
- implicit val mutatedInfo = mutateTransformers(info, prepForThis, info.nx.nxPrepThis, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForThis, info.nx.nxPrepThis, tree, cur)
if (mutatedInfo eq null) tree
else goThis(tree, mutatedInfo.nx.nxTransThis(cur))
case tree: Super =>
- implicit val mutatedInfo = mutateTransformers(info, prepForSuper, info.nx.nxPrepSuper, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForSuper, info.nx.nxPrepSuper, tree, cur)
if (mutatedInfo eq null) tree
else {
val qual = transform(tree.qual, mutatedInfo, cur)
goSuper(cpy.Super(tree, qual, tree.mix), mutatedInfo.nx.nxTransSuper(cur))
}
case tree: Apply =>
- implicit val mutatedInfo = mutateTransformers(info, prepForApply, info.nx.nxPrepApply, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForApply, info.nx.nxPrepApply, tree, cur)
if (mutatedInfo eq null) tree
else {
val fun = transform(tree.fun, mutatedInfo, cur)
@@ -963,7 +964,7 @@ object TreeTransforms {
goApply(cpy.Apply(tree, fun, args), mutatedInfo.nx.nxTransApply(cur))
}
case tree: TypeApply =>
- implicit val mutatedInfo = mutateTransformers(info, prepForTypeApply, info.nx.nxPrepTypeApply, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForTypeApply, info.nx.nxPrepTypeApply, tree, cur)
if (mutatedInfo eq null) tree
else {
val fun = transform(tree.fun, mutatedInfo, cur)
@@ -971,18 +972,18 @@ object TreeTransforms {
goTypeApply(cpy.TypeApply(tree, fun, args), mutatedInfo.nx.nxTransTypeApply(cur))
}
case tree: Literal =>
- implicit val mutatedInfo = mutateTransformers(info, prepForLiteral, info.nx.nxPrepLiteral, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForLiteral, info.nx.nxPrepLiteral, tree, cur)
if (mutatedInfo eq null) tree
else goLiteral(tree, mutatedInfo.nx.nxTransLiteral(cur))
case tree: New =>
- implicit val mutatedInfo = mutateTransformers(info, prepForNew, info.nx.nxPrepNew, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForNew, info.nx.nxPrepNew, tree, cur)
if (mutatedInfo eq null) tree
else {
val tpt = transform(tree.tpt, mutatedInfo, cur)
goNew(cpy.New(tree, tpt), mutatedInfo.nx.nxTransNew(cur))
}
case tree: Pair =>
- implicit val mutatedInfo = mutateTransformers(info, prepForPair, info.nx.nxPrepPair, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForPair, info.nx.nxPrepPair, tree, cur)
if (mutatedInfo eq null) tree
else {
val left = transform(tree.left, mutatedInfo, cur)
@@ -990,7 +991,7 @@ object TreeTransforms {
goPair(cpy.Pair(tree, left, right), mutatedInfo.nx.nxTransPair(cur))
}
case tree: Typed =>
- implicit val mutatedInfo = mutateTransformers(info, prepForTyped, info.nx.nxPrepTyped, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForTyped, info.nx.nxPrepTyped, tree, cur)
if (mutatedInfo eq null) tree
else {
val expr = transform(tree.expr, mutatedInfo, cur)
@@ -998,7 +999,7 @@ object TreeTransforms {
goTyped(cpy.Typed(tree, expr, tpt), mutatedInfo.nx.nxTransTyped(cur))
}
case tree: Assign =>
- implicit val mutatedInfo = mutateTransformers(info, prepForAssign, info.nx.nxPrepAssign, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForAssign, info.nx.nxPrepAssign, tree, cur)
if (mutatedInfo eq null) tree
else {
val lhs = transform(tree.lhs, mutatedInfo, cur)
@@ -1006,7 +1007,7 @@ object TreeTransforms {
goAssign(cpy.Assign(tree, lhs, rhs), mutatedInfo.nx.nxTransAssign(cur))
}
case tree: Block =>
- implicit val mutatedInfo = mutateTransformers(info, prepForBlock, info.nx.nxPrepBlock, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForBlock, info.nx.nxPrepBlock, tree, cur)
if (mutatedInfo eq null) tree
else {
val stats = transformStats(tree.stats, ctx.owner, mutatedInfo, cur)
@@ -1014,7 +1015,7 @@ object TreeTransforms {
goBlock(cpy.Block(tree, stats, expr), mutatedInfo.nx.nxTransBlock(cur))
}
case tree: If =>
- implicit val mutatedInfo = mutateTransformers(info, prepForIf, info.nx.nxPrepIf, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForIf, info.nx.nxPrepIf, tree, cur)
if (mutatedInfo eq null) tree
else {
val cond = transform(tree.cond, mutatedInfo, cur)
@@ -1023,7 +1024,7 @@ object TreeTransforms {
goIf(cpy.If(tree, cond, thenp, elsep), mutatedInfo.nx.nxTransIf(cur))
}
case tree: Closure =>
- implicit val mutatedInfo = mutateTransformers(info, prepForClosure, info.nx.nxPrepClosure, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForClosure, info.nx.nxPrepClosure, tree, cur)
if (mutatedInfo eq null) tree
else {
val env = transformTrees(tree.env, mutatedInfo, cur)
@@ -1032,7 +1033,7 @@ object TreeTransforms {
goClosure(cpy.Closure(tree, env, meth, tpt), mutatedInfo.nx.nxTransClosure(cur))
}
case tree: Match =>
- implicit val mutatedInfo = mutateTransformers(info, prepForMatch, info.nx.nxPrepMatch, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForMatch, info.nx.nxPrepMatch, tree, cur)
if (mutatedInfo eq null) tree
else {
val selector = transform(tree.selector, mutatedInfo, cur)
@@ -1040,7 +1041,7 @@ object TreeTransforms {
goMatch(cpy.Match(tree, selector, cases), mutatedInfo.nx.nxTransMatch(cur))
}
case tree: CaseDef =>
- implicit val mutatedInfo = mutateTransformers(info, prepForCaseDef, info.nx.nxPrepCaseDef, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForCaseDef, info.nx.nxPrepCaseDef, tree, cur)
if (mutatedInfo eq null) tree
else {
val pat = transform(tree.pat, mutatedInfo, cur)
@@ -1049,7 +1050,7 @@ object TreeTransforms {
goCaseDef(cpy.CaseDef(tree, pat, guard, body), mutatedInfo.nx.nxTransCaseDef(cur))
}
case tree: Return =>
- implicit val mutatedInfo = mutateTransformers(info, prepForReturn, info.nx.nxPrepReturn, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForReturn, info.nx.nxPrepReturn, tree, cur)
if (mutatedInfo eq null) tree
else {
val expr = transform(tree.expr, mutatedInfo, cur)
@@ -1057,7 +1058,7 @@ object TreeTransforms {
goReturn(cpy.Return(tree, expr, from), mutatedInfo.nx.nxTransReturn(cur))
}
case tree: Try =>
- implicit val mutatedInfo = mutateTransformers(info, prepForTry, info.nx.nxPrepTry, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForTry, info.nx.nxPrepTry, tree, cur)
if (mutatedInfo eq null) tree
else {
val block = transform(tree.expr, mutatedInfo, cur)
@@ -1066,35 +1067,35 @@ object TreeTransforms {
goTry(cpy.Try(tree, block, handler, finalizer), mutatedInfo.nx.nxTransTry(cur))
}
case tree: Throw =>
- implicit val mutatedInfo = mutateTransformers(info, prepForThrow, info.nx.nxPrepThrow, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForThrow, info.nx.nxPrepThrow, tree, cur)
if (mutatedInfo eq null) tree
else {
val expr = transform(tree.expr, mutatedInfo, cur)
goThrow(cpy.Throw(tree, expr), mutatedInfo.nx.nxTransThrow(cur))
}
case tree: SeqLiteral =>
- implicit val mutatedInfo = mutateTransformers(info, prepForSeqLiteral, info.nx.nxPrepSeqLiteral, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForSeqLiteral, info.nx.nxPrepSeqLiteral, tree, cur)
if (mutatedInfo eq null) tree
else {
val elems = transformTrees(tree.elems, mutatedInfo, cur)
goSeqLiteral(cpy.SeqLiteral(tree, elems), mutatedInfo.nx.nxTransLiteral(cur))
}
case tree: TypeTree =>
- implicit val mutatedInfo = mutateTransformers(info, prepForTypeTree, info.nx.nxPrepTypeTree, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForTypeTree, info.nx.nxPrepTypeTree, tree, cur)
if (mutatedInfo eq null) tree
else {
val original = transform(tree.original, mutatedInfo, cur)
goTypeTree(cpy.TypeTree(tree, original), mutatedInfo.nx.nxTransTypeTree(cur))
}
case tree: Alternative =>
- implicit val mutatedInfo = mutateTransformers(info, prepForAlternative, info.nx.nxPrepAlternative, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForAlternative, info.nx.nxPrepAlternative, tree, cur)
if (mutatedInfo eq null) tree
else {
val trees = transformTrees(tree.trees, mutatedInfo, cur)
goAlternative(cpy.Alternative(tree, trees), mutatedInfo.nx.nxTransAlternative(cur))
}
case tree: UnApply =>
- implicit val mutatedInfo = mutateTransformers(info, prepForUnApply, info.nx.nxPrepUnApply, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForUnApply, info.nx.nxPrepUnApply, tree, cur)
if (mutatedInfo eq null) tree
else {
val fun = transform(tree.fun, mutatedInfo, cur)
@@ -1103,7 +1104,7 @@ object TreeTransforms {
goUnApply(cpy.UnApply(tree, fun, implicits, patterns), mutatedInfo.nx.nxTransUnApply(cur))
}
case tree: Template =>
- implicit val mutatedInfo = mutateTransformers(info, prepForTemplate, info.nx.nxPrepTemplate, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForTemplate, info.nx.nxPrepTemplate, tree, cur)
if (mutatedInfo eq null) tree
else {
val constr = transformSub(tree.constr, mutatedInfo, cur)
@@ -1113,7 +1114,7 @@ object TreeTransforms {
goTemplate(cpy.Template(tree, constr, parents, self, body), mutatedInfo.nx.nxTransTemplate(cur))
}
case tree: PackageDef =>
- implicit val mutatedInfo = mutateTransformers(info, prepForPackageDef, info.nx.nxPrepPackageDef, tree, cur)
+ implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForPackageDef, info.nx.nxPrepPackageDef, tree, cur)
if (mutatedInfo eq null) tree
else {
val nestedCtx = localContext(tree.symbol)
diff --git a/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/src/dotty/tools/dotc/transform/TypeTestsCasts.scala
index a36bf6500..5f65ee414 100644
--- a/src/dotty/tools/dotc/transform/TypeTestsCasts.scala
+++ b/src/dotty/tools/dotc/transform/TypeTestsCasts.scala
@@ -68,10 +68,10 @@ class TypeTestsCasts extends TreeTransform {
runtimeCall(nme.isArray, arg :: Literal(Constant(ndims)) :: Nil)
if (ndims == 1) isArrayTest(qual)
else evalOnce(qual) { qual1 =>
- mkAnd(derivedTree(qual1, defn.Object_isInstanceOf, qual1.tpe), isArrayTest(qual1))
+ mkAnd(derivedTree(qual1, defn.Any_isInstanceOf, qual1.tpe), isArrayTest(qual1))
}
case _ =>
- derivedTree(expr, defn.Object_isInstanceOf, argType)
+ derivedTree(expr, defn.Any_isInstanceOf, argType)
}
}
@@ -81,10 +81,10 @@ class TypeTestsCasts extends TreeTransform {
else if (qualCls.isPrimitiveValueClass) {
val argCls = argType.classSymbol
if (argCls.isPrimitiveValueClass) primitiveConversion(qual, argCls)
- else derivedTree(box(qual), defn.Object_asInstanceOf, argType)
+ else derivedTree(box(qual), defn.Any_asInstanceOf, argType)
}
else
- derivedTree(qual, defn.Object_asInstanceOf, argType)
+ derivedTree(qual, defn.Any_asInstanceOf, argType)
}
if (sym eq defn.Any_isInstanceOf)
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala
index ae325af2a..5e52c5d7e 100644
--- a/src/dotty/tools/dotc/typer/Checking.scala
+++ b/src/dotty/tools/dotc/typer/Checking.scala
@@ -69,15 +69,6 @@ trait Checking {
defn.ObjectClass.typeRef
}
- /** Check that (return) type of implicit definition is not empty */
- def checkImplicitTptNonEmpty(defTree: untpd.ValOrDefDef)(implicit ctx: Context): Unit = defTree.tpt match {
- case tpt: untpd.DerivedTypeTree =>
- case TypeTree(untpd.EmptyTree) =>
- val resStr = if (defTree.isInstanceOf[untpd.DefDef]) "result " else ""
- ctx.error(d"${resStr}type of implicit definition needs to be given explicitly", defTree.pos)
- case _ =>
- }
-
/** Check that a non-implicit parameter making up the first parameter section of an
* implicit conversion is not a singleton type.
*/
@@ -150,7 +141,6 @@ trait NoChecking extends Checking {
override def checkStable(tp: Type, pos: Position)(implicit ctx: Context): Unit = ()
override def checkLegalPrefix(tp: Type, pos: Position)(implicit ctx: Context): Unit = ()
override def checkClassTypeWithStablePrefix(tp: Type, pos: Position, traitReq: Boolean)(implicit ctx: Context): Type = tp
- override def checkImplicitTptNonEmpty(defTree: untpd.ValOrDefDef)(implicit ctx: Context): Unit = ()
override def checkImplicitParamsNotSingletons(vparamss: List[List[ValDef]])(implicit ctx: Context): Unit = ()
override def checkFeasible(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp
override def checkNoDoubleDefs(cls: Symbol)(implicit ctx: Context): Unit = ()
diff --git a/src/dotty/tools/dotc/typer/EtaExpansion.scala b/src/dotty/tools/dotc/typer/EtaExpansion.scala
index 099dd943a..110dc6152 100644
--- a/src/dotty/tools/dotc/typer/EtaExpansion.scala
+++ b/src/dotty/tools/dotc/typer/EtaExpansion.scala
@@ -116,6 +116,7 @@ object EtaExpansion {
*/
def etaExpand(tree: Tree, mt: MethodType, xarity: Int)(implicit ctx: Context): untpd.Tree = {
import untpd._
+ assert(!ctx.isAfterTyper)
val defs = new mutable.ListBuffer[tpd.Tree]
val lifted: Tree = TypedSplice(liftApp(defs, tree))
val paramTypes: List[Tree] =
diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala
index 93876651a..a32f552ed 100644
--- a/src/dotty/tools/dotc/typer/Implicits.scala
+++ b/src/dotty/tools/dotc/typer/Implicits.scala
@@ -65,7 +65,7 @@ object Implicits {
case tpw =>
//if (ctx.typer.isApplicable(tp, argType :: Nil, resultType))
// println(i"??? $tp is applicable to $this / typeSymbol = ${tpw.typeSymbol}")
- !tpw.derivesFrom(defn.FunctionClass(1))
+ !tpw.derivesFrom(defn.FunctionClass(1)) || tpw.isRef(defn.PredefConformsClass)
}
def discardForValueType(tpw: Type): Boolean = tpw match {
@@ -400,6 +400,9 @@ trait Implicits { self: Typer =>
* !!! todo: catch potential cycles
*/
def inferImplicit(pt: Type, argument: Tree, pos: Position)(implicit ctx: Context): SearchResult = track("inferImplicit") {
+ assert(!ctx.isAfterTyper,
+ if (argument.isEmpty) i"missing implicit parameter of type $pt after typer"
+ else i"type error: ${argument.tpe} does not conform to $pt")
ctx.traceIndented(s"search implicit ${pt.show}, arg = ${argument.show}: ${argument.tpe.show}", implicits, show = true) {
assert(!pt.isInstanceOf[ExprType])
val isearch =
@@ -472,7 +475,7 @@ trait Implicits { self: Typer =>
shadowedImplicit(ref, methPart(shadowing).tpe)
}
else
- SearchSuccess(generated, ref, ctx.typerState)
+ SearchSuccess(generated1, ref, ctx.typerState)
}}
/** Given a list of implicit references, produce a list of all implicit search successes,
diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala
index 2d4bf8099..c3f1dcc81 100644
--- a/src/dotty/tools/dotc/typer/Namer.scala
+++ b/src/dotty/tools/dotc/typer/Namer.scala
@@ -519,80 +519,92 @@ class Namer { typer: Typer =>
* defined symbol, given its final return type
*/
def valOrDefDefSig(mdef: ValOrDefDef, sym: Symbol, typeParams: List[Symbol], paramFn: Type => Type)(implicit ctx: Context): Type = {
- val pt =
- if (!mdef.tpt.isEmpty) WildcardType
- else {
- /** An type for this definition that might be inherited from elsewhere:
- * If this is a setter parameter, the corresponding getter type.
- * If this is a class member, the conjunction of all result types
- * of overridden methods.
- * NoType if neither case holds.
- */
- val inherited =
- if (sym.owner.isTerm) NoType
- else {
- // TODO: Look only at member of supertype instead?
- lazy val schema = paramFn(WildcardType)
- val site = sym.owner.thisType
- ((NoType: Type) /: sym.owner.info.baseClasses.tail) { (tp, cls) =>
- val iRawInfo =
- cls.info.nonPrivateDecl(sym.name).matchingDenotation(site, schema).info
- val iInstInfo = iRawInfo match {
- case iRawInfo: PolyType =>
- if (iRawInfo.paramNames.length == typeParams.length)
- iRawInfo.instantiate(typeParams map (_.typeRef))
- else NoType
- case _ =>
- if (typeParams.isEmpty) iRawInfo
- else NoType
- }
- val iResType = iInstInfo.finalResultType.asSeenFrom(site, cls)
- if (iResType.exists)
- typr.println(s"using inherited type; raw: $iRawInfo, inst: $iInstInfo, inherited: $iResType")
- tp & iResType
+ def inferredType = {
+ /** A type for this definition that might be inherited from elsewhere:
+ * If this is a setter parameter, the corresponding getter type.
+ * If this is a class member, the conjunction of all result types
+ * of overridden methods.
+ * NoType if neither case holds.
+ */
+ val inherited =
+ if (sym.owner.isTerm) NoType
+ else {
+ // TODO: Look only at member of supertype instead?
+ lazy val schema = paramFn(WildcardType)
+ val site = sym.owner.thisType
+ ((NoType: Type) /: sym.owner.info.baseClasses.tail) { (tp, cls) =>
+ val iRawInfo =
+ cls.info.nonPrivateDecl(sym.name).matchingDenotation(site, schema).info
+ val iInstInfo = iRawInfo match {
+ case iRawInfo: PolyType =>
+ if (iRawInfo.paramNames.length == typeParams.length)
+ iRawInfo.instantiate(typeParams map (_.typeRef))
+ else NoType
+ case _ =>
+ if (typeParams.isEmpty) iRawInfo
+ else NoType
}
+ val iResType = iInstInfo.finalResultType.asSeenFrom(site, cls)
+ if (iResType.exists)
+ typr.println(s"using inherited type; raw: $iRawInfo, inst: $iInstInfo, inherited: $iResType")
+ tp & iResType
}
+ }
- /** The proto-type to be used when inferring the result type from
- * the right hand side. This is `WildcardType` except if the definition
- * is a default getter. In that case, the proto-type is the type of
- * the corresponding parameter where bound parameters are replaced by
- * Wildcards.
- */
- def rhsProto = {
- val name = sym.asTerm.name
- val idx = name.defaultGetterIndex
- if (idx < 0) WildcardType
- else {
- val original = name.defaultGetterToMethod
- val meth: Denotation =
- if (original.isConstructorName && (sym.owner is ModuleClass))
- sym.owner.companionClass.info.decl(nme.CONSTRUCTOR)
- else
- ctx.defContext(sym).denotNamed(original)
- def paramProto(paramss: List[List[Type]], idx: Int): Type = paramss match {
- case params :: paramss1 =>
- if (idx < params.length) wildApprox(params(idx))
- else paramProto(paramss1, idx - params.length)
- case nil =>
- WildcardType
- }
- val defaultAlts = meth.altsWith(_.hasDefaultParams)
- if (defaultAlts.length == 1)
- paramProto(defaultAlts.head.info.widen.paramTypess, idx)
+ /** The proto-type to be used when inferring the result type from
+ * the right hand side. This is `WildcardType` except if the definition
+ * is a default getter. In that case, the proto-type is the type of
+ * the corresponding parameter where bound parameters are replaced by
+ * Wildcards.
+ */
+ def rhsProto = {
+ val name = sym.asTerm.name
+ val idx = name.defaultGetterIndex
+ if (idx < 0) WildcardType
+ else {
+ val original = name.defaultGetterToMethod
+ val meth: Denotation =
+ if (original.isConstructorName && (sym.owner is ModuleClass))
+ sym.owner.companionClass.info.decl(nme.CONSTRUCTOR)
else
+ ctx.defContext(sym).denotNamed(original)
+ def paramProto(paramss: List[List[Type]], idx: Int): Type = paramss match {
+ case params :: paramss1 =>
+ if (idx < params.length) wildApprox(params(idx))
+ else paramProto(paramss1, idx - params.length)
+ case nil =>
WildcardType
}
+ val defaultAlts = meth.altsWith(_.hasDefaultParams)
+ if (defaultAlts.length == 1)
+ paramProto(defaultAlts.head.info.widen.paramTypess, idx)
+ else
+ WildcardType
}
+ }
- // println(s"final inherited for $sym: ${inherited.toString}") !!!
- // println(s"owner = ${sym.owner}, decls = ${sym.owner.info.decls.show}")
- val rhsCtx = ctx.fresh addMode Mode.InferringReturnType
- def rhsType = typedAheadExpr(mdef.rhs, rhsProto)(rhsCtx).tpe.widen.approximateUnion
- def lhsType = fullyDefinedType(rhsType, "right-hand side", mdef.pos)
- inherited orElse lhsType orElse WildcardType
+ // println(s"final inherited for $sym: ${inherited.toString}") !!!
+ // println(s"owner = ${sym.owner}, decls = ${sym.owner.info.decls.show}")
+ val rhsCtx = ctx.fresh addMode Mode.InferringReturnType
+ def rhsType = typedAheadExpr(mdef.rhs, rhsProto)(rhsCtx).tpe.widen.approximateUnion
+ def lhsType = fullyDefinedType(rhsType, "right-hand side", mdef.pos)
+ if (inherited.exists) inherited
+ else {
+ if (sym is Implicit) {
+ val resStr = if (mdef.isInstanceOf[DefDef]) "result " else ""
+ ctx.error(d"${resStr}type of implicit definition needs to be given explicitly", mdef.pos)
+ sym.resetFlag(Implicit)
+ }
+ lhsType orElse WildcardType
}
+ }
+
+ val pt = mdef.tpt match {
+ case _: untpd.DerivedTypeTree => WildcardType
+ case TypeTree(untpd.EmptyTree) => inferredType
+ case _ => WildcardType
+ }
paramFn(typedAheadType(mdef.tpt, pt).tpe)
}
diff --git a/src/dotty/tools/dotc/typer/ProtoTypes.scala b/src/dotty/tools/dotc/typer/ProtoTypes.scala
index aeba02648..4aba4fb59 100644
--- a/src/dotty/tools/dotc/typer/ProtoTypes.scala
+++ b/src/dotty/tools/dotc/typer/ProtoTypes.scala
@@ -46,7 +46,7 @@ object ProtoTypes {
* fits the given expected result type.
*/
def constrainResult(mt: Type, pt: Type)(implicit ctx: Context): Boolean = pt match {
- case FunProto(_, result, _) =>
+ case _: FunProto =>
mt match {
case mt: MethodType =>
mt.isDependent || constrainResult(mt.resultType, pt.resultType)
@@ -60,6 +60,8 @@ object ProtoTypes {
case _ =>
isCompatible(mt, pt)
}
+ case _: WildcardType =>
+ isCompatible(mt, pt)
case _ =>
true
}
@@ -217,9 +219,8 @@ object ProtoTypes {
*/
abstract case class ViewProto(argType: Type, override val resultType: Type)(implicit ctx: Context)
extends CachedGroundType with ApplyingProto {
- def isMatchedBy(tp: Type)(implicit ctx: Context): Boolean = /*ctx.conditionalTraceIndented(lookingForInfo, i"?.info isMatchedBy $tp ${tp.getClass}")*/ {
+ def isMatchedBy(tp: Type)(implicit ctx: Context): Boolean =
ctx.typer.isApplicable(tp, argType :: Nil, resultType)
- }
def derivedViewProto(argType: Type, resultType: Type)(implicit ctx: Context) =
if ((argType eq this.argType) && (resultType eq this.resultType)) this
@@ -352,17 +353,15 @@ object ProtoTypes {
tp.derivedRefinedType(wildApprox(tp.parent, theMap), tp.refinedName, wildApprox(tp.refinedInfo, theMap))
case tp: TypeBounds if tp.lo eq tp.hi => // default case, inlined for speed
tp.derivedTypeAlias(wildApprox(tp.lo, theMap))
- case PolyParam(pt, pnum) =>
- WildcardType(wildApprox(pt.paramBounds(pnum)).bounds)
+ case tp @ PolyParam(poly, pnum) =>
+ ctx.typerState.constraint.at(tp) match {
+ case bounds: TypeBounds => wildApprox(WildcardType(bounds))
+ case _ => WildcardType(wildApprox(poly.paramBounds(pnum)).bounds)
+ }
case MethodParam(mt, pnum) =>
WildcardType(TypeBounds.upper(wildApprox(mt.paramTypes(pnum))))
case tp: TypeVar =>
- val inst = tp.instanceOpt
- if (inst.exists) wildApprox(inst)
- else ctx.typerState.constraint.at(tp.origin) match {
- case bounds: TypeBounds => wildApprox(WildcardType(bounds))
- case NoType => WildcardType
- }
+ wildApprox(tp.underlying)
case tp: AndType =>
val tp1a = wildApprox(tp.tp1)
val tp2a = wildApprox(tp.tp2)
diff --git a/src/dotty/tools/dotc/typer/ReTyper.scala b/src/dotty/tools/dotc/typer/ReTyper.scala
index c2f627b1e..76817fd16 100644
--- a/src/dotty/tools/dotc/typer/ReTyper.scala
+++ b/src/dotty/tools/dotc/typer/ReTyper.scala
@@ -4,6 +4,7 @@ package typer
import core.Contexts._
import core.Types._
import core.Symbols._
+import core.Decorators._
import typer.ProtoTypes._
import ast.{tpd, untpd}
import ast.Trees._
@@ -20,7 +21,7 @@ class ReTyper extends Typer {
import tpd._
protected def promote(tree: untpd.Tree)(implicit ctx: Context): tree.ThisTree[Type] = {
- assert(tree.hasType)
+ assert(tree.hasType, i"$tree ${tree.getClass} ${tree.uniqueId}")
tree.withType(tree.typeOpt)
}
@@ -39,6 +40,9 @@ class ReTyper extends Typer {
untpd.cpy.SelectFromTypeTree(tree, qual1, tree.name).withType(tree.typeOpt)
}
+ override def typedLiteral(tree: untpd.Literal)(implicit ctc: Context): Literal =
+ promote(tree)
+
override def typedTypeTree(tree: untpd.TypeTree, pt: Type)(implicit ctx: Context): TypeTree =
promote(tree)
diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala
index 12f2415d8..13f65d424 100644
--- a/src/dotty/tools/dotc/typer/TypeAssigner.scala
+++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala
@@ -166,17 +166,14 @@ trait TypeAssigner {
* - any further information it needs to access to compute that type.
*/
- def assignType(tree: untpd.Ident, rawType: Type)(implicit ctx: Context) = {
- tree.withType(if (tree.isType) rawType else rawType.underlyingIfRepeated)
- }
+ def assignType(tree: untpd.Ident, tp: Type)(implicit ctx: Context) =
+ tree.withType(tp)
- def assignType(tree: untpd.Select, qual: Tree)(implicit ctx: Context) = {
+ def assignType(tree: untpd.Select, qual: Tree)(implicit ctx: Context) =
tree.withType(accessibleSelectionType(tree, qual))
- }
- def assignType(tree: untpd.SelectFromTypeTree, qual: Tree)(implicit ctx: Context) = {
+ def assignType(tree: untpd.SelectFromTypeTree, qual: Tree)(implicit ctx: Context) =
tree.withType(accessibleSelectionType(tree, qual))
- }
def assignType(tree: untpd.New, tpt: Tree)(implicit ctx: Context) =
tree.withType(tpt.tpe)
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index e4acff536..f4b52ce09 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -260,7 +260,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
error(d"not found: $kind$name", tree.pos)
ErrorType
}
- checkValue(tree.withType(ownType.underlyingIfRepeated), pt)
+ checkValue(tree.withType(ownType), pt)
}
def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = track("typedSelect") {
@@ -753,7 +753,6 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
val ValDef(mods, name, tpt, rhs) = vdef
val mods1 = typedModifiers(mods, sym)
val tpt1 = typedType(tpt)
- if ((sym is Implicit) && sym.owner.isType) checkImplicitTptNonEmpty(vdef)
val rhs1 = rhs match {
case Ident(nme.WILDCARD) => rhs withType tpt1.tpe
case _ => typedExpr(rhs, tpt1.tpe)
@@ -766,10 +765,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
val mods1 = typedModifiers(mods, sym)
val tparams1 = tparams mapconserve (typed(_).asInstanceOf[TypeDef])
val vparamss1 = vparamss nestedMapconserve (typed(_).asInstanceOf[ValDef])
- if (sym is Implicit) {
- if (sym.owner.isType) checkImplicitTptNonEmpty(ddef)
- checkImplicitParamsNotSingletons(vparamss1)
- }
+ if (sym is Implicit) checkImplicitParamsNotSingletons(vparamss1)
val tpt1 = typedType(tpt)
val rhs1 = typedExpr(rhs, tpt1.tpe)
assignType(cpy.DefDef(ddef, mods1, name, tparams1, vparamss1, tpt1, rhs1), sym)
@@ -1137,7 +1133,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def where = d"parameter $pname of $methodStr"
inferImplicit(formal, EmptyTree, tree.pos.endPos) match {
case SearchSuccess(arg, _, _) =>
- arg
+ adapt(arg, formal)
case ambi: AmbiguousImplicits =>
implicitArgError(s"ambiguous implicits: ${ambi.explanation} of $where")
case failure: SearchFailure =>
diff --git a/test/dotc/comptest.scala b/test/dotc/comptest.scala
index e7f60488b..63c400304 100644
--- a/test/dotc/comptest.scala
+++ b/test/dotc/comptest.scala
@@ -15,7 +15,7 @@ object comptest extends CompilerTest {
dotcDir + "tools/dotc/ast/Trees.scala",
"#runs", "2",
"-Ylog:frontend",
- "-Xprompt"))
+ "-Xprompt"))(Nil)
// compileDir(dotcDir + "tools/dotc/printing", List("-Xprompt", "-Ylog:frontend", "#runs", "2", "-uniqid"))
}
diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala
index c6fbcabf4..31ab15b57 100644
--- a/test/dotc/tests.scala
+++ b/test/dotc/tests.scala
@@ -5,15 +5,18 @@ import test._
class tests extends CompilerTest {
- override val defaultOptions =
- List(
+ val noCheckOptions = List(
// "-verbose",
// "-Ylog:frontend",
// "-Xprompt",
// "-explaintypes",
// "-Yshow-suppressed-errors",
- "-pagewidth", "160"
- )
+ "-pagewidth", "160")
+
+ implicit val defaultOptions = noCheckOptions ++ List(
+ "-Ycheck:front"//, "-Ystop-before:terminal"
+ )
+
val twice = List("#runs", "2", "-YnoDoubleBindings")
val doErase = List("-Ystop-before:terminal")
@@ -68,7 +71,10 @@ class tests extends CompilerTest {
@Test def neg_i50_volatile = compileFile(negDir, "i50-volatile", xerrors = 4)
@Test def neg_t0273_doubledefs = compileFile(negDir, "t0273", xerrors = 1)
@Test def neg_t0586_structural = compileFile(negDir, "t0586", xerrors = 1)
- @Test def neg_t0625_structural = compileFile(negDir, "t0625", xerrors = 1)
+ @Test def neg_t0625_structural = compileFile(negDir, "t0625", xerrors = 1)(
+ defaultOptions = noCheckOptions)
+ // -Ycheck fails because there are structural types involving higher-kinded types.
+ // these are illegal, but are tested only later.
@Test def neg_t0654_polyalias = compileFile(negDir, "t0654", xerrors = 2)
@Test def neg_t1192_legalPrefix = compileFile(negDir, "t1192", xerrors = 1)
@Test def neg_tailcall_t1672b = compileFile(negDir, "tailcall/t1672b", xerrors = 6)
@@ -83,7 +89,8 @@ class tests extends CompilerTest {
@Test def dotc_config = compileDir(dotcDir + "tools/dotc/config", twice)
@Test def dotc_core = compileDir(dotcDir + "tools/dotc/core", twice)
@Test def dotc_core_pickling = compileDir(dotcDir + "tools/dotc/core/pickling", twice)
- @Test def dotc_transform = compileDir(dotcDir + "tools/dotc/core/transform", twice)
+ @Test def dotc_core_transform = compileDir(dotcDir + "tools/dotc/core/transform", twice)
+ @Test def dotc_transform = compileDir(dotcDir + "tools/dotc/transform", twice)
@Test def dotc_parsing = compileDir(dotcDir + "tools/dotc/parsing", twice)
@Test def dotc_printing = compileDir(dotcDir + "tools/dotc/printing", twice)
@Test def dotc_reporting = compileDir(dotcDir + "tools/dotc/reporting", twice)
diff --git a/test/test/CompilerTest.scala b/test/test/CompilerTest.scala
index d52e74de7..1bf138d54 100644
--- a/test/test/CompilerTest.scala
+++ b/test/test/CompilerTest.scala
@@ -8,29 +8,27 @@ import dotty.tools.dotc.reporting.Reporter
class CompilerTest extends DottyTest {
- def defaultOptions: List[String] = Nil
-
- def compileArgs(args: Array[String], xerrors: Int = 0): Unit = {
+ def compileArgs(args: Array[String], xerrors: Int = 0)(implicit defaultOptions: List[String]): Unit = {
val allArgs = args ++ defaultOptions
val processor = if (allArgs.exists(_.startsWith("#"))) Bench else Main
val nerrors = processor.process(allArgs, ctx).count(Reporter.ERROR.level)
assert(nerrors == xerrors, s"Wrong # of errors. Expected: $xerrors, found: $nerrors")
}
- def compileLine(cmdLine: String, xerrors: Int = 0): Unit = compileArgs(cmdLine.split("\n"), xerrors)
+ def compileLine(cmdLine: String, xerrors: Int = 0)(implicit defaultOptions: List[String]): Unit = compileArgs(cmdLine.split("\n"), xerrors)
- def compileFile(prefix: String, fileName: String, args: List[String] = Nil, xerrors: Int = 0): Unit =
+ def compileFile(prefix: String, fileName: String, args: List[String] = Nil, xerrors: Int = 0)(implicit defaultOptions: List[String]): Unit =
compileArgs((s"$prefix$fileName.scala" :: args).toArray, xerrors)
- def compileDir(path: String, args: List[String] = Nil, xerrors: Int = 0): Unit =
+ def compileDir(path: String, args: List[String] = Nil, xerrors: Int = 0)(implicit defaultOptions: List[String]): Unit =
compileDir(Directory(path), args, xerrors)
- def compileDir(dir: Directory, args: List[String], xerrors: Int): Unit = {
+ def compileDir(dir: Directory, args: List[String], xerrors: Int)(implicit defaultOptions: List[String]): Unit = {
val fileNames = dir.files.toArray.map(_.toString).filter(_ endsWith ".scala")
compileArgs(fileNames ++ args, xerrors)
}
- def compileFiles(path: String, args: List[String] = Nil): Unit = {
+ def compileFiles(path: String, args: List[String] = Nil)(implicit defaultOptions: List[String]): Unit = {
val dir = Directory(path)
val fileNames = dir.files.toArray.map(_.toString).filter(_ endsWith ".scala")
for (name <- fileNames) {
@@ -43,7 +41,7 @@ class CompilerTest extends DottyTest {
}
}
}
-object CompilerText extends App {
+object CompilerTest extends App {
// val dotcDir = "/Users/odersky/workspace/dotty/src/dotty/"
diff --git a/test/test/transform/LazyValsTest.scala b/test/test/transform/LazyValsTest.scala
index 98853ad60..30c093f70 100644
--- a/test/test/transform/LazyValsTest.scala
+++ b/test/test/transform/LazyValsTest.scala
@@ -183,8 +183,9 @@ class LazyValsTest extends DottyTest {
(tree, ctx) =>
val accessor = "DefDef(Modifiers(,,List(Apply(Select(New(Ident(volatile)),<init>),List()))),s,List(),List(),TypeTree[TypeRef(ThisType(module class lang),String)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(null))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(a))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))"
val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class lang),String)],Literal(Constant(null))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))"
- val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
+ val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(Apply(Select(New(TypeTree[TypeRef(ThisType(module class lang),Object)]),<init>),List())),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
val treeS = tree.toString
+ println(treeS)
Assert.assertTrue("volatile field lazy ref rewritten to class creation",
treeS.contains(accessor) && treeS.contains(fields) && treeS.contains(moduleField))
}
@@ -196,7 +197,7 @@ class LazyValsTest extends DottyTest {
(tree, ctx) =>
val accessor = "DefDef(Modifiers(,,List(Apply(Select(New(Ident(volatile)),<init>),List()))),s,List(),List(),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(0))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(1))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))"
val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class scala),Int)],Literal(Constant(0))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))"
- val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
+ val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(Apply(Select(New(TypeTree[TypeRef(ThisType(module class lang),Object)]),<init>),List())),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
val treeS = tree.toString
Assert.assertTrue("volatile field lazy ref rewritten to class creation",
treeS.contains(accessor) && treeS.contains(fields) && treeS.contains(moduleField))
@@ -209,7 +210,7 @@ class LazyValsTest extends DottyTest {
(tree, ctx) =>
val accessor = "DefDef(Modifiers(,,List(Apply(Select(New(Ident(volatile)),<init>),List()))),s,List(),List(),TypeTree[TypeRef(ThisType(module class scala),Long)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(0))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(1))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))"
val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))"
- val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
+ val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(Apply(Select(New(TypeTree[TypeRef(ThisType(module class lang),Object)]),<init>),List())),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
val treeS = tree.toString
Assert.assertTrue("volatile field lazy ref rewritten to class creation",
treeS.contains(accessor) && treeS.contains(fields) && treeS.contains(moduleField))
@@ -222,7 +223,7 @@ class LazyValsTest extends DottyTest {
(tree, ctx) =>
val accessor = "DefDef(Modifiers(,,List(Apply(Select(New(Ident(volatile)),<init>),List()))),s,List(),List(),TypeTree[TypeRef(ThisType(module class scala),Float)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(0.0))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(1.0))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))"
val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class scala),Float)],Literal(Constant(0.0))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))"
- val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
+ val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(Apply(Select(New(TypeTree[TypeRef(ThisType(module class lang),Object)]),<init>),List())),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
val treeS = tree.toString
Assert.assertTrue("volatile field lazy ref rewritten to class creation",
treeS.contains(accessor) && treeS.contains(fields) && treeS.contains(moduleField))
@@ -235,7 +236,7 @@ class LazyValsTest extends DottyTest {
(tree, ctx) =>
val accessor = "DefDef(Modifiers(,,List(Apply(Select(New(Ident(volatile)),<init>),List()))),s,List(),List(),TypeTree[TypeRef(ThisType(module class scala),Double)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(0.0))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(1.0))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))"
val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class scala),Double)],Literal(Constant(0.0))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))"
- val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
+ val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(Apply(Select(New(TypeTree[TypeRef(ThisType(module class lang),Object)]),<init>),List())),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
val treeS = tree.toString
Assert.assertTrue("volatile field lazy ref rewritten to class creation",
treeS.contains(accessor) && treeS.contains(fields) && treeS.contains(moduleField))
@@ -248,7 +249,7 @@ class LazyValsTest extends DottyTest {
(tree, ctx) =>
val accessor = "DefDef(Modifiers(,,List(Apply(Select(New(Ident(volatile)),<init>),List()))),s,List(),List(),TypeTree[TypeRef(ThisType(module class scala),Boolean)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(false))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(true))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))"
val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(false))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))"
- val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
+ val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(Apply(Select(New(TypeTree[TypeRef(ThisType(module class lang),Object)]),<init>),List())),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
val treeS = tree.toString
Assert.assertTrue("volatile field lazy ref rewritten to class creation",
treeS.contains(accessor) && treeS.contains(fields) && treeS.contains(moduleField))
@@ -261,7 +262,7 @@ class LazyValsTest extends DottyTest {
(tree, ctx) =>
val accessor = "DefDef(Modifiers(,,List(Apply(Select(New(Ident(volatile)),<init>),List()))),s,List(),List(),TypeTree[TypeRef(TermRef(ThisType(module class <root>),scala),Byte)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(0))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(1))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))"
val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(TermRef(ThisType(module class <root>),scala),Byte)],Literal(Constant(0))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))"
- val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
+ val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(Apply(Select(New(TypeTree[TypeRef(ThisType(module class lang),Object)]),<init>),List())),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
val treeS = tree.toString
Assert.assertTrue("volatile field lazy ref rewritten to class creation",
treeS.contains(accessor) && treeS.contains(fields) && treeS.contains(moduleField))
@@ -274,7 +275,7 @@ class LazyValsTest extends DottyTest {
(tree, ctx) =>
val accessor = "DefDef(Modifiers(,,List(Apply(Select(New(Ident(volatile)),<init>),List()))),s,List(),List(),TypeTree[TypeRef(TermRef(ThisType(module class <root>),scala),Short)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(0))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(1))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))"
val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(TermRef(ThisType(module class <root>),scala),Short)],Literal(Constant(0))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))"
- val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
+ val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(Apply(Select(New(TypeTree[TypeRef(ThisType(module class lang),Object)]),<init>),List())),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
val treeS = tree.toString
Assert.assertTrue("volatile field lazy ref rewritten to class creation",
treeS.contains(accessor) && treeS.contains(fields) && treeS.contains(moduleField))
@@ -287,7 +288,7 @@ class LazyValsTest extends DottyTest {
(tree, ctx) =>
val accessor = "DefDef(Modifiers(,,List(Apply(Select(New(Ident(volatile)),<init>),List()))),s,List(),List(),TypeTree[TypeRef(ThisType(module class scala),Char)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(\u0000))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(a))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))"
val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class scala),Char)],Literal(Constant(\u0000))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))"
- val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
+ val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(Apply(Select(New(TypeTree[TypeRef(ThisType(module class lang),Object)]),<init>),List())),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
val treeS = tree.toString
Assert.assertTrue("volatile field lazy ref rewritten to class creation",
@@ -299,7 +300,7 @@ class LazyValsTest extends DottyTest {
def volatilesReuseBitmaps = {
checkCompile("LazyVals", "class LV { @volatile lazy val a = 'a'; @volatile lazy val b = 'b'; }") {
(tree, ctx) =>
- val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
+ val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(Apply(Select(New(TypeTree[TypeRef(ThisType(module class lang),Object)]),<init>),List())),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
val reuseFieldPattern = "Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(1))))"
val treeS = tree.toString
Assert.assertTrue("volatile field lazy ref rewritten to class creation",
@@ -349,7 +350,7 @@ class LazyValsTest extends DottyTest {
| }
""".stripMargin ){
(tree, ctx) =>
- val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$1,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$1))))), ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
+ val moduleField = "TypeDef(Modifiers(final module <synthetic>,,List()),LV$,Template(DefDef(Modifiers(,,List()),<init>,List(),List(List()),TypeTree[TypeRef(ThisType(module class <empty>),LV$)],EmptyTree),List(Apply(Select(New(TypeTree[TypeRef(ThisType(module class lang),Object)]),<init>),List())),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class <empty>),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$1,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$1))))), ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))"
val reuseFieldPattern = "Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$1), Literal(Constant(3)), Literal(Constant(1))))"
val treeS = tree.toString
Assert.assertTrue("volatile field lazy ref rewritten to class creation",
diff --git a/tests/neg/tailcall/tailrec-2.scala b/tests/neg/tailcall/tailrec-2.scala
index d6b8b1355..bc594293d 100644
--- a/tests/neg/tailcall/tailrec-2.scala
+++ b/tests/neg/tailcall/tailrec-2.scala
@@ -13,7 +13,7 @@ class Bop2[+A](val element: A) extends Super[A] {
@annotation.tailrec final def f[B >: A](mem: List[B]): List[B] = (null: Bop2[A]).f(mem)
}
object Bop3 extends Super[Nothing] {
- @annotation.tailrec final def f[B](mem: List[B]): List[B] = (null: Bop3.type).f(mem)
+ @annotation.tailrec final def f[B](mem: List[B]): List[B] = (???: Bop3.type).f(mem)
}
class Bop4[+A](val element: A) extends Super[A] {
@annotation.tailrec final def f[B >: A](mem: List[B]): List[B] = Other.f[A].f(mem)
diff --git a/tests/pos/t1164.scala b/tests/pending/pos/t1164.scala
index ab58c1d6b..ab58c1d6b 100644
--- a/tests/pos/t1164.scala
+++ b/tests/pending/pos/t1164.scala