Skip to content

Commit

Permalink
fix: type-var generalization bug
Browse files Browse the repository at this point in the history
  • Loading branch information
mtshiba committed Dec 16, 2023
1 parent a10d9e8 commit 03a45de
Showing 1 changed file with 60 additions and 18 deletions.
78 changes: 60 additions & 18 deletions crates/erg_compiler/context/generalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,9 +360,8 @@ impl Generalizer {

pub struct Dereferencer<'c, 'q, 'l, L: Locational> {
ctx: &'c Context,
variance: Variance,
coerce: bool,
stash: Variance,
variance_stack: Vec<Variance>,
qnames: &'q Set<Str>,
loc: &'l L,
}
Expand All @@ -377,9 +376,8 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
) -> Self {
Self {
ctx,
variance,
coerce,
stash: Variance::Invariant,
variance_stack: vec![Invariant, variance],
qnames,
loc,
}
Expand All @@ -390,12 +388,15 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
}

fn push_variance(&mut self, variance: Variance) {
self.stash = self.variance;
self.variance = variance; // self.variance * variance;
self.variance_stack.push(variance);
}

fn pop_variance(&mut self) {
self.variance = self.stash;
self.variance_stack.pop();
}

fn current_variance(&self) -> Variance {
*self.variance_stack.last().unwrap()
}

pub(crate) fn deref_tp(&mut self, tp: TyParam) -> TyCheckResult<TyParam> {
Expand Down Expand Up @@ -655,29 +656,51 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
let variances = ctx.type_params_variance();
for (param, variance) in params.iter_mut().zip(variances.into_iter()) {
self.push_variance(variance);
*param = self.deref_tp(mem::take(param))?;
*param = self.deref_tp(mem::take(param)).map_err(|e| {
self.pop_variance();
e
})?;
self.pop_variance();
}
Ok(Type::Poly { name, params })
}
Type::Subr(mut subr) => {
for param in subr.non_default_params.iter_mut() {
self.push_variance(Contravariant);
*param.typ_mut() = self.deref_tyvar(mem::take(param.typ_mut()))?;
*param.typ_mut() =
self.deref_tyvar(mem::take(param.typ_mut())).map_err(|e| {
self.pop_variance();
e
})?;
self.pop_variance();
}
if let Some(var_args) = &mut subr.var_params {
self.push_variance(Contravariant);
*var_args.typ_mut() = self.deref_tyvar(mem::take(var_args.typ_mut()))?;
*var_args.typ_mut() =
self.deref_tyvar(mem::take(var_args.typ_mut()))
.map_err(|e| {
self.pop_variance();
e
})?;
self.pop_variance();
}
for d_param in subr.default_params.iter_mut() {
self.push_variance(Contravariant);
*d_param.typ_mut() = self.deref_tyvar(mem::take(d_param.typ_mut()))?;
*d_param.typ_mut() =
self.deref_tyvar(mem::take(d_param.typ_mut()))
.map_err(|e| {
self.pop_variance();
e
})?;
self.pop_variance();
}
self.push_variance(Covariant);
subr.return_t = Box::new(self.deref_tyvar(mem::take(&mut subr.return_t))?);
*subr.return_t = self
.deref_tyvar(mem::take(&mut subr.return_t))
.map_err(|e| {
self.pop_variance();
e
})?;
self.pop_variance();
Ok(Type::Subr(subr))
}
Expand Down Expand Up @@ -832,7 +855,7 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
if sub_t == super_t {
Ok(sub_t)
} else if is_subtype {
match self.variance {
match self.current_variance() {
// ?T(<: Sup) --> Sup (Sup != Obj), because completion will not work if Never is selected.
// ?T(:> Never, <: Obj) --> Never
// ?T(:> Never, <: Int) --> Never..Int == Int
Expand Down Expand Up @@ -888,28 +911,47 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
let essential_qnames = subr.essential_qnames();
let mut _self = Dereferencer::new(
self.ctx,
self.variance,
self.current_variance(),
self.coerce,
&essential_qnames,
self.loc,
);
for param in subr.non_default_params.iter_mut() {
_self.push_variance(Contravariant);
*param.typ_mut() = _self.deref_tyvar(mem::take(param.typ_mut()))?;
*param.typ_mut() = _self.deref_tyvar(mem::take(param.typ_mut())).map_err(|e| {
_self.pop_variance();
e
})?;
_self.pop_variance();
}
if let Some(var_args) = &mut subr.var_params {
_self.push_variance(Contravariant);
*var_args.typ_mut() = _self.deref_tyvar(mem::take(var_args.typ_mut()))?;
*var_args.typ_mut() =
_self
.deref_tyvar(mem::take(var_args.typ_mut()))
.map_err(|e| {
_self.pop_variance();
e
})?;
_self.pop_variance();
}
for d_param in subr.default_params.iter_mut() {
_self.push_variance(Contravariant);
*d_param.typ_mut() = _self.deref_tyvar(mem::take(d_param.typ_mut()))?;
*d_param.typ_mut() = _self
.deref_tyvar(mem::take(d_param.typ_mut()))
.map_err(|e| {
_self.pop_variance();
e
})?;
_self.pop_variance();
}
_self.push_variance(Covariant);
subr.return_t = Box::new(_self.deref_tyvar(mem::take(&mut subr.return_t))?);
*subr.return_t = _self
.deref_tyvar(mem::take(&mut subr.return_t))
.map_err(|e| {
_self.pop_variance();
e
})?;
_self.pop_variance();
let subr = Type::Subr(subr);
if subr.has_qvar() {
Expand Down

0 comments on commit 03a45de

Please sign in to comment.