Skip to content

Fix/erasure 2 #128

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 36 commits into from
May 9, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
5700ca9
Erasure of term refs without symbols
odersky Apr 15, 2014
5c11da2
Fix withSymAndName
odersky Apr 15, 2014
92c02ee
Removing duplication between Any and Object methods
odersky Apr 18, 2014
a8894ed
Fixing stillValid code
odersky Apr 18, 2014
861f10b
Added a unique identifier to trees.
odersky Apr 18, 2014
9203e01
Some more debug info.
odersky Apr 18, 2014
d78885f
isAfterTyper test
odersky Apr 19, 2014
0fed5dd
Avoid -Ycheck after errors
odersky Apr 21, 2014
b4e5d39
Better printing of type variables
odersky Apr 21, 2014
6f7fc52
Avoid checking for tpt non empty in implicit defs after typer.
odersky Apr 21, 2014
8298eb2
Addiong an adapt to implicit parameters.
odersky Apr 21, 2014
60527d6
Making reporters configurable
odersky Apr 21, 2014
b6e3c9d
Refining TreeChecker to work immediately after typer.
odersky Apr 21, 2014
afb541a
Fix of TyperState#instType
odersky Apr 21, 2014
35366df
Make sure AnyVal is loaded by classfile parser.
odersky Apr 21, 2014
782c24f
Changed handling of repeated parameters.
odersky Apr 21, 2014
3ae8452
Moved tests to pending because they fail -Ycheck:front
odersky Apr 21, 2014
79632fb
Avoid retyping of Literals
odersky Apr 22, 2014
f84a49d
Fixing tailrec test.
odersky Apr 29, 2014
ef8f242
Tightened satisfiablity checks.
odersky Apr 29, 2014
1534539
Excluding <:< from eligible candidates for views.
odersky Apr 29, 2014
90aa3ba
Better wildcard type approximation
odersky Apr 29, 2014
ba2913b
Changes to test framework and tests
odersky Apr 29, 2014
4d47745
Re-enable t0786.
odersky Apr 29, 2014
cb1f9cb
Optimization: Avoid substituting when checking satisfiability
odersky Apr 30, 2014
9099df6
Fix for type applications.
odersky May 1, 2014
615ad1f
Making dotc/transform Dotty compliant
odersky May 1, 2014
620b2f4
Handling of higher-kinded types in intersections and unions.
odersky May 1, 2014
4ae473e
Tightening of rules for explicit types for implicit defs
odersky May 1, 2014
94c1348
Added compliing dotc/transform to tests
odersky May 1, 2014
640feb1
Adding dependency tracking to constraint satisfaction
odersky May 1, 2014
69403ee
Adding a check that owner chains are correct for -Ycheck
odersky May 1, 2014
9a25199
Adding descriptive message to no-implicits-after-typer assertion.
odersky May 1, 2014
8baa5de
Fixing tpd.ClassDef.
odersky May 5, 2014
ed4cba0
Fix lazy vals test broken by fixing fixing tpd.ClassDef.
DarkDimius May 7, 2014
e83df26
Fix dotty deviation failure in TailRec
DarkDimius May 8, 2014
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/dotty/annotation/internal/Repeated.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package dotty.annotation.internal

import scala.annotation.Annotation

final class Repeated() extends Annotation
4 changes: 2 additions & 2 deletions src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
Expand Down
2 changes: 0 additions & 2 deletions src/dotty/tools/dotc/Main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 =>
Expand Down
6 changes: 4 additions & 2 deletions src/dotty/tools/dotc/Run.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
11 changes: 11 additions & 0 deletions src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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]`.
Expand All @@ -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]

Expand Down
29 changes: 24 additions & 5 deletions src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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),
Expand Down
6 changes: 6 additions & 0 deletions src/dotty/tools/dotc/config/Config.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/config/PathResolver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
167 changes: 158 additions & 9 deletions src/dotty/tools/dotc/core/Constraint.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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) =
Expand Down
Loading