pub fn variance(self : Type, va : Var) -> Variance {
letrec go = (ty : Type, polarity : Bool) => match ty {
TyVar(v) if v == va => if polarity { Covariant } else { Contravariant }
TyVar(_) | TyTop | TyBot => Constant
TyFun(_, params, ret) => {
let param_variance = params
.map(p => go(p, !polarity))
.fold(init=Constant, combine_variance)
combine_variance(param_variance, go(ret, polarity))
}
}
and combine_variance = (v1 : Variance, v2 : Variance) => match (v1, v2) {
(Constant, v) | (v, Constant) => v
(Covariant, Covariant) | (Contravariant, Contravariant) => v1
(Covariant, Contravariant) | (Contravariant, Covariant) => Invariant
(Invariant, _) | (_, Invariant) => Invariant
}
go(self, true)
}