Skip to content

Commit 6629101

Browse files
committed
Fix constructor completion problem detected in t0054
Constructors need to be completed in the context which immediately encloses a class. Otherwise type references in the constructor see the wrong types, as is demonstrated in t0054. The difficulty here is that the inner class B nested in A also extends from A. Then it makes a difference whether the constructor parameter types of B are resolved in the context of B or in the context of A. Added explanation for context handling of constructors.
1 parent 7fa7859 commit 6629101

File tree

4 files changed

+20
-7
lines changed

4 files changed

+20
-7
lines changed

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,9 @@ object SymDenotations {
148148
// completions.println(s"completing ${this.debugString}")
149149
try completer.complete(this)
150150
catch {
151-
case ex: CyclicReference =>
152-
completions.println(s"error while completing ${this.debugString}")
153-
throw ex
151+
case ex: CyclicReference =>
152+
completions.println(s"error while completing ${this.debugString}")
153+
throw ex
154154
}
155155
// completions.println(s"completed ${this.debugString}")
156156
}

src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,9 +216,18 @@ class Namer { typer: Typer =>
216216
checkNoConflict(name)
217217
val deferred = if (lacksDefinition(tree)) Deferred else EmptyFlags
218218
val method = if (tree.isInstanceOf[DefDef]) Method else EmptyFlags
219+
220+
// to complete a constructor, move one context further out -- this
221+
// is the context enclosing the class. Note that the context in which a
222+
// constructor is recorded and the context in which it is completed are
223+
// different: The former must have the class as owner (because the
224+
// constructor is owned by the class), the latter must not (because
225+
// constructor parameters are interpreted as if they are outside the class).
226+
val cctx = if (tree.name == nme.CONSTRUCTOR) ctx.outer else ctx
227+
219228
record(ctx.newSymbol(
220229
ctx.owner, name, tree.mods.flags | deferred | method,
221-
adjustIfModule(new Completer(tree), tree),
230+
adjustIfModule(new Completer(tree)(cctx), tree),
222231
privateWithinClass(tree.mods), tree.pos))
223232
case tree: Import =>
224233
record(ctx.newSymbol(

src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -699,9 +699,9 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
699699
val TypeBoundsTree(lo, hi) = desugar.typeBoundsTree(tree)
700700
val lo1 = typed(lo)
701701
val hi1 = typed(hi)
702-
if (false) // need to do in later phase, as this might cause a cyclic reference error. See pos/t0039.scala
703-
if (!(lo1.tpe <:< hi1.tpe))
704-
ctx.error(i"lower bound ${lo1.tpe} does not conform to upper bound ${hi1.tpe}", tree.pos)
702+
// need to do in later phase, as this might cause a cyclic reference error. See pos/t0039.scala
703+
// if (!(lo1.tpe <:< hi1.tpe))
704+
// ctx.error(i"lower bound ${lo1.tpe} does not conform to upper bound ${hi1.tpe}", tree.pos)
705705
assignType(cpy.TypeBoundsTree(tree, lo1, hi1), lo1, hi1)
706706
}
707707

tests/pos/t0054.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
class A {
2+
case class B(x: C) extends A { val z: A.this.C = x }
3+
class C {}
4+
}

0 commit comments

Comments
 (0)