summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala9
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Variances.scala14
-rw-r--r--test/files/run/t1500.check3
-rw-r--r--test/files/run/t1500.scala44
-rw-r--r--test/files/run/t1501.check3
-rw-r--r--test/files/run/t1501.scala55
6 files changed, 127 insertions, 1 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index 0cb94b899f..81a4258b06 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -1903,6 +1903,15 @@ A type's typeSymbol should never be inspected directly.
}
}
+ // ** Replace formal type parameter symbols with actual type arguments. * /
+ override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]) = {
+ val attributes1 = attributes.map(info => AnnotationInfo(info.atp.instantiateTypeParams(
+ formals, actuals), info.args, info.assocs))
+ val underlying1 = underlying.instantiateTypeParams(formals, actuals)
+ if ((attributes1 eq attributes) && (underlying1 eq underlying)) this
+ else AnnotatedType(attributes1, underlying1, selfsym)
+ }
+
/** Return the base type sequence of tp, dropping the annotations, unless the base type sequence of tp
* is precisely tp itself. */
override def baseTypeSeq: BaseTypeSeq = {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Variances.scala b/src/compiler/scala/tools/nsc/typechecker/Variances.scala
index b5efa7035d..e0cbc99fa0 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Variances.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Variances.scala
@@ -64,6 +64,18 @@ trait Variances {
v
}
+ /** Compute variance of type parameter `tparam' in all type annotations `attribs'. */
+ def varianceInAttribs(attribs: List[AnnotationInfo])(tparam: Symbol): Int = {
+ (VARIANCES /: attribs) ((v, attrib) => v & varianceInAttrib(attrib)(tparam))
+ }
+
+ /** Compute variance of type parameter `tparam' in type annotation `attrib'. */
+ def varianceInAttrib(attrib: AnnotationInfo)(tparam: Symbol): Int = {
+ varianceInType(attrib.atp)(tparam)
+ }
+
+
+
/** Compute variance of type parameter <code>tparam</code> in type <code>tp</code>. */
def varianceInType(tp: Type)(tparam: Symbol): Int = tp match {
case ErrorType | WildcardType | NoType | NoPrefix | ThisType(_) | ConstantType(_) =>
@@ -84,6 +96,6 @@ trait Variances {
case ExistentialType(tparams, restpe) =>
varianceInSyms(tparams)(tparam) & varianceInType(restpe)(tparam)
case AnnotatedType(attribs, tp, _) =>
- varianceInType(tp)(tparam)
+ varianceInAttribs(attribs)(tparam) & varianceInType(tp)(tparam)
}
}
diff --git a/test/files/run/t1500.check b/test/files/run/t1500.check
new file mode 100644
index 0000000000..b4e94e95ee
--- /dev/null
+++ b/test/files/run/t1500.check
@@ -0,0 +1,3 @@
+defined class posingAs
+resolve: [A,B](A @posingAs[B])B
+x: Any = 7
diff --git a/test/files/run/t1500.scala b/test/files/run/t1500.scala
new file mode 100644
index 0000000000..a2f4192130
--- /dev/null
+++ b/test/files/run/t1500.scala
@@ -0,0 +1,44 @@
+import scala.tools.nsc._
+
+object Test {
+
+ /**
+ * Type inference overlooks constraints posed by type parameters in annotations on types.
+ */
+
+ val testCode = <code>
+
+ class posingAs[A] extends TypeConstraint
+
+ def resolve[A,B](x: A @posingAs[B]): B = x.asInstanceOf[B]
+
+ val x = resolve(7: @posingAs[Any])
+
+ </code>.text
+
+ def main(args: Array[String]) = {
+
+ val tool = new Interpreter(new Settings())
+ val global = tool.compiler
+
+ import global._
+ import definitions._
+
+ object checker extends AnnotationChecker {
+
+ /** Check annotations to decide whether tpe1 <:< tpe2 */
+ def annotationsConform(tpe1: Type, tpe2: Type): Boolean = {
+
+ tpe1.attributes.forall(a1 => tpe2.attributes.forall(a2 => a1.atp <:< a2.atp))
+
+ }
+ }
+
+ global.addAnnotationChecker(checker)
+
+ tool.interpret(testCode)
+
+ }
+
+}
+
diff --git a/test/files/run/t1501.check b/test/files/run/t1501.check
new file mode 100644
index 0000000000..7ec1495292
--- /dev/null
+++ b/test/files/run/t1501.check
@@ -0,0 +1,3 @@
+defined class xyz
+loopWhile: [T](=> Boolean)(=> Unit @xyz[T])Unit @xyz[T]
+test: ()Unit @xyz[Int]
diff --git a/test/files/run/t1501.scala b/test/files/run/t1501.scala
new file mode 100644
index 0000000000..07190a3b2c
--- /dev/null
+++ b/test/files/run/t1501.scala
@@ -0,0 +1,55 @@
+import scala.tools.nsc._
+
+object Test {
+
+ /**
+ * ...
+ */
+
+ val testCode = <code>
+
+ class xyz[A] extends TypeConstraint
+
+ def loopWhile[T](cond: =>Boolean)(body: =>(Unit @xyz[T])): Unit @ xyz[T] = {{
+ if (cond) {{
+ body
+ loopWhile[T](cond)(body)
+ }}
+ }}
+
+ def test() = {{
+ var x = 7
+ loopWhile(x != 0) {{
+ x = x - 1
+ (): @xyz[Int]
+ }}
+ }}
+
+ </code>.text
+
+ def main(args: Array[String]) = {
+
+ val tool = new Interpreter(new Settings())
+ val global = tool.compiler
+
+ import global._
+ import definitions._
+
+ object checker extends AnnotationChecker {
+
+ /** Check annotations to decide whether tpe1 <:< tpe2 */
+ def annotationsConform(tpe1: Type, tpe2: Type): Boolean = {
+
+ tpe1.attributes.forall(a1 => tpe2.attributes.forall(a2 => a1.atp <:< a2.atp))
+
+ }
+ }
+
+ global.addAnnotationChecker(checker)
+
+ tool.interpret(testCode)
+
+ }
+
+}
+