diff options
author | Guillaume Martres <smarter@ubuntu.com> | 2017-02-13 15:36:57 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-02-13 15:36:57 +0100 |
commit | b29783237c03ade1dd19cc564170c7a87d7b8b84 (patch) | |
tree | 9aa30b02b5267665bb204a38c4912c3b763f4375 /compiler/src | |
parent | 07b67a8416c501d7f7b37442f3a294d9f9252895 (diff) | |
parent | 36e91d4ed0a293943d66f409f7515953e961067f (diff) | |
download | dotty-b29783237c03ade1dd19cc564170c7a87d7b8b84.tar.gz dotty-b29783237c03ade1dd19cc564170c7a87d7b8b84.tar.bz2 dotty-b29783237c03ade1dd19cc564170c7a87d7b8b84.zip |
Merge pull request #1931 from dotty-staging/fix-#1501
Fix #1501 - Check trait inheritance condition
Diffstat (limited to 'compiler/src')
-rw-r--r-- | compiler/src/dotty/tools/dotc/ast/tpd.scala | 2 | ||||
-rw-r--r-- | compiler/src/dotty/tools/dotc/core/Definitions.scala | 2 | ||||
-rw-r--r-- | compiler/src/dotty/tools/dotc/typer/Checking.scala | 27 | ||||
-rw-r--r-- | compiler/src/dotty/tools/dotc/typer/Typer.scala | 2 |
4 files changed, 30 insertions, 3 deletions
diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 565ec5ce2..ed268fda7 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -260,7 +260,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def AnonClass(parents: List[Type], fns: List[TermSymbol], methNames: List[TermName])(implicit ctx: Context): Block = { val owner = fns.head.owner val parents1 = - if (parents.head.classSymbol.is(Trait)) defn.ObjectType :: parents + if (parents.head.classSymbol.is(Trait)) parents.head.parents.head :: parents else parents val cls = ctx.newNormalizedClassSymbol(owner, tpnme.ANON_FUN, Synthetic, parents1, coord = fns.map(_.pos).reduceLeft(_ union _)) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 866f6e7fa..2797bb8a6 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -476,7 +476,7 @@ class Definitions { lazy val BoxedNumberClass = ctx.requiredClass("java.lang.Number") lazy val ThrowableClass = ctx.requiredClass("java.lang.Throwable") lazy val ClassCastExceptionClass = ctx.requiredClass("java.lang.ClassCastException") - lazy val JavaSerializableClass = ctx.requiredClass("java.lang.Serializable") + lazy val JavaSerializableClass = ctx.requiredClass("java.io.Serializable") lazy val ComparableClass = ctx.requiredClass("java.lang.Comparable") // in scalac modified to have Any as parent diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index ca62ed0a9..27b0f28ca 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -448,7 +448,6 @@ object Checking { } stats.foreach(checkValueClassMember) } - } } @@ -601,6 +600,31 @@ trait Checking { /** Verify classes extending AnyVal meet the requirements */ def checkDerivedValueClass(clazz: Symbol, stats: List[Tree])(implicit ctx: Context) = Checking.checkDerivedValueClass(clazz, stats) + + /** Given a parent `parent` of a class `cls`, if `parent` is a trait check that + * the superclass of `cls` derived from the superclass of `parent`. + * + * An exception is made if `cls` extends `Any`, and `parent` is `java.io.Serializable` + * or `java.lang.Comparable`. These two classes are treated by Scala as universal + * traits. E.g. the following is OK: + * + * ... extends Any with java.io.Serializable + * + * The standard library relies on this idiom. + */ + def checkTraitInheritance(parent: Symbol, cls: ClassSymbol, pos: Position)(implicit ctx: Context): Unit = { + parent match { + case parent: ClassSymbol if parent is Trait => + val psuper = parent.superClass + val csuper = cls.superClass + val ok = csuper.derivesFrom(psuper) || + parent.is(JavaDefined) && csuper == defn.AnyClass && + (parent == defn.JavaSerializableClass || parent == defn.ComparableClass) + if (!ok) + ctx.error(em"illegal trait inheritance: super$csuper does not derive from $parent's super$psuper", pos) + case _ => + } + } } trait NoChecking extends Checking { @@ -617,4 +641,5 @@ trait NoChecking extends Checking { override def checkSimpleKinded(tpt: Tree)(implicit ctx: Context): Tree = tpt override def checkNotSingleton(tpt: Tree, where: String)(implicit ctx: Context): Tree = tpt override def checkDerivedValueClass(clazz: Symbol, stats: List[Tree])(implicit ctx: Context) = () + override def checkTraitInheritance(parentSym: Symbol, cls: ClassSymbol, pos: Position)(implicit ctx: Context) = () } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 652c89094..ded8993fb 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1288,6 +1288,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit if (tree.isType) { val result = typedType(tree)(superCtx) val psym = result.tpe.typeSymbol + checkTraitInheritance(psym, cls, tree.pos) if (psym.is(Trait) && !cls.is(Trait) && !cls.superClass.isSubClass(psym)) maybeCall(result, psym, psym.primaryConstructor.info) else @@ -1295,6 +1296,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } else { val result = typedExpr(tree)(superCtx) + checkTraitInheritance(result.symbol, cls, tree.pos) checkParentCall(result, cls) result } |