From 8c69f4da333f17290da26c3951fa9c8805014e47 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 18 Sep 2012 17:21:35 +0200 Subject: SI-6336 Now also catches return types As Mark's comments on SI-6336 shows, we also need to disallow value classes as return types of structural types. --- src/compiler/scala/tools/nsc/typechecker/Typers.scala | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 089245e124..6ecd7911fd 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1977,6 +1977,8 @@ 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) @@ -1986,8 +1988,8 @@ trait Typers extends Modes with Adaptations with Tags { case PolyType(_, restpe) => restpe case _ => NoType } - def failStruct(what: String) = - fail(s"Parameter type in structural refinement may not refer to $what") + def failStruct(what: String, where: String = "Parameter") = + fail(s"$where type in structural refinement may not refer to $what") for (paramType <- tp.paramTypes) { val sym = paramType.typeSymbol @@ -2002,7 +2004,10 @@ trait Typers extends Modes with Adaptations with Tags { if (paramType.isInstanceOf[ThisType] && sym == meth.owner) failStruct("the type of that refinement (self type)") } + if (tp.resultType.typeSymbol.isDerivedValueClass) + failStruct("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) { -- cgit v1.2.3 From beb08c206b24e00167a11ea13d1cd998b8e3b067 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Wed, 19 Sep 2012 10:22:22 -0700 Subject: Error message improvement for SI-6336. Position error messages about structural type members at the problematic parameter or type. --- .../scala/tools/nsc/typechecker/Typers.scala | 29 ++++++++++++++-------- test/files/neg/structural.check | 18 +++++++------- test/files/neg/t0565.check | 2 +- test/files/neg/t2144.check | 2 +- test/files/neg/t6336.check | 4 +-- 5 files changed, 31 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 6ecd7911fd..ac02b67463 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1980,32 +1980,39 @@ trait Typers extends Modes with Adaptations with Tags { * - 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, where: String = "Parameter") = - fail(s"$where 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("a user-defined value class", where = "Result") + failStruct(ddef.tpt.pos, "a user-defined value class", where = "Result") } def typedUseCase(useCase: UseCase) { @@ -2124,7 +2131,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 => diff --git a/test/files/neg/structural.check b/test/files/neg/structural.check index 6ef57db1b4..5b2f352a76 100644 --- a/test/files/neg/structural.check +++ b/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 diff --git a/test/files/neg/t0565.check b/test/files/neg/t0565.check index c5a64d0e53..98e61a2503 100644 --- a/test/files/neg/t0565.check +++ b/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 diff --git a/test/files/neg/t2144.check b/test/files/neg/t2144.check index 7239f4406e..670e188c2a 100644 --- a/test/files/neg/t2144.check +++ b/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 diff --git a/test/files/neg/t6336.check b/test/files/neg/t6336.check index c3ddf81f21..f70a5f70ab 100644 --- a/test/files/neg/t6336.check +++ b/test/files/neg/t6336.check @@ -1,7 +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 } - ^ + ^ 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 -- cgit v1.2.3