From fb59174be6193d7cb05bea6d375e34ec1cd52f46 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 10 Nov 2016 16:35:39 +0100 Subject: Don't allow redefinition of core classes Fixes #1688. --- src/dotty/tools/dotc/ast/Desugar.scala | 32 +++++++++++++++++++++-------- src/dotty/tools/dotc/core/Definitions.scala | 20 ++++++++++-------- src/dotty/tools/dotc/core/NameOps.scala | 2 ++ 3 files changed, 38 insertions(+), 16 deletions(-) (limited to 'src') 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 { * 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 -- cgit v1.2.3