Skip to content

Commit 8a4186f

Browse files
committed
Merge pull request #128 from dotty-staging/fix/erasure-2
Fix/erasure 2
2 parents c5c400c + e83df26 commit 8a4186f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+742
-363
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package dotty.annotation.internal
2+
3+
import scala.annotation.Annotation
4+
5+
final class Repeated() extends Annotation

src/dotty/tools/dotc/Compiler.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ class Compiler {
2121
List(
2222
List(new FrontEnd),
2323
List(new LazyValsCreateCompanionObjects,
24-
/* new Constructors, */
2524
new TailRec), //force separataion between lazyVals and LVCreateCO
2625
List(new PatternMatcher,
2726
new LazyValTranformContext().transformer,
@@ -30,7 +29,8 @@ class Compiler {
3029
new TypeTestsCasts,
3130
new InterceptedMethods),
3231
List(new Erasure),
33-
List(new UncurryTreeTransform, new CollectEntryPoints)
32+
List(new UncurryTreeTransform
33+
/* , new Constructors */)
3434
)
3535

3636
var runId = 1

src/dotty/tools/dotc/Main.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ import core.Contexts.Context
99
import reporting.Reporter
1010

1111
/* To do:
12-
s * - Revise the way classes are inherited - when not followed by [...] or (...),
13-
* assume the unparameterized type and forward type parameters as we do now for the synthetic head class.
1412
*/
1513
object Main extends Driver {
1614
def resident(compiler: Compiler): Reporter = unsupported("resident") /*loop { line =>

src/dotty/tools/dotc/Run.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,10 @@ class Run(comp: Compiler)(implicit ctx: Context) {
4242
phase.runOn(units)
4343
def foreachUnit(op: Context => Unit)(implicit ctx: Context): Unit =
4444
for (unit <- units) op(ctx.fresh.setPhase(phase.next).setCompilationUnit(unit))
45-
if (ctx.settings.Xprint.value.containsPhase(phase)) foreachUnit(printTree)
46-
if (ctx.settings.Ycheck.value.containsPhase(phase)) foreachUnit(TreeChecker.check)
45+
if (ctx.settings.Xprint.value.containsPhase(phase))
46+
foreachUnit(printTree)
47+
if (ctx.settings.Ycheck.value.containsPhase(phase) && !ctx.reporter.hasErrors)
48+
foreachUnit(TreeChecker.check)
4749
}
4850
}
4951
}

src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,9 @@ object desugar {
751751
makeBinop(l, op, r)
752752
case PostfixOp(t, op) =>
753753
if ((ctx.mode is Mode.Type) && op == nme.raw.STAR)
754-
AppliedTypeTree(ref(defn.RepeatedParamType), t)
754+
Annotated(
755+
New(ref(defn.RepeatedAnnot.typeRef), Nil :: Nil),
756+
AppliedTypeTree(ref(defn.SeqClass.typeRef), t))
755757
else {
756758
assert(ctx.mode.isExpr, ctx.mode)
757759
Select(t, op)

src/dotty/tools/dotc/ast/Trees.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ object Trees {
180180
def tokenPos: Seq[(Token, Position)] = ???
181181
}
182182

183+
private var nextId = 0
184+
183185
/** Trees take a parameter indicating what the type of their `tpe` field
184186
* is. Two choices: `Type` or `Untyped`.
185187
* Untyped trees have type `Tree[Untyped]`.
@@ -204,6 +206,15 @@ object Trees {
204206

205207
if (Stats.enabled) ntrees += 1
206208

209+
/** A unique identifier for this tree. Used for debugging, and potentially
210+
* tracking presentation compiler interactions
211+
*/
212+
val uniqueId = {
213+
nextId += 1
214+
//assert(nextId != 214, this)
215+
nextId
216+
}
217+
207218
/** The type constructor at the root of the tree */
208219
type ThisTree[T >: Untyped] <: Tree[T]
209220

src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,24 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
210210
def TypeDef(sym: TypeSymbol)(implicit ctx: Context): TypeDef =
211211
ta.assignType(untpd.TypeDef(Modifiers(sym), sym.name, TypeTree(sym.info)), sym)
212212

213-
def ClassDef(cls: ClassSymbol, constr: DefDef, body: List[Tree])(implicit ctx: Context): TypeDef = {
214-
val parents = cls.info.parents map (TypeTree(_))
213+
def ClassDef(cls: ClassSymbol, constr: DefDef, body: List[Tree], superArgs: List[Tree] = Nil)(implicit ctx: Context): TypeDef = {
214+
val firstParent :: otherParents = cls.info.parents
215+
val superRef =
216+
if (cls is Trait) TypeTree(firstParent)
217+
else {
218+
def isApplicable(ctpe: Type): Boolean = ctpe match {
219+
case ctpe: PolyType =>
220+
isApplicable(ctpe.instantiate(firstParent.argTypes))
221+
case ctpe: MethodType =>
222+
(superArgs corresponds ctpe.paramTypes)(_.tpe <:< _)
223+
case _ =>
224+
false
225+
}
226+
val constr = firstParent.decl(nme.CONSTRUCTOR).suchThat(constr => isApplicable(constr.info))
227+
New(firstParent, constr.symbol.asTerm, superArgs)
228+
}
229+
val parents = superRef :: otherParents.map(TypeTree(_))
230+
215231
val selfType =
216232
if (cls.classInfo.selfInfo ne NoType) ValDef(ctx.newSelfSym(cls))
217233
else EmptyValDef
@@ -260,10 +276,13 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
260276

261277
// ------ Creating typed equivalents of trees that exist only in untyped form -------
262278

263-
/** new C(args) */
264-
def New(tp: Type, args: List[Tree])(implicit ctx: Context): Apply = {
279+
/** new C(args), calling the primary constructor of C */
280+
def New(tp: Type, args: List[Tree])(implicit ctx: Context): Apply =
281+
New(tp, tp.typeSymbol.primaryConstructor.asTerm, args)
282+
283+
/** new C(args), calling given constructor `constr` of C */
284+
def New(tp: Type, constr: TermSymbol, args: List[Tree])(implicit ctx: Context): Apply = {
265285
val targs = tp.argTypes
266-
val constr = tp.typeSymbol.primaryConstructor.asTerm
267286
Apply(
268287
Select(
269288
New(tp withoutArgs targs),

src/dotty/tools/dotc/config/Config.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,10 @@ object Config {
3737

3838
/** The recursion depth for showing a summarized string */
3939
final val summarizeDepth = 2
40+
41+
/** Track dependencies for constraint propagation satisfiability checking
42+
* If turned off, constraint checking is simpler but potentially slower
43+
* for large constraints.
44+
*/
45+
final val trackConstrDeps = true
4046
}

src/dotty/tools/dotc/config/PathResolver.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ object PathResolver {
148148
println(Defaults)
149149
}
150150
else {
151-
implicit val ctx = (new ContextBase).initialCtx
151+
implicit val ctx: Context = (new ContextBase).initialCtx // Dotty deviation: implicits need explicit type
152152
val ArgsSummary(sstate, rest, errors) =
153153
ctx.settings.processArguments(args.toList, true)
154154
errors.foreach(println)

src/dotty/tools/dotc/core/Constraint.scala

Lines changed: 158 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,55 @@ import printing.Texts._
1010
import config.Config
1111
import config.Printers._
1212

13+
object Constraint {
14+
15+
/** The type of `Constraint#myMap` */
16+
type ParamInfo = SimpleMap[PolyType, Array[Type]]
17+
18+
/** The type of `Constraint#dependents */
19+
type DependentMap = SimpleMap[PolyType, Array[Set[PolyParam]]]
20+
21+
/** The type of functions that include or exclude a `PolyParam` in or from a set*/
22+
private type DepDelta = (Set[PolyParam], PolyParam) => Set[PolyParam]
23+
24+
private val addDep: DepDelta = (_ + _)
25+
private val removeDep: DepDelta = (_ - _)
26+
27+
private val NoTypeBounds = new TypeBounds(WildcardType, WildcardType){}
28+
29+
/** An accumulator that changes dependencies on `param`.
30+
* @param param The parameter to which changed dependencies refer.
31+
* @param ofVariance Include `PolyParams` occurring at this variance in the dependencies.
32+
* @param delta The dependency change to perform (add or remove).
33+
*/
34+
private class ChangeDependencies(param: PolyParam, ofVariance: Int, delta: DepDelta)(implicit ctx: Context)
35+
extends TypeAccumulator[DependentMap] {
36+
def apply(deps: DependentMap, tp: Type): DependentMap = tp match {
37+
case tp @ PolyParam(pt, n) if
38+
this.variance == 0 || this.variance == ofVariance =>
39+
val oldDeps = deps(pt)
40+
val original = safeSelect(oldDeps, n)
41+
val changed = delta(original, param)
42+
if (original eq changed) deps
43+
else {
44+
val newDeps =
45+
if (oldDeps == null) new Array[Set[PolyParam]](pt.paramBounds.length)
46+
else oldDeps.clone
47+
newDeps(n) = changed
48+
deps.updated(pt, newDeps)
49+
}
50+
case _ => foldOver(deps, tp)
51+
}
52+
}
53+
54+
/** `deps(n)`, except that `Set()` is returned if `deps` or `deps(n)` are null */
55+
private def safeSelect(deps: Array[Set[PolyParam]], n: Int) : Set[PolyParam] =
56+
if (deps == null || deps(n) == null) Set()
57+
else deps(n)
58+
}
59+
60+
import Constraint._
61+
1362
/** Constraint over undetermined type parameters
1463
* @param myMap a map from PolyType to arrays.
1564
* Each array contains twice the number of entries as there a type parameters
@@ -18,8 +67,20 @@ import config.Printers._
1867
* track the corresponding parameters, or is left empty (filled with nulls).
1968
* An instantiated type parameter is represented by having its instance type in
2069
* the corresponding array entry.
70+
* @param dependents a map from PolyTypes to arrays of Sets of PolyParams.
71+
* The i'th set in an array corresponding to polytype `pt` contains
72+
* those dependent `PolyParam`s `dp` that have `PolyParam(pt, i)` in their bounds in
73+
* significant position. A position is significant if solving the
74+
* constraint for `(pt, i)` with a type higher than its lower bound
75+
* would lead to a constraint for `dp` that was not looser than
76+
* the existing constraint. Specifically, it means that all poly params
77+
* appearing covariantly in the lower bound and contravariantly in the
78+
* upper bound, as well as all poly params appearing nonvariantly are
79+
* significant.
80+
* The `dependents` map is maintained and queried only of `Config.trackConstrDeps` is set.
2181
*/
22-
class Constraint(val myMap: SimpleMap[PolyType, Array[Type]]) extends Showable {
82+
class Constraint(private val myMap: ParamInfo,
83+
private val dependents: DependentMap) extends Showable {
2384

2485
/** Does the constraint's domain contain the type parameters of `pt`? */
2586
def contains(pt: PolyType): Boolean = myMap(pt) != null
@@ -66,16 +127,88 @@ class Constraint(val myMap: SimpleMap[PolyType, Array[Type]]) extends Showable {
66127
def typeVarOfParam(param: PolyParam): Type = {
67128
val entries = myMap(param.binder)
68129
if (entries == null) NoType
69-
else typeVar(entries, param.paramNum)
130+
else {
131+
val tvar = typeVar(entries, param.paramNum)
132+
if (tvar != null) tvar else NoType
133+
}
134+
}
135+
136+
/** Change dependencies in map `deps` to reflect new parameter bounds.
137+
* @param deps The map to change
138+
* @param pt the polytype that contains the parameters which might have new bounds
139+
* @param entries the entries for the parameters which might have new bounds
140+
* @param delta the change operation, one of `addDep` or `removeDep`.
141+
* @param cmpEntries the comparison entries or `null` if no such entries exist.
142+
* As an optimization, only bounds that differ between `entries`
143+
* and `cmpEntries` will record their dependencies.
144+
*/
145+
def changeDependencies(deps: DependentMap, pt: PolyType, entries: Array[Type], delta: DepDelta, cmpEntries: Array[Type])(implicit ctx: Context): DependentMap = {
146+
val limit = paramCount(entries)
147+
def loop(deps: DependentMap, n: Int): DependentMap = {
148+
if (n >= limit) deps
149+
else {
150+
val newDeps = entries(n) match {
151+
case bounds @ TypeBounds(lo, hi) =>
152+
val cmpBounds =
153+
if (cmpEntries == null) NoTypeBounds
154+
else cmpEntries(n) match {
155+
case bounds: TypeBounds => bounds
156+
case _ => NoTypeBounds
157+
}
158+
if (cmpBounds eq bounds) deps
159+
else {
160+
val param = PolyParam(pt, n)
161+
val deps1 =
162+
if (cmpBounds.lo eq lo) deps
163+
else new ChangeDependencies(param, 1, delta).apply(deps, lo)
164+
val deps2 =
165+
if (cmpBounds.hi eq hi) deps1
166+
else new ChangeDependencies(param, -1, delta).apply(deps1, hi)
167+
deps2
168+
}
169+
case _ =>
170+
deps
171+
}
172+
loop(newDeps, n + 1)
173+
}
174+
}
175+
if (Config.trackConstrDeps) loop(deps, 0) else deps
70176
}
71177

178+
/** Change dependencies to reflect all changes between the bounds in `oldMap` and `newMap`.
179+
*/
180+
def diffDependencies(deps: DependentMap, oldMap: ParamInfo, newMap: ParamInfo)(implicit ctx: Context): DependentMap =
181+
if (Config.trackConstrDeps) {
182+
var d = deps
183+
oldMap foreachBinding { (poly, entries) =>
184+
val newEntries = newMap(poly)
185+
if (newEntries ne entries) d = changeDependencies(d, poly, entries, removeDep, newEntries)
186+
}
187+
newMap foreachBinding { (poly, entries) =>
188+
val oldEntries = oldMap(poly)
189+
if (oldEntries ne entries) d = changeDependencies(d, poly, entries, addDep, oldEntries)
190+
}
191+
d
192+
} else deps
193+
194+
/** The set of parameters that depend directly on `param`
195+
* according to what's stored in `dependents`.
196+
*/
197+
def dependentParams(param: PolyParam): Set[PolyParam] =
198+
safeSelect(dependents(param.binder), param.paramNum)
199+
72200
/** A new constraint which is derived from this constraint by adding or replacing
73201
* the entries corresponding to `pt` with `entries`.
74202
*/
75203
private def updateEntries(pt: PolyType, entries: Array[Type])(implicit ctx: Context) : Constraint = {
76-
val res = new Constraint(myMap.updated(pt, entries))
204+
val res = new Constraint(
205+
myMap.updated(pt, entries),
206+
changeDependencies(dependents, pt, entries, addDep, myMap(pt)))
207+
208+
//assert(res.domainPolys.filter(pt =>
209+
// pt.resultType.resultType.widen.classSymbol.name.toString == "Ensuring").length < 2) //DEBUG
77210
if (Config.checkConstraintsNonCyclic) checkNonCyclic(pt, entries)
78-
ctx.runInfo.recordConstraintSize(res)
211+
ctx.runInfo.recordConstraintSize(res, res.myMap.size)
79212
res
80213
}
81214

@@ -114,7 +247,10 @@ class Constraint(val myMap: SimpleMap[PolyType, Array[Type]]) extends Showable {
114247
updateEntries(poly, myMap(poly) map op)
115248

116249
/** A new constraint with all entries coming from `pt` removed. */
117-
def remove(pt: PolyType) = new Constraint(myMap remove pt)
250+
def remove(pt: PolyType)(implicit ctx: Context) =
251+
new Constraint(
252+
myMap remove pt,
253+
changeDependencies(dependents, pt, myMap(pt), removeDep, null))
118254

119255
/** Is entry associated with `pt` removable?
120256
* @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 {
185321

186322
val pt = param.binder
187323
val constr1 = if (isRemovable(pt, param.paramNum)) remove(pt) else updated(param, tp)
188-
val result = new Constraint(constr1.myMap mapValues subst)
324+
val substMap = constr1.myMap mapValues subst
325+
val result = new Constraint(
326+
substMap,
327+
diffDependencies(constr1.dependents, constr1.myMap, substMap))
189328
if (Config.checkConstraintsNonCyclic) result.checkNonCyclic()
190329
result
191330
}
@@ -243,6 +382,16 @@ class Constraint(val myMap: SimpleMap[PolyType, Array[Type]]) extends Showable {
243382
if isBounds(entries(n))
244383
} yield PolyParam(poly, n)
245384

385+
/** Check whether predicate holds for all parameters in constraint
386+
*/
387+
def forallParams(p: PolyParam => Boolean): Boolean = {
388+
myMap.foreachBinding { (poly, entries) =>
389+
for (i <- 0 until paramCount(entries))
390+
if (isBounds(entries(i)) && !p(PolyParam(poly, i))) return false
391+
}
392+
true
393+
}
394+
246395
/** Perform operation `op` on all typevars, or only on uninstantiated
247396
* typevars, depending on whether `uninstOnly` is set or not.
248397
*/
@@ -299,9 +448,9 @@ class Constraint(val myMap: SimpleMap[PolyType, Array[Type]]) extends Showable {
299448
trait ConstraintRunInfo { self: RunInfo =>
300449
private var maxSize = 0
301450
private var maxConstraint: Constraint = _
302-
def recordConstraintSize(c: Constraint) =
303-
if (c.myMap.size > maxSize) {
304-
maxSize = c.myMap.size
451+
def recordConstraintSize(c: Constraint, size: Int) =
452+
if (size > maxSize) {
453+
maxSize = size
305454
maxConstraint = c
306455
}
307456
def printMaxConstraint()(implicit ctx: Context) =

0 commit comments

Comments
 (0)