Skip to content

Commit

Permalink
Drop requirement that self types are closed (#16648)
Browse files Browse the repository at this point in the history
#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
  • Loading branch information
odersky authored Jan 12, 2023
2 parents e62ae12 + 689a942 commit a517afb
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 17 deletions.
11 changes: 4 additions & 7 deletions compiler/src/dotty/tools/dotc/core/Denotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -610,16 +610,13 @@ object Denotations {
*/
def signature(sourceLanguage: SourceLanguage)(using Context): Signature =
if (isType) Signature.NotAMethod // don't force info if this is a type denotation
else info match {
else info match
case info: MethodOrPoly =>
try info.signature(sourceLanguage)
catch { // !!! DEBUG
case scala.util.control.NonFatal(ex) =>
report.echo(s"cannot take signature of $info")
throw ex
}
catch case ex: Exception =>
if ctx.debug then report.echo(s"cannot take signature of $info")
throw ex
case _ => Signature.NotAMethod
}

def derivedSingleDenotation(symbol: Symbol, info: Type, pre: Type = this.prefix, isRefinedMethod: Boolean = this.isRefinedMethod)(using Context): SingleDenotation =
if ((symbol eq this.symbol) && (info eq this.info) && (pre eq this.prefix) && (isRefinedMethod == this.isRefinedMethod)) this
Expand Down
9 changes: 3 additions & 6 deletions compiler/src/dotty/tools/dotc/typer/RefChecks.scala
Original file line number Diff line number Diff line change
Expand Up @@ -102,18 +102,15 @@ object RefChecks {
withMode(Mode.CheckBoundsOrSelfType) {
val cinfo = cls.classInfo

def checkSelfConforms(other: ClassSymbol, category: String, relation: String) =
def checkSelfConforms(other: ClassSymbol) =
val otherSelf = other.declaredSelfTypeAsSeenFrom(cls.thisType)
if otherSelf.exists then
if !(cinfo.selfType <:< otherSelf) then
report.error(DoesNotConformToSelfType(category, cinfo.selfType, cls, otherSelf, relation, other),
report.error(DoesNotConformToSelfType("illegal inheritance", cinfo.selfType, cls, otherSelf, "parent", other),
cls.srcPos)

for psym <- parents do
checkSelfConforms(psym.asClass, "illegal inheritance", "parent")
for reqd <- cls.asClass.givenSelfType.classSymbols do
if reqd != cls then
checkSelfConforms(reqd, "missing requirement", "required")
checkSelfConforms(psym.asClass)
}
end checkSelfAgainstParents

Expand Down
12 changes: 12 additions & 0 deletions tests/neg/i16407.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-- Error: tests/neg/i16407.scala:2:2 -----------------------------------------------------------------------------------
2 | f(g()) // error // error
| ^
| cannot resolve reference to type (X.this : Y & X).A
| the classfile defining the type might be missing from the classpath
| or the self type of (X.this : Y & X) might not contain all transitive dependencies
-- Error: tests/neg/i16407.scala:2:4 -----------------------------------------------------------------------------------
2 | f(g()) // error // error
| ^
| cannot resolve reference to type (X.this : Y & X).A
| the classfile defining the type might be missing from the classpath
| or the self type of (X.this : Y & X) might not contain all transitive dependencies
11 changes: 11 additions & 0 deletions tests/neg/i16407.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
trait X { self: Y =>
f(g()) // error // error
}
trait Y { self: Z =>
type B = A
def f(a: B): Unit = ()
def g(): A = ???
}
trait Z {
type A
}
4 changes: 0 additions & 4 deletions tests/neg/selfInheritance.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,3 @@ object Test {
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

}

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
7 changes: 7 additions & 0 deletions tests/pos/i16407.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
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
self: Z[_] =>
}

trait Z[A] extends X {
self: Z[A] => // comment this to compile successfully
}
8 changes: 8 additions & 0 deletions tests/pos/open-selftype.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

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

package squants:
trait Quantity[A <: Quantity[A]] { self: A => }
trait TimeDerivative[A <: Quantity[A]] { self: Quantity[_] => }

0 comments on commit a517afb

Please sign in to comment.