Skip to content

Commit 586302a

Browse files
authored
Merge pull request scala#9808 from lrytz/t12481-2.12
2 parents 0c84876 + 5c58e43 commit 586302a

File tree

5 files changed

+71
-47
lines changed

5 files changed

+71
-47
lines changed

src/compiler/scala/tools/nsc/typechecker/RefChecks.scala

+46-47
Original file line numberDiff line numberDiff line change
@@ -1411,40 +1411,60 @@ abstract class RefChecks extends Transform {
14111411
false
14121412
}
14131413

1414-
private def checkTypeRef(tp: Type, tree: Tree, skipBounds: Boolean) = tp match {
1415-
case TypeRef(pre, sym, args) =>
1416-
tree match {
1417-
case tt: TypeTree if tt.original == null => // scala/bug#7783 don't warn about inferred types
1418-
// FIXME: reconcile this check with one in resetAttrs
1419-
case _ => checkUndesiredProperties(sym, tree.pos)
1414+
private object RefCheckTypeMap extends TypeMap {
1415+
object ExistentialToWildcard extends TypeMap {
1416+
override def apply(tpe: Type): Type =
1417+
if (tpe.typeSymbol.isExistential) WildcardType else mapOver(tpe)
1418+
}
1419+
1420+
private[this] var skipBounds = false
1421+
private[this] var tree: Tree = EmptyTree
1422+
1423+
def check(tpe: Type, tree: Tree): Type = {
1424+
this.tree = tree
1425+
try apply(tpe) finally {
1426+
skipBounds = false
1427+
this.tree = EmptyTree
14201428
}
1421-
if(sym.isJavaDefined)
1422-
sym.typeParams foreach (_.cookJavaRawInfo())
1423-
if (!tp.isHigherKinded && !skipBounds)
1424-
checkBounds(tree, pre, sym.owner, sym.typeParams, args)
1425-
case _ =>
1426-
}
1429+
}
14271430

1428-
private def checkTypeRefBounds(tp: Type, tree: Tree) = {
1429-
var skipBounds = false
1430-
tp match {
1431-
case AnnotatedType(ann :: Nil, underlying) if ann.symbol == UncheckedBoundsClass =>
1431+
// check all bounds, except those that are existential type parameters
1432+
// or those within typed annotated with @uncheckedBounds
1433+
override def apply(tpe: Type): Type = tpe match {
1434+
case tpe: AnnotatedType if tpe.hasAnnotation(UncheckedBoundsClass) =>
1435+
// scala/bug#7694 Allow code synthesizers to disable checking of bounds for TypeTrees based on inferred LUBs
1436+
// which might not conform to the constraints.
1437+
val savedSkipBounds = skipBounds
14321438
skipBounds = true
1433-
underlying
1439+
try mapOver(tpe).filterAnnotations(_.symbol != UncheckedBoundsClass)
1440+
finally skipBounds = savedSkipBounds
1441+
case tpe: TypeRef =>
1442+
checkTypeRef(ExistentialToWildcard(tpe))
1443+
mapOver(tpe)
1444+
case tpe =>
1445+
mapOver(tpe)
1446+
}
1447+
1448+
private def checkTypeRef(tpe: Type): Unit = tpe match {
14341449
case TypeRef(pre, sym, args) =>
1435-
if (!tp.isHigherKinded && !skipBounds)
1450+
tree match {
1451+
// scala/bug#7783 don't warn about inferred types
1452+
// FIXME: reconcile this check with one in resetAttrs
1453+
case tree: TypeTree if tree.original == null =>
1454+
case tree => checkUndesiredProperties(sym, tree.pos)
1455+
}
1456+
if (sym.isJavaDefined)
1457+
sym.typeParams.foreach(_.cookJavaRawInfo())
1458+
if (!tpe.isHigherKinded && !skipBounds)
14361459
checkBounds(tree, pre, sym.owner, sym.typeParams, args)
1437-
tp
14381460
case _ =>
1439-
tp
14401461
}
14411462
}
14421463

14431464
private def applyRefchecksToAnnotations(tree: Tree): Unit = {
14441465
def applyChecks(annots: List[AnnotationInfo]): List[AnnotationInfo] = if (annots.isEmpty) Nil else {
14451466
annots.foreach { ann =>
1446-
checkTypeRef(ann.tpe, tree, skipBounds = false)
1447-
checkTypeRefBounds(ann.tpe, tree)
1467+
RefCheckTypeMap.check(ann.tpe, tree)
14481468
}
14491469

14501470
val annotsBySymbol = new mutable.LinkedHashMap[Symbol, ListBuffer[AnnotationInfo]]()
@@ -1800,29 +1820,8 @@ abstract class RefChecks extends Transform {
18001820
}
18011821
}
18021822

1803-
val existentialParams = new ListBuffer[Symbol]
1804-
var skipBounds = false
1805-
// check all bounds, except those that are existential type parameters
1806-
// or those within typed annotated with @uncheckedBounds
1807-
if (!inPattern) tree.tpe foreach {
1808-
case tp @ ExistentialType(tparams, tpe) =>
1809-
existentialParams ++= tparams
1810-
case ann: AnnotatedType if ann.hasAnnotation(UncheckedBoundsClass) =>
1811-
// scala/bug#7694 Allow code synthesizers to disable checking of bounds for TypeTrees based on inferred LUBs
1812-
// which might not conform to the constraints.
1813-
skipBounds = true
1814-
case tp: TypeRef =>
1815-
val tpWithWildcards = deriveTypeWithWildcards(existentialParams.toList)(tp)
1816-
checkTypeRef(tpWithWildcards, tree, skipBounds)
1817-
case _ =>
1818-
}
1819-
if (skipBounds) {
1820-
tree.setType(tree.tpe.map {
1821-
_.filterAnnotations(_.symbol != UncheckedBoundsClass)
1822-
})
1823-
}
1824-
1825-
tree
1823+
if (inPattern) tree
1824+
else tree.setType(RefCheckTypeMap.check(tree.tpe, tree))
18261825

18271826
case TypeApply(fn, args) =>
18281827
checkBounds(tree, NoPrefix, NoSymbol, fn.tpe.typeParams, args map (_.tpe))
@@ -1857,8 +1856,8 @@ abstract class RefChecks extends Transform {
18571856
case x @ Select(_, _) =>
18581857
transformSelect(x)
18591858

1860-
case Literal(Constant(tp: Type)) =>
1861-
checkTypeRef(tp, tree, skipBounds = false)
1859+
case Literal(Constant(tpe: Type)) =>
1860+
RefCheckTypeMap.check(tpe, tree)
18621861
tree
18631862

18641863
case UnApply(fun, args) =>

test/files/neg/ref-checks.check

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
ref-checks.scala:8: error: type arguments [Int] do not conform to trait Chars's type parameter bounds [A <: CharSequence]
2+
@ann[Chars[Int]] val x = 42
3+
^
4+
ref-checks.scala:9: error: type arguments [Double] do not conform to trait Chars's type parameter bounds [A <: CharSequence]
5+
val y: Two[Chars[Long] @uncheckedBounds, Chars[Double]] = null
6+
^
7+
two errors found

test/files/neg/ref-checks.scala

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import scala.annotation.StaticAnnotation
2+
import scala.reflect.internal.annotations.uncheckedBounds
3+
4+
object Test {
5+
trait Chars[A <: CharSequence]
6+
trait Two[A, B]
7+
class ann[A] extends StaticAnnotation
8+
@ann[Chars[Int]] val x = 42
9+
val y: Two[Chars[Long] @uncheckedBounds, Chars[Double]] = null
10+
}

test/files/run/t12481.check

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Test$Universe[_ <: Any]
2+
Test$Universe[<?>]

test/files/run/t12481.scala

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
object Test extends App {
2+
trait Txn[T <: Txn[T]]
3+
trait Universe[T <: Txn[T]]
4+
println(implicitly[Manifest[Universe[_]]])
5+
println(implicitly[OptManifest[Universe[_]]])
6+
}

0 commit comments

Comments
 (0)