aboutsummaryrefslogtreecommitdiff
path: root/src/dotty
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2016-11-10 16:35:39 +0100
committerMartin Odersky <odersky@gmail.com>2016-11-10 16:55:30 +0100
commitfb59174be6193d7cb05bea6d375e34ec1cd52f46 (patch)
treeed15d3de773eb2052fcc02be24a26c104390739c /src/dotty
parent28c2e04dd33b6389a44460f977a97b8691265994 (diff)
downloaddotty-fb59174be6193d7cb05bea6d375e34ec1cd52f46.tar.gz
dotty-fb59174be6193d7cb05bea6d375e34ec1cd52f46.tar.bz2
dotty-fb59174be6193d7cb05bea6d375e34ec1cd52f46.zip
Don't allow redefinition of core classes
Fixes #1688.
Diffstat (limited to 'src/dotty')
-rw-r--r--src/dotty/tools/dotc/ast/Desugar.scala32
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala20
-rw-r--r--src/dotty/tools/dotc/core/NameOps.scala2
3 files changed, 38 insertions, 16 deletions
diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala
index 349fbfb2c..d568e3d31 100644
--- a/src/dotty/tools/dotc/ast/Desugar.scala
+++ b/src/dotty/tools/dotc/ast/Desugar.scala
@@ -250,7 +250,8 @@ object desugar {
/** The expansion of a class definition. See inline comments for what is involved */
def classDef(cdef: TypeDef)(implicit ctx: Context): Tree = {
- val TypeDef(name, impl @ Template(constr0, parents, self, _)) = cdef
+ val className = checkNotReservedName(cdef).asTypeName
+ val impl @ Template(constr0, parents, self, _) = cdef.rhs
val mods = cdef.mods
val companionMods = mods.withFlags((mods.flags & AccessFlags).toCommonFlags)
@@ -384,7 +385,7 @@ object desugar {
def companionDefs(parentTpt: Tree, defs: List[Tree]) =
moduleDef(
ModuleDef(
- name.toTermName, Template(emptyConstructor, parentTpt :: Nil, EmptyValDef, defs))
+ className.toTermName, Template(emptyConstructor, parentTpt :: Nil, EmptyValDef, defs))
.withMods(companionMods | Synthetic))
.withPos(cdef.pos).toList
@@ -443,7 +444,7 @@ object desugar {
else
// implicit wrapper is typechecked in same scope as constructor, so
// we can reuse the constructor parameters; no derived params are needed.
- DefDef(name.toTermName, constrTparams, constrVparamss, classTypeRef, creatorExpr)
+ DefDef(className.toTermName, constrTparams, constrVparamss, classTypeRef, creatorExpr)
.withMods(companionMods | Synthetic | Implicit)
.withPos(cdef.pos) :: Nil
@@ -460,6 +461,7 @@ object desugar {
val caseAccessor = if (isCaseClass) CaseAccessor else EmptyFlags
val vparamAccessors = derivedVparamss.flatten.map(_.withMods(originalVparams.next.mods | caseAccessor))
cpy.TypeDef(cdef)(
+ name = className,
rhs = cpy.Template(impl)(constr, parents1, self1,
tparamAccessors ::: vparamAccessors ::: normalizedBody ::: caseClassMeths),
tparams = Nil)
@@ -485,20 +487,21 @@ object desugar {
* <module> final class name$ extends parents { self: name.type => body }
*/
def moduleDef(mdef: ModuleDef)(implicit ctx: Context): Tree = {
- val ModuleDef(name, tmpl) = mdef
+ val moduleName = checkNotReservedName(mdef).asTermName
+ val tmpl = mdef.impl
val mods = mdef.mods
if (mods is Package)
- PackageDef(Ident(name), cpy.ModuleDef(mdef)(nme.PACKAGE, tmpl).withMods(mods &~ Package) :: Nil)
+ PackageDef(Ident(moduleName), cpy.ModuleDef(mdef)(nme.PACKAGE, tmpl).withMods(mods &~ Package) :: Nil)
else {
- val clsName = name.moduleClassName
+ val clsName = moduleName.moduleClassName
val clsRef = Ident(clsName)
- val modul = ValDef(name, clsRef, New(clsRef, Nil))
+ val modul = ValDef(moduleName, clsRef, New(clsRef, Nil))
.withMods(mods | ModuleCreationFlags | mods.flags & AccessFlags)
.withPos(mdef.pos)
val ValDef(selfName, selfTpt, _) = tmpl.self
val selfMods = tmpl.self.mods
if (!selfTpt.isEmpty) ctx.error(ObjectMayNotHaveSelfType(mdef), tmpl.self.pos)
- val clsSelf = ValDef(selfName, SingletonTypeTree(Ident(name)), tmpl.self.rhs)
+ val clsSelf = ValDef(selfName, SingletonTypeTree(Ident(moduleName)), tmpl.self.rhs)
.withMods(selfMods)
.withPos(tmpl.self.pos orElse tmpl.pos.startPos)
val clsTmpl = cpy.Template(tmpl)(self = clsSelf, body = tmpl.body)
@@ -508,6 +511,19 @@ object desugar {
}
}
+ /** The name of `mdef`, after checking that it does not redefine a Scala core class.
+ * If it does redefine, issue an error and return a mangled name instead of the original one.
+ */
+ def checkNotReservedName(mdef: MemberDef)(implicit ctx: Context): Name = {
+ val name = mdef.name
+ if (ctx.owner == defn.ScalaPackageClass && defn.reservedScalaClassNames.contains(name.toTypeName)) {
+ def kind = if (name.isTypeName) "class" else "object"
+ ctx.error(em"illegal redefinition of standard $kind $name", mdef.pos)
+ name.errorName
+ }
+ else name
+ }
+
/** val p1, ..., pN: T = E
* ==>
* makePatDef[[val p1: T1 = E]]; ...; makePatDef[[val pN: TN = E]]
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index 62fa2d07d..4e9518a2a 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)
@@ -761,7 +761,7 @@ class Definitions {
// ----- Initialization ---------------------------------------------------
/** Lists core classes that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */
- lazy val syntheticCoreClasses = List(
+ lazy val syntheticScalaClasses = List(
AnyClass,
AnyRefAlias,
RepeatedParamClass,
@@ -770,12 +770,16 @@ class Definitions {
NullClass,
NothingClass,
SingletonClass,
- EqualsPatternClass,
+ EqualsPatternClass)
+
+ lazy val syntheticCoreClasses = syntheticScalaClasses ++ List(
EmptyPackageVal,
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)
+ /** 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)
+
+ lazy val reservedScalaClassNames: Set[Name] = syntheticScalaClasses.map(_.name).toSet
private[this] var _isInitialized = false
private def isInitialized = _isInitialized
@@ -785,8 +789,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/core/NameOps.scala b/src/dotty/tools/dotc/core/NameOps.scala
index 48e823e81..4c7f5b0a9 100644
--- a/src/dotty/tools/dotc/core/NameOps.scala
+++ b/src/dotty/tools/dotc/core/NameOps.scala
@@ -186,6 +186,8 @@ object NameOps {
def implClassName: N = likeTyped(name ++ tpnme.IMPL_CLASS_SUFFIX)
+ def errorName: N = likeTyped(name ++ nme.ERROR)
+
def freshened(implicit ctx: Context): N =
likeTyped(
if (name.isModuleClassName) name.stripModuleClassSuffix.freshened.moduleClassName