Skip to content

Fix/#692 transitive selfrefs #702

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 6, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/dotty/tools/dotc/core/TypeErasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
case ErasedValueType(_, underlying) =>
sigName(underlying)
case tp: TypeRef =>
if (!tp.denot.exists) throw new MissingType(tp.prefix, tp.name)
val sym = tp.symbol
if (!sym.isClass) sigName(tp.info)
else if (isDerivedValueClass(sym)) sigName(eraseDerivedValueClassRef(tp))
Expand Down
20 changes: 15 additions & 5 deletions src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -936,6 +936,7 @@ object Types {
/** the self type of the underlying classtype */
def givenSelfType(implicit ctx: Context): Type = this match {
case tp @ RefinedType(parent, name) => tp.wrapIfMember(parent.givenSelfType)
case tp: ThisType => tp.tref.givenSelfType
case tp: TypeProxy => tp.underlying.givenSelfType
case _ => NoType
}
Expand Down Expand Up @@ -3181,14 +3182,23 @@ object Types {
// ----- Exceptions -------------------------------------------------------------

class TypeError(msg: String) extends Exception(msg)
class FatalTypeError(msg: String) extends TypeError(msg)

class MalformedType(pre: Type, denot: Denotation, absMembers: Set[Name])
extends FatalTypeError(
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(", ")}""")
extends TypeError(
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(", ")}")

class MissingType(pre: Type, name: Name)(implicit ctx: Context) extends TypeError(
i"""cannot resolve reference to type $pre.$name
|the classfile defining the type might be missing from the classpath${otherReason(pre)}""".stripMargin)

private def otherReason(pre: Type)(implicit ctx: Context): String = pre match {
case pre: ThisType if pre.givenSelfType.exists =>
i"\nor the self type of $pre might not contain all transitive dependencies"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: "nor" -> "or"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't \n here an escaped "end of line" character?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, you're right, I misread that.

case _ => ""
}

class CyclicReference private (val denot: SymDenotation)
extends FatalTypeError(s"cyclic reference involving $denot") {
extends TypeError(s"cyclic reference involving $denot") {
def show(implicit ctx: Context) = s"cyclic reference involving ${denot.show}"
}

Expand All @@ -3204,7 +3214,7 @@ object Types {
}
}

class MergeError(msg: String) extends FatalTypeError(msg)
class MergeError(msg: String) extends TypeError(msg)

// ----- Debug ---------------------------------------------------------

Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/printing/PlainPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ class PlainPrinter(_ctx: Context) extends Printer {
case tp: TermRef if tp.denot.isOverloaded =>
"<overloaded " ~ toTextRef(tp) ~ ">"
case tp: SingletonType =>
toText(tp.underlying) ~ "(" ~ toTextRef(tp) ~ ")"
toTextLocal(tp.underlying) ~ "(" ~ toTextRef(tp) ~ ")"
case tp: TypeRef =>
toTextPrefix(tp.prefix) ~ selectionString(tp)
case tp: RefinedType =>
Expand Down
20 changes: 13 additions & 7 deletions src/dotty/tools/dotc/typer/RefChecks.scala
Original file line number Diff line number Diff line change
Expand Up @@ -73,19 +73,25 @@ object RefChecks {

/** Check that final and sealed restrictions on class parents
* and that self type of this class conforms to self types of parents.
* and required classes.
*/
private def checkParents(clazz: Symbol)(implicit ctx: Context): Unit = clazz.info match {
private def checkParents(cls: Symbol)(implicit ctx: Context): Unit = cls.info match {
case cinfo: ClassInfo =>
def checkSelfConforms(other: TypeRef, category: String, relation: String) = {
val otherSelf = other.givenSelfType.asSeenFrom(cls.thisType, other.classSymbol)
if (otherSelf.exists && !(cinfo.selfType <:< otherSelf))
ctx.error(d"$category: self type ${cinfo.selfType} of $cls does not conform to self type $otherSelf of $relation ${other.classSymbol}", cls.pos)
}
for (parent <- cinfo.classParents) {
val pclazz = parent.classSymbol
if (pclazz.is(Final))
ctx.error(d"cannot extend final $pclazz", clazz.pos)
if (pclazz.is(Sealed) && pclazz.associatedFile != clazz.associatedFile)
ctx.error(d"cannot extend sealed $pclazz in different compilation unit", clazz.pos)
val pself = parent.givenSelfType.asSeenFrom(clazz.thisType, parent.classSymbol)
if (pself.exists && !(cinfo.selfType <:< pself))
ctx.error(d"illegal inheritance: self type ${cinfo.selfType} of $clazz does not conform to self type $pself of parent ${parent.classSymbol}", clazz.pos)
ctx.error(d"cannot extend final $pclazz", cls.pos)
if (pclazz.is(Sealed) && pclazz.associatedFile != cls.associatedFile)
ctx.error(d"cannot extend sealed $pclazz in different compilation unit", cls.pos)
checkSelfConforms(parent, "illegal inheritance", "parent")
}
for (reqd <- cinfo.givenSelfType.classSymbols)
checkSelfConforms(reqd.typeRef, "missing requirement", "required")
case _ =>
}

Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1087,7 +1087,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
try adapt(typedUnadapted(tree, pt), pt, tree)
catch {
case ex: CyclicReference => errorTree(tree, cyclicErrorMsg(ex))
case ex: FatalTypeError => errorTree(tree, ex.getMessage)
case ex: TypeError => errorTree(tree, ex.getMessage)
}
}

Expand Down
3 changes: 2 additions & 1 deletion test/dotc/tests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ class tests extends CompilerTest {
@Test def neg_moduleSubtyping = compileFile(negDir, "moduleSubtyping", xerrors = 4)
@Test def neg_escapingRefs = compileFile(negDir, "escapingRefs", xerrors = 2)
@Test def neg_instantiateAbstract = compileFile(negDir, "instantiateAbstract", xerrors = 8)
@Test def neg_selfInheritance = compileFile(negDir, "selfInheritance", xerrors = 5)
@Test def neg_selfInheritance = compileFile(negDir, "selfInheritance", xerrors = 6)
@Test def neg_selfreq = compileFile(negDir, "selfreq", xerrors = 4)
@Test def neg_shadowedImplicits = compileFile(negDir, "arrayclone-new", xerrors = 2)
@Test def neg_traitParamsTyper = compileFile(negDir, "traitParamsTyper", xerrors = 5)
@Test def neg_traitParamsMixin = compileFile(negDir, "traitParamsMixin", xerrors = 2)
Expand Down
4 changes: 4 additions & 0 deletions tests/neg/selfInheritance.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@ object Test {
object M extends C // error

}

trait X { self: Y => }
trait Y { self: Z => }
trait Z
37 changes: 37 additions & 0 deletions tests/neg/selfreq.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
trait X { self: Y =>

type T <: self.U

def foo(x: T): T
def foo(x: String): String

}

trait Y { self: Z =>

type U <: self.V

}

trait Z {

class V

}

object O {
val x: X = ???
x.foo("a")
}

import scala.tools.nsc.interpreter.IMain

object Test extends dotty.runtime.LegacyApp {
val engine = new IMain.Factory getScriptEngine()
engine.asInstanceOf[IMain].settings.usejavacp.value = true
val res2 = engine.asInstanceOf[javax.script.Compilable]
res2 compile "8" eval()
val res5 = res2 compile """println("hello") ; 8"""
res5 eval()
res5 eval()
}