Variance Code [blog/lti-english/variance_code][edit]

pub fn Type::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)
}