Skip to content

Commit

Permalink
[move-prover] Translate quantifiers from expanded AST to move-model AST
Browse files Browse the repository at this point in the history
  • Loading branch information
ma2bd authored and bors-libra committed Jan 15, 2021
1 parent 2672e77 commit 4d2a3c9
Showing 1 changed file with 92 additions and 1 deletion.
93 changes: 92 additions & 1 deletion language/move-model/src/builder/exp_translator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use move_lang::{
};

use crate::{
ast::{Exp, LocalVarDecl, ModuleName, Operation, QualifiedSymbol, Value},
ast::{Exp, LocalVarDecl, ModuleName, Operation, QualifiedSymbol, QuantKind, Value},
builder::{
model_builder::{ConstEntry, LocalVarEntry, SpecFunEntry},
module_builder::ModuleBuilder,
Expand Down Expand Up @@ -739,6 +739,9 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
EA::Exp_::Lambda(bindings, exp) => {
self.translate_lambda(&loc, bindings, exp, expected_type)
}
EA::Exp_::Quant(kind, ranges, exp) => {
self.translate_quant(&loc, *kind, ranges, exp, expected_type)
}
EA::Exp_::BinopExp(l, op, r) => {
let args = vec![l.as_ref(), r.as_ref()];
let QualifiedSymbol {
Expand Down Expand Up @@ -1785,6 +1788,94 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo
Exp::Lambda(id, decls, Box::new(rbody))
}

fn translate_quant(
&mut self,
loc: &Loc,
kind: PA::QuantKind,
ranges: &EA::LValueWithRangeList,
body: &EA::Exp,
expected_type: &Type,
) -> Exp {
// Enter the quantifier variables into a new local scope and collect their declarations.
self.enter_scope();
let mut rranges = vec![];
for range in &ranges.value {
// The quantified variable and its domain expression.
let (bind, exp) = &range.value;
let loc = self.to_loc(&bind.loc);
let (exp_ty, rexp) = self.translate_exp_free(exp);
let ty = self.fresh_type_var();
let exp_ty = self.subs.specialize(&exp_ty);
match &exp_ty {
Type::Vector(..) => {
self.check_type(
&loc,
&exp_ty,
&Type::Vector(Box::new(ty.clone())),
"in quantification over vector",
);
}
Type::TypeDomain(..) => {
self.check_type(
&loc,
&exp_ty,
&Type::TypeDomain(Box::new(ty.clone())),
"in quantification over domain",
);
}
Type::Primitive(PrimitiveType::Range) => {
self.check_type(
&loc,
&ty,
&Type::Primitive(PrimitiveType::Num),
"in quantification over range",
);
}
_ => {
self.error(&loc, "quantified variables must range over a vector, a type domain, or a number range");
return self.new_error_exp();
}
}
match &bind.value {
EA::LValue_::Var(
Spanned {
value: EA::ModuleAccess_::Name(n),
..
},
_,
) => {
let name = self.symbol_pool().make(&n.value);
let id = self.new_node_id_with_type_loc(&ty, &loc);
self.define_local(&loc, name, ty.clone(), None);
let rbind = LocalVarDecl {
id,
name,
binding: None,
};
rranges.push((rbind, rexp));
}
EA::LValue_::Unpack(..) | EA::LValue_::Var(..) => self.error(
&loc,
"[current restriction] tuples not supported in quantifiers",
),
}
}
let rty = self.check_type(
loc,
&Type::new_prim(PrimitiveType::Bool),
expected_type,
"in quantified expression",
);
let rbody = self.translate_exp(body, &rty);
self.exit_scope();
let id = self.new_node_id_with_type_loc(&rty, loc);
let rkind = match kind.value {
PA::QuantKind_::Forall => QuantKind::Forall,
PA::QuantKind_::Exists => QuantKind::Exists,
};
Exp::Quant(id, rkind, rranges, Box::new(rbody))
}

pub fn check_type(&mut self, loc: &Loc, ty: &Type, expected: &Type, context_msg: &str) -> Type {
// Because of Rust borrow semantics, we must temporarily detach the substitution from
// the build. This is because we also need to inherently borrow self via the
Expand Down

0 comments on commit 4d2a3c9

Please sign in to comment.