fix: type-var comparison bug

This commit is contained in:
Shunsuke Shibayama 2024-11-08 13:14:28 +09:00
parent 5bbb421b7f
commit b84bd19237
2 changed files with 66 additions and 29 deletions

View file

@ -482,7 +482,7 @@ impl Context {
// ?T(:> Int, <: Eq) :> ?U(:> Nat, <: Eq) // ?T(:> Int, <: Eq) :> ?U(:> Nat, <: Eq)
(FreeVar(lfv), FreeVar(rfv)) => match (lfv.get_subsup(), rfv.get_subsup()) { (FreeVar(lfv), FreeVar(rfv)) => match (lfv.get_subsup(), rfv.get_subsup()) {
(Some((l_sub, l_supe)), Some((r_sub, _))) => { (Some((l_sub, l_supe)), Some((r_sub, _))) => {
self.related(&l_sub, &r_sub) && self.supertype_of(&l_supe, &r_sub) self.supertype_of(&l_supe, &r_sub) && self.related(&l_sub, &r_sub)
} }
(Some((l_sub, _)), None) if &l_sub == rhs => true, (Some((l_sub, _)), None) if &l_sub == rhs => true,
(None, Some((_, r_sup))) if lhs == &r_sup => true, (None, Some((_, r_sup))) if lhs == &r_sup => true,

View file

@ -177,10 +177,25 @@ impl<'c> Substituter<'c> {
qt: &Type, qt: &Type,
st: &Type, st: &Type,
) -> EvalResult<Option<Self>> { ) -> EvalResult<Option<Self>> {
let qtps = qt.typarams(); let mut qtps = qt.typarams();
let mut stps = st.typarams(); let mut stps = st.typarams();
// Or, And are commutative, choose fitting order // Or, And are commutative, choose fitting order
if qt.qual_name() == st.qual_name() && (st.qual_name() == "Or" || st.qual_name() == "And") { if qt.qual_name() == st.qual_name() {
if st.is_union_type() || st.is_intersection_type() {
let mut q_indices = vec![];
let mut s_indices = vec![];
for (i, qtp) in qtps.iter().enumerate() {
if let Some(j) = stps.iter().position(|stp| stp == qtp) {
q_indices.push(i);
s_indices.push(j);
}
}
for q_index in q_indices {
qtps[q_index] = TyParam::Failure;
}
for s_index in s_indices {
stps[s_index] = TyParam::Failure;
}
// REVIEW: correct condition? // REVIEW: correct condition?
if qt != st if qt != st
&& ctx.covariant_supertype_of_tp(&qtps[0], &stps[1]) && ctx.covariant_supertype_of_tp(&qtps[0], &stps[1])
@ -188,7 +203,8 @@ impl<'c> Substituter<'c> {
{ {
stps.swap(0, 1); stps.swap(0, 1);
} }
} else if qt.qual_name() != st.qual_name() || qtps.len() != stps.len() { }
} else {
// e.g. qt: Iterable(T), st: Vec(<: Iterable(Int)) // e.g. qt: Iterable(T), st: Vec(<: Iterable(Int))
if let Some(st_sups) = ctx.get_super_types(st) { if let Some(st_sups) = ctx.get_super_types(st) {
for sup in st_sups.skip(1) { for sup in st_sups.skip(1) {
@ -198,11 +214,15 @@ impl<'c> Substituter<'c> {
for (sup_tp, stp) in sup_tps.into_iter().zip(stps.into_iter()) { for (sup_tp, stp) in sup_tps.into_iter().zip(stps.into_iter()) {
let _ = child.substitute_typaram(sup_tp, stp); let _ = child.substitute_typaram(sup_tp, stp);
} }
if st == &sup {
return Ok(Some(child));
} else {
return Self::substitute_typarams(ctx, qt, &sup) return Self::substitute_typarams(ctx, qt, &sup)
.map(|opt_subs| opt_subs.map(|sub| sub.with_child(child))); .map(|opt_subs| opt_subs.map(|sub| sub.with_child(child)));
} }
} }
} }
}
if let Some(inner) = st.ref_inner().or_else(|| st.ref_mut_inner()) { if let Some(inner) = st.ref_inner().or_else(|| st.ref_mut_inner()) {
return Self::substitute_typarams(ctx, qt, &inner); return Self::substitute_typarams(ctx, qt, &inner);
} else if let Some(sub) = st.get_sub() { } else if let Some(sub) = st.get_sub() {
@ -231,9 +251,33 @@ impl<'c> Substituter<'c> {
qt: &Type, qt: &Type,
st: &Type, st: &Type,
) -> EvalResult<Option<Self>> { ) -> EvalResult<Option<Self>> {
let qtps = qt.typarams(); let mut qtps = qt.typarams();
let stps = st.typarams(); let mut stps = st.typarams();
if qt.qual_name() != st.qual_name() || qtps.len() != stps.len() { if qt.qual_name() == st.qual_name() {
if st.is_union_type() || st.is_intersection_type() {
let mut q_indices = vec![];
let mut s_indices = vec![];
for (i, qtp) in qtps.iter().enumerate() {
if let Some(j) = stps.iter().position(|stp| stp == qtp) {
q_indices.push(i);
s_indices.push(j);
}
}
for q_index in q_indices {
qtps[q_index] = TyParam::Failure;
}
for s_index in s_indices {
stps[s_index] = TyParam::Failure;
}
// REVIEW: correct condition?
if qt != st
&& ctx.covariant_supertype_of_tp(&qtps[0], &stps[1])
&& ctx.covariant_supertype_of_tp(&qtps[1], &stps[0])
{
stps.swap(0, 1);
}
}
} else {
// e.g. qt: Iterable(T), st: Vec(<: Iterable(Int)) // e.g. qt: Iterable(T), st: Vec(<: Iterable(Int))
if let Some(st_sups) = ctx.get_super_types(st) { if let Some(st_sups) = ctx.get_super_types(st) {
for sup in st_sups.skip(1) { for sup in st_sups.skip(1) {
@ -243,11 +287,15 @@ impl<'c> Substituter<'c> {
for (sup_tp, stp) in sup_tps.into_iter().zip(stps.into_iter()) { for (sup_tp, stp) in sup_tps.into_iter().zip(stps.into_iter()) {
let _ = child.overwrite_typaram(sup_tp, stp); let _ = child.overwrite_typaram(sup_tp, stp);
} }
if st == &sup {
return Ok(Some(child));
} else {
return Self::overwrite_typarams(ctx, qt, &sup) return Self::overwrite_typarams(ctx, qt, &sup)
.map(|opt_subs| opt_subs.map(|sub| sub.with_child(child))); .map(|opt_subs| opt_subs.map(|sub| sub.with_child(child)));
} }
} }
} }
}
if let Some(inner) = st.ref_inner().or_else(|| st.ref_mut_inner()) { if let Some(inner) = st.ref_inner().or_else(|| st.ref_mut_inner()) {
return Self::overwrite_typarams(ctx, qt, &inner); return Self::overwrite_typarams(ctx, qt, &inner);
} else if let Some(sub) = st.get_sub() { } else if let Some(sub) = st.get_sub() {
@ -2058,18 +2106,7 @@ impl Context {
TyParam::erased(t) TyParam::erased(t)
} }
}, },
TyParam::Value(val) => { TyParam::Value(val) => TyParam::Value(val),
match val
.clone()
.try_map_t(&mut |t| self.eval_t_params(t, self.level, &()))
{
Ok(val) => TyParam::Value(val),
Err((_t, es)) => {
errs.extend(es);
TyParam::Value(val)
}
}
}
TyParam::ProjCall { obj, attr, args } => { TyParam::ProjCall { obj, attr, args } => {
match self.eval_proj_call(*obj, attr, args, &()) { match self.eval_proj_call(*obj, attr, args, &()) {
Ok(tp) => tp, Ok(tp) => tp,