Skip to content

Commit 6561d4c

Browse files
committed
Merge pull request #702 from dotty-staging/fix/#692-transitive-selfrefs
Fix/#692 transitive selfrefs
2 parents 70f18eb + 1754995 commit 6561d4c

File tree

8 files changed

+74
-15
lines changed

8 files changed

+74
-15
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
439439
case ErasedValueType(_, underlying) =>
440440
sigName(underlying)
441441
case tp: TypeRef =>
442+
if (!tp.denot.exists) throw new MissingType(tp.prefix, tp.name)
442443
val sym = tp.symbol
443444
if (!sym.isClass) sigName(tp.info)
444445
else if (isDerivedValueClass(sym)) sigName(eraseDerivedValueClassRef(tp))

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

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,7 @@ object Types {
936936
/** the self type of the underlying classtype */
937937
def givenSelfType(implicit ctx: Context): Type = this match {
938938
case tp @ RefinedType(parent, name) => tp.wrapIfMember(parent.givenSelfType)
939+
case tp: ThisType => tp.tref.givenSelfType
939940
case tp: TypeProxy => tp.underlying.givenSelfType
940941
case _ => NoType
941942
}
@@ -3181,14 +3182,23 @@ object Types {
31813182
// ----- Exceptions -------------------------------------------------------------
31823183

31833184
class TypeError(msg: String) extends Exception(msg)
3184-
class FatalTypeError(msg: String) extends TypeError(msg)
31853185

31863186
class MalformedType(pre: Type, denot: Denotation, absMembers: Set[Name])
3187-
extends FatalTypeError(
3188-
s"""malformed type: $pre is not a legal prefix for $denot because it contains abstract type member${if (absMembers.size == 1) "" else "s"} ${absMembers.mkString(", ")}""")
3187+
extends TypeError(
3188+
s"malformed type: $pre is not a legal prefix for $denot because it contains abstract type member${if (absMembers.size == 1) "" else "s"} ${absMembers.mkString(", ")}")
3189+
3190+
class MissingType(pre: Type, name: Name)(implicit ctx: Context) extends TypeError(
3191+
i"""cannot resolve reference to type $pre.$name
3192+
|the classfile defining the type might be missing from the classpath${otherReason(pre)}""".stripMargin)
3193+
3194+
private def otherReason(pre: Type)(implicit ctx: Context): String = pre match {
3195+
case pre: ThisType if pre.givenSelfType.exists =>
3196+
i"\nor the self type of $pre might not contain all transitive dependencies"
3197+
case _ => ""
3198+
}
31893199

31903200
class CyclicReference private (val denot: SymDenotation)
3191-
extends FatalTypeError(s"cyclic reference involving $denot") {
3201+
extends TypeError(s"cyclic reference involving $denot") {
31923202
def show(implicit ctx: Context) = s"cyclic reference involving ${denot.show}"
31933203
}
31943204

@@ -3204,7 +3214,7 @@ object Types {
32043214
}
32053215
}
32063216

3207-
class MergeError(msg: String) extends FatalTypeError(msg)
3217+
class MergeError(msg: String) extends TypeError(msg)
32083218

32093219
// ----- Debug ---------------------------------------------------------
32103220

src/dotty/tools/dotc/printing/PlainPrinter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ class PlainPrinter(_ctx: Context) extends Printer {
120120
case tp: TermRef if tp.denot.isOverloaded =>
121121
"<overloaded " ~ toTextRef(tp) ~ ">"
122122
case tp: SingletonType =>
123-
toText(tp.underlying) ~ "(" ~ toTextRef(tp) ~ ")"
123+
toTextLocal(tp.underlying) ~ "(" ~ toTextRef(tp) ~ ")"
124124
case tp: TypeRef =>
125125
toTextPrefix(tp.prefix) ~ selectionString(tp)
126126
case tp: RefinedType =>

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

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,19 +73,25 @@ object RefChecks {
7373

7474
/** Check that final and sealed restrictions on class parents
7575
* and that self type of this class conforms to self types of parents.
76+
* and required classes.
7677
*/
77-
private def checkParents(clazz: Symbol)(implicit ctx: Context): Unit = clazz.info match {
78+
private def checkParents(cls: Symbol)(implicit ctx: Context): Unit = cls.info match {
7879
case cinfo: ClassInfo =>
80+
def checkSelfConforms(other: TypeRef, category: String, relation: String) = {
81+
val otherSelf = other.givenSelfType.asSeenFrom(cls.thisType, other.classSymbol)
82+
if (otherSelf.exists && !(cinfo.selfType <:< otherSelf))
83+
ctx.error(d"$category: self type ${cinfo.selfType} of $cls does not conform to self type $otherSelf of $relation ${other.classSymbol}", cls.pos)
84+
}
7985
for (parent <- cinfo.classParents) {
8086
val pclazz = parent.classSymbol
8187
if (pclazz.is(Final))
82-
ctx.error(d"cannot extend final $pclazz", clazz.pos)
83-
if (pclazz.is(Sealed) && pclazz.associatedFile != clazz.associatedFile)
84-
ctx.error(d"cannot extend sealed $pclazz in different compilation unit", clazz.pos)
85-
val pself = parent.givenSelfType.asSeenFrom(clazz.thisType, parent.classSymbol)
86-
if (pself.exists && !(cinfo.selfType <:< pself))
87-
ctx.error(d"illegal inheritance: self type ${cinfo.selfType} of $clazz does not conform to self type $pself of parent ${parent.classSymbol}", clazz.pos)
88+
ctx.error(d"cannot extend final $pclazz", cls.pos)
89+
if (pclazz.is(Sealed) && pclazz.associatedFile != cls.associatedFile)
90+
ctx.error(d"cannot extend sealed $pclazz in different compilation unit", cls.pos)
91+
checkSelfConforms(parent, "illegal inheritance", "parent")
8892
}
93+
for (reqd <- cinfo.givenSelfType.classSymbols)
94+
checkSelfConforms(reqd.typeRef, "missing requirement", "required")
8995
case _ =>
9096
}
9197

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1087,7 +1087,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
10871087
try adapt(typedUnadapted(tree, pt), pt, tree)
10881088
catch {
10891089
case ex: CyclicReference => errorTree(tree, cyclicErrorMsg(ex))
1090-
case ex: FatalTypeError => errorTree(tree, ex.getMessage)
1090+
case ex: TypeError => errorTree(tree, ex.getMessage)
10911091
}
10921092
}
10931093

test/dotc/tests.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,8 @@ class tests extends CompilerTest {
138138
@Test def neg_moduleSubtyping = compileFile(negDir, "moduleSubtyping", xerrors = 4)
139139
@Test def neg_escapingRefs = compileFile(negDir, "escapingRefs", xerrors = 2)
140140
@Test def neg_instantiateAbstract = compileFile(negDir, "instantiateAbstract", xerrors = 8)
141-
@Test def neg_selfInheritance = compileFile(negDir, "selfInheritance", xerrors = 5)
141+
@Test def neg_selfInheritance = compileFile(negDir, "selfInheritance", xerrors = 6)
142+
@Test def neg_selfreq = compileFile(negDir, "selfreq", xerrors = 4)
142143
@Test def neg_shadowedImplicits = compileFile(negDir, "arrayclone-new", xerrors = 2)
143144
@Test def neg_traitParamsTyper = compileFile(negDir, "traitParamsTyper", xerrors = 5)
144145
@Test def neg_traitParamsMixin = compileFile(negDir, "traitParamsMixin", xerrors = 2)

tests/neg/selfInheritance.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,7 @@ object Test {
2626
object M extends C // error
2727

2828
}
29+
30+
trait X { self: Y => }
31+
trait Y { self: Z => }
32+
trait Z

tests/neg/selfreq.scala

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
trait X { self: Y =>
2+
3+
type T <: self.U
4+
5+
def foo(x: T): T
6+
def foo(x: String): String
7+
8+
}
9+
10+
trait Y { self: Z =>
11+
12+
type U <: self.V
13+
14+
}
15+
16+
trait Z {
17+
18+
class V
19+
20+
}
21+
22+
object O {
23+
val x: X = ???
24+
x.foo("a")
25+
}
26+
27+
import scala.tools.nsc.interpreter.IMain
28+
29+
object Test extends dotty.runtime.LegacyApp {
30+
val engine = new IMain.Factory getScriptEngine()
31+
engine.asInstanceOf[IMain].settings.usejavacp.value = true
32+
val res2 = engine.asInstanceOf[javax.script.Compilable]
33+
res2 compile "8" eval()
34+
val res5 = res2 compile """println("hello") ; 8"""
35+
res5 eval()
36+
res5 eval()
37+
}

0 commit comments

Comments
 (0)