From e8d307686f70372f9098c196dc246b5dc1edd351 Mon Sep 17 00:00:00 2001 From: Felix Mulder Date: Wed, 9 Nov 2016 09:24:29 +0100 Subject: [PATCH 1/2] Fix #1688: don't allow override of synthetic or primitive classes --- src/dotty/tools/dotc/Compiler.scala | 1 + src/dotty/tools/dotc/core/Definitions.scala | 11 ++--- .../transform/CheckIllegalOverrides.scala | 41 +++++++++++++++++++ tests/neg/i1688.scala | 5 +++ tests/neg/i1688b.scala | 3 ++ 5 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 src/dotty/tools/dotc/transform/CheckIllegalOverrides.scala create mode 100644 tests/neg/i1688.scala create mode 100644 tests/neg/i1688b.scala diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala index 178cba7c4080..6def08ea08ed 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 CheckIllegalOverrides, // Check restrictions that apply to phantom types and value 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/CheckIllegalOverrides.scala b/src/dotty/tools/dotc/transform/CheckIllegalOverrides.scala new file mode 100644 index 000000000000..10588512a021 --- /dev/null +++ b/src/dotty/tools/dotc/transform/CheckIllegalOverrides.scala @@ -0,0 +1,41 @@ +package dotty.tools.dotc +package transform + +import TreeTransforms._ +import core._ +import Contexts._, Definitions._, Decorators._ + +/** Checks if the user is trying to illegally override synthetic classes, + * primitives or their boxed equivalent + */ +class CheckIllegalOverrides extends MiniPhaseTransform { + import ast.tpd._ + + override def phaseName = "checkPhantom" + + override def transformTypeDef(tree: TypeDef)(implicit ctx: Context, info: TransformerInfo) = { + val defn = ctx.definitions + val tpe = tree.tpe + val fullName = tree.symbol.showFullName + + 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 class `$tpe`", tree.pos) + } + + tree + } +} 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 From 1ff06f8abc2c1d3a59a6bc08ebd92c21e4f48905 Mon Sep 17 00:00:00 2001 From: Felix Mulder Date: Wed, 9 Nov 2016 10:59:56 +0100 Subject: [PATCH 2/2] Make CheckRedefs a SymTransformer --- src/dotty/tools/dotc/Compiler.scala | 2 +- ...llegalOverrides.scala => CheckRedefs.scala} | 18 ++++++++++-------- tests/neg/i1688c.scala | 5 +++++ 3 files changed, 16 insertions(+), 9 deletions(-) rename src/dotty/tools/dotc/transform/{CheckIllegalOverrides.scala => CheckRedefs.scala} (59%) create mode 100644 tests/neg/i1688c.scala diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala index 6def08ea08ed..f60299bdb006 100644 --- a/src/dotty/tools/dotc/Compiler.scala +++ b/src/dotty/tools/dotc/Compiler.scala @@ -50,7 +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 CheckIllegalOverrides, // Check restrictions that apply to phantom types and value classes + 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/transform/CheckIllegalOverrides.scala b/src/dotty/tools/dotc/transform/CheckRedefs.scala similarity index 59% rename from src/dotty/tools/dotc/transform/CheckIllegalOverrides.scala rename to src/dotty/tools/dotc/transform/CheckRedefs.scala index 10588512a021..948e9d726f17 100644 --- a/src/dotty/tools/dotc/transform/CheckIllegalOverrides.scala +++ b/src/dotty/tools/dotc/transform/CheckRedefs.scala @@ -3,21 +3,23 @@ package transform import TreeTransforms._ import core._ -import Contexts._, Definitions._, Decorators._ +import DenotTransformers._, Contexts._, Definitions._, Decorators._ +import SymDenotations._ /** Checks if the user is trying to illegally override synthetic classes, * primitives or their boxed equivalent */ -class CheckIllegalOverrides extends MiniPhaseTransform { +class CheckRedefs extends MiniPhaseTransform with SymTransformer { import ast.tpd._ - override def phaseName = "checkPhantom" + override def phaseName = "checkRedefs" - override def transformTypeDef(tree: TypeDef)(implicit ctx: Context, info: TransformerInfo) = { + def transformSym(sym: SymDenotation)(implicit ctx: Context) = { val defn = ctx.definitions - val tpe = tree.tpe - val fullName = tree.symbol.showFullName + 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) @@ -33,9 +35,9 @@ class CheckIllegalOverrides extends MiniPhaseTransform { None illegalOverride.foreach { overriden => - ctx.error(i"Cannot define symbol overriding $overriden class `$tpe`", tree.pos) + ctx.error(i"Cannot define symbol overriding $overriden `${sym.fullName}`", sym.symbol.pos) } - tree + sym } } 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 = ??? +}