@@ -25,57 +25,46 @@ object VarianceChecker {
2525 * Note: this is achieved by a mechanism separate from checking class type parameters.
2626 * Question: Can the two mechanisms be combined in one?
2727 */
28- def checkLambda (tree : tpd.LambdaTypeTree )(implicit ctx : Context ): Unit = {
29- def checkType (tl : HKTypeLambda ): Unit = {
30- val checkOK = new TypeAccumulator [Boolean ] {
31- def paramVarianceSign (tref : TypeParamRef ) =
32- tl.typeParams(tref.paramNum).paramVarianceSign
33- def error (tref : TypeParamRef ) = {
34- val paramName = tl.paramNames(tref.paramNum).toTermName
35- val v = paramVarianceSign(tref)
36- val paramVarianceStr = if (v == 0 ) " contra" else " co"
37- val occursStr = variance match {
38- case - 1 => " contra"
39- case 0 => " in"
40- case 1 => " co"
28+ def checkLambda (tree : tpd.LambdaTypeTree , bounds : TypeBounds )(implicit ctx : Context ): Unit =
29+ def checkType (tpe : Type ): Unit = tpe match
30+ case tl : HKTypeLambda if tl.isVariantLambda =>
31+ val checkOK = new TypeAccumulator [Boolean ] {
32+ def paramVarianceSign (tref : TypeParamRef ) =
33+ tl.typeParams(tref.paramNum).paramVarianceSign
34+ def error (tref : TypeParamRef ) = {
35+ val paramName = tl.paramNames(tref.paramNum).toTermName
36+ val v = paramVarianceSign(tref)
37+ val paramVarianceStr = if (v < 0 ) " contra" else " co"
38+ val occursStr = variance match {
39+ case - 1 => " contra"
40+ case 0 => " in"
41+ case 1 => " co"
42+ }
43+ val pos = tree.tparams
44+ .find(_.name.toTermName == paramName)
45+ .map(_.sourcePos)
46+ .getOrElse(tree.sourcePos)
47+ ctx.error(em " ${paramVarianceStr}variant type parameter $paramName occurs in ${occursStr}variant position in ${tl.resType}" , pos)
4148 }
42- val pos = tree.tparams
43- .find(_.name.toTermName == paramName)
44- .map(_.sourcePos)
45- .getOrElse(tree.sourcePos)
46- ctx.error(em " ${paramVarianceStr}variant type parameter $paramName occurs in ${occursStr}variant position in ${tl.resType}" , pos)
47- }
48- def apply (x : Boolean , t : Type ) = x && {
49- t match {
50- case tref : TypeParamRef if tref.binder `eq` tl =>
51- val v = paramVarianceSign(tref)
52- varianceConforms(variance, v) || { error(tref); false }
53- case AnnotatedType (_, annot) if annot.symbol == defn.UncheckedVarianceAnnot =>
54- x
55- case _ =>
56- foldOver(x, t)
49+ def apply (x : Boolean , t : Type ) = x && {
50+ t match {
51+ case tref : TypeParamRef if tref.binder `eq` tl =>
52+ val v = paramVarianceSign(tref)
53+ varianceConforms(variance, v) || { error(tref); false }
54+ case AnnotatedType (_, annot) if annot.symbol == defn.UncheckedVarianceAnnot =>
55+ x
56+ case _ =>
57+ foldOver(x, t)
58+ }
5759 }
5860 }
59- }
60- checkOK.apply( true , tl.resType)
61- }
61+ checkOK( true , tl.resType)
62+ case _ =>
63+ end checkType
6264
63- (tree.tpe: @ unchecked) match {
64- case tl : HKTypeLambda =>
65- checkType(tl)
66- // The type of a LambdaTypeTree can be a TypeBounds, see the documentation
67- // of `LambdaTypeTree`.
68- case TypeBounds (lo, hi : HKTypeLambda ) =>
69- // Can't assume that the lower bound is a type lambda, it could also be
70- // a reference to `Nothing`.
71- lo match {
72- case lo : HKTypeLambda =>
73- checkType(lo)
74- case _ =>
75- }
76- checkType(hi)
77- }
78- }
65+ checkType(bounds.lo)
66+ checkType(bounds.hi)
67+ end checkLambda
7968}
8069
8170class VarianceChecker ()(implicit ctx : Context ) {
0 commit comments