let check_preconditions kf kinstr ~slevel header active_behaviors 
    init_state spec =
  let env = env_pre_f (State_set.join init_state) in
  let incorporate_behavior states b =
    if b.b_requires = [] then states
    else
      let header = header ^ ActiveBehaviors.header b in
      let update_status st vc =
        let ip = Property.ip_of_requires kf kinstr b vc in
        emit_status ip st
      in
      match ActiveBehaviors.active active_behaviors b with
      | True ->
        List.fold_left (fun state ({ip_content=pr;ip_loc=loc} as pre) ->
          let source = fst loc in
          if State_set.is_empty state then
            (Value_parameters.result ~once:true ~source
               "%s: no state in which to evaluate precondition, status not computed.%t"
               header pp_callstack;
             state)
          else
            let pr = Ast_info.predicate loc pr in
            let res = fold_join_predicate State_set.fold
              (fun state ->
                eval_predicate ~result:None (env_pre_f state) pr)
              state
            in
            Value_parameters.result ~once:true ~source
              "%s: precondition got status %a.%t"
              header pretty_predicate_value res pp_callstack;
            match res with
              | False ->
                  update_status Property_status.False_if_reachable pre;
                  State_set.empty
              | True ->
                  update_status Property_status.True pre;
                  (* The reduction is needed in the True case,
                     because the function is "reduce_by_disjunction".
                     Example: //@ assert x<0 || x>=0; *)

                  reduce_by_disjunction ~result:None ~env state slevel pr
              | Unknown ->
                  update_status Property_status.Dont_know pre;
                  reduce_by_disjunction ~result:None ~env state slevel pr
        ) states b.b_requires
      | Unknown ->
        List.fold_left
          (fun state ({ip_content=pr;ip_loc=loc} as pre) ->
            let source = fst loc in
            if State_set.is_empty state then
              (Value_parameters.result ~once:true ~source
                 "%s: no state in which to evaluate precondition, status not computed.%t"
                 header pp_callstack;
               state)
            else
              let pr = Ast_info.predicate loc pr in
              let res = fold_join_predicate State_set.fold
                (fun state ->
                  eval_predicate ~result:None (env_pre_f state) pr)
                state
              in
              Value_parameters.result ~once:true ~source:(fst loc)
                "%s: precondition got status %a.%t"
                header pretty_predicate_value res pp_callstack;
              match res with
                | Unknown | False ->
                    update_status Property_status.Dont_know pre;
                    Value_parameters.result ~once:true ~source
                      "%s: precondition got status %a, but it is unknown if the behavior is active.%t"
                      header pretty_predicate_value res pp_callstack;
                    state
                | True ->
                    update_status Property_status.True pre;
                    Value_parameters.result ~once:true ~source
                      "%s: precondition got status %a.%t"
                      header pretty_predicate_value res pp_callstack;
                    state
          ) states b.b_requires
      | False ->
        (* if assumes is false, post-condition status is not updated *)
        (match b.b_requires with
        | [] -> ()
        | {ip_loc=(source,_)}::_ ->
          Value_parameters.result ~once:true ~source
            "%s: assumption got status invalid; precondition not evaluated.%t"
            header pp_callstack);
        states
  in
  List.fold_left
    incorporate_behavior
    init_state spec.spec_behavior