diff options
-rw-r--r-- | src/compiler/scala/reflect/internal/Definitions.scala | 8 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/Parsers.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala | 13 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Namers.scala | 6 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/RefChecks.scala | 23 | ||||
-rw-r--r-- | src/library/scala/AnyVal.scala | 2 | ||||
-rw-r--r-- | src/library/scala/NotNull.scala | 2 | ||||
-rw-r--r-- | test/files/neg/anyval-children-2.check | 4 | ||||
-rw-r--r-- | test/files/neg/anyval-children-2.scala | 1 | ||||
-rw-r--r-- | test/files/neg/anyval-children.check | 26 | ||||
-rw-r--r-- | test/files/neg/anyval-children.scala | 14 | ||||
-rw-r--r-- | test/files/pos/anyval-children.scala | 2 |
12 files changed, 88 insertions, 15 deletions
diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index f8342444c8..ce0505bf44 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -910,6 +910,12 @@ trait Definitions extends reflect.api.StandardDefinitions { private lazy val scalaValueClassesSet = ScalaValueClasses.toSet private lazy val boxedValueClassesSet = boxedClass.values.toSet + BoxedUnitClass + /** Now that AnyVal is unsealing we need less ambiguous names + * for when we need to distinguish the Nine Original AnyVals + * from the heathen masses. + */ + def isPrimitiveValueClass(sym: Symbol) = scalaValueClassesSet(sym) + /** Is symbol a value class? */ def isValueClass(sym: Symbol) = scalaValueClassesSet(sym) def isNonUnitValueClass(sym: Symbol) = (sym != UnitClass) && isValueClass(sym) @@ -1029,7 +1035,7 @@ trait Definitions extends reflect.api.StandardDefinitions { /** Removing the anyref parent they acquire from having a source file. */ - setParents(AnyValClass, anyparam) + setParents(AnyValClass, List(NotNullClass.tpe, AnyClass.tpe)) ScalaValueClasses foreach { sym => setParents(sym, anyvalparam) } diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index eb7c5a6699..3ee8b62bc6 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -2757,7 +2757,7 @@ self => Template(List(scalaDot(tpnme.AnyVal)), self, body) } else if (parents0 exists isReferenceToAnyVal) { - // TODO - enforce @inline annotation, and no other parents + // @inline and other restrictions enforced in refchecks Template(parents0, self, body) } else if (name == tpnme.AnyVal) { diff --git a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala index 5f62dfab39..c308a3633e 100644 --- a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala +++ b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala @@ -84,10 +84,11 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { def extensionMethInfo(extensionMeth: Symbol, origInfo: Type, clazz: Symbol): Type = { var newTypeParams = cloneSymbolsAtOwner(clazz.typeParams, extensionMeth) val thisParamType = appliedType(clazz.typeConstructor, newTypeParams map (_.tpe)) - val thisParam = extensionMeth.newValueParameter(nme.SELF, extensionMeth.pos) setInfo thisParamType + val thisParam = extensionMeth.newValueParameter(nme.SELF, extensionMeth.pos) setInfo thisParamType def transform(clonedType: Type): Type = clonedType match { case MethodType(params, restpe) => - MethodType(List(thisParam), clonedType) + // I assume it was a bug that this was dropping params... + MethodType(thisParam :: params, clonedType) case NullaryMethodType(restpe) => MethodType(List(thisParam), restpe) } @@ -116,7 +117,13 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { val extensionMeth = companion.moduleClass.newMethod(extensionName, origMeth.pos, origMeth.flags & ~OVERRIDE | FINAL) .setAnnotations(origMeth.annotations) companion.info.decls.enter(extensionMeth) - extensionMeth.setInfo(extensionMethInfo(extensionMeth, origMeth.info, currentOwner)) + val newInfo = extensionMethInfo(extensionMeth, origMeth.info, currentOwner) + extensionMeth setInfo newInfo + log("Inline class %s spawns extension method.\n Old: %s\n New: %s".format( + currentOwner, + origMeth.defString, + extensionMeth.defString)) // extensionMeth.defStringSeenAs(origInfo + def thisParamRef = gen.mkAttributedIdent(extensionMeth.info.params.head setPos extensionMeth.pos) val GenPolyType(extensionTpeParams, extensionMono) = extensionMeth.info val origTpeParams = origMeth.typeParams ::: currentOwner.typeParams diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index b9f3adec75..2f31347829 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -1407,7 +1407,9 @@ trait Namers extends MethodSynthesis { } if (sym.isClass && sym.hasAnnotation(ScalaInlineClass) && !phase.erasedTypes) { - ensureParent(NotNullClass) + if (!sym.isSubClass(AnyValClass)) + ensureParent(NotNullClass) + sym setFlag FINAL } @@ -1437,7 +1439,7 @@ trait Namers extends MethodSynthesis { checkNoConflict(PRIVATE, PROTECTED) // checkNoConflict(PRIVATE, OVERRIDE) // this one leads to bad error messages like #4174, so catch in refchecks // checkNoConflict(PRIVATE, FINAL) // can't do this because FINAL also means compile-time constant - checkNoConflict(ABSTRACT, FINAL) + // checkNoConflict(ABSTRACT, FINAL) // this one gives a bad error for non-@inline classes which extend AnyVal // @PP: I added this as a sanity check because these flags are supposed to be // converted to ABSOVERRIDE before arriving here. checkNoConflict(ABSTRACT, OVERRIDE) diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 4449116fd1..f7a6815905 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -683,16 +683,16 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R if (abstractErrors.nonEmpty) unit.error(clazz.pos, abstractErrorMessage) - } else if (clazz.isTrait) { - // prevent abstract methods in interfaces that override final members in Object; see #4431 - if (!(clazz isSubClass AnyValClass)) { + } + else if (clazz.isTrait && !(clazz isSubClass AnyValClass)) { + // For non-AnyVal classes, prevent abstract methods in interfaces that override + // final members in Object; see #4431 for (decl <- clazz.info.decls.iterator) { val overridden = decl.overriddenSymbol(ObjectClass) if (overridden.isFinal) unit.error(decl.pos, "trait cannot redefine final method from class AnyRef") } } - } /** Returns whether there is a symbol declared in class `inclazz` * (which must be different from `clazz`) whose name and type @@ -1527,6 +1527,19 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R ) case _ => () } + + // verify classes extending AnyVal meet the requirements + // (whatever those are to be, but at least: @inline annotation) + private def checkAnyValSubclass(clazz: Symbol) = { + if ((clazz isSubClass AnyValClass) && (clazz ne AnyValClass) && !isPrimitiveValueClass(clazz)) { + if (!clazz.hasAnnotation(ScalaInlineClass)) + unit.error(clazz.pos, "Only @inline classes are allowed to extend AnyVal") + if (clazz.isTrait) + unit.error(clazz.pos, "Only @inline classes (not traits) are allowed to extend AnyVal") + if (clazz.tpe <:< AnyRefClass.tpe) + unit.error(clazz.pos, "Classes which extend AnyVal may not have an ancestor which inherits AnyRef") + } + } override def transform(tree: Tree): Tree = { val savedLocalTyper = localTyper @@ -1562,6 +1575,8 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R checkOverloadedRestrictions(currentOwner) val bridges = addVarargBridges(currentOwner) checkAllOverrides(currentOwner) + checkAnyValSubclass(currentOwner) + if (bridges.nonEmpty) treeCopy.Template(tree, parents, self, body ::: bridges) else tree diff --git a/src/library/scala/AnyVal.scala b/src/library/scala/AnyVal.scala index fb36d61c57..ed32fb7302 100644 --- a/src/library/scala/AnyVal.scala +++ b/src/library/scala/AnyVal.scala @@ -25,7 +25,7 @@ package scala * The ''integer types'' include the subrange types as well as [[scala.Int]] and [[scala.Long]]. * The ''floating point types'' are [[scala.Float]] and [[scala.Double]]. */ -trait AnyVal { +trait AnyVal extends NotNull { // disabled for now to make the standard build go through. // Once we have a new strap we can uncomment this and delete the AnyVal_getClass entry in Definitions. // def getClass(): Class[_ <: AnyVal] = ??? diff --git a/src/library/scala/NotNull.scala b/src/library/scala/NotNull.scala index d47d47a83e..f90b95c789 100644 --- a/src/library/scala/NotNull.scala +++ b/src/library/scala/NotNull.scala @@ -6,8 +6,6 @@ ** |/ ** \* */ - - package scala /** diff --git a/test/files/neg/anyval-children-2.check b/test/files/neg/anyval-children-2.check new file mode 100644 index 0000000000..cb327faeeb --- /dev/null +++ b/test/files/neg/anyval-children-2.check @@ -0,0 +1,4 @@ +anyval-children-2.scala:1: error: Only @inline classes (not traits) are allowed to extend AnyVal +@inline trait NotOkDingus1 extends AnyVal // fail + ^ +one error found diff --git a/test/files/neg/anyval-children-2.scala b/test/files/neg/anyval-children-2.scala new file mode 100644 index 0000000000..4034eb22dd --- /dev/null +++ b/test/files/neg/anyval-children-2.scala @@ -0,0 +1 @@ +@inline trait NotOkDingus1 extends AnyVal // fail diff --git a/test/files/neg/anyval-children.check b/test/files/neg/anyval-children.check new file mode 100644 index 0000000000..cbb5a2b1d1 --- /dev/null +++ b/test/files/neg/anyval-children.check @@ -0,0 +1,26 @@ +anyval-children.scala:7: error: illegal inheritance; superclass Bippy + is not a subclass of the superclass Object + of the mixin trait ScalaObject +class NotOkBippy1 extends Bippy // fail + ^ +anyval-children.scala:9: error: illegal inheritance; superclass Bippy + is not a subclass of the superclass Object + of the mixin trait Immutable +class NotOkBippy2 extends Bippy with Immutable //fail + ^ +anyval-children.scala:9: error: illegal inheritance; superclass Bippy + is not a subclass of the superclass Object + of the mixin trait ScalaObject +class NotOkBippy2 extends Bippy with Immutable //fail + ^ +anyval-children.scala:11: error: illegal inheritance; superclass Bippy + is not a subclass of the superclass Object + of the mixin trait Immutable +@inline class NotOkBippy3 extends Bippy with Immutable //fail + ^ +anyval-children.scala:11: error: illegal inheritance; superclass Bippy + is not a subclass of the superclass Object + of the mixin trait ScalaObject +@inline class NotOkBippy3 extends Bippy with Immutable //fail + ^ +5 errors found diff --git a/test/files/neg/anyval-children.scala b/test/files/neg/anyval-children.scala new file mode 100644 index 0000000000..5a6109f786 --- /dev/null +++ b/test/files/neg/anyval-children.scala @@ -0,0 +1,14 @@ +class Bippy extends AnyVal // fail + +@inline class NotOkDingus2 extends Immutable with AnyVal // fail + +@inline object NotOkDingus3 extends AnyVal // fail + +class NotOkBippy1 extends Bippy // fail + +class NotOkBippy2 extends Bippy with Immutable //fail + +@inline class NotOkBippy3 extends Bippy with Immutable //fail + + +@inline class OkBippy extends AnyVal // ok diff --git a/test/files/pos/anyval-children.scala b/test/files/pos/anyval-children.scala index 7a2eda8b3f..4ef10a094f 100644 --- a/test/files/pos/anyval-children.scala +++ b/test/files/pos/anyval-children.scala @@ -1 +1 @@ -class Bippy extends AnyVal
\ No newline at end of file +@inline class Bippy extends AnyVal
\ No newline at end of file |