Skip to content

Commit

Permalink
[erlang] Add field about first usage in variable scope
Browse files Browse the repository at this point in the history
Summary: During scope pre-analysis, mark first usages of a variable. This way, later we'll know if in a pattern it needs to be translated as an equality check or an assignment.

Reviewed By: rgrig

Differential Revision: D62127340

fbshipit-source-id: 90a705a16547ad0f1bbdefdb47fbd5a8c9d0944b
  • Loading branch information
hajduakos authored and facebook-github-bot committed Sep 9, 2024
1 parent 2030d03 commit a29568a
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 11 deletions.
4 changes: 3 additions & 1 deletion infer/src/erlang/ErlangAst.ml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ type literal = Atom of string | Char of string | Float of float | Int of string

(** {2 S8.4: Expressions} *)

type scope = {procname: (Procname.t[@sexp.opaque]); is_first_use: bool} [@@deriving sexp_of]

type body = expression list

and simple_expression =
Expand Down Expand Up @@ -104,7 +106,7 @@ and simple_expression =
| TryCatch of {body: body; ok_cases: case_clause list; catch_cases: catch_clause list; after: body}
| Tuple of expression list
| UnaryOperator of unary_operator * expression
| Variable of {vname: string; mutable scope: (Procname.t option[@sexp.opaque])}
| Variable of {vname: string; mutable scope: scope option}

and expression = {location: location; simple_expression: simple_expression}

Expand Down
12 changes: 8 additions & 4 deletions infer/src/erlang/ErlangScopes.ml
Original file line number Diff line number Diff line change
Expand Up @@ -172,20 +172,24 @@ let rec annotate_expression (env : (_, _) Env.t) lambda_cntr (scopes : scope lis
| Variable v -> (
match scopes with
| hd :: tl -> (
if String.Set.mem hd.locals v.vname then (
if String.equal "_" v.vname then (
(* The anonymus variable is always fresh in the local scope *)
v.scope <- Some {procname= hd.procname; is_first_use= true} ;
scopes )
else if String.Set.mem hd.locals v.vname then (
(* Known local var *)
v.scope <- Some hd.procname ;
v.scope <- Some {procname= hd.procname; is_first_use= false} ;
scopes )
else
(* Check if it's captured from outside *)
match lookup_var tl v.vname with
| Some procname ->
let pvar = Pvar.mk (Mangled.from_string v.vname) procname in
v.scope <- Some procname ;
v.scope <- Some {procname; is_first_use= false} ;
{hd with captured= Pvar.Set.add pvar hd.captured} :: tl
| None ->
(* It's a local we see here first *)
v.scope <- Some hd.procname ;
v.scope <- Some {procname= hd.procname; is_first_use= true} ;
{hd with locals= String.Set.add hd.locals v.vname} :: tl )
| [] ->
L.die InternalError "No scope found during variable annotation." )
Expand Down
12 changes: 6 additions & 6 deletions infer/src/erlang/ErlangTranslator.ml
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,10 @@ let unbox_integer env expr : Exp.t * Block.t =
(unboxed_expr, {start; exit_success= unbox_block.exit_success; exit_failure= Node.make_nop env})


let procname_exn scope =
let scope_exn (scope : Ast.scope option) =
match scope with
| Some name ->
name
| Some scope ->
scope
| None ->
(* Can happen e.g. if we have the _ variable in record field initializers (T134336886) *)
L.die InternalError "Scope not found for variable, probably missing annotation."
Expand Down Expand Up @@ -210,7 +210,7 @@ let vars_of_pattern p =
| UnaryOperator (_, e) ->
f acc e
| Variable {vname; scope} ->
let procname = procname_exn scope in
let procname = (scope_exn scope).procname in
Pvar.Set.add (Pvar.mk (Mangled.from_string vname) procname) acc
| Literal _ | Nil | RecordIndex _ ->
acc
Expand Down Expand Up @@ -523,7 +523,7 @@ and translate_pattern_number_expression (env : (_, _) Env.t) value location simp
and translate_pattern_variable (env : (_, _) Env.t) value vname scope : Block.t =
(* We also assign to _ so that stuff like f()->_=1. works. But if we start checking for
re-binding, we should exclude _ from such checks. *)
let procname = procname_exn scope in
let procname = (scope_exn scope).procname in
let store : Sil.instr =
let e1 : Exp.t = Lvar (Pvar.mk (Mangled.from_string vname) procname) in
let e2 : Exp.t = Var value in
Expand Down Expand Up @@ -1486,7 +1486,7 @@ and translate_expression_unary_operator (env : (_, _) Env.t) ret_var (op : Ast.u


and translate_expression_variable (env : (_, _) Env.t) ret_var vname scope : Block.t =
let procname = procname_exn scope in
let procname = (scope_exn scope).procname in
let e = Exp.Lvar (Pvar.mk (Mangled.from_string vname) procname) in
let load_instr = Sil.Load {id= ret_var; e; typ= any_typ; loc= env.location} in
Block.make_instruction env [load_instr]
Expand Down

0 comments on commit a29568a

Please sign in to comment.