mirror of
				https://github.com/Z3Prover/z3
				synced 2025-11-03 21:09:11 +00:00 
			
		
		
		
	Handle additional cases in rule_properties::check_accessor (#5821)
* Handle additional cases in rule_properties::check_accessor * Walk parents depth first in rule_properties::check_accessor
This commit is contained in:
		
							parent
							
								
									882fc31aea
								
							
						
					
					
						commit
						e3568d5b47
					
				
					 1 changed files with 72 additions and 21 deletions
				
			
		| 
						 | 
					@ -211,18 +211,34 @@ bool rule_properties::check_accessor(app* n) {
 | 
				
			||||||
    if (m_dt.get_datatype_constructors(s)->size() <= 1)
 | 
					    if (m_dt.get_datatype_constructors(s)->size() <= 1)
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    func_decl* f = n->get_decl();
 | 
					    func_decl* f = n->get_decl();
 | 
				
			||||||
    func_decl * c = m_dt.get_accessor_constructor(f);
 | 
					    func_decl* c = m_dt.get_accessor_constructor(f);
 | 
				
			||||||
    unsigned ut_size = m_rule->get_uninterpreted_tail_size();
 | 
					    unsigned ut_size = m_rule->get_uninterpreted_tail_size();
 | 
				
			||||||
    unsigned t_size  = m_rule->get_tail_size();
 | 
					    unsigned t_size  = m_rule->get_tail_size();
 | 
				
			||||||
 | 
					    ptr_vector<func_decl> ctors;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // add recognizer constructor to ctors
 | 
				
			||||||
 | 
					    auto add_recognizer = [&](expr* r) {
 | 
				
			||||||
 | 
					        if (!m_dt.is_recognizer(r))
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        if (n->get_arg(0) != to_app(r)->get_arg(0))
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        auto* c2 = m_dt.get_recognizer_constructor(to_app(r)->get_decl());
 | 
				
			||||||
 | 
					        if (c == c2)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        ctors.push_back(c2);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    auto add_not_recognizer = [&](expr* r) {
 | 
				
			||||||
 | 
					        if (m.is_not(r, r))
 | 
				
			||||||
 | 
					            add_recognizer(r);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // t is a recognizer for n
 | 
				
			||||||
    auto is_recognizer_base = [&](expr* t) {
 | 
					    auto is_recognizer_base = [&](expr* t) {
 | 
				
			||||||
        return m_dt.is_recognizer(t) &&
 | 
					        return m_dt.is_recognizer(t) &&
 | 
				
			||||||
            to_app(t)->get_arg(0) == n->get_arg(0) &&
 | 
					            to_app(t)->get_arg(0) == n->get_arg(0) &&
 | 
				
			||||||
            m_dt.get_recognizer_constructor(to_app(t)->get_decl()) == c;
 | 
					            m_dt.get_recognizer_constructor(to_app(t)->get_decl()) == c;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    auto is_recognizer = [&](expr* t) {
 | 
					    auto is_recognizer = [&](expr* t) {
 | 
				
			||||||
        if (m.is_and(t))
 | 
					        if (m.is_and(t))
 | 
				
			||||||
            for (expr* arg : *to_app(t))
 | 
					            for (expr* arg : *to_app(t))
 | 
				
			||||||
| 
						 | 
					@ -231,11 +247,12 @@ bool rule_properties::check_accessor(app* n) {
 | 
				
			||||||
        return is_recognizer_base(t);
 | 
					        return is_recognizer_base(t);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    
 | 
					    for (unsigned i = ut_size; i < t_size; ++i) {
 | 
				
			||||||
    for (unsigned i = ut_size; i < t_size; ++i)
 | 
					        auto* tail = m_rule->get_tail(i);
 | 
				
			||||||
        if (is_recognizer(m_rule->get_tail(i)))
 | 
					        if (is_recognizer(tail))
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
 | 
					        add_not_recognizer(tail);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // create parent use list for every sub-expression in the rule
 | 
					    // create parent use list for every sub-expression in the rule
 | 
				
			||||||
    obj_map<expr, ptr_vector<expr>> use_list;
 | 
					    obj_map<expr, ptr_vector<expr>> use_list;
 | 
				
			||||||
| 
						 | 
					@ -248,26 +265,60 @@ bool rule_properties::check_accessor(app* n) {
 | 
				
			||||||
                    use_list.insert_if_not_there(arg, ptr_vector<expr>()).push_back(sub);
 | 
					                    use_list.insert_if_not_there(arg, ptr_vector<expr>()).push_back(sub);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // walk parents of n to check that each path is guarded by a recognizer.
 | 
					    // walk parents of n depth first to check that each path is guarded by a recognizer.
 | 
				
			||||||
    ptr_vector<expr> todo;
 | 
					    vector<std::tuple<expr *, unsigned int, bool>> todo;
 | 
				
			||||||
    todo.push_back(n);
 | 
					    todo.push_back({n, ctors.size(), false});
 | 
				
			||||||
    for (unsigned i = 0; i < todo.size(); ++i) {
 | 
					    while(!todo.empty()) {
 | 
				
			||||||
        expr* e = todo[i];
 | 
					        auto [e, ctors_size, visited] = todo.back();
 | 
				
			||||||
 | 
					        if (visited) {
 | 
				
			||||||
 | 
					            todo.pop_back();
 | 
				
			||||||
 | 
					            while (ctors.size() > ctors_size) ctors.pop_back();
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        std::get<2>(todo.back()) = true; // set visited
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!use_list.contains(e))
 | 
					        if (!use_list.contains(e))
 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        for (expr* parent : use_list[e]) {
 | 
					        for (expr* parent : use_list[e]) {
 | 
				
			||||||
            if (!parent)
 | 
					            if (!parent) { // top-level expression
 | 
				
			||||||
                return false; // top-level expressions are not guarded
 | 
					                // check if n is an unguarded "else" branch
 | 
				
			||||||
 | 
					                ptr_vector<func_decl> diff;
 | 
				
			||||||
 | 
					                for (auto* dtc : *m_dt.get_datatype_constructors(s))
 | 
				
			||||||
 | 
					                    if (!ctors.contains(dtc))
 | 
				
			||||||
 | 
					                        diff.push_back(dtc);
 | 
				
			||||||
 | 
					                // the only unguarded constructor for s is c:
 | 
				
			||||||
 | 
					                // all the others are guarded and we are in an "else" branch so the accessor is safe
 | 
				
			||||||
 | 
					                if (diff.size() == 1 && diff[0] == c)
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                return false; // the accessor is not safe
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            if (is_recognizer(parent))
 | 
					            if (is_recognizer(parent))
 | 
				
			||||||
                continue;
 | 
					                continue;
 | 
				
			||||||
            if (m.is_ite(parent) && to_app(parent)->get_arg(1) == e && is_recognizer(to_app(parent)->get_arg(0))) 
 | 
					
 | 
				
			||||||
                continue;
 | 
					            expr *cnd, *thn, *els;
 | 
				
			||||||
            todo.push_back(parent);                
 | 
					            if (m.is_ite(parent, cnd, thn, els)) {
 | 
				
			||||||
 | 
					                if (thn == e) {
 | 
				
			||||||
 | 
					                    if (is_recognizer(cnd) && els != e)
 | 
				
			||||||
 | 
					                        continue; // e is guarded
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                add_recognizer(cnd);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (m.is_and(parent))
 | 
				
			||||||
 | 
					                for (expr* arg : *to_app(parent))
 | 
				
			||||||
 | 
					                    add_not_recognizer(arg);
 | 
				
			||||||
 | 
					            if (m.is_or(parent))
 | 
				
			||||||
 | 
					                for (expr* arg : *to_app(parent)) {
 | 
				
			||||||
 | 
					                    add_recognizer(arg);
 | 
				
			||||||
 | 
					                    // if one branch is not(recognizer) then the accessor is safe
 | 
				
			||||||
 | 
					                    if (m.is_not(arg, arg) && is_recognizer(arg))
 | 
				
			||||||
 | 
					                        goto _continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            todo.push_back({parent, ctors.size(), false});
 | 
				
			||||||
 | 
					        _continue:;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void rule_properties::operator()(app* n) {
 | 
					void rule_properties::operator()(app* n) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue