diff options
Diffstat (limited to 'src/Values.ml')
-rw-r--r-- | src/Values.ml | 844 |
1 files changed, 0 insertions, 844 deletions
diff --git a/src/Values.ml b/src/Values.ml deleted file mode 100644 index e404f40d..00000000 --- a/src/Values.ml +++ /dev/null @@ -1,844 +0,0 @@ -open Identifiers -open Types - -(* TODO: I often write "abstract" (value, borrow content, etc.) while I should - * write "abstraction" (because those values are not abstract, they simply are - * inside abstractions) *) - -module VarId = IdGen () -module BorrowId = IdGen () -module SymbolicValueId = IdGen () -module AbstractionId = IdGen () -module FunCallId = IdGen () - -(** A variable *) - -type big_int = Z.t - -let big_int_of_yojson (json : Yojson.Safe.t) : (big_int, string) result = - match json with - | `Int i -> Ok (Z.of_int i) - | `Intlit is -> Ok (Z.of_string is) - | _ -> Error "not an integer or an integer literal" - -let big_int_to_yojson (i : big_int) = `Intlit (Z.to_string i) - -let pp_big_int (fmt : Format.formatter) (bi : big_int) : unit = - Format.pp_print_string fmt (Z.to_string bi) - -let show_big_int (bi : big_int) : string = Z.to_string bi - -(** A scalar value - - Note that we use unbounded integers everywhere. - We then harcode the boundaries for the different types. - *) -type scalar_value = { value : big_int; int_ty : integer_type } [@@deriving show] - -(** A constant value *) -type constant_value = - | Scalar of scalar_value - | Bool of bool - | Char of char - | String of string -[@@deriving show] - -(** The kind of a symbolic value, which precises how the value was generated *) -type sv_kind = - | FunCallRet (** The value is the return value of a function call *) - | FunCallGivenBack - (** The value is a borrowed value given back by an abstraction - (happens when giving a borrow to a function: when the abstraction - introduced to model the function call ends we reintroduce a symbolic - value in the context for the value modified by the abstraction through - the borrow). - *) - | SynthInput - (** The value is an input value of the function whose body we are - currently synthesizing. - *) - | SynthRetGivenBack - (** The value is a borrowed value that the function whose body we are - synthesizing returned, and which was given back because we ended - one of the lifetimes of this function (we do this to synthesize - the backward functions). - *) - | SynthInputGivenBack - (** The value was given back upon ending one of the input abstractions *) - | Global (** The value is a global *) -[@@deriving show] - -(** A symbolic value *) -type symbolic_value = { - sv_kind : sv_kind; - sv_id : SymbolicValueId.id; - sv_ty : rty; -} -[@@deriving show] - -(** Ancestor for {!typed_value} iter visitor *) -class ['self] iter_typed_value_base = - object (_self : 'self) - inherit [_] VisitorsRuntime.iter - method visit_constant_value : 'env -> constant_value -> unit = fun _ _ -> () - method visit_erased_region : 'env -> erased_region -> unit = fun _ _ -> () - method visit_symbolic_value : 'env -> symbolic_value -> unit = fun _ _ -> () - method visit_ety : 'env -> ety -> unit = fun _ _ -> () - end - -(** Ancestor for {!typed_value} map visitor for *) -class ['self] map_typed_value_base = - object (_self : 'self) - inherit [_] VisitorsRuntime.map - - method visit_constant_value : 'env -> constant_value -> constant_value = - fun _ cv -> cv - - method visit_erased_region : 'env -> erased_region -> erased_region = - fun _ r -> r - - method visit_symbolic_value : 'env -> symbolic_value -> symbolic_value = - fun _ sv -> sv - - method visit_ety : 'env -> ety -> ety = fun _ ty -> ty - end - -(** An untyped value, used in the environments *) -type value = - | Concrete of constant_value (** Concrete (non-symbolic) value *) - | Adt of adt_value (** Enumerations and structures *) - | Bottom (** No value (uninitialized or moved value) *) - | Borrow of borrow_content (** A borrowed value *) - | Loan of loan_content (** A loaned value *) - | Symbolic of symbolic_value - (** Borrow projector over a symbolic value. - - Note that contrary to the abstraction-values case, symbolic values - appearing in regular values are interpreted as *borrow* projectors, - they can never be *loan* projectors. - *) - -and adt_value = { - variant_id : (VariantId.id option[@opaque]); - field_values : typed_value list; -} - -and borrow_content = - | SharedBorrow of mvalue * (BorrowId.id[@opaque]) - (** A shared borrow. - - We remember the shared value which was borrowed as a meta value. - This is necessary for synthesis: upon translating to "pure" values, - we can't perform any lookup because we don't have an environment - anymore. Note that it is ok to keep the shared value and copy - the shared value this way, because shared values are immutable - for as long as they are shared (i.e., as long as we can use the - shared borrow). - *) - | MutBorrow of (BorrowId.id[@opaque]) * typed_value - (** A mutably borrowed value. *) - | InactivatedMutBorrow of mvalue * (BorrowId.id[@opaque]) - (** An inactivated mut borrow. - - This is used to model {{: https://rustc-dev-guide.rust-lang.org/borrow_check/two_phase_borrows.html} two-phase borrows}. - When evaluating a two-phase mutable borrow, we first introduce an inactivated - borrow which behaves like a shared borrow, until the moment we actually *use* - the borrow: at this point, we end all the other shared borrows (or inactivated - borrows - though there shouldn't be any other inactivated borrows if the program - is well typed) of this value and replace the inactivated borrow with a - mutable borrow. - - A simple use case of two-phase borrows: - {[ - let mut v = Vec::new(); - v.push(v.len()); - ]} - - This gets desugared to (something similar to) the following MIR: - {[ - v = Vec::new(); - v1 = &mut v; - v2 = &v; // We need this borrow, but v has already been mutably borrowed! - l = Vec::len(move v2); - Vec::push(move v1, move l); // In practice, v1 gets activated only here - ]} - - The meta-value is used for the same purposes as with shared borrows, - at the exception that in case of inactivated borrows it is not - *necessary* for the synthesis: we keep it only as meta-information. - To be more precise: - - when generating the synthesized program, we may need to convert - shared borrows to pure values - - we never need to do so for inactivated borrows: such borrows must - be activated at the moment we use them (meaning we convert a *mutable* - borrow to a pure value). However, we save meta-data about the assignments, - which is used to make the code cleaner: when generating this meta-data, - we may need to convert inactivated borrows to pure values, in which - situation we convert the meta-value we stored in the inactivated - borrow. - *) - -and loan_content = - | SharedLoan of (BorrowId.Set.t[@opaque]) * typed_value - | MutLoan of (BorrowId.id[@opaque]) - (** TODO: we might want to add a set of borrow ids (useful for inactivated - borrows, and extremely useful when giving shared values to abstractions). - *) - -(** "Meta"-value: information we store for the synthesis. - - Note that we never automatically visit the meta-values with the - visitors: they really are meta information, and shouldn't be considered - as part of the environment during a symbolic execution. - - TODO: we may want to create wrappers, to prevent accidently mixing meta - values and regular values. - *) -and mvalue = typed_value - -(** "Regular" typed value (we map variables to typed values) *) -and typed_value = { value : value; ty : ety } -[@@deriving - show, - visitors - { - name = "iter_typed_value_visit_mvalue"; - variety = "iter"; - ancestors = [ "iter_typed_value_base" ]; - nude = true (* Don't inherit {!VisitorsRuntime.iter} *); - concrete = true; - }, - visitors - { - name = "map_typed_value_visit_mvalue"; - variety = "map"; - ancestors = [ "map_typed_value_base" ]; - nude = true (* Don't inherit {!VisitorsRuntime.iter} *); - concrete = true; - }] - -(** We have to override the {!iter_typed_value_visit_mvalue.visit_mvalue} method, - to ignore meta-values *) -class ['self] iter_typed_value = - object (_self : 'self) - inherit [_] iter_typed_value_visit_mvalue - method! visit_mvalue : 'env -> mvalue -> unit = fun _ _ -> () - end - -(** We have to override the {!iter_typed_value_visit_mvalue.visit_mvalue} method, - to ignore meta-values *) -class ['self] map_typed_value = - object (_self : 'self) - inherit [_] map_typed_value_visit_mvalue - method! visit_mvalue : 'env -> mvalue -> mvalue = fun _ x -> x - end - -(** "Meta"-symbolic value. - - See the explanations for {!mvalue} - - TODO: we may want to create wrappers, to prevent mixing meta values - and regular values. - *) -type msymbolic_value = symbolic_value [@@deriving show] - -(** When giving shared borrows to functions (i.e., inserting shared borrows inside - abstractions) we need to reborrow the shared values. When doing so, we lookup - the shared values and apply some special projections to the shared value - (until we can't go further, i.e., we find symbolic values which may get - expanded upon reading them later), which don't generate avalues but - sets of borrow ids and symbolic values. - - Note that as shared values can't get modified it is ok to forget the - structure of the values we projected, and only keep the set of borrows - (and symbolic values). - - TODO: we may actually need to remember the structure, in order to know - which borrows are inside which other borrows... -*) -type abstract_shared_borrow = - | AsbBorrow of (BorrowId.id[@opaque]) - | AsbProjReborrows of (symbolic_value[@opaque]) * (rty[@opaque]) -[@@deriving show] - -(** A set of abstract shared borrows *) -type abstract_shared_borrows = abstract_shared_borrow list [@@deriving show] - -(** Ancestor for {!aproj} iter visitor *) -class ['self] iter_aproj_base = - object (_self : 'self) - inherit [_] iter_typed_value - method visit_rty : 'env -> rty -> unit = fun _ _ -> () - - method visit_msymbolic_value : 'env -> msymbolic_value -> unit = - fun _ _ -> () - end - -(** Ancestor for {!aproj} map visitor *) -class ['self] map_aproj_base = - object (_self : 'self) - inherit [_] map_typed_value - method visit_rty : 'env -> rty -> rty = fun _ ty -> ty - - method visit_msymbolic_value : 'env -> msymbolic_value -> msymbolic_value = - fun _ m -> m - end - -type aproj = - | AProjLoans of symbolic_value * (msymbolic_value * aproj) list - (** A projector of loans over a symbolic value. - - Note that the borrows of a symbolic value may be spread between - different abstractions, meaning that the projector of loans might - receive *several* (symbolic) given back values. - - This is the case in the following example: - {[ - fn f<'a> (...) -> (&'a mut u32, &'a mut u32); - fn g<'b, 'c>(p : (&'b mut u32, &'c mut u32)); - - let p = f(...); - g(move p); - - // Symbolic context after the call to g: - // abs'a {'a} { [s@0 <: (&'a mut u32, &'a mut u32)] } - // - // abs'b {'b} { (s@0 <: (&'b mut u32, &'c mut u32)) } - // abs'c {'c} { (s@0 <: (&'b mut u32, &'c mut u32)) } - ]} - - Upon evaluating the call to [f], we introduce a symbolic value [s@0] - and a projector of loans (projector loans from the region 'c). - This projector will later receive two given back values: one for - 'a and one for 'b. - - We accumulate those values in the list of projections (note that - the meta value stores the value which was given back). - - We can later end the projector of loans if [s@0] is not referenced - anywhere in the context below a projector of borrows which intersects - this projector of loans. - *) - | AProjBorrows of symbolic_value * rty - (** Note that an AProjBorrows only operates on a value which is not below - a shared loan: under a shared loan, we use {!abstract_shared_borrow}. - - Also note that once given to a borrow projection, a symbolic value - can't get updated/expanded: this means that we don't need to save - any meta-value here. - *) - | AEndedProjLoans of msymbolic_value * (msymbolic_value * aproj) list - (** An ended projector of loans over a symbolic value. - - See the explanations for {!AProjLoans} - - Note that we keep the original symbolic value as a meta-value. - *) - | AEndedProjBorrows of msymbolic_value - (** The only purpose of {!AEndedProjBorrows} is to store, for synthesis - purposes, the symbolic value which was generated and given back upon - ending the borrow. - *) - | AIgnoredProjBorrows -[@@deriving - show, - visitors - { - name = "iter_aproj"; - variety = "iter"; - ancestors = [ "iter_aproj_base" ]; - nude = true (* Don't inherit {!VisitorsRuntime.iter} *); - concrete = true; - }, - visitors - { - name = "map_aproj"; - variety = "map"; - ancestors = [ "map_aproj_base" ]; - nude = true (* Don't inherit {!VisitorsRuntime.iter} *); - concrete = true; - }] - -type region = RegionVarId.id Types.region [@@deriving show] - -(** Ancestor for {!typed_avalue} iter visitor *) -class ['self] iter_typed_avalue_base = - object (_self : 'self) - inherit [_] iter_aproj - method visit_id : 'env -> BorrowId.id -> unit = fun _ _ -> () - method visit_region : 'env -> region -> unit = fun _ _ -> () - - method visit_abstract_shared_borrows - : 'env -> abstract_shared_borrows -> unit = - fun _ _ -> () - end - -(** Ancestor for {!typed_avalue} map visitor *) -class ['self] map_typed_avalue_base = - object (_self : 'self) - inherit [_] map_aproj - method visit_id : 'env -> BorrowId.id -> BorrowId.id = fun _ id -> id - method visit_region : 'env -> region -> region = fun _ r -> r - - method visit_abstract_shared_borrows - : 'env -> abstract_shared_borrows -> abstract_shared_borrows = - fun _ asb -> asb - end - -(** Abstraction values are used inside of abstractions to properly model - borrowing relations introduced by function calls. - - When calling a function, we lose information about the borrow graph: - part of it is thus "abstracted" away. -*) -type avalue = - | AConcrete of constant_value - (** TODO: remove. We actually don't use that for the synthesis, but the - meta-values. - - Note that this case is not used in the projections to keep track of the - borrow graph (because there are no borrows in "concrete" values!) but - to correctly instantiate the backward functions (we may give back some - values at different moments: we need to remember what those values were - precisely). Also note that even though avalues and values are not the - same, once values are projected to avalues, those avalues still have - the structure of the original values (this is necessary, again, to - correctly instantiate the backward functions) - *) - | AAdt of adt_avalue - | ABottom - | ALoan of aloan_content - | ABorrow of aborrow_content - | ASymbolic of aproj - | AIgnored - (** A value which doesn't contain borrows, or which borrows we - don't own and thus ignore *) - -and adt_avalue = { - variant_id : (VariantId.id option[@opaque]); - field_values : typed_avalue list; -} - -(** A loan content as stored in an abstraction. - - Note that the children avalues are independent of the parent avalues. - For instance, the child avalue contained in an {!AMutLoan} will likely - contain other, independent loans. - Keeping track of the hierarchy is not necessary to maintain the borrow graph - (which is the primary role of the abstractions), but it is necessary - to properly instantiate the backward functions when generating the pure - translation. -*) -and aloan_content = - | AMutLoan of (BorrowId.id[@opaque]) * typed_avalue - (** A mutable loan owned by an abstraction. - - Example: - ======== - {[ - fn f<'a>(...) -> &'a mut &'a mut u32; - - let px = f(...); - ]} - - We get (after some symbolic exansion): - {[ - abs0 { - a_mut_loan l0 (a_mut_loan l1) - } - px -> mut_borrow l0 (mut_borrow @s1) - ]} - *) - | ASharedLoan of (BorrowId.Set.t[@opaque]) * typed_value * typed_avalue - (** A shared loan owned by an abstraction. - - Example: - ======== - {[ - fn f<'a>(...) -> &'a u32; - - let px = f(...); - ]} - - We get: - {[ - abs0 { a_shared_loan {l0} @s0 ⊥ } - px -> shared_loan l0 - ]} - *) - | AEndedMutLoan of { - child : typed_avalue; - given_back : typed_avalue; - given_back_meta : mvalue; - } - (** An ended mutable loan in an abstraction. - We need it because abstractions must keep track of the values - we gave back to them, so that we can correctly instantiate - backward functions. - - Rk.: *DO NOT* use [visit_AEndedMutLoan]. If we update the order of - the arguments and you forget to swap them at the level of - [visit_AEndedMutLoan], you will not notice it. - - Example: - ======== - {[ - abs0 { a_mut_loan l0 ⊥ } - x -> mut_borrow l0 (U32 3) - ]} - - After ending [l0]: - - {[ - abs0 { a_ended_mut_loan { given_back = U32 3; child = ⊥; } - x -> ⊥ - ]} - *) - | AEndedSharedLoan of typed_value * typed_avalue - (** Similar to {!AEndedMutLoan} but in this case there are no avalues to - give back. We keep the shared value because it now behaves as a - "regular" value (which contains borrows we might want to end...). - *) - | AIgnoredMutLoan of (BorrowId.id[@opaque]) * typed_avalue - (** An ignored mutable loan. - - We need to keep track of ignored mutable loans, because we may have - to apply projections on the values given back to those loans (say - you have a borrow of type [&'a mut &'b mut], in the abstraction 'b, - the outer loan is ignored, however you need to keep track of it so - that when ending the borrow corresponding to 'a you can correctly - project on the inner value). - - Example: - ======== - {[ - fn f<'a,'b>(...) -> &'a mut &'b mut u32; - let x = f(...); - - > abs'a { a_mut_loan l0 (a_ignored_mut_loan l1 ⊥) } - > abs'b { a_ignored_mut_loan l0 (a_mut_loan l1 ⊥) } - > x -> mut_borrow l0 (mut_borrow l1 @s1) - ]} - *) - | AEndedIgnoredMutLoan of { - child : typed_avalue; - given_back : typed_avalue; - given_back_meta : mvalue; - } - (** Similar to {!AEndedMutLoan}, for ignored loans. - - Rk.: *DO NOT* use [visit_AEndedIgnoredMutLoan]. - See the comment for {!AEndedMutLoan}. - *) - | AIgnoredSharedLoan of typed_avalue - (** An ignored shared loan. - - Example: - ======== - {[ - fn f<'a,'b>(...) -> &'a &'b u32; - let x = f(...); - - > abs'a { a_shared_loan {l0} (shared_borrow l1) (a_ignored_shared_loan ⊥) } - > abs'b { a_ignored_shared_loan (a_shared_loan {l1} @s1 ⊥) } - > x -> shared_borrow l0 - ]} - *) - -(** Note that when a borrow content is ended, it is replaced by ⊥ (while - we need to track ended loans more precisely, especially because of their - children values). - - Note that contrary to {!aloan_content}, here the children avalues are - not independent of the parent avalues. For instance, a value - [AMutBorrow (_, AMutBorrow (_, ...)] (ignoring the types) really is - to be seen like a [mut_borrow ... (mut_borrow ...)]. - - TODO: be more precise about the ignored borrows (keep track of the borrow - ids)? -*) -and aborrow_content = - | AMutBorrow of mvalue * (BorrowId.id[@opaque]) * typed_avalue - (** A mutable borrow owned by an abstraction. - - Is used when an abstraction "consumes" borrows, when giving borrows - as arguments to a function. - - Example: - ======== - {[ - fn f<'a>(px : &'a mut u32); - - > x -> mut_loan l0 - > px -> mut_borrow l0 (U32 0) - - f(move px); - - > x -> mut_loan l0 - > px -> ⊥ - > abs0 { a_mut_borrow l0 (U32 0) } - ]} - - The meta-value stores the initial value on which the projector was - applied, which reduced to this mut borrow. This meta-information - is only used for the synthesis. - TODO: do we really use it actually? - *) - | ASharedBorrow of (BorrowId.id[@opaque]) - (** A shared borrow owned by an abstraction. - - Example: - ======== - {[ - fn f<'a>(px : &'a u32); - - > x -> shared_loan {l0} (U32 0) - > px -> shared_borrow l0 - - f(move px); - - > x -> shared_loan {l0} (U32 0) - > px -> ⊥ - > abs0 { a_shared_borrow l0 } - ]} - *) - | AIgnoredMutBorrow of BorrowId.id option * typed_avalue - (** An ignored mutable borrow. - - We need to keep track of ignored mut borrows because when ending such - borrows, we need to project the loans of the given back value to - insert them in the proper abstractions. - - Note that we need to do so only for borrows consumed by parent - abstractions (hence the optional borrow id). - - TODO: the below explanations are obsolete - - Example: - ======== - {[ - fn f<'a,'b>(ppx : &'a mut &'b mut u32); - - > x -> mut_loan l0 - > px -> mut_loan l1 - > ppx -> mut_borrow l1 (mut_borrow l0 (U32 0)) - - f(move ppx); - - > x -> mut_loan l0 - > px -> mut_loan l1 - > ppx -> ⊥ - > abs'a { a_mut_borrow l1 (a_ignored_mut_borrow None (U32 0)) } // TODO: duplication - > abs'b {parents={abs'a}} { a_ignored_mut_borrow (Some l1) (a_mut_borrow l0 (U32 0)) } - - ... // abs'a ends - - > x -> mut_loan l0 - > px -> @s0 - > ppx -> ⊥ - > abs'b { - > a_ended_ignored_mut_borrow (a_proj_loans (@s0 <: &'b mut u32)) // <-- loan projector - > (a_mut_borrow l0 (U32 0)) - > } - - ... // [@s0] gets expanded to [&mut l2 @s1] - - > x -> mut_loan l0 - > px -> &mut l2 @s1 - > ppx -> ⊥ - > abs'b { - > a_ended_ignored_mut_borrow (a_mut_loan l2) // <-- loan l2 is here - > (a_mut_borrow l0 (U32 0)) - > } - - ]} - - Note that we could use AIgnoredMutLoan in the case the borrow id is not - None, which would allow us to simplify the rules (to not have rules - to specifically handle the case of AIgnoredMutBorrow with Some borrow - id) and also remove the AEndedIgnoredMutBorrow variant. - For now, the rules are implemented and it allows us to make the avalues - more precise and clearer, so we will keep it that way. - - TODO: this is annoying, we are duplicating information. Maybe we - could introduce an "Ignored" value? We have to pay attention to - two things: - - introducing ⊥ when ignoring a value is not always possible, because - we check whether the borrowed value contains ⊥ when giving back a - borrowed value (if it is the case we give back ⊥, otherwise we - introduce a symbolic value). This is necessary when ending nested - borrows with the same lifetime: when ending the inner borrow we - actually give back a value, however when ending the outer borrow - we need to give back ⊥. - TODO: actually we don't do that anymore, we check if the borrowed - avalue contains ended regions (which is cleaner and more robust). - - we may need to remember the precise values given to the - abstraction so that we can properly call the backward functions - when generating the pure translation. - *) - | AEndedMutBorrow of msymbolic_value * typed_avalue - (** The sole purpose of {!AEndedMutBorrow} is to store the (symbolic) value - that we gave back as a meta-value, to help with the synthesis. - - We also remember the child {!avalue} because this structural information - is useful for the synthesis (but not for the symbolic execution): - in practice the child value should only contain ended borrows, ignored - values, bottom values, etc. - *) - | AEndedSharedBorrow - (** We don't really need {!AEndedSharedBorrow}: we simply want to be - precise, and not insert ⊥ when ending borrows. - *) - | AEndedIgnoredMutBorrow of { - child : typed_avalue; - given_back_loans_proj : typed_avalue; - given_back_meta : msymbolic_value; - (** [given_back_meta] is used to store the (symbolic) value we gave back - upon ending the borrow. - - Rk.: *DO NOT* use [visit_AEndedIgnoredMutLoan]. - See the comment for {!AEndedMutLoan}. - *) - } (** See the explanations for {!AIgnoredMutBorrow} *) - | AProjSharedBorrow of abstract_shared_borrows - (** A projected shared borrow. - - When giving shared borrows as arguments to function calls, we - introduce new borrows to keep track of the fact that the function - might reborrow values inside. Note that as shared values are immutable, - we don't really need to remember the structure of the shared values. - - Example: - ======== - Below, when calling [f], we need to introduce one shared borrow per - borrow in the argument. - {[ - fn f<'a,'b>(pppx : &'a &'b &'c mut u32); - - > x -> mut_loan l0 - > px -> shared_loan {l1} (mut_borrow l0 (U32 0)) - > ppx -> shared_loan {l2} (shared_borrow l1) - > pppx -> shared_borrow l2 - - f(move pppx); - - > x -> mut_loan l0 - > px -> shared_loan {l1, l3, l4} (mut_borrow l0 (U32 0)) - > ppx -> shared_loan {l2} (shared_borrow l1) - > pppx -> ⊥ - > abs'a { a_proj_shared_borrow {l2} } - > abs'b { a_proj_shared_borrow {l3} } // l3 reborrows l1 - > abs'c { a_proj_shared_borrow {l4} } // l4 reborrows l0 - ]} - *) - -(* TODO: the type of avalues doesn't make sense for loan avalues: they currently - are typed as [& (mut) T] instead of [T]... -*) -and typed_avalue = { value : avalue; ty : rty } -[@@deriving - show, - visitors - { - name = "iter_typed_avalue"; - variety = "iter"; - ancestors = [ "iter_typed_avalue_base" ]; - nude = true (* Don't inherit {!VisitorsRuntime.iter} *); - concrete = true; - }, - visitors - { - name = "map_typed_avalue"; - variety = "map"; - ancestors = [ "map_typed_avalue_base" ]; - nude = true (* Don't inherit {!VisitorsRuntime.iter} *); - concrete = true; - }] - -(** The kind of an abstraction, which keeps track of its origin *) -type abs_kind = - | FunCall (** The abstraction was introduced because of a function call *) - | SynthInput - (** The abstraction keeps track of the input values of the function - we are currently synthesizing. *) - | SynthRet - (** The abstraction "absorbed" the value returned by the function we - are currently synthesizing *) -[@@deriving show] - -(** Abstractions model the parts in the borrow graph where the borrowing relations - have been abstracted because of a function call. - - In order to model the relations between the borrows, we use "abstraction values", - which are a special kind of value. -*) -type abs = { - abs_id : (AbstractionId.id[@opaque]); - call_id : (FunCallId.id[@opaque]); - (** The identifier of the function call which introduced this - abstraction. This is not used by the symbolic execution: - this is only used for pretty-printing and debugging, in the - symbolic AST, generated by the symbolic execution. - *) - back_id : (RegionGroupId.id[@opaque]); - (** The region group id to which this abstraction is linked. - - In most situations, it gives the id of the backward function (hence - the name), but it is a bit more subtle in the case of synth input - and synth ret abstractions. - - This is not used by the symbolic execution: it is a utility for - the symbolic AST, generated by the symbolic execution. - *) - kind : (abs_kind[@opaque]); - can_end : (bool[@opaque]); - (** Controls whether the region can be ended or not. - - This allows to "pin" some regions, and is useful when generating - backward functions. - - For instance, if we have: [fn f<'a, 'b>(...) -> (&'a mut T, &'b mut T)], - when generating the backward function for 'a, we have to make sure we - don't need to end the return region for 'b (if it is the case, it means - the function doesn't borrow check). - *) - parents : (AbstractionId.Set.t[@opaque]); (** The parent abstractions *) - original_parents : (AbstractionId.id list[@opaque]); - (** The original list of parents, ordered. This is used for synthesis. *) - regions : (RegionId.Set.t[@opaque]); (** Regions owned by this abstraction *) - ancestors_regions : (RegionId.Set.t[@opaque]); - (** Union of the regions owned by this abstraction's ancestors (not - including the regions of this abstraction itself) *) - avalues : typed_avalue list; (** The values in this abstraction *) -} -[@@deriving - show, - visitors - { - name = "iter_abs"; - variety = "iter"; - ancestors = [ "iter_typed_avalue" ]; - nude = true (* Don't inherit {!VisitorsRuntime.iter} *); - concrete = true; - }, - visitors - { - name = "map_abs"; - variety = "map"; - ancestors = [ "map_typed_avalue" ]; - nude = true (* Don't inherit {!VisitorsRuntime.iter} *); - concrete = true; - }] - -(** A symbolic expansion - - A symbolic expansion doesn't represent a value, but rather an operation - that we apply to values. - - TODO: this should rather be name "expanded_symbolic" - *) -type symbolic_expansion = - | SeConcrete of constant_value - | SeAdt of (VariantId.id option * symbolic_value list) - | SeMutRef of BorrowId.id * symbolic_value - | SeSharedRef of BorrowId.Set.t * symbolic_value |