aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/Compiler.scala3
-rw-r--r--src/dotty/tools/dotc/ast/Desugar.scala2
-rw-r--r--src/dotty/tools/dotc/core/Decorators.scala3
-rw-r--r--src/dotty/tools/dotc/core/TypeApplications.scala6
-rw-r--r--src/dotty/tools/dotc/core/Types.scala45
-rw-r--r--src/dotty/tools/dotc/printing/PlainPrinter.scala3
-rw-r--r--src/dotty/tools/dotc/reporting/ConsoleReporter.scala2
-rw-r--r--src/dotty/tools/dotc/transform/FirstTransform.scala4
-rw-r--r--src/dotty/tools/dotc/transform/Pickler.scala34
-rw-r--r--src/dotty/tools/dotc/typer/Checking.scala2
-rw-r--r--src/dotty/tools/dotc/typer/FrontEnd.scala2
-rw-r--r--src/dotty/tools/dotc/typer/InstChecks.scala90
-rw-r--r--src/dotty/tools/dotc/typer/RefChecks.scala12
-rw-r--r--test/dotc/tests.scala2
-rw-r--r--tests/neg/instantiateAbstract.scala38
-rw-r--r--tests/neg/selfInheritance.scala28
16 files changed, 233 insertions, 43 deletions
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala
index 25a4c578b..c67fb124a 100644
--- a/src/dotty/tools/dotc/Compiler.scala
+++ b/src/dotty/tools/dotc/Compiler.scala
@@ -6,7 +6,7 @@ import Contexts._
import Periods._
import Symbols._
import Scopes._
-import typer.{FrontEnd, Typer, Mode, ImportInfo, RefChecks}
+import typer.{FrontEnd, Typer, Mode, ImportInfo, RefChecks, InstChecks}
import reporting.ConsoleReporter
import dotty.tools.dotc.core.Phases.Phase
import dotty.tools.dotc.transform._
@@ -38,6 +38,7 @@ class Compiler {
def phases: List[List[Phase]] =
List(
List(new FrontEnd),
+ List(new InstChecks),
List(new FirstTransform,
new SyntheticMethods),
List(new SuperAccessors),
diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala
index 165f4f535..0c13d1ecc 100644
--- a/src/dotty/tools/dotc/ast/Desugar.scala
+++ b/src/dotty/tools/dotc/ast/Desugar.scala
@@ -786,7 +786,7 @@ object desugar {
New(ref(defn.RepeatedAnnot.typeRef), Nil :: Nil),
AppliedTypeTree(ref(seqClass.typeRef), t))
} else {
- assert(ctx.mode.isExpr, ctx.mode)
+ assert(ctx.mode.isExpr || ctx.reporter.hasErrors, ctx.mode)
Select(t, op)
}
case PrefixOp(op, t) =>
diff --git a/src/dotty/tools/dotc/core/Decorators.scala b/src/dotty/tools/dotc/core/Decorators.scala
index 1ce834428..4e672ef40 100644
--- a/src/dotty/tools/dotc/core/Decorators.scala
+++ b/src/dotty/tools/dotc/core/Decorators.scala
@@ -7,6 +7,7 @@ import Contexts._, Names._, Phases._, printing.Texts._, printing.Printer, printi
import util.Positions.Position, util.SourcePosition
import collection.mutable.ListBuffer
import dotty.tools.dotc.transform.TreeTransforms._
+import typer.Mode
import scala.language.implicitConversions
/** This object provides useful implicit decorators for types defined elsewhere */
@@ -172,7 +173,7 @@ object Decorators {
def treatSingleArg(arg: Any) : Any =
try
arg match {
- case arg: Showable => arg.show
+ case arg: Showable => arg.show(ctx.fresh.addMode(Mode.FutureDefsOK))
case _ => arg
}
catch {
diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala
index df18813b9..de42b3e5f 100644
--- a/src/dotty/tools/dotc/core/TypeApplications.scala
+++ b/src/dotty/tools/dotc/core/TypeApplications.scala
@@ -268,9 +268,7 @@ class TypeApplications(val self: Type) extends AnyVal {
case _ => default
}
case tp @ RefinedType(parent, name) if !tp.member(name).symbol.is(ExpandedTypeParam) =>
- val pbase = parent.baseTypeWithArgs(base)
- if (pbase.member(name).exists) RefinedType(pbase, name, tp.refinedInfo)
- else pbase
+ tp.wrapIfMember(parent.baseTypeWithArgs(base))
case tp: TermRef =>
tp.underlying.baseTypeWithArgs(base)
case AndType(tp1, tp2) =>
@@ -281,7 +279,7 @@ class TypeApplications(val self: Type) extends AnyVal {
default
}
}
-
+
/** Translate a type of the form From[T] to To[T], keep other types as they are.
* `from` and `to` must be static classes, both with one type parameter, and the same variance.
*/
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index e6235695e..fe95219b8 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -858,6 +858,13 @@ object Types {
case _ => defn.AnyClass.typeRef
}
+ /** 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: TypeProxy => tp.underlying.givenSelfType
+ case _ => NoType
+ }
+
/** The parameter types of a PolyType or MethodType, Empty list for others */
final def paramTypess(implicit ctx: Context): List[List[Type]] = this match {
case mt: MethodType => mt.paramTypes :: mt.resultType.paramTypess
@@ -1781,7 +1788,12 @@ object Types {
if (false) RefinedType(parent, refinedName, refinedInfo)
else RefinedType(parent, refinedName, rt => refinedInfo.substSkolem(this, SkolemType(rt)))
}
-
+
+ /** Add this refinement to `parent`, provided If `refinedName` is a member of `parent`. */
+ def wrapIfMember(parent: Type)(implicit ctx: Context): Type =
+ if (parent.member(refinedName).exists) derivedRefinedType(parent, refinedName, refinedInfo)
+ else parent
+
override def equals(that: Any) = that match {
case that: RefinedType =>
this.parent == that.parent &&
@@ -2398,22 +2410,27 @@ object Types {
* - the fully applied reference to the class itself.
*/
def selfType(implicit ctx: Context): Type = {
- if (selfTypeCache == null) {
- def fullRef = fullyAppliedRef(cls.typeRef, cls.typeParams)
- def withFullRef(tp: Type): Type =
- if (ctx.erasedTypes) fullRef else AndType(tp, fullRef)
- selfTypeCache = selfInfo match {
- case NoType =>
- fullRef
- case tp: Type =>
- if (cls is Module) tp else withFullRef(tp)
- case self: Symbol =>
- assert(!(cls is Module))
- withFullRef(self.info)
+ if (selfTypeCache == null)
+ selfTypeCache = {
+ def fullRef = fullyAppliedRef(cls.typeRef, cls.typeParams)
+ val given = givenSelfType
+ val raw =
+ if (!given.exists) fullRef
+ else if (cls is Module) given
+ else if (ctx.erasedTypes) fullRef
+ else AndType(given, fullRef)
+ raw//.asSeenFrom(prefix, cls.owner)
}
- }
selfTypeCache
}
+
+ /** The explicitly given self type (self types of modules are assumed to be
+ * explcitly given here).
+ */
+ override def givenSelfType(implicit ctx: Context): Type = selfInfo match {
+ case tp: Type => tp
+ case self: Symbol => self.info
+ }
private var selfTypeCache: Type = null
diff --git a/src/dotty/tools/dotc/printing/PlainPrinter.scala b/src/dotty/tools/dotc/printing/PlainPrinter.scala
index 2762d9b51..0a7edd2aa 100644
--- a/src/dotty/tools/dotc/printing/PlainPrinter.scala
+++ b/src/dotty/tools/dotc/printing/PlainPrinter.scala
@@ -354,7 +354,8 @@ class PlainPrinter(_ctx: Context) extends Printer {
def toText(sym: Symbol): Text =
(kindString(sym) ~~ {
- if (hasMeaninglessName(sym)) simpleNameString(sym.owner) + idString(sym)
+ if (sym.isAnonymousClass) toText(sym.info.parents, " with ") ~ "{...}"
+ else if (hasMeaninglessName(sym)) simpleNameString(sym.owner) + idString(sym)
else nameString(sym)
}).close
diff --git a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala
index a7f7f70bb..f07f43a63 100644
--- a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala
+++ b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala
@@ -41,7 +41,7 @@ class ConsoleReporter(
}
override def doReport(d: Diagnostic)(implicit ctx: Context): Unit =
- if (!d.isSuppressed) d match {
+ if (!d.isSuppressed || !hasErrors) d match {
case d: Error =>
printMessageAndPos(s"error: ${d.msg}", d.pos)
if (ctx.settings.prompt.value) displayPrompt()
diff --git a/src/dotty/tools/dotc/transform/FirstTransform.scala b/src/dotty/tools/dotc/transform/FirstTransform.scala
index cfe650b99..02d0bb2ba 100644
--- a/src/dotty/tools/dotc/transform/FirstTransform.scala
+++ b/src/dotty/tools/dotc/transform/FirstTransform.scala
@@ -35,6 +35,10 @@ class FirstTransform extends MiniPhaseTransform with IdentityDenotTransformer wi
import ast.tpd._
override def phaseName = "firstTransform"
+
+ override def runsAfter = Set(classOf[typer.InstChecks])
+ // This phase makes annotations disappear in types, so InstChecks should
+ // run before so that it can get at all annotations.
def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type = tp
diff --git a/src/dotty/tools/dotc/transform/Pickler.scala b/src/dotty/tools/dotc/transform/Pickler.scala
index 445fed2c4..515dad2aa 100644
--- a/src/dotty/tools/dotc/transform/Pickler.scala
+++ b/src/dotty/tools/dotc/transform/Pickler.scala
@@ -27,26 +27,24 @@ class Pickler extends Phase {
override def run(implicit ctx: Context): Unit = {
val unit = ctx.compilationUnit
- if (!unit.isJava) {
- val tree = unit.tpdTree
- pickling.println(i"unpickling in run ${ctx.runId}")
- if (ctx.settings.YtestPickler.value) beforePickling(unit) = tree.show
+ val tree = unit.tpdTree
+ pickling.println(i"unpickling in run ${ctx.runId}")
+ if (ctx.settings.YtestPickler.value) beforePickling(unit) = tree.show
- val pickler = unit.pickler
- val treePkl = new TreePickler(pickler)
- treePkl.pickle(tree :: Nil)
- unit.addrOfTree = treePkl.buf.addrOfTree
- unit.addrOfSym = treePkl.addrOfSym
- if (tree.pos.exists)
- new PositionPickler(pickler, treePkl.buf.addrOfTree).picklePositions(tree :: Nil, tree.pos)
+ val pickler = unit.pickler
+ val treePkl = new TreePickler(pickler)
+ treePkl.pickle(tree :: Nil)
+ unit.addrOfTree = treePkl.buf.addrOfTree
+ unit.addrOfSym = treePkl.addrOfSym
+ if (tree.pos.exists)
+ new PositionPickler(pickler, treePkl.buf.addrOfTree).picklePositions(tree :: Nil, tree.pos)
- def rawBytes = // not needed right now, but useful to print raw format.
- unit.pickler.assembleParts().iterator.grouped(10).toList.zipWithIndex.map {
- case (row, i) => s"${i}0: ${row.mkString(" ")}"
- }
- // println(i"rawBytes = \n$rawBytes%\n%") // DEBUG
- if (pickling ne noPrinter) new TastyPrinter(pickler.assembleParts()).printContents()
- }
+ def rawBytes = // not needed right now, but useful to print raw format.
+ unit.pickler.assembleParts().iterator.grouped(10).toList.zipWithIndex.map {
+ case (row, i) => s"${i}0: ${row.mkString(" ")}"
+ }
+ // println(i"rawBytes = \n$rawBytes%\n%") // DEBUG
+ if (pickling ne noPrinter) new TastyPrinter(pickler.assembleParts()).printContents()
}
override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = {
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala
index 9303572d2..b28afa6f2 100644
--- a/src/dotty/tools/dotc/typer/Checking.scala
+++ b/src/dotty/tools/dotc/typer/Checking.scala
@@ -232,7 +232,7 @@ trait Checking {
/** Check that type `tp` is stable. */
def checkStable(tp: Type, pos: Position)(implicit ctx: Context): Unit =
- if (!tp.isStable)
+ if (!tp.isStable && !tp.isErroneous)
ctx.error(d"$tp is not stable", pos)
/** Check that type `tp` is a legal prefix for '#'.
diff --git a/src/dotty/tools/dotc/typer/FrontEnd.scala b/src/dotty/tools/dotc/typer/FrontEnd.scala
index bb313501d..ceb806e52 100644
--- a/src/dotty/tools/dotc/typer/FrontEnd.scala
+++ b/src/dotty/tools/dotc/typer/FrontEnd.scala
@@ -51,7 +51,7 @@ class FrontEnd extends Phase {
unitContexts foreach (enterSyms(_))
unitContexts foreach (typeCheck(_))
record("totalTrees", ast.Trees.ntrees)
- unitContexts.map(_.compilationUnit)
+ unitContexts.map(_.compilationUnit).filter(!_.isJava)
}
override def run(implicit ctx: Context): Unit = {
diff --git a/src/dotty/tools/dotc/typer/InstChecks.scala b/src/dotty/tools/dotc/typer/InstChecks.scala
new file mode 100644
index 000000000..7148a6e68
--- /dev/null
+++ b/src/dotty/tools/dotc/typer/InstChecks.scala
@@ -0,0 +1,90 @@
+package dotty.tools.dotc
+package typer
+
+import core._
+import Contexts.Context
+import Decorators._
+import Phases._
+import Types._, Symbols._, Flags._, StdNames._
+import util.Positions._
+import ast.Trees._
+import typer.ErrorReporting._
+import DenotTransformers._
+
+/** This checks `New` nodes, verifying that they can be instantiated. */
+class InstChecks extends Phase with IdentityDenotTransformer {
+ import ast.tpd._
+
+ override def phaseName: String = "instchecks"
+
+ override def run(implicit ctx: Context): Unit =
+ instCheck.traverse(ctx.compilationUnit.tpdTree)
+
+ /** Check that `tp` refers to a nonAbstract class
+ * and that the instance conforms to the self type of the created class.
+ */
+ def checkInstantiatable(tp: Type, pos: Position)(implicit ctx: Context): Unit =
+ tp.underlyingClassRef(refinementOK = false) match {
+ case tref: TypeRef =>
+ val cls = tref.symbol
+ if (cls.is(AbstractOrTrait))
+ ctx.error(d"$cls is abstract; cannot be instantiated", pos)
+ if (!cls.is(Module)) {
+ val selfType = tp.givenSelfType.asSeenFrom(tref.prefix, cls.owner)
+ if (selfType.exists && !(tp <:< selfType))
+ ctx.error(d"$tp does not conform to its self type $selfType; cannot be instantiated")
+ }
+ case _ =>
+ }
+
+ def checkValidJavaAnnotation(annot: Tree)(implicit ctx: Context): Unit = {
+ // TODO fill in
+ }
+
+ val instCheck = new TreeTraverser {
+
+ def checkAnnot(annot: Tree)(implicit ctx: Context): Unit =
+ if (annot.symbol.is(JavaDefined)) checkValidJavaAnnotation(annot)
+ else traverse(annot)
+
+ def traverseNoCheck(tree: Tree)(implicit ctx: Context): Unit = tree match {
+ case Apply(fn, args) =>
+ traverseNoCheck(fn)
+ args.foreach(traverse)
+ case TypeApply(fn, args) =>
+ traverseNoCheck(fn)
+ args.foreach(traverse)
+ case Select(qual, nme.CONSTRUCTOR) =>
+ traverseNoCheck(qual)
+ case New(tpt) =>
+ traverse(tpt)
+ case _ =>
+ traverse(tree)
+ }
+
+ def traverse(tree: Tree)(implicit ctx: Context): Unit = tree match {
+ case tree: New =>
+ checkInstantiatable(tree.tpe, tree.pos)
+ traverseChildren(tree)
+ case impl @ Template(constr, parents, self, _) =>
+ traverse(constr)
+ parents.foreach(traverseNoCheck)
+ traverse(self)
+ impl.body.foreach(traverse)
+ case Annotated(annot, tree) =>
+ checkAnnot(annot)
+ traverse(tree)
+ case TypeTree(original) =>
+ tree.tpe match {
+ case AnnotatedType(annot, tpe) => checkAnnot(annot.tree)
+ case _ =>
+ }
+ traverse(original)
+ case tree: MemberDef =>
+ tree.symbol.annotations.foreach(annot => checkAnnot(annot.tree))
+ traverseChildren(tree)
+ case _ =>
+ traverseChildren(tree)
+ }
+ }
+}
diff --git a/src/dotty/tools/dotc/typer/RefChecks.scala b/src/dotty/tools/dotc/typer/RefChecks.scala
index 9b14fffc0..6a1f3652b 100644
--- a/src/dotty/tools/dotc/typer/RefChecks.scala
+++ b/src/dotty/tools/dotc/typer/RefChecks.scala
@@ -71,6 +71,17 @@ object RefChecks {
}
}
+ /** Check that self type of this class conforms to self types of parents */
+ private def checkSelfType(clazz: Symbol)(implicit ctx: Context): Unit = clazz.info match {
+ case cinfo: ClassInfo =>
+ for (parent <- cinfo.classParents) {
+ 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)
+ }
+ case _ =>
+ }
+
// Override checking ------------------------------------------------------------
/** 1. Check all members of class `clazz` for overriding conditions.
@@ -770,6 +781,7 @@ class RefChecks extends MiniPhase with SymTransformer { thisTransformer =>
override def transformTemplate(tree: Template)(implicit ctx: Context, info: TransformerInfo) = {
val cls = ctx.owner
checkOverloadedRestrictions(cls)
+ checkSelfType(cls)
checkAllOverrides(cls)
checkAnyValSubclass(cls)
tree
diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala
index ebd4673ef..85a3e317a 100644
--- a/test/dotc/tests.scala
+++ b/test/dotc/tests.scala
@@ -138,6 +138,8 @@ class tests extends CompilerTest {
@Test def neg_i0281 = compileFile(negDir, "i0281-null-primitive-conforms", xerrors = 3)
@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 dotc = compileDir(toolsDir, "dotc", failedOther)(allowDeepSubtypes ++ twice) // see dotc_core
@Test def dotc_ast = compileDir(dotcDir, "ast", failedOther ++ twice)
diff --git a/tests/neg/instantiateAbstract.scala b/tests/neg/instantiateAbstract.scala
new file mode 100644
index 000000000..1e119a8b5
--- /dev/null
+++ b/tests/neg/instantiateAbstract.scala
@@ -0,0 +1,38 @@
+abstract class AA
+
+trait TT
+
+class A { self: B =>
+
+}
+
+@scala.annotation.Annotation class C // error
+
+class B extends A() {
+}
+
+object Test {
+
+ @scala.annotation.Annotation type T = String // error
+ @scala.annotation.Annotation val x = 1 // error
+ @scala.annotation.Annotation def f = 1 //error
+
+ (1: @scala.annotation.Annotation) // error
+
+
+ new AA // error
+
+ new TT // error
+
+ new A // error
+
+// the following are OK in Typer but would be caught later in RefChecks
+
+ new A() {}
+
+ new AA() {}
+
+ object O extends A
+
+ object OO extends AA
+}
diff --git a/tests/neg/selfInheritance.scala b/tests/neg/selfInheritance.scala
new file mode 100644
index 000000000..5f61c5bbb
--- /dev/null
+++ b/tests/neg/selfInheritance.scala
@@ -0,0 +1,28 @@
+trait T { self: B => }
+
+abstract class A { self: B =>
+
+}
+
+class B extends A with T {
+}
+
+class C { self: B =>
+
+}
+
+class D extends A // error
+
+class E extends T // error
+
+object Test {
+
+ new B() {}
+
+ new A() {} // error
+
+ object O extends A // error
+
+ object M extends C // error
+
+}