diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala index 178cba7c4080..f60299bdb006 100644 --- a/src/dotty/tools/dotc/Compiler.scala +++ b/src/dotty/tools/dotc/Compiler.scala @@ -50,6 +50,7 @@ class Compiler { new CheckReentrant), // Internal use only: Check that compiled program has no data races involving global vars List(new RefChecks, // Various checks mostly related to abstract members and overriding new CheckStatic, // Check restrictions that apply to @static members + new CheckRedefs, // Check redefinitions of primitives and synthetic classes new ElimRepeated, // Rewrite vararg parameters and arguments new NormalizeFlags, // Rewrite some definition flags new ExtensionMethods, // Expand methods of value classes with extension methods diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala index 62fa2d07de88..c43b7221ed57 100644 --- a/src/dotty/tools/dotc/core/Definitions.scala +++ b/src/dotty/tools/dotc/core/Definitions.scala @@ -633,9 +633,9 @@ class Definitions { name.startsWith(prefix) && name.drop(prefix.length).forall(_.isDigit) } - def isBottomClass(cls: Symbol) = + def isBottomClass(cls: Symbol) = cls == NothingClass || cls == NullClass - def isBottomType(tp: Type) = + def isBottomType(tp: Type) = tp.derivesFrom(NothingClass) || tp.derivesFrom(NullClass) def isFunctionClass(cls: Symbol) = isVarArityClass(cls, tpnme.Function) @@ -772,7 +772,8 @@ class Definitions { SingletonClass, EqualsPatternClass, EmptyPackageVal, - OpsPackageClass) + OpsPackageClass + ) /** Lists core methods that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */ lazy val syntheticCoreMethods = AnyMethods ++ ObjectMethods ++ List(String_+, throwMethod) @@ -785,8 +786,8 @@ class Definitions { if (!_isInitialized) { // force initialization of every symbol that is synthesized or hijacked by the compiler val forced = syntheticCoreClasses ++ syntheticCoreMethods ++ ScalaValueClasses() - - // Enter all symbols from the scalaShadowing package in the scala package + + // Enter all symbols from the scalaShadowing package in the scala package for (m <- ScalaShadowingPackageClass.info.decls) ScalaPackageClass.enter(m) diff --git a/src/dotty/tools/dotc/transform/CheckRedefs.scala b/src/dotty/tools/dotc/transform/CheckRedefs.scala new file mode 100644 index 000000000000..948e9d726f17 --- /dev/null +++ b/src/dotty/tools/dotc/transform/CheckRedefs.scala @@ -0,0 +1,43 @@ +package dotty.tools.dotc +package transform + +import TreeTransforms._ +import core._ +import DenotTransformers._, Contexts._, Definitions._, Decorators._ +import SymDenotations._ + +/** Checks if the user is trying to illegally override synthetic classes, + * primitives or their boxed equivalent + */ +class CheckRedefs extends MiniPhaseTransform with SymTransformer { + import ast.tpd._ + + override def phaseName = "checkRedefs" + + def transformSym(sym: SymDenotation)(implicit ctx: Context) = { + val defn = ctx.definitions + val fullName = sym.symbol.showFullName + + // Since symbols cannot be compared with `==` since they rely on hashes for + // uniqueness, we compare the full names instead + val syntheticClasses = defn.syntheticCoreClasses.map(_.showFullName) + val primitives = defn.ScalaValueClasses().map(_.showFullName) + val boxedPrimitives = defn.ScalaBoxedClasses().map(_.showFullName) + + val illegalOverride = + if (syntheticClasses.contains(fullName)) + Some("synthetic") + else if (primitives.contains(fullName)) + Some("primitive") + else if (boxedPrimitives.contains(fullName)) + Some("boxed primitive") + else + None + + illegalOverride.foreach { overriden => + ctx.error(i"Cannot define symbol overriding $overriden `${sym.fullName}`", sym.symbol.pos) + } + + sym + } +} diff --git a/tests/neg/i1688.scala b/tests/neg/i1688.scala new file mode 100644 index 000000000000..48fff6f01ca6 --- /dev/null +++ b/tests/neg/i1688.scala @@ -0,0 +1,5 @@ +package scala + +sealed trait Null // error + +trait Char // error diff --git a/tests/neg/i1688b.scala b/tests/neg/i1688b.scala new file mode 100644 index 000000000000..dec13e8099bd --- /dev/null +++ b/tests/neg/i1688b.scala @@ -0,0 +1,3 @@ +package java.lang + +trait Byte // error diff --git a/tests/neg/i1688c.scala b/tests/neg/i1688c.scala new file mode 100644 index 000000000000..047e7548325e --- /dev/null +++ b/tests/neg/i1688c.scala @@ -0,0 +1,5 @@ +package scala + +object Null { // error + def foo: Int = ??? +}