summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/reflect/internal/Definitions.scala8
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala13
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala23
-rw-r--r--src/library/scala/AnyVal.scala2
-rw-r--r--src/library/scala/NotNull.scala2
-rw-r--r--test/files/neg/anyval-children-2.check4
-rw-r--r--test/files/neg/anyval-children-2.scala1
-rw-r--r--test/files/neg/anyval-children.check26
-rw-r--r--test/files/neg/anyval-children.scala14
-rw-r--r--test/files/pos/anyval-children.scala2
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