Skip to content

Commit

Permalink
Merge pull request scala#1356 from paulp/pullreq-1342
Browse files Browse the repository at this point in the history
Pullreq 1342
  • Loading branch information
jsuereth committed Sep 20, 2012
2 parents 45c0b24 + beb08c2 commit 9ec19f3
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 23 deletions.
32 changes: 22 additions & 10 deletions src/compiler/scala/tools/nsc/typechecker/Typers.scala
Expand Up @@ -1987,32 +1987,44 @@ trait Typers extends Modes with Adaptations with Tags {
* - the self-type of the refinement
* - a type member of the refinement
* - an abstract type declared outside of the refinement.
* - an instance of a value class
* Furthermore, the result type may not be a value class either
*/
def checkMethodStructuralCompatible(meth: Symbol): Unit = {
def fail(msg: String) = unit.error(meth.pos, msg)
def checkMethodStructuralCompatible(ddef: DefDef): Unit = {
val meth = ddef.symbol
def fail(pos: Position, msg: String) = unit.error(pos, msg)
val tp: Type = meth.tpe match {
case mt @ MethodType(_, _) => mt
case NullaryMethodType(restpe) => restpe // TODO_NMT: drop NullaryMethodType from resultType?
case PolyType(_, restpe) => restpe
case _ => NoType
}
def failStruct(what: String) =
fail(s"Parameter type in structural refinement may not refer to $what")
for (paramType <- tp.paramTypes) {
def nthParamPos(n: Int) = ddef.vparamss match {
case xs :: _ if xs.length > n => xs(n).pos
case _ => meth.pos
}
def failStruct(pos: Position, what: String, where: String = "Parameter") =
fail(pos, s"$where type in structural refinement may not refer to $what")

foreachWithIndex(tp.paramTypes) { (paramType, idx) =>
val sym = paramType.typeSymbol
def paramPos = nthParamPos(idx)

if (sym.isAbstractType) {
if (!sym.hasTransOwner(meth.owner))
failStruct("an abstract type defined outside that refinement")
failStruct(paramPos, "an abstract type defined outside that refinement")
else if (!sym.hasTransOwner(meth))
failStruct("a type member of that refinement")
failStruct(paramPos, "a type member of that refinement")
}
if (sym.isDerivedValueClass)
failStruct("a user-defined value class")
failStruct(paramPos, "a user-defined value class")
if (paramType.isInstanceOf[ThisType] && sym == meth.owner)
failStruct("the type of that refinement (self type)")
failStruct(paramPos, "the type of that refinement (self type)")
}
if (tp.resultType.typeSymbol.isDerivedValueClass)
failStruct(ddef.tpt.pos, "a user-defined value class", where = "Result")
}

def typedUseCase(useCase: UseCase) {
def stringParser(str: String): syntaxAnalyzer.Parser = {
val file = new BatchSourceFile(context.unit.source.file, str) {
Expand Down Expand Up @@ -2129,7 +2141,7 @@ trait Typers extends Modes with Adaptations with Tags {
}
}
if (meth.isStructuralRefinementMember)
checkMethodStructuralCompatible(meth)
checkMethodStructuralCompatible(ddef)

if (meth.isImplicit && !meth.isSynthetic) meth.info.paramss match {
case List(param) :: _ if !param.isImplicit =>
Expand Down
18 changes: 9 additions & 9 deletions test/files/neg/structural.check
@@ -1,28 +1,28 @@
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: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 }
^
^
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 }) = ()
^
^
9 errors found
2 changes: 1 addition & 1 deletion test/files/neg/t0565.check
@@ -1,4 +1,4 @@
t0565.scala:8: error: Parameter type in structural refinement may not refer to a type member of that refinement
def z (w : T) : T } =
^
^
one error found
2 changes: 1 addition & 1 deletion test/files/neg/t2144.check
@@ -1,4 +1,4 @@
t2144.scala:2: error: Parameter type in structural refinement may not refer to an abstract type defined outside that refinement
def foo[A](a: A) = new { def bar(x: A): A = x }
^
^
one error found
7 changes: 5 additions & 2 deletions test/files/neg/t6336.check
@@ -1,4 +1,7 @@
t6336.scala:3: error: Parameter type in structural refinement may not refer to a user-defined value class
val a = new { def y[T](x: X[T]) = x.i }
^
one error found
^
t6336.scala:4: error: Result type in structural refinement may not refer to a user-defined value class
val b = new { def y[T](x: T): X[T] = new X(2) }
^
two errors found
1 change: 1 addition & 0 deletions test/files/neg/t6336.scala
@@ -1,6 +1,7 @@
object D {
def main(args: Array[String]) {
val a = new { def y[T](x: X[T]) = x.i }
val b = new { def y[T](x: T): X[T] = new X(2) }
val x = new X(3)
val t = a.y(x)
println(t)
Expand Down

0 comments on commit 9ec19f3

Please sign in to comment.