package scala.tools.nsc
package typechecker
import symtab.Flags.{ VarianceFlags => VARIANCES, _ }
trait Variances {
val global: Global
import global._
private def flip(v: Int): Int = {
if (v == COVARIANT) CONTRAVARIANT
else if (v == CONTRAVARIANT) COVARIANT
else v
}
private def cut(v: Int): Int =
if (v == VARIANCES) v else 0
def varianceInSyms(syms: List[Symbol])(tparam: Symbol): Int =
(VARIANCES /: syms) ((v, sym) => v & varianceInSym(sym)(tparam))
def varianceInSym(sym: Symbol)(tparam: Symbol): Int =
if (sym.isAliasType) cut(varianceInType(sym.info)(tparam))
else varianceInType(sym.info)(tparam)
def varianceInTypes(tps: List[Type])(tparam: Symbol): Int =
(VARIANCES /: tps) ((v, tp) => v & varianceInType(tp)(tparam))
def varianceInArgs(tps: List[Type], tparams1: List[Symbol])(tparam: Symbol): Int = {
var v: Int = VARIANCES;
for ((tp, tparam1) <- tps zip tparams1) {
val v1 = varianceInType(tp)(tparam)
v = v & (if (tparam1.isCovariant) v1
else if (tparam1.isContravariant) flip(v1)
else cut(v1))
}
v
}
def varianceInAttribs(annots: List[AnnotationInfo])(tparam: Symbol): Int = {
(VARIANCES /: annots) ((v, annot) => v & varianceInAttrib(annot)(tparam))
}
def varianceInAttrib(annot: AnnotationInfo)(tparam: Symbol): Int = {
varianceInType(annot.atp)(tparam)
}
def varianceInType(tp: Type)(tparam: Symbol): Int = tp match {
case ErrorType | WildcardType | NoType | NoPrefix | ThisType(_) | ConstantType(_) =>
VARIANCES
case SingleType(pre, sym) =>
varianceInType(pre)(tparam)
case TypeRef(pre, sym, args) =>
if (sym == tparam) COVARIANT
else varianceInType(pre)(tparam) & varianceInArgs(args, sym.typeParams)(tparam)
case TypeBounds(lo, hi) =>
flip(varianceInType(lo)(tparam)) & varianceInType(hi)(tparam)
case RefinedType(parents, defs) =>
varianceInTypes(parents)(tparam) & varianceInSyms(defs.toList)(tparam)
case MethodType(params, restpe) =>
flip(varianceInSyms(params)(tparam)) & varianceInType(restpe)(tparam)
case NullaryMethodType(restpe) =>
varianceInType(restpe)(tparam)
case PolyType(tparams, restpe) =>
flip(varianceInSyms(tparams)(tparam)) & varianceInType(restpe)(tparam)
case ExistentialType(tparams, restpe) =>
varianceInSyms(tparams)(tparam) & varianceInType(restpe)(tparam)
case AnnotatedType(annots, tp, _) =>
varianceInAttribs(annots)(tparam) & varianceInType(tp)(tparam)
}
}