Skip to content

Fix #1688: don't allow override of synthetic or primitive classes #1689

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 6 additions & 5 deletions src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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)

Expand Down
43 changes: 43 additions & 0 deletions src/dotty/tools/dotc/transform/CheckRedefs.scala
Original file line number Diff line number Diff line change
@@ -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
}
}
5 changes: 5 additions & 0 deletions tests/neg/i1688.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package scala

sealed trait Null // error

trait Char // error
3 changes: 3 additions & 0 deletions tests/neg/i1688b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package java.lang

trait Byte // error
5 changes: 5 additions & 0 deletions tests/neg/i1688c.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package scala

object Null { // error
def foo: Int = ???
}