Fix a refinement subtype checking bug

This commit is contained in:
Shunsuke Shibayama 2022-12-10 13:18:07 +09:00
parent 747974d37c
commit acb3eac043
3 changed files with 77 additions and 41 deletions

View file

@ -836,12 +836,29 @@ impl LimitedDisplay for RefinementType {
impl RefinementType {
pub fn new(var: Str, t: Type, preds: Set<Predicate>) -> Self {
Self {
var,
t: Box::new(t),
preds,
match t.deconstruct_refinement() {
Ok((inner_var, inner_t, inner_preds)) => {
let new_preds = preds
.into_iter()
.map(|pred| pred.change_subject_name(inner_var.clone()))
.collect::<Set<_>>();
Self {
var: inner_var,
t: Box::new(inner_t),
preds: inner_preds.concat(new_preds),
}
}
Err(t) => Self {
var,
t: Box::new(t),
preds,
},
}
}
pub fn deconstruct(self) -> (Str, Type, Set<Predicate>) {
(self.var, *self.t, self.preds)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@ -1611,6 +1628,14 @@ impl Type {
}
}
pub fn is_refinement(&self) -> bool {
match self {
Self::FreeVar(fv) if fv.is_linked() => fv.crack().is_refinement(),
Self::Refinement(_) => true,
_ => false,
}
}
pub fn is_record(&self) -> bool {
match self {
Self::FreeVar(fv) if fv.is_linked() => fv.crack().is_record(),
@ -1852,6 +1877,41 @@ impl Type {
|| (self.has_no_qvar() && self.has_no_unbound_var())
}
pub fn into_refinement(self) -> RefinementType {
match self {
Type::FreeVar(fv) if fv.is_linked() => fv.crack().clone().into_refinement(),
Type::Nat => {
let var = Str::from(fresh_varname());
RefinementType::new(
var.clone(),
Type::Int,
set! {Predicate::ge(var, TyParam::value(0))},
)
}
Type::Bool => {
let var = Str::from(fresh_varname());
RefinementType::new(
var.clone(),
Type::Int,
set! {Predicate::ge(var.clone(), TyParam::value(true)), Predicate::le(var, TyParam::value(false))},
)
}
Type::Refinement(r) => r,
t => {
let var = Str::from(fresh_varname());
RefinementType::new(var, t, set! {})
}
}
}
pub fn deconstruct_refinement(self) -> Result<(Str, Type, Set<Predicate>), Type> {
match self {
Type::FreeVar(fv) if fv.is_linked() => fv.crack().clone().deconstruct_refinement(),
Type::Refinement(r) => Ok(r.deconstruct()),
_ => Err(self),
}
}
pub fn qvars(&self) -> Set<(Str, Constraint)> {
match self {
Self::FreeVar(fv) if fv.is_linked() => fv.forced_as_ref().linked().unwrap().qvars(),