summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala6
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala16
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala68
-rw-r--r--test/files/neg/structural.check44
-rw-r--r--test/files/neg/structural.scala55
5 files changed, 135 insertions, 54 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index 25f418bc19..3b9ffa4f58 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -599,6 +599,12 @@ trait Symbols {
isClass && (isAnonymousClass || isRefinementClass || isLocal ||
!owner.isPackageClass && owner.isLocalClass)
+ /** Is this class or type defined as a structural refinement type?
+ */
+ final def isStructuralRefinement: Boolean =
+ (isClass || isType || isModule) && info.normalize/*.underlying*/.isStructuralRefinement
+
+
/** Is this symbol a member of class `clazz'
*/
def isMemberOf(clazz: Symbol) =
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index e155f18489..676f19205a 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -262,6 +262,9 @@ trait Types {
/** Is this type guaranteed not to have `null' as a value? */
def isNotNull: Boolean = false
+ /** Is this type a structural refinement type (it 'refines' members that have not been inherited) */
+ def isStructuralRefinement: Boolean = false
+
/** Does this depend on an enclosing method parameter? */
def isDependent: Boolean = IsDependentCollector.collect(this)
@@ -1232,6 +1235,10 @@ trait Types {
override def narrow: Type = typeSymbol.thisType
override def isNotNull: Boolean = parents exists (_.isNotNull)
+ override def isStructuralRefinement: Boolean =
+ (typeSymbol.isRefinementClass || typeSymbol.isAnonymousClass) &&
+ (decls.toList exists { entry => !entry.isConstructor && entry.allOverriddenSymbols.isEmpty })
+
// override def isNullable: Boolean =
// parents forall (p => p.isNullable && !p.typeSymbol.isAbstractType);
@@ -1729,7 +1736,14 @@ A type's typeSymbol should never be inspected directly.
else if (sym.isModuleClass)
objectPrefix + str
else if (sym.isAnonymousClass && sym.isInitialized && !settings.debug.value)
- thisInfo.parents.mkString("", " with ", "{ ... }")
+ thisInfo.parents.mkString(" with ") + {
+ if (sym.isStructuralRefinement)
+ ((decls.toList filter { entry =>
+ !entry.isConstructor && entry.allOverriddenSymbols.isEmpty && !entry.hasFlag(PRIVATE)
+ }) map { entry => entry.defString }).mkString("{", "; ", "}")
+ else
+ ""
+ }
else if (sym.isRefinementClass && sym.isInitialized)
thisInfo.toString
else str
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 389e26f273..619f5324be 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1573,11 +1573,28 @@ trait Typers { self: Analyzer =>
}
}
- private def checkStructuralCondition(refinement: Symbol, vparam: ValDef) {
- val tp = vparam.symbol.tpe
- if (tp.typeSymbol.isAbstractType && !(tp.typeSymbol.hasTransOwner(refinement)))
- error(vparam.tpt.pos,"Parameter type in structural refinement may not refer to abstract type defined outside that same refinement")
- }
+ /** Check if a method is defined in such a way that it can be called.
+ * A method cannot be called if it is a non-private member of a structural type
+ * and if its parameter's types are not one of
+ * - this.type
+ * - a type member of the structural type
+ * - an abstract type declared outside of the structural type. */
+ def checkMethodStructuralCompatible(meth: Symbol): Unit =
+ if (meth.owner.isStructuralRefinement && meth.allOverriddenSymbols.isEmpty && (!meth.hasFlag(PRIVATE) && meth.privateWithin == NoSymbol)) {
+ val tp: Type = meth.tpe match {
+ case mt: MethodType => mt
+ case pt: PolyType => pt.resultType
+ case _ => NoType
+ }
+ for (paramType <- tp.paramTypes) {
+ if (paramType.typeSymbol.isAbstractType && !(paramType.typeSymbol.hasTransOwner(meth.owner)))
+ unit.error(meth.pos,"Parameter type in structural refinement may not refer to an abstract type defined outside that refinement")
+ else if (paramType.typeSymbol.isAbstractType && !(paramType.typeSymbol.hasTransOwner(meth)))
+ unit.error(meth.pos,"Parameter type in structural refinement may not refer to a type member of that refinement")
+ else if (paramType.isInstanceOf[ThisType] && paramType.typeSymbol == meth.owner)
+ unit.error(meth.pos,"Parameter type in structural refinement may not refer to the type of that refinement (self type)")
+ }
+ }
/** does given name name an identifier visible at this point?
*
@@ -1697,24 +1714,20 @@ trait Typers { self: Analyzer =>
} else {
transformedOrTyped(ddef.rhs, tpt1.tpe)
}
+
+ checkMethodStructuralCompatible(meth)
+
if (meth.isPrimaryConstructor && meth.isClassConstructor &&
phase.id <= currentRun.typerPhase.id && !reporter.hasErrors)
computeParamAliases(meth.owner, vparamss1, rhs1)
if (tpt1.tpe.typeSymbol != NothingClass && !context.returnsSeen) rhs1 = checkDead(rhs1)
- // If only refinement owned methods are checked, invalid code can result; see ticket #2144.
- def requiresStructuralCheck = meth.allOverriddenSymbols.isEmpty && (
- meth.owner.isRefinementClass ||
- (!meth.isConstructor && !meth.isSetter && meth.owner.isAnonymousClass)
- )
- if (requiresStructuralCheck)
- for (vparam <- ddef.vparamss.flatten)
- checkStructuralCondition(meth.owner, vparam)
-
if (phase.id <= currentRun.typerPhase.id && meth.owner.isClass &&
meth.paramss.exists(ps => ps.exists(_.hasFlag(DEFAULTPARAM)) && isRepeatedParamType(ps.last.tpe)))
error(meth.pos, "a parameter section with a `*'-parameter is not allowed to have default arguments")
+ checkMethodStructuralCompatible(meth)
+
treeCopy.DefDef(ddef, typedMods, ddef.name, tparams1, vparamss1, tpt1, rhs1) setType NoType
}
@@ -1770,6 +1783,33 @@ trait Typers { self: Analyzer =>
if (settings.YwarnShadow.value) checkShadowings(stat)
enterLabelDef(stat)
}
+ if (phaseId(currentPeriod) <= currentRun.typerPhase.id) {
+ block match {
+ case block @ Block(List(classDef @ ClassDef(_, _, _, _)), newInst @ Apply(Select(New(_), _), _)) =>
+ // The block is an anonymous class definitions/instantiation pair
+ // -> members that are hidden by the type of the block are made private
+ val visibleMembers = pt match {
+ case WildcardType => classDef.symbol.info.decls.toList
+ case BoundedWildcardType(TypeBounds(lo, hi)) => lo.members
+ case _ => pt.members
+ }
+ for (member <- classDef.symbol.info.decls.toList
+ if member.isTerm && !member.isConstructor &&
+ member.allOverriddenSymbols.isEmpty &&
+ (!member.hasFlag(PRIVATE) && member.privateWithin == NoSymbol) &&
+ !(visibleMembers exists { visible =>
+ visible.name == member.name &&
+ member.tpe <:< visible.tpe.substThis(visible.owner, ThisType(classDef.symbol))
+ })
+ ) {
+ member.resetFlag(PROTECTED)
+ member.resetFlag(LOCAL)
+ member.setFlag(PRIVATE)
+ member.privateWithin = NoSymbol
+ }
+ case _ =>
+ }
+ }
val stats1 = typedStats(block.stats, context.owner)
val expr1 = typed(block.expr, mode & ~(FUNmode | QUALmode), pt)
val block1 = treeCopy.Block(block, stats1, expr1)
diff --git a/test/files/neg/structural.check b/test/files/neg/structural.check
index cc2b5c5920..100b989a2f 100644
--- a/test/files/neg/structural.check
+++ b/test/files/neg/structural.check
@@ -1,19 +1,31 @@
-structural.scala:3: error: illegal dependent method type
- def f(x: { type D; def m: D }) = x.m
- ^
+structural.scala:47: error: Parameter type in structural refinement may not refer to the type of that refinement (self type)
+ val s1 = new { def f(p: this.type): Unit = () }
+ ^
structural.scala:19: error: illegal dependent method type
- def f9[C <: AnyRef](x: AnyRef{ type D <: AnyRef; def m[E >: Null <: AnyRef](x: AnyRef): D }) = x.m[Tata](new AnyRef) //suceed
+ def f9[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: Object): D }) = x.m[Tata](null) //fail
^
-structural.scala:10: error: Parameter type in structural refinement may not refer to abstract type defined outside that same refinement
- def f1[C <: AnyRef](x: AnyRef{ type D <: AnyRef; def m[E >: Null <: AnyRef](x: A): AnyRef; val x: A }) = x.m[Tata](x.x) //fail
- ^
-structural.scala:11: error: Parameter type in structural refinement may not refer to abstract type defined outside that same refinement
- def f2[C <: AnyRef](x: AnyRef{ type D <: AnyRef; def m[E >: Null <: AnyRef](x: B): AnyRef; val x: B }) = x.m[Tata](x.x) //fail
- ^
-structural.scala:12: error: Parameter type in structural refinement may not refer to abstract type defined outside that same refinement
- def f3[C <: AnyRef](x: AnyRef{ type D <: AnyRef; def m[E >: Null <: AnyRef](x: C): AnyRef; val x: C }) = x.m[Tata](x.x) //fail
- ^
-structural.scala:42: error: Parameter type in structural refinement may not refer to abstract type defined outside that same refinement
+structural.scala:10: error: Parameter type in structural refinement may not refer to an abstract type defined outside that refinement
+ def f1[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: A): Object; val x: A }) = x.m[Tata](x.x) //fail
+ ^
+structural.scala:11: error: Parameter type in structural refinement may not refer to an abstract type defined outside that refinement
+ def f2[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: B): Object; val x: B }) = x.m[Tata](x.x) //fail
+ ^
+structural.scala:12: error: Parameter type in structural refinement may not refer to an abstract type defined outside that refinement
+ def f3[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: C): Object; val x: C }) = x.m[Tata](x.x) //fail
+ ^
+structural.scala:13: error: Parameter type in structural refinement may not refer to a type member of that refinement
+ def f4[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: D): Object; val x: D }) = x.m[Tata](x.x) //fail
+ ^
+structural.scala:42: error: Parameter type in structural refinement may not refer to an abstract type defined outside that refinement
type Summable[T] = { def +(v : T) : T }
- ^
-6 errors found
+ ^
+structural.scala:46: error: Parameter type in structural refinement may not refer to the type of that refinement (self type)
+ type S1 = { def f(p: this.type): Unit }
+ ^
+structural.scala:49: error: Parameter type in structural refinement may not refer to a type member of that refinement
+ type S2 = { type T; def f(p: T): Unit }
+ ^
+structural.scala:52: error: Parameter type in structural refinement may not refer to an abstract type defined outside that refinement
+ def s3[U >: Null <: Object](p: { def f(p: U): Unit; def u: U }) = ()
+ ^
+10 errors found
diff --git a/test/files/neg/structural.scala b/test/files/neg/structural.scala
index dd8817d902..181a32654e 100644
--- a/test/files/neg/structural.scala
+++ b/test/files/neg/structural.scala
@@ -1,23 +1,23 @@
object Test extends Application {
- def f(x: { type D; def m: D }) = x.m
+ def f(x: { type D; def m: D }): Null = null
class Tata
- abstract class Toto[A <: AnyRef] {
- type B <: AnyRef
+ abstract class Toto[A <: Object] {
+ type B <: Object
- def f1[C <: AnyRef](x: AnyRef{ type D <: AnyRef; def m[E >: Null <: AnyRef](x: A): AnyRef; val x: A }) = x.m[Tata](x.x) //fail
- def f2[C <: AnyRef](x: AnyRef{ type D <: AnyRef; def m[E >: Null <: AnyRef](x: B): AnyRef; val x: B }) = x.m[Tata](x.x) //fail
- def f3[C <: AnyRef](x: AnyRef{ type D <: AnyRef; def m[E >: Null <: AnyRef](x: C): AnyRef; val x: C }) = x.m[Tata](x.x) //fail
- def f4[C <: AnyRef](x: AnyRef{ type D <: AnyRef; def m[E >: Null <: AnyRef](x: D): AnyRef; val x: D }) = x.m[Tata](x.x) //suceed
- def f5[C <: AnyRef](x: AnyRef{ type D <: AnyRef; def m[E >: Null <: AnyRef](x: E): AnyRef; val x: Tata }) = x.m[Tata](x.x) //suceed
+ def f1[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: A): Object; val x: A }) = x.m[Tata](x.x) //fail
+ def f2[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: B): Object; val x: B }) = x.m[Tata](x.x) //fail
+ def f3[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: C): Object; val x: C }) = x.m[Tata](x.x) //fail
+ def f4[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: D): Object; val x: D }) = x.m[Tata](x.x) //fail
+ def f5[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: E): Object; val x: Tata }) = x.m[Tata](x.x) //suceed
- def f6[C <: AnyRef](x: AnyRef{ type D <: AnyRef; def m[E >: Null <: AnyRef](x: AnyRef): A }) = x.m[Tata](new AnyRef) //suceed
- def f7[C <: AnyRef](x: AnyRef{ type D <: AnyRef; def m[E >: Null <: AnyRef](x: AnyRef): B }) = x.m[Tata](new AnyRef) //suceed
- def f8[C <: AnyRef](x: AnyRef{ type D <: AnyRef; def m[E >: Null <: AnyRef](x: AnyRef): C }) = x.m[Tata](new AnyRef) //suceed
- def f9[C <: AnyRef](x: AnyRef{ type D <: AnyRef; def m[E >: Null <: AnyRef](x: AnyRef): D }) = x.m[Tata](new AnyRef) //suceed
- def f0[C <: AnyRef](x: AnyRef{ type D <: AnyRef; def m[E >: Null <: AnyRef](x: AnyRef): E }) = x.m[Tata](new AnyRef) //suceed
+ def f6[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: Object): A }) = x.m[Tata](null) //suceed
+ def f7[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: Object): B }) = x.m[Tata](null) //suceed
+ def f8[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: Object): C }) = x.m[Tata](null) //suceed
+ def f9[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: Object): D }) = x.m[Tata](null) //fail
+ def f0[C <: Object](x: Object{ type D <: Object; def m[E >: Null <: Object](x: Object): E }) = x.m[Tata](null) //suceed
}
@@ -26,20 +26,29 @@ object Test extends Application {
type B = Tata
}
- toto.f1[Tata](new AnyRef{ type D = Tata; def m[E >: Null <: AnyRef](x: Tata): AnyRef = null; val x = tata })
- toto.f2[Tata](new AnyRef{ type D = Tata; def m[E >: Null <: AnyRef](x: Tata): AnyRef = null; val x = tata })
- toto.f3[Tata](new AnyRef{ type D = Tata; def m[E >: Null <: AnyRef](x: Tata): AnyRef = null; val x = tata })
- toto.f4[Tata](new AnyRef{ type D = Tata; def m[E >: Null <: AnyRef](x: D): AnyRef = null; val x = tata })
- toto.f5[Tata](new AnyRef{ type D = Tata; def m[E >: Null <: AnyRef](x: E): AnyRef = null; val x = tata })
+ //toto.f1[Tata](new Object{ type D = Tata; def m[E >: Null <: Object](x: Tata): Object = null; val x = tata })
+ //toto.f2[Tata](new Object{ type D = Tata; def m[E >: Null <: Object](x: Tata): Object = null; val x = tata })
+ //toto.f3[Tata](new Object{ type D = Tata; def m[E >: Null <: Object](x: Tata): Object = null; val x = tata })
+ //toto.f4[Tata](new Object{ type D = Tata; def m[E >: Null <: Object](x: D): Object = null; val x = tata })
+ toto.f5[Tata](new Object{ type D = Tata; def m[E >: Null <: Object](x: E): Object = null; val x: Test.Tata = tata })
- toto.f6[Tata](new AnyRef{ type D = Tata; def m[E >: Null <: AnyRef](x: AnyRef): Tata = null })
- toto.f7[Tata](new AnyRef{ type D = Tata; def m[E >: Null <: AnyRef](x: AnyRef): Tata = null })
- toto.f8[Tata](new AnyRef{ type D = Tata; def m[E >: Null <: AnyRef](x: AnyRef): Tata = null })
- toto.f9[Tata](new AnyRef{ type D = Tata; def m[E >: Null <: AnyRef](x: AnyRef): D = null })
- toto.f0[Tata](new AnyRef{ type D = Tata; def m[E >: Null <: AnyRef](x: AnyRef): E = null })
+ toto.f6[Tata](new Object{ type D = Tata; def m[E >: Null <: Object](x: Object): Tata = null })
+ toto.f7[Tata](new Object{ type D = Tata; def m[E >: Null <: Object](x: Object): Tata = null })
+ toto.f8[Tata](new Object{ type D = Tata; def m[E >: Null <: Object](x: Object): Tata = null })
+ //toto.f9[Tata](new Object{ type D = Tata; def m[E >: Null <: Object](x: Object): D = null })
+ toto.f0[Tata](new Object{ type D = Tata; def m[E >: Null <: Object](x: Object): E = null })
/* Bug #1246 */
type Summable[T] = { def +(v : T) : T }
def sum[T <: Summable[T]](xs : List[T]) = xs.reduceLeft[T](_ + _)
+ /* Bug #1004 & #967 */
+ type S1 = { def f(p: this.type): Unit }
+ val s1 = new { def f(p: this.type): Unit = () }
+
+ type S2 = { type T; def f(p: T): Unit }
+ //val s2: S2 = new { type T = A; def f(p: T): Unit = () }
+
+ def s3[U >: Null <: Object](p: { def f(p: U): Unit; def u: U }) = ()
+
}