Skip to content

Commit a517afb

Browse files
authored
Drop requirement that self types are closed (#16648)
#702 introduced a requirement that self types are closed. This means > If trait X has self type S and C is a class symbol of S, then S also conforms to the self type of C. An example that violates this requirement is ```scala trait X { self: Y => } // error: missing requirement: self type Y & X of trait X does not conform to self type Z of required trait Y trait Y { self: Z => } trait Z ``` But it's no longer clear what the requirement should achieve. If we let the example above typecheck and try to implement X with something like ```scala class C extends X, Y ``` we would at that point get an error saying that `C` does not conform to the self type Z of Y. So it would have to be ```scala class C extends X, Y, Z ``` and this one looks fine. The original change in #702 was made to avoid a crash in pending/run/t7933.scala. Unfortunately, we cannot reproduce this anymore since it depends on nsc.interpreter, which is no longer part of Scala 2.13. Since we are no longer sure what the restriction should achieve I think it's better to drop it for now. If people discover problems with code that uses "open" self types, we can try to fix those problems, and if that does not work, would fallback re-instituting the restriction. It's not ideal, but I don't see another way. Fixes #16407
2 parents e62ae12 + 689a942 commit a517afb

File tree

7 files changed

+45
-17
lines changed

7 files changed

+45
-17
lines changed

compiler/src/dotty/tools/dotc/core/Denotations.scala

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -610,16 +610,13 @@ object Denotations {
610610
*/
611611
def signature(sourceLanguage: SourceLanguage)(using Context): Signature =
612612
if (isType) Signature.NotAMethod // don't force info if this is a type denotation
613-
else info match {
613+
else info match
614614
case info: MethodOrPoly =>
615615
try info.signature(sourceLanguage)
616-
catch { // !!! DEBUG
617-
case scala.util.control.NonFatal(ex) =>
618-
report.echo(s"cannot take signature of $info")
619-
throw ex
620-
}
616+
catch case ex: Exception =>
617+
if ctx.debug then report.echo(s"cannot take signature of $info")
618+
throw ex
621619
case _ => Signature.NotAMethod
622-
}
623620

624621
def derivedSingleDenotation(symbol: Symbol, info: Type, pre: Type = this.prefix, isRefinedMethod: Boolean = this.isRefinedMethod)(using Context): SingleDenotation =
625622
if ((symbol eq this.symbol) && (info eq this.info) && (pre eq this.prefix) && (isRefinedMethod == this.isRefinedMethod)) this

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -102,18 +102,15 @@ object RefChecks {
102102
withMode(Mode.CheckBoundsOrSelfType) {
103103
val cinfo = cls.classInfo
104104

105-
def checkSelfConforms(other: ClassSymbol, category: String, relation: String) =
105+
def checkSelfConforms(other: ClassSymbol) =
106106
val otherSelf = other.declaredSelfTypeAsSeenFrom(cls.thisType)
107107
if otherSelf.exists then
108108
if !(cinfo.selfType <:< otherSelf) then
109-
report.error(DoesNotConformToSelfType(category, cinfo.selfType, cls, otherSelf, relation, other),
109+
report.error(DoesNotConformToSelfType("illegal inheritance", cinfo.selfType, cls, otherSelf, "parent", other),
110110
cls.srcPos)
111111

112112
for psym <- parents do
113-
checkSelfConforms(psym.asClass, "illegal inheritance", "parent")
114-
for reqd <- cls.asClass.givenSelfType.classSymbols do
115-
if reqd != cls then
116-
checkSelfConforms(reqd, "missing requirement", "required")
113+
checkSelfConforms(psym.asClass)
117114
}
118115
end checkSelfAgainstParents
119116

tests/neg/i16407.check

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
-- Error: tests/neg/i16407.scala:2:2 -----------------------------------------------------------------------------------
2+
2 | f(g()) // error // error
3+
| ^
4+
| cannot resolve reference to type (X.this : Y & X).A
5+
| the classfile defining the type might be missing from the classpath
6+
| or the self type of (X.this : Y & X) might not contain all transitive dependencies
7+
-- Error: tests/neg/i16407.scala:2:4 -----------------------------------------------------------------------------------
8+
2 | f(g()) // error // error
9+
| ^
10+
| cannot resolve reference to type (X.this : Y & X).A
11+
| the classfile defining the type might be missing from the classpath
12+
| or the self type of (X.this : Y & X) might not contain all transitive dependencies

tests/neg/i16407.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
trait X { self: Y =>
2+
f(g()) // error // error
3+
}
4+
trait Y { self: Z =>
5+
type B = A
6+
def f(a: B): Unit = ()
7+
def g(): A = ???
8+
}
9+
trait Z {
10+
type A
11+
}

tests/neg/selfInheritance.scala

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,3 @@ object Test {
2626
object M extends C // error: illegal inheritance: self type Test.M.type of object M$ does not conform to self type B of parent class C
2727

2828
}
29-
30-
trait X { self: Y => } // error: missing requirement: self type Y & X of trait X does not conform to self type Z of required trait Y
31-
trait Y { self: Z => }
32-
trait Z

tests/pos/i16407.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
trait X { //missing requirement: self type Z[?] & X of trait X does not conform to self type Z[X.this.A] of required trait Z
2+
self: Z[_] =>
3+
}
4+
5+
trait Z[A] extends X {
6+
self: Z[A] => // comment this to compile successfully
7+
}

tests/pos/open-selftype.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
trait X { self: Y => } // error: missing requirement: self type Y & X of trait X does not conform to self type Z of required trait Y
3+
trait Y { self: Z => }
4+
trait Z
5+
6+
package squants:
7+
trait Quantity[A <: Quantity[A]] { self: A => }
8+
trait TimeDerivative[A <: Quantity[A]] { self: Quantity[_] => }

0 commit comments

Comments
 (0)