mirror of
https://github.com/erg-lang/erg.git
synced 2025-07-23 21:18:19 +00:00
fix: sub-unification bugs
This commit is contained in:
parent
b318395a32
commit
0079aed860
10 changed files with 190 additions and 153 deletions
|
@ -1184,7 +1184,7 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Type::FreeVar(fv) = &lhs {
|
if let Some(fv) = lhs.as_free() {
|
||||||
let (sub, sup) = fv.get_subsup().unwrap();
|
let (sub, sup) = fv.get_subsup().unwrap();
|
||||||
if self.is_trait(&sup) && !self.trait_impl_exists(&sub, &sup) {
|
if self.is_trait(&sup) && !self.trait_impl_exists(&sub, &sup) {
|
||||||
// link to `Never` to prevent double errors from being reported
|
// link to `Never` to prevent double errors from being reported
|
||||||
|
|
|
@ -23,70 +23,69 @@ use Variance::*;
|
||||||
impl Context {
|
impl Context {
|
||||||
pub const TOP_LEVEL: usize = 1;
|
pub const TOP_LEVEL: usize = 1;
|
||||||
|
|
||||||
fn generalize_tp(&self, free: TyParam, variance: Variance, uninit: bool) -> TyParam {
|
fn generalize_tp(
|
||||||
|
&self,
|
||||||
|
free: TyParam,
|
||||||
|
variance: Variance,
|
||||||
|
qnames: &Set<Str>,
|
||||||
|
uninit: bool,
|
||||||
|
) -> TyParam {
|
||||||
match free {
|
match free {
|
||||||
TyParam::Type(t) => TyParam::t(self.generalize_t_inner(*t, variance, uninit)),
|
TyParam::Type(t) => TyParam::t(self.generalize_t_inner(*t, variance, qnames, uninit)),
|
||||||
TyParam::FreeVar(fv) if fv.is_generalized() => TyParam::FreeVar(fv),
|
TyParam::FreeVar(fv) if fv.is_generalized() => TyParam::FreeVar(fv),
|
||||||
TyParam::FreeVar(fv) if fv.is_linked() => {
|
TyParam::FreeVar(fv) if fv.is_linked() => {
|
||||||
self.generalize_tp(fv.crack().clone(), variance, uninit)
|
self.generalize_tp(fv.crack().clone(), variance, qnames, uninit)
|
||||||
/*let fv_mut = unsafe { fv.as_ptr().as_mut().unwrap() };
|
|
||||||
if let FreeKind::Linked(tp) = fv_mut {
|
|
||||||
*tp = self.generalize_tp(tp.clone(), variance, uninit);
|
|
||||||
} else {
|
|
||||||
assume_unreachable!()
|
|
||||||
}
|
|
||||||
TyParam::FreeVar(fv)*/
|
|
||||||
}
|
}
|
||||||
// TODO: Polymorphic generalization
|
// TODO: Polymorphic generalization
|
||||||
TyParam::FreeVar(fv) if fv.level() > Some(self.level) => {
|
TyParam::FreeVar(fv) if fv.level() > Some(self.level) => {
|
||||||
let constr = self.generalize_constraint(&fv, variance);
|
let constr = self.generalize_constraint(&fv, qnames, variance);
|
||||||
fv.update_constraint(constr, true);
|
fv.update_constraint(constr, true);
|
||||||
fv.generalize();
|
fv.generalize();
|
||||||
TyParam::FreeVar(fv)
|
TyParam::FreeVar(fv)
|
||||||
}
|
}
|
||||||
TyParam::Array(tps) => TyParam::Array(
|
TyParam::Array(tps) => TyParam::Array(
|
||||||
tps.into_iter()
|
tps.into_iter()
|
||||||
.map(|tp| self.generalize_tp(tp, variance, uninit))
|
.map(|tp| self.generalize_tp(tp, variance, qnames, uninit))
|
||||||
.collect(),
|
.collect(),
|
||||||
),
|
),
|
||||||
TyParam::Tuple(tps) => TyParam::Tuple(
|
TyParam::Tuple(tps) => TyParam::Tuple(
|
||||||
tps.into_iter()
|
tps.into_iter()
|
||||||
.map(|tp| self.generalize_tp(tp, variance, uninit))
|
.map(|tp| self.generalize_tp(tp, variance, qnames, uninit))
|
||||||
.collect(),
|
.collect(),
|
||||||
),
|
),
|
||||||
TyParam::Dict(tps) => TyParam::Dict(
|
TyParam::Dict(tps) => TyParam::Dict(
|
||||||
tps.into_iter()
|
tps.into_iter()
|
||||||
.map(|(k, v)| {
|
.map(|(k, v)| {
|
||||||
(
|
(
|
||||||
self.generalize_tp(k, variance, uninit),
|
self.generalize_tp(k, variance, qnames, uninit),
|
||||||
self.generalize_tp(v, variance, uninit),
|
self.generalize_tp(v, variance, qnames, uninit),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
),
|
),
|
||||||
TyParam::Record(rec) => TyParam::Record(
|
TyParam::Record(rec) => TyParam::Record(
|
||||||
rec.into_iter()
|
rec.into_iter()
|
||||||
.map(|(field, tp)| (field, self.generalize_tp(tp, variance, uninit)))
|
.map(|(field, tp)| (field, self.generalize_tp(tp, variance, qnames, uninit)))
|
||||||
.collect(),
|
.collect(),
|
||||||
),
|
),
|
||||||
TyParam::Lambda(lambda) => {
|
TyParam::Lambda(lambda) => {
|
||||||
let nd_params = lambda
|
let nd_params = lambda
|
||||||
.nd_params
|
.nd_params
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|pt| pt.map_type(|t| self.generalize_t_inner(t, variance, uninit)))
|
.map(|pt| pt.map_type(|t| self.generalize_t_inner(t, variance, qnames, uninit)))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let var_params = lambda
|
let var_params = lambda.var_params.map(|pt| {
|
||||||
.var_params
|
pt.map_type(|t| self.generalize_t_inner(t, variance, qnames, uninit))
|
||||||
.map(|pt| pt.map_type(|t| self.generalize_t_inner(t, variance, uninit)));
|
});
|
||||||
let d_params = lambda
|
let d_params = lambda
|
||||||
.d_params
|
.d_params
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|pt| pt.map_type(|t| self.generalize_t_inner(t, variance, uninit)))
|
.map(|pt| pt.map_type(|t| self.generalize_t_inner(t, variance, qnames, uninit)))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let body = lambda
|
let body = lambda
|
||||||
.body
|
.body
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|tp| self.generalize_tp(tp, variance, uninit))
|
.map(|tp| self.generalize_tp(tp, variance, qnames, uninit))
|
||||||
.collect();
|
.collect();
|
||||||
TyParam::Lambda(TyParamLambda::new(
|
TyParam::Lambda(TyParamLambda::new(
|
||||||
lambda.const_,
|
lambda.const_,
|
||||||
|
@ -98,24 +97,26 @@ impl Context {
|
||||||
}
|
}
|
||||||
TyParam::FreeVar(_) => free,
|
TyParam::FreeVar(_) => free,
|
||||||
TyParam::Proj { obj, attr } => {
|
TyParam::Proj { obj, attr } => {
|
||||||
let obj = self.generalize_tp(*obj, variance, uninit);
|
let obj = self.generalize_tp(*obj, variance, qnames, uninit);
|
||||||
TyParam::proj(obj, attr)
|
TyParam::proj(obj, attr)
|
||||||
}
|
}
|
||||||
TyParam::Erased(t) => TyParam::erased(self.generalize_t_inner(*t, variance, uninit)),
|
TyParam::Erased(t) => {
|
||||||
|
TyParam::erased(self.generalize_t_inner(*t, variance, qnames, uninit))
|
||||||
|
}
|
||||||
TyParam::App { name, args } => {
|
TyParam::App { name, args } => {
|
||||||
let args = args
|
let args = args
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|tp| self.generalize_tp(tp, variance, uninit))
|
.map(|tp| self.generalize_tp(tp, variance, qnames, uninit))
|
||||||
.collect();
|
.collect();
|
||||||
TyParam::App { name, args }
|
TyParam::App { name, args }
|
||||||
}
|
}
|
||||||
TyParam::BinOp { op, lhs, rhs } => {
|
TyParam::BinOp { op, lhs, rhs } => {
|
||||||
let lhs = self.generalize_tp(*lhs, variance, uninit);
|
let lhs = self.generalize_tp(*lhs, variance, qnames, uninit);
|
||||||
let rhs = self.generalize_tp(*rhs, variance, uninit);
|
let rhs = self.generalize_tp(*rhs, variance, qnames, uninit);
|
||||||
TyParam::bin(op, lhs, rhs)
|
TyParam::bin(op, lhs, rhs)
|
||||||
}
|
}
|
||||||
TyParam::UnaryOp { op, val } => {
|
TyParam::UnaryOp { op, val } => {
|
||||||
let val = self.generalize_tp(*val, variance, uninit);
|
let val = self.generalize_tp(*val, variance, qnames, uninit);
|
||||||
TyParam::unary(op, val)
|
TyParam::unary(op, val)
|
||||||
}
|
}
|
||||||
other if other.has_no_unbound_var() => other,
|
other if other.has_no_unbound_var() => other,
|
||||||
|
@ -126,7 +127,7 @@ impl Context {
|
||||||
/// Quantification occurs only once in function types.
|
/// Quantification occurs only once in function types.
|
||||||
/// Therefore, this method is called only once at the top level, and `generalize_t_inner` is called inside.
|
/// Therefore, this method is called only once at the top level, and `generalize_t_inner` is called inside.
|
||||||
pub(crate) fn generalize_t(&self, free_type: Type) -> Type {
|
pub(crate) fn generalize_t(&self, free_type: Type) -> Type {
|
||||||
let maybe_unbound_t = self.generalize_t_inner(free_type, Covariant, false);
|
let maybe_unbound_t = self.generalize_t_inner(free_type, Covariant, &set! {}, false);
|
||||||
if maybe_unbound_t.is_subr() && maybe_unbound_t.has_qvar() {
|
if maybe_unbound_t.is_subr() && maybe_unbound_t.has_qvar() {
|
||||||
maybe_unbound_t.quantify()
|
maybe_unbound_t.quantify()
|
||||||
} else {
|
} else {
|
||||||
|
@ -141,56 +142,64 @@ impl Context {
|
||||||
/// generalize_t(?T(<: Add(?T(<: Eq(?T(<: ...)))) -> ?T) == |'T <: Add('T)| 'T -> 'T
|
/// generalize_t(?T(<: Add(?T(<: Eq(?T(<: ...)))) -> ?T) == |'T <: Add('T)| 'T -> 'T
|
||||||
/// generalize_t(?T(<: TraitX) -> Int) == TraitX -> Int // 戻り値に現れないなら量化しない
|
/// generalize_t(?T(<: TraitX) -> Int) == TraitX -> Int // 戻り値に現れないなら量化しない
|
||||||
/// ```
|
/// ```
|
||||||
fn generalize_t_inner(&self, free_type: Type, variance: Variance, uninit: bool) -> Type {
|
fn generalize_t_inner(
|
||||||
|
&self,
|
||||||
|
free_type: Type,
|
||||||
|
variance: Variance,
|
||||||
|
qnames: &Set<Str>,
|
||||||
|
uninit: bool,
|
||||||
|
) -> Type {
|
||||||
match free_type {
|
match free_type {
|
||||||
FreeVar(fv) if fv.is_linked() => {
|
FreeVar(fv) if fv.is_linked() => {
|
||||||
self.generalize_t_inner(fv.crack().clone(), variance, uninit)
|
self.generalize_t_inner(fv.crack().clone(), variance, qnames, uninit)
|
||||||
/*let fv_mut = unsafe { fv.as_ptr().as_mut().unwrap() };
|
|
||||||
if let FreeKind::Linked(t) = fv_mut {
|
|
||||||
*t = self.generalize_t_inner(t.clone(), variance, uninit);
|
|
||||||
} else {
|
|
||||||
assume_unreachable!()
|
|
||||||
}
|
|
||||||
Type::FreeVar(fv)*/
|
|
||||||
}
|
}
|
||||||
FreeVar(fv) if fv.is_generalized() => Type::FreeVar(fv),
|
FreeVar(fv) if fv.is_generalized() => Type::FreeVar(fv),
|
||||||
// TODO: Polymorphic generalization
|
// TODO: Polymorphic generalization
|
||||||
FreeVar(fv) if fv.level().unwrap() > self.level => {
|
FreeVar(fv) if fv.level().unwrap() > self.level => {
|
||||||
if uninit {
|
if uninit {
|
||||||
// use crate::ty::free::GENERIC_LEVEL;
|
|
||||||
// return named_free_var(fv.unbound_name().unwrap(), GENERIC_LEVEL, Constraint::Uninited);
|
|
||||||
fv.generalize();
|
fv.generalize();
|
||||||
return Type::FreeVar(fv);
|
return Type::FreeVar(fv);
|
||||||
}
|
}
|
||||||
if let Some((l, r)) = fv.get_subsup() {
|
if let Some((sub, sup)) = fv.get_subsup() {
|
||||||
// |Int <: T <: Int| T -> T ==> Int -> Int
|
// |Int <: T <: Int| T -> T ==> Int -> Int
|
||||||
if l == r {
|
if sub == sup {
|
||||||
let t = self.generalize_t_inner(l, variance, uninit);
|
let t = self.generalize_t_inner(sub, variance, qnames, uninit);
|
||||||
fv.forced_link(&t);
|
fv.forced_link(&t);
|
||||||
FreeVar(fv)
|
FreeVar(fv)
|
||||||
} else if r != Obj && self.is_class(&r) && variance == Contravariant {
|
} else if sup != Obj
|
||||||
|
&& !qnames.contains(&fv.unbound_name().unwrap())
|
||||||
|
&& variance == Contravariant
|
||||||
|
{
|
||||||
// |T <: Bool| T -> Int ==> Bool -> Int
|
// |T <: Bool| T -> Int ==> Bool -> Int
|
||||||
self.generalize_t_inner(r, variance, uninit)
|
self.generalize_t_inner(sup, variance, qnames, uninit)
|
||||||
} else if l != Never && self.is_class(&l) && variance == Covariant {
|
} else if sub != Never
|
||||||
|
&& !qnames.contains(&fv.unbound_name().unwrap())
|
||||||
|
&& variance == Covariant
|
||||||
|
{
|
||||||
// |T :> Int| X -> T ==> X -> Int
|
// |T :> Int| X -> T ==> X -> Int
|
||||||
self.generalize_t_inner(l, variance, uninit)
|
self.generalize_t_inner(sub, variance, qnames, uninit)
|
||||||
} else {
|
} else {
|
||||||
fv.update_constraint(self.generalize_constraint(&fv, variance), true);
|
fv.update_constraint(
|
||||||
|
self.generalize_constraint(&fv, qnames, variance),
|
||||||
|
true,
|
||||||
|
);
|
||||||
fv.generalize();
|
fv.generalize();
|
||||||
Type::FreeVar(fv)
|
Type::FreeVar(fv)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// ?S(: Str) => 'S
|
// ?S(: Str) => 'S
|
||||||
fv.update_constraint(self.generalize_constraint(&fv, variance), true);
|
fv.update_constraint(self.generalize_constraint(&fv, qnames, variance), true);
|
||||||
fv.generalize();
|
fv.generalize();
|
||||||
Type::FreeVar(fv)
|
Type::FreeVar(fv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Subr(mut subr) => {
|
Subr(mut subr) => {
|
||||||
|
let qnames = subr.essential_qnames();
|
||||||
subr.non_default_params.iter_mut().for_each(|nd_param| {
|
subr.non_default_params.iter_mut().for_each(|nd_param| {
|
||||||
*nd_param.typ_mut() = self.generalize_t_inner(
|
*nd_param.typ_mut() = self.generalize_t_inner(
|
||||||
mem::take(nd_param.typ_mut()),
|
mem::take(nd_param.typ_mut()),
|
||||||
Contravariant,
|
Contravariant,
|
||||||
|
&qnames,
|
||||||
uninit,
|
uninit,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -198,6 +207,7 @@ impl Context {
|
||||||
*var_args.typ_mut() = self.generalize_t_inner(
|
*var_args.typ_mut() = self.generalize_t_inner(
|
||||||
mem::take(var_args.typ_mut()),
|
mem::take(var_args.typ_mut()),
|
||||||
Contravariant,
|
Contravariant,
|
||||||
|
&qnames,
|
||||||
uninit,
|
uninit,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -205,10 +215,11 @@ impl Context {
|
||||||
*d_param.typ_mut() = self.generalize_t_inner(
|
*d_param.typ_mut() = self.generalize_t_inner(
|
||||||
mem::take(d_param.typ_mut()),
|
mem::take(d_param.typ_mut()),
|
||||||
Contravariant,
|
Contravariant,
|
||||||
|
&qnames,
|
||||||
uninit,
|
uninit,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
let return_t = self.generalize_t_inner(*subr.return_t, Covariant, uninit);
|
let return_t = self.generalize_t_inner(*subr.return_t, Covariant, &qnames, uninit);
|
||||||
subr_t(
|
subr_t(
|
||||||
subr.kind,
|
subr.kind,
|
||||||
subr.non_default_params,
|
subr.non_default_params,
|
||||||
|
@ -220,30 +231,34 @@ impl Context {
|
||||||
Record(rec) => {
|
Record(rec) => {
|
||||||
let fields = rec
|
let fields = rec
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(name, t)| (name, self.generalize_t_inner(t, variance, uninit)))
|
.map(|(name, t)| (name, self.generalize_t_inner(t, variance, qnames, uninit)))
|
||||||
.collect();
|
.collect();
|
||||||
Type::Record(fields)
|
Type::Record(fields)
|
||||||
}
|
}
|
||||||
Callable { .. } => todo!(),
|
Callable { .. } => todo!(),
|
||||||
Ref(t) => ref_(self.generalize_t_inner(*t, variance, uninit)),
|
Ref(t) => ref_(self.generalize_t_inner(*t, variance, qnames, uninit)),
|
||||||
RefMut { before, after } => {
|
RefMut { before, after } => {
|
||||||
let after = after.map(|aft| self.generalize_t_inner(*aft, variance, uninit));
|
let after =
|
||||||
ref_mut(self.generalize_t_inner(*before, variance, uninit), after)
|
after.map(|aft| self.generalize_t_inner(*aft, variance, qnames, uninit));
|
||||||
|
ref_mut(
|
||||||
|
self.generalize_t_inner(*before, variance, qnames, uninit),
|
||||||
|
after,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Refinement(refine) => {
|
Refinement(refine) => {
|
||||||
let t = self.generalize_t_inner(*refine.t, variance, uninit);
|
let t = self.generalize_t_inner(*refine.t, variance, qnames, uninit);
|
||||||
let pred = self.generalize_pred(*refine.pred, variance, uninit);
|
let pred = self.generalize_pred(*refine.pred, variance, qnames, uninit);
|
||||||
refinement(refine.var, t, pred)
|
refinement(refine.var, t, pred)
|
||||||
}
|
}
|
||||||
Poly { name, mut params } => {
|
Poly { name, mut params } => {
|
||||||
let params = params
|
let params = params
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.map(|p| self.generalize_tp(mem::take(p), variance, uninit))
|
.map(|p| self.generalize_tp(mem::take(p), variance, qnames, uninit))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
poly(name, params)
|
poly(name, params)
|
||||||
}
|
}
|
||||||
Proj { lhs, rhs } => {
|
Proj { lhs, rhs } => {
|
||||||
let lhs = self.generalize_t_inner(*lhs, variance, uninit);
|
let lhs = self.generalize_t_inner(*lhs, variance, qnames, uninit);
|
||||||
proj(lhs, rhs)
|
proj(lhs, rhs)
|
||||||
}
|
}
|
||||||
ProjCall {
|
ProjCall {
|
||||||
|
@ -251,83 +266,94 @@ impl Context {
|
||||||
attr_name,
|
attr_name,
|
||||||
mut args,
|
mut args,
|
||||||
} => {
|
} => {
|
||||||
let lhs = self.generalize_tp(*lhs, variance, uninit);
|
let lhs = self.generalize_tp(*lhs, variance, qnames, uninit);
|
||||||
for arg in args.iter_mut() {
|
for arg in args.iter_mut() {
|
||||||
*arg = self.generalize_tp(mem::take(arg), variance, uninit);
|
*arg = self.generalize_tp(mem::take(arg), variance, qnames, uninit);
|
||||||
}
|
}
|
||||||
proj_call(lhs, attr_name, args)
|
proj_call(lhs, attr_name, args)
|
||||||
}
|
}
|
||||||
And(l, r) => {
|
And(l, r) => {
|
||||||
let l = self.generalize_t_inner(*l, variance, uninit);
|
let l = self.generalize_t_inner(*l, variance, qnames, uninit);
|
||||||
let r = self.generalize_t_inner(*r, variance, uninit);
|
let r = self.generalize_t_inner(*r, variance, qnames, uninit);
|
||||||
// not `self.intersection` because types are generalized
|
// not `self.intersection` because types are generalized
|
||||||
and(l, r)
|
and(l, r)
|
||||||
}
|
}
|
||||||
Or(l, r) => {
|
Or(l, r) => {
|
||||||
let l = self.generalize_t_inner(*l, variance, uninit);
|
let l = self.generalize_t_inner(*l, variance, qnames, uninit);
|
||||||
let r = self.generalize_t_inner(*r, variance, uninit);
|
let r = self.generalize_t_inner(*r, variance, qnames, uninit);
|
||||||
// not `self.union` because types are generalized
|
// not `self.union` because types are generalized
|
||||||
or(l, r)
|
or(l, r)
|
||||||
}
|
}
|
||||||
Not(l) => not(self.generalize_t_inner(*l, variance, uninit)),
|
Not(l) => not(self.generalize_t_inner(*l, variance, qnames, uninit)),
|
||||||
Structural(t) => self
|
Structural(t) => self
|
||||||
.generalize_t_inner(*t, variance, uninit)
|
.generalize_t_inner(*t, variance, qnames, uninit)
|
||||||
.structuralize(),
|
.structuralize(),
|
||||||
// REVIEW: その他何でもそのまま通していいのか?
|
// REVIEW: その他何でもそのまま通していいのか?
|
||||||
other => other,
|
other => other,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generalize_constraint<T: CanbeFree>(&self, fv: &Free<T>, variance: Variance) -> Constraint {
|
fn generalize_constraint<T: CanbeFree>(
|
||||||
|
&self,
|
||||||
|
fv: &Free<T>,
|
||||||
|
qnames: &Set<Str>,
|
||||||
|
variance: Variance,
|
||||||
|
) -> Constraint {
|
||||||
if let Some((sub, sup)) = fv.get_subsup() {
|
if let Some((sub, sup)) = fv.get_subsup() {
|
||||||
let sub = self.generalize_t_inner(sub, variance, true);
|
let sub = self.generalize_t_inner(sub, variance, qnames, true);
|
||||||
let sup = self.generalize_t_inner(sup, variance, true);
|
let sup = self.generalize_t_inner(sup, variance, qnames, true);
|
||||||
Constraint::new_sandwiched(sub, sup)
|
Constraint::new_sandwiched(sub, sup)
|
||||||
} else if let Some(ty) = fv.get_type() {
|
} else if let Some(ty) = fv.get_type() {
|
||||||
let t = self.generalize_t_inner(ty, variance, true);
|
let t = self.generalize_t_inner(ty, variance, qnames, true);
|
||||||
Constraint::new_type_of(t)
|
Constraint::new_type_of(t)
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generalize_pred(&self, pred: Predicate, variance: Variance, uninit: bool) -> Predicate {
|
fn generalize_pred(
|
||||||
|
&self,
|
||||||
|
pred: Predicate,
|
||||||
|
variance: Variance,
|
||||||
|
qnames: &Set<Str>,
|
||||||
|
uninit: bool,
|
||||||
|
) -> Predicate {
|
||||||
match pred {
|
match pred {
|
||||||
Predicate::Const(_) => pred,
|
Predicate::Const(_) => pred,
|
||||||
Predicate::Value(ValueObj::Type(mut typ)) => {
|
Predicate::Value(ValueObj::Type(mut typ)) => {
|
||||||
*typ.typ_mut() =
|
*typ.typ_mut() =
|
||||||
self.generalize_t_inner(mem::take(typ.typ_mut()), variance, uninit);
|
self.generalize_t_inner(mem::take(typ.typ_mut()), variance, qnames, uninit);
|
||||||
Predicate::Value(ValueObj::Type(typ))
|
Predicate::Value(ValueObj::Type(typ))
|
||||||
}
|
}
|
||||||
Predicate::Value(_) => pred,
|
Predicate::Value(_) => pred,
|
||||||
Predicate::Equal { lhs, rhs } => {
|
Predicate::Equal { lhs, rhs } => {
|
||||||
let rhs = self.generalize_tp(rhs, variance, uninit);
|
let rhs = self.generalize_tp(rhs, variance, qnames, uninit);
|
||||||
Predicate::eq(lhs, rhs)
|
Predicate::eq(lhs, rhs)
|
||||||
}
|
}
|
||||||
Predicate::GreaterEqual { lhs, rhs } => {
|
Predicate::GreaterEqual { lhs, rhs } => {
|
||||||
let rhs = self.generalize_tp(rhs, variance, uninit);
|
let rhs = self.generalize_tp(rhs, variance, qnames, uninit);
|
||||||
Predicate::ge(lhs, rhs)
|
Predicate::ge(lhs, rhs)
|
||||||
}
|
}
|
||||||
Predicate::LessEqual { lhs, rhs } => {
|
Predicate::LessEqual { lhs, rhs } => {
|
||||||
let rhs = self.generalize_tp(rhs, variance, uninit);
|
let rhs = self.generalize_tp(rhs, variance, qnames, uninit);
|
||||||
Predicate::le(lhs, rhs)
|
Predicate::le(lhs, rhs)
|
||||||
}
|
}
|
||||||
Predicate::NotEqual { lhs, rhs } => {
|
Predicate::NotEqual { lhs, rhs } => {
|
||||||
let rhs = self.generalize_tp(rhs, variance, uninit);
|
let rhs = self.generalize_tp(rhs, variance, qnames, uninit);
|
||||||
Predicate::ne(lhs, rhs)
|
Predicate::ne(lhs, rhs)
|
||||||
}
|
}
|
||||||
Predicate::And(lhs, rhs) => {
|
Predicate::And(lhs, rhs) => {
|
||||||
let lhs = self.generalize_pred(*lhs, variance, uninit);
|
let lhs = self.generalize_pred(*lhs, variance, qnames, uninit);
|
||||||
let rhs = self.generalize_pred(*rhs, variance, uninit);
|
let rhs = self.generalize_pred(*rhs, variance, qnames, uninit);
|
||||||
Predicate::and(lhs, rhs)
|
Predicate::and(lhs, rhs)
|
||||||
}
|
}
|
||||||
Predicate::Or(lhs, rhs) => {
|
Predicate::Or(lhs, rhs) => {
|
||||||
let lhs = self.generalize_pred(*lhs, variance, uninit);
|
let lhs = self.generalize_pred(*lhs, variance, qnames, uninit);
|
||||||
let rhs = self.generalize_pred(*rhs, variance, uninit);
|
let rhs = self.generalize_pred(*rhs, variance, qnames, uninit);
|
||||||
Predicate::or(lhs, rhs)
|
Predicate::or(lhs, rhs)
|
||||||
}
|
}
|
||||||
Predicate::Not(pred) => {
|
Predicate::Not(pred) => {
|
||||||
let pred = self.generalize_pred(*pred, variance, uninit);
|
let pred = self.generalize_pred(*pred, variance, qnames, uninit);
|
||||||
!pred
|
!pred
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ impl Context {
|
||||||
expected: &Type,
|
expected: &Type,
|
||||||
found: &Type,
|
found: &Type,
|
||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
let expected = if let Type::FreeVar(fv) = expected {
|
let expected = if let Some(fv) = expected.as_free() {
|
||||||
if fv.is_linked() {
|
if fv.is_linked() {
|
||||||
fv.crack().clone()
|
fv.crack().clone()
|
||||||
} else {
|
} else {
|
||||||
|
@ -191,7 +191,7 @@ impl Context {
|
||||||
pub(crate) fn get_no_candidate_hint(&self, proj: &Type) -> Option<String> {
|
pub(crate) fn get_no_candidate_hint(&self, proj: &Type) -> Option<String> {
|
||||||
match proj {
|
match proj {
|
||||||
Type::Proj { lhs, rhs: _ } => {
|
Type::Proj { lhs, rhs: _ } => {
|
||||||
if let Type::FreeVar(fv) = lhs.as_ref() {
|
if let Some(fv) = lhs.as_free() {
|
||||||
let (sub, sup) = fv.get_subsup()?;
|
let (sub, sup) = fv.get_subsup()?;
|
||||||
let (verb, preposition, sequence) = Self::get_verb_and_preposition(&sup)?;
|
let (verb, preposition, sequence) = Self::get_verb_and_preposition(&sup)?;
|
||||||
let sup = *option_enum_unwrap!(sup.typarams().get(0)?.clone(), TyParam::Type)?;
|
let sup = *option_enum_unwrap!(sup.typarams().get(0)?.clone(), TyParam::Type)?;
|
||||||
|
|
|
@ -563,7 +563,7 @@ impl Context {
|
||||||
// => ?T(<: Structural({ .aaa = ?U }))
|
// => ?T(<: Structural({ .aaa = ?U }))
|
||||||
if self.in_subr() && cfg!(feature = "py_compatible") {
|
if self.in_subr() && cfg!(feature = "py_compatible") {
|
||||||
let t = free_var(self.level, Constraint::new_type_of(Type));
|
let t = free_var(self.level, Constraint::new_type_of(Type));
|
||||||
if let Type::FreeVar(fv) = obj.ref_t() {
|
if let Some(fv) = obj.ref_t().as_free() {
|
||||||
if fv.get_sub().is_some() {
|
if fv.get_sub().is_some() {
|
||||||
let vis = self.instantiate_vis_modifier(&ident.vis).unwrap();
|
let vis = self.instantiate_vis_modifier(&ident.vis).unwrap();
|
||||||
let structural = Type::Record(
|
let structural = Type::Record(
|
||||||
|
@ -910,7 +910,7 @@ impl Context {
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let return_t = free_var(self.level, Constraint::new_type_of(Type));
|
let return_t = free_var(self.level, Constraint::new_type_of(Type));
|
||||||
let subr_t = fn_met(obj.t(), nd_params, None, d_params, return_t);
|
let subr_t = fn_met(obj.t(), nd_params, None, d_params, return_t);
|
||||||
if let Type::FreeVar(fv) = obj.ref_t() {
|
if let Some(fv) = obj.ref_t().as_free() {
|
||||||
if fv.get_sub().is_some() {
|
if fv.get_sub().is_some() {
|
||||||
let vis = self.instantiate_vis_modifier(&attr_name.vis).unwrap();
|
let vis = self.instantiate_vis_modifier(&attr_name.vis).unwrap();
|
||||||
let structural = Type::Record(
|
let structural = Type::Record(
|
||||||
|
|
|
@ -224,7 +224,7 @@ impl Context {
|
||||||
Ok(tp)
|
Ok(tp)
|
||||||
} else if let Some(t) = tmp_tv_cache.get_tyvar(&name) {
|
} else if let Some(t) = tmp_tv_cache.get_tyvar(&name) {
|
||||||
let t = t.clone();
|
let t = t.clone();
|
||||||
if let Type::FreeVar(fv) = &t {
|
if let Some(fv) = t.as_free() {
|
||||||
if fv
|
if fv
|
||||||
.constraint()
|
.constraint()
|
||||||
.map(|cons| cons.is_uninited())
|
.map(|cons| cons.is_uninited())
|
||||||
|
|
|
@ -307,6 +307,27 @@ impl Context {
|
||||||
Ok(vi)
|
Ok(vi)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn type_self_param(
|
||||||
|
&self,
|
||||||
|
pat: &ast::ParamPattern,
|
||||||
|
name: &VarName,
|
||||||
|
spec_t: &Type,
|
||||||
|
errs: &mut TyCheckErrors,
|
||||||
|
) {
|
||||||
|
if let Some(self_t) = self.rec_get_self_t() {
|
||||||
|
let self_t = match pat {
|
||||||
|
ast::ParamPattern::Ref(_) => ref_(self_t),
|
||||||
|
ast::ParamPattern::RefMut(_) => ref_mut(self_t, None),
|
||||||
|
_ => self_t,
|
||||||
|
};
|
||||||
|
if let Err(es) = self.sub_unify(spec_t, &self_t, name, Some(name.inspect())) {
|
||||||
|
errs.extend(es);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log!(err "self_t is None");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// TODO: sig should be immutable
|
/// TODO: sig should be immutable
|
||||||
/// 宣言が既にある場合、opt_decl_tに宣言の型を渡す
|
/// 宣言が既にある場合、opt_decl_tに宣言の型を渡す
|
||||||
fn assign_param(
|
fn assign_param(
|
||||||
|
@ -387,15 +408,7 @@ impl Context {
|
||||||
spec_t
|
spec_t
|
||||||
};
|
};
|
||||||
if &name.inspect()[..] == "self" {
|
if &name.inspect()[..] == "self" {
|
||||||
if let Some(self_t) = self.rec_get_self_t() {
|
self.type_self_param(&sig.raw.pat, name, &spec_t, &mut errs);
|
||||||
if let Err(es) =
|
|
||||||
self.sub_unify(&spec_t, &self_t, name, Some(name.inspect()))
|
|
||||||
{
|
|
||||||
errs.extend(es);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log!(err "self_t is None");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let def_id = DefId(get_hash(&(&self.name, name)));
|
let def_id = DefId(get_hash(&(&self.name, name)));
|
||||||
let kind = VarKind::parameter(def_id, is_var_params, default);
|
let kind = VarKind::parameter(def_id, is_var_params, default);
|
||||||
|
@ -446,15 +459,7 @@ impl Context {
|
||||||
Err(errs) => (Type::Failure, errs),
|
Err(errs) => (Type::Failure, errs),
|
||||||
};
|
};
|
||||||
if &name.inspect()[..] == "self" {
|
if &name.inspect()[..] == "self" {
|
||||||
if let Some(self_t) = self.rec_get_self_t() {
|
self.type_self_param(&sig.raw.pat, name, &spec_t, &mut errs);
|
||||||
if let Err(es) =
|
|
||||||
self.sub_unify(&spec_t, &ref_(self_t), name, Some(name.inspect()))
|
|
||||||
{
|
|
||||||
errs.extend(es);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log!(err "self_t is None");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let kind = VarKind::parameter(
|
let kind = VarKind::parameter(
|
||||||
DefId(get_hash(&(&self.name, name))),
|
DefId(get_hash(&(&self.name, name))),
|
||||||
|
@ -506,18 +511,7 @@ impl Context {
|
||||||
Err(errs) => (Type::Failure, errs),
|
Err(errs) => (Type::Failure, errs),
|
||||||
};
|
};
|
||||||
if &name.inspect()[..] == "self" {
|
if &name.inspect()[..] == "self" {
|
||||||
if let Some(self_t) = self.rec_get_self_t() {
|
self.type_self_param(&sig.raw.pat, name, &spec_t, &mut errs);
|
||||||
if let Err(es) = self.sub_unify(
|
|
||||||
&spec_t,
|
|
||||||
&ref_mut(self_t, None),
|
|
||||||
name,
|
|
||||||
Some(name.inspect()),
|
|
||||||
) {
|
|
||||||
errs.extend(es);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log!(err "self_t is None");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let kind = VarKind::parameter(
|
let kind = VarKind::parameter(
|
||||||
DefId(get_hash(&(&self.name, name))),
|
DefId(get_hash(&(&self.name, name))),
|
||||||
|
@ -862,7 +856,7 @@ impl Context {
|
||||||
let Some((_, vi)) = self.get_var_info(ident.inspect()) else {
|
let Some((_, vi)) = self.get_var_info(ident.inspect()) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if let Type::FreeVar(fv) = &vi.t {
|
if let Some(fv) = vi.t.as_free() {
|
||||||
fv.link(&typ);
|
fv.link(&typ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ impl Context {
|
||||||
/// occur(X -> ?T, ?T) ==> Error
|
/// occur(X -> ?T, ?T) ==> Error
|
||||||
/// occur(?T, ?T -> X) ==> Error
|
/// occur(?T, ?T -> X) ==> Error
|
||||||
/// occur(?T, Option(?T)) ==> Error
|
/// occur(?T, Option(?T)) ==> Error
|
||||||
/// occur(?T, ?T.Output) ==> Error
|
/// occur(?T, ?T.Output) ==> OK
|
||||||
pub(crate) fn occur(
|
pub(crate) fn occur(
|
||||||
&self,
|
&self,
|
||||||
maybe_sub: &Type,
|
maybe_sub: &Type,
|
||||||
|
@ -127,30 +127,6 @@ impl Context {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
(Type::Proj { lhs, .. }, rhs) => self.occur(lhs, rhs, loc),
|
|
||||||
(Type::ProjCall { lhs, args, .. }, rhs) => {
|
|
||||||
if let TyParam::Type(t) = lhs.as_ref() {
|
|
||||||
self.occur(t, rhs, loc)?;
|
|
||||||
}
|
|
||||||
for arg in args.iter() {
|
|
||||||
if let TyParam::Type(t) = arg {
|
|
||||||
self.occur(t, rhs, loc)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
(lhs, Type::Proj { lhs: rhs, .. }) => self.occur(lhs, rhs, loc),
|
|
||||||
(lhs, Type::ProjCall { lhs: rhs, args, .. }) => {
|
|
||||||
if let TyParam::Type(t) = rhs.as_ref() {
|
|
||||||
self.occur(lhs, t, loc)?;
|
|
||||||
}
|
|
||||||
for arg in args.iter() {
|
|
||||||
if let TyParam::Type(t) = arg {
|
|
||||||
self.occur(lhs, t, loc)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
(lhs, Type::Or(l, r)) | (lhs, Type::And(l, r)) => {
|
(lhs, Type::Or(l, r)) | (lhs, Type::And(l, r)) => {
|
||||||
self.occur(lhs, l, loc)?;
|
self.occur(lhs, l, loc)?;
|
||||||
self.occur(lhs, r, loc)
|
self.occur(lhs, r, loc)
|
||||||
|
@ -759,7 +735,6 @@ impl Context {
|
||||||
if sup.is_structural() {
|
if sup.is_structural() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
// REVIEW: correct?
|
|
||||||
if let Some(new_sup) = self.min(&sup, maybe_sup) {
|
if let Some(new_sup) = self.min(&sup, maybe_sup) {
|
||||||
let constr =
|
let constr =
|
||||||
Constraint::new_sandwiched(mem::take(&mut sub), new_sup.clone());
|
Constraint::new_sandwiched(mem::take(&mut sub), new_sup.clone());
|
||||||
|
@ -781,7 +756,6 @@ impl Context {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
(Type::FreeVar(_fv), _r) => todo!(),
|
|
||||||
(Type::Record(lrec), Type::Record(rrec)) => {
|
(Type::Record(lrec), Type::Record(rrec)) => {
|
||||||
for (k, l) in lrec.iter() {
|
for (k, l) in lrec.iter() {
|
||||||
if let Some(r) = rrec.get(k) {
|
if let Some(r) = rrec.get(k) {
|
||||||
|
@ -992,8 +966,18 @@ impl Context {
|
||||||
self.sub_unify(l, r, loc, param_name)
|
self.sub_unify(l, r, loc, param_name)
|
||||||
}
|
}
|
||||||
(_, Type::RefMut { before, .. }) => self.sub_unify(maybe_sub, before, loc, param_name),
|
(_, Type::RefMut { before, .. }) => self.sub_unify(maybe_sub, before, loc, param_name),
|
||||||
(Type::Proj { .. }, _) => todo!(),
|
(_, Type::Proj { lhs, rhs }) => {
|
||||||
(_, Type::Proj { .. }) => todo!(),
|
if let Ok(evaled) = self.eval_proj(*lhs.clone(), rhs.clone(), self.level, loc) {
|
||||||
|
self.sub_unify(maybe_sub, &evaled, loc, param_name)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
(Type::Proj { lhs, rhs }, _) => {
|
||||||
|
if let Ok(evaled) = self.eval_proj(*lhs.clone(), rhs.clone(), self.level, loc) {
|
||||||
|
self.sub_unify(&evaled, maybe_sup, loc, param_name)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
// TODO: Judgment for any number of preds
|
// TODO: Judgment for any number of preds
|
||||||
(Refinement(sub), Refinement(sup)) => {
|
(Refinement(sub), Refinement(sup)) => {
|
||||||
// {I: Int or Str | I == 0} <: {I: Int}
|
// {I: Int or Str | I == 0} <: {I: Int}
|
||||||
|
|
|
@ -1934,12 +1934,10 @@ impl ASTLowerer {
|
||||||
&self,
|
&self,
|
||||||
impl_trait: &Type,
|
impl_trait: &Type,
|
||||||
class: &Type,
|
class: &Type,
|
||||||
typ_ctx: (&Type, &Context),
|
(trait_type, trait_ctx): (&Type, &Context),
|
||||||
t_spec: &TypeSpecWithOp,
|
t_spec: &TypeSpecWithOp,
|
||||||
) -> (Set<&VarName>, CompileErrors) {
|
) -> (Set<&VarName>, CompileErrors) {
|
||||||
let mut errors = CompileErrors::empty();
|
let mut errors = CompileErrors::empty();
|
||||||
let trait_type = typ_ctx.0;
|
|
||||||
let trait_ctx = typ_ctx.1;
|
|
||||||
let mut unverified_names = self.module.context.locals.keys().collect::<Set<_>>();
|
let mut unverified_names = self.module.context.locals.keys().collect::<Set<_>>();
|
||||||
for (decl_name, decl_vi) in trait_ctx.decls.iter() {
|
for (decl_name, decl_vi) in trait_ctx.decls.iter() {
|
||||||
if let Some((name, vi)) = self.module.context.get_var_kv(decl_name.inspect()) {
|
if let Some((name, vi)) = self.module.context.get_var_kv(decl_name.inspect()) {
|
||||||
|
|
|
@ -587,6 +587,25 @@ impl<T> Free<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Free<Type> {
|
||||||
|
pub fn deep_clone(&self) -> Self {
|
||||||
|
Self::new_named_unbound(
|
||||||
|
self.unbound_name().unwrap(),
|
||||||
|
self.level().unwrap(),
|
||||||
|
self.constraint().unwrap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Free<TyParam> {
|
||||||
|
pub fn deep_clone(&self) -> Self {
|
||||||
|
Self::new_named_unbound(
|
||||||
|
self.unbound_name().unwrap(),
|
||||||
|
self.level().unwrap(),
|
||||||
|
self.constraint().unwrap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: StructuralEq + CanbeFree + Clone + Default> StructuralEq for Free<T> {
|
impl<T: StructuralEq + CanbeFree + Clone + Default> StructuralEq for Free<T> {
|
||||||
fn structural_eq(&self, other: &Self) -> bool {
|
fn structural_eq(&self, other: &Self) -> bool {
|
||||||
if let (Some((l, r)), Some((l2, r2))) = (self.get_subsup(), other.get_subsup()) {
|
if let (Some((l, r)), Some((l2, r2))) = (self.get_subsup(), other.get_subsup()) {
|
||||||
|
|
|
@ -990,7 +990,7 @@ impl LimitedDisplay for Type {
|
||||||
|
|
||||||
impl CanbeFree for Type {
|
impl CanbeFree for Type {
|
||||||
fn unbound_name(&self) -> Option<Str> {
|
fn unbound_name(&self) -> Option<Str> {
|
||||||
if let Type::FreeVar(fv) = self {
|
if let Some(fv) = self.as_free() {
|
||||||
fv.unbound_name()
|
fv.unbound_name()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -998,7 +998,7 @@ impl CanbeFree for Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn constraint(&self) -> Option<Constraint> {
|
fn constraint(&self) -> Option<Constraint> {
|
||||||
if let Type::FreeVar(fv) = self {
|
if let Some(fv) = self.as_free() {
|
||||||
fv.constraint()
|
fv.constraint()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -1006,7 +1006,7 @@ impl CanbeFree for Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_constraint(&self, new_constraint: Constraint, in_instantiation: bool) {
|
fn update_constraint(&self, new_constraint: Constraint, in_instantiation: bool) {
|
||||||
if let Self::FreeVar(fv) = self {
|
if let Some(fv) = self.as_free() {
|
||||||
fv.update_constraint(new_constraint, in_instantiation);
|
fv.update_constraint(new_constraint, in_instantiation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1048,6 +1048,17 @@ impl From<Dict<Type, Type>> for Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'t> TryFrom<&'t Type> for &'t FreeTyVar {
|
||||||
|
type Error = ();
|
||||||
|
fn try_from(t: &'t Type) -> Result<&'t FreeTyVar, ()> {
|
||||||
|
match t {
|
||||||
|
Type::FreeVar(fv) => Ok(fv),
|
||||||
|
Type::Refinement(refine) => Self::try_from(refine.t.as_ref()),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Dict<Field, Type>> for Type {
|
impl From<Dict<Field, Type>> for Type {
|
||||||
fn from(rec: Dict<Field, Type>) -> Self {
|
fn from(rec: Dict<Field, Type>) -> Self {
|
||||||
Type::Record(rec)
|
Type::Record(rec)
|
||||||
|
@ -1582,6 +1593,10 @@ impl Type {
|
||||||
matches!(self, Self::Structural(_))
|
matches!(self, Self::Structural(_))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_free(&self) -> Option<&FreeTyVar> {
|
||||||
|
<&FreeTyVar>::try_from(self).ok()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn contains_tvar(&self, target: &FreeTyVar) -> bool {
|
pub fn contains_tvar(&self, target: &FreeTyVar) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::FreeVar(fv) if fv.is_linked() => fv.crack().contains_tvar(target),
|
Self::FreeVar(fv) if fv.is_linked() => fv.crack().contains_tvar(target),
|
||||||
|
@ -2331,6 +2346,7 @@ impl Type {
|
||||||
match self {
|
match self {
|
||||||
Self::FreeVar(fv) if fv.is_linked() => fv.crack().clone()._replace(target, to),
|
Self::FreeVar(fv) if fv.is_linked() => fv.crack().clone()._replace(target, to),
|
||||||
Self::FreeVar(fv) => {
|
Self::FreeVar(fv) => {
|
||||||
|
let fv = fv.deep_clone();
|
||||||
if let Some((sub, sup)) = fv.get_subsup() {
|
if let Some((sub, sup)) = fv.get_subsup() {
|
||||||
fv.forced_undoable_link(&sub);
|
fv.forced_undoable_link(&sub);
|
||||||
let sub = sub._replace(target, to);
|
let sub = sub._replace(target, to);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue