From c277b9865b8a9a0f72279e0a33184ec3a4efcc33 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 28 Jun 2015 19:23:37 +0200 Subject: [PATCH 1/3] Put proper parentheses around complex widened types of singletons. In the type `(A & B)(C.this)`, the first parens were missing, so the type displayed as A & B(C.this), which is confusing. --- src/dotty/tools/dotc/printing/PlainPrinter.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dotty/tools/dotc/printing/PlainPrinter.scala b/src/dotty/tools/dotc/printing/PlainPrinter.scala index 5d2309e95158..45928af4b7bd 100644 --- a/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -120,7 +120,7 @@ class PlainPrinter(_ctx: Context) extends Printer { case tp: TermRef if tp.denot.isOverloaded => "" case tp: SingletonType => - toText(tp.underlying) ~ "(" ~ toTextRef(tp) ~ ")" + toTextLocal(tp.underlying) ~ "(" ~ toTextRef(tp) ~ ")" case tp: TypeRef => toTextPrefix(tp.prefix) ~ selectionString(tp) case tp: RefinedType => From 1061743aaaf2b18419c8fdb1cc89cb1498c9673f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 28 Jun 2015 19:26:21 +0200 Subject: [PATCH 2/3] Error instead of crash when sigName comes up with a missing reference. A TypeRef can have be unresolved, either because it refers to something that's missing from the classpath or because of transitive self type references. Instead of crashing in sigName, we now report the error. Achieved by defining a new exception type, MissingType, which derives from TypeError. This catches t7933.scala, now integrated in the neg/selfreq.scala. The problem there was a reference to AbsSettings, which was not a member of StandardScalaSettings.this, but was a member of the required type of AbsSettings, which itself appeared in the required type of StandardScalaSettings. We will outlaw in the next commit such transitive required references. Also collapsed TypeError and FatalTypeError. It was a misnomer anyway. Fatal were those type errors that were caught and reported! Open: Where else we should check for unresolved NamedTypes. --- src/dotty/tools/dotc/core/TypeErasure.scala | 1 + src/dotty/tools/dotc/core/Types.scala | 20 ++++++++--- src/dotty/tools/dotc/typer/Typer.scala | 2 +- test/dotc/tests.scala | 1 + tests/neg/selfreq.scala | 37 +++++++++++++++++++++ 5 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 tests/neg/selfreq.scala diff --git a/src/dotty/tools/dotc/core/TypeErasure.scala b/src/dotty/tools/dotc/core/TypeErasure.scala index 9b41eb982a5e..0ef31015c2de 100644 --- a/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/src/dotty/tools/dotc/core/TypeErasure.scala @@ -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)) diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index d6bb9c3c574e..f4dbfb0e32c0 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -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 } @@ -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" + 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}" } @@ -3204,7 +3214,7 @@ object Types { } } - class MergeError(msg: String) extends FatalTypeError(msg) + class MergeError(msg: String) extends TypeError(msg) // ----- Debug --------------------------------------------------------- diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 479eedd380a4..33ec156a1d72 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -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) } } diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index f222daca4e49..ee7b9329794d 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -139,6 +139,7 @@ class tests extends CompilerTest { @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_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) diff --git a/tests/neg/selfreq.scala b/tests/neg/selfreq.scala new file mode 100644 index 000000000000..e75e03c16442 --- /dev/null +++ b/tests/neg/selfreq.scala @@ -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() +} From 175499537c87c78d0b926d84b7a9030011e42c00 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 28 Jun 2015 19:33:35 +0200 Subject: [PATCH 3/3] Check that a self type T is closed. What is checked: A self type T is a subtype of all selftypes of classes refernced by T. That is, a self type has to subsume all self types of its required type. Ot, otherwise said, requirements must be closed; you cannot discover new ones in following them. --- src/dotty/tools/dotc/typer/RefChecks.scala | 20 +++++++++++++------- test/dotc/tests.scala | 2 +- tests/neg/selfInheritance.scala | 4 ++++ 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/dotty/tools/dotc/typer/RefChecks.scala b/src/dotty/tools/dotc/typer/RefChecks.scala index bb22e20452af..71fba158871c 100644 --- a/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/src/dotty/tools/dotc/typer/RefChecks.scala @@ -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 _ => } diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index ee7b9329794d..3bce26253025 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -138,7 +138,7 @@ 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) diff --git a/tests/neg/selfInheritance.scala b/tests/neg/selfInheritance.scala index 5f61c5bbbdb8..993765817dfa 100644 --- a/tests/neg/selfInheritance.scala +++ b/tests/neg/selfInheritance.scala @@ -26,3 +26,7 @@ object Test { object M extends C // error } + +trait X { self: Y => } +trait Y { self: Z => } +trait Z