Skip to content

Commit

Permalink
[infer/py] adding support for BUILD_TUPLE and BUILD_SET
Browse files Browse the repository at this point in the history
Summary: BUILD_TUPLE and BUILD_SET are virtually clones of the already implemented BUILD_LIST

Reviewed By: ngorogiannis

Differential Revision: D49369159

fbshipit-source-id: feb0ba1f24fe266cfbc79680e90c52f962caeee7
  • Loading branch information
Vincent Siles authored and facebook-github-bot committed Sep 20, 2023
1 parent ffb414a commit f0d9ccd
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 2 deletions.
10 changes: 10 additions & 0 deletions infer/src/python/PyBuiltin.ml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ module Builtin = struct
| PythonIter
| PythonIterNext
| PythonBuildList
| PythonBuildSet
| PythonBuildTuple
| PythonSubscriptGet
| PythonSubscriptSet
| CompareOp of Compare.t
Expand Down Expand Up @@ -158,6 +160,10 @@ let to_proc_name = function
"python_iter_next"
| PythonBuildList ->
"python_build_list"
| PythonBuildSet ->
"python_build_set"
| PythonBuildTuple ->
"python_build_tuple"
| PythonSubscriptGet ->
"python_subscript_get"
| PythonSubscriptSet ->
Expand Down Expand Up @@ -298,6 +304,10 @@ module Set = struct
; used_struct_types= [PyCommon.pyIterItemStruct] } )
; ( Builtin.PythonBuildList
, {formals_types= None; result_type= annot PyCommon.pyList; used_struct_types= []} )
; ( Builtin.PythonBuildSet
, {formals_types= None; result_type= annot PyCommon.pySet; used_struct_types= []} )
; ( Builtin.PythonBuildTuple
, {formals_types= None; result_type= annot PyCommon.pyTuple; used_struct_types= []} )
; ( Builtin.PythonSubscriptGet
, { formals_types= Some [annotatedObject; annotatedObject]
; result_type= annotatedObject
Expand Down
2 changes: 2 additions & 0 deletions infer/src/python/PyBuiltin.mli
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ type textual =
| PythonIter
| PythonIterNext
| PythonBuildList
| PythonBuildSet
| PythonBuildTuple
| PythonSubscriptGet
| PythonSubscriptSet
| CompareOp of Compare.t
Expand Down
4 changes: 4 additions & 0 deletions infer/src/python/PyCommon.ml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ let pyClass = mk_type "PyClass"

let pyList = mk_type "PyList"

let pySet = mk_type "PySet"

let pyTuple = mk_type "PyTuple"

let py_iter_item = type_name "PyIterItem"

let pyIterItem = T.Typ.Ptr (Struct py_iter_item)
Expand Down
6 changes: 6 additions & 0 deletions infer/src/python/PyCommon.mli
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ val pyNone : Textual.Typ.t
val pyList : Textual.Typ.t
(** Python's builtin [list] type *)

val pySet : Textual.Typ.t
(** Python's builtin [set] type *)

val pyTuple : Textual.Typ.t
(** Python's builtin [tuple] type *)

val mk_int : int64 -> Textual.Exp.t
(** Helper function to define typed Textual expression for literal integers. *)

Expand Down
38 changes: 36 additions & 2 deletions infer/src/python/PyTrans.ml
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ let rec py_to_exp env c =
Ok (env, e) )
in
let exp = T.Exp.call_non_virtual PyCommon.python_tuple args in
Ok (env, exp, PyCommon.pyObject)
Ok (env, exp, PyCommon.pyTuple)


let annotated_type_of_annotation typ =
Expand Down Expand Up @@ -1201,7 +1201,7 @@ module BUILD = struct
module LIST = struct
(** {v BUILD_LIST(count) v}
Creates a list consuming count items from the stack, and pushes the resulting tuple onto the
Creates a list consuming count items from the stack, and pushes the resulting list onto the
stack. *)
let run env code {FFI.Instruction.opname; arg= count} =
let open IResult.Let_syntax in
Expand All @@ -1212,6 +1212,36 @@ module BUILD = struct
let env = Env.push env (DataStack.Temp id) in
Ok (env, None)
end

module SET = struct
(** {v BUILD_SET(count) v}
Creates a set consuming count items from the stack, and pushes the resulting set onto the
stack. *)
let run env code {FFI.Instruction.opname; arg= count} =
let open IResult.Let_syntax in
Debug.p "[%s] count = %d\n" opname count ;
let* env, items = pop_n_datastack opname env count in
let* env, items = cells_to_textual env code items in
let env, id, _typ = Env.mk_builtin_call env Builtin.PythonBuildSet items in
let env = Env.push env (DataStack.Temp id) in
Ok (env, None)
end

module TUPLE = struct
(** {v BUILD_TUPLE(count) v}
Creates a tuple consuming count items from the stack, and pushes the resulting tuple onto
the stack. *)
let run env code {FFI.Instruction.opname; arg= count} =
let open IResult.Let_syntax in
Debug.p "[%s] count = %d\n" opname count ;
let* env, items = pop_n_datastack opname env count in
let* env, items = cells_to_textual env code items in
let env, id, _typ = Env.mk_builtin_call env Builtin.PythonBuildTuple items in
let env = Env.push env (DataStack.Temp id) in
Ok (env, None)
end
end

(** Return the offset of the next opcode, if any *)
Expand Down Expand Up @@ -1768,6 +1798,10 @@ let run_instruction env code ({FFI.Instruction.opname; starts_line} as instr) ne
JUMP.IF_OR_POP.run ~jump_if:false env code instr next_offset_opt
| "BUILD_LIST" ->
BUILD.LIST.run env code instr
| "BUILD_SET" ->
BUILD.SET.run env code instr
| "BUILD_TUPLE" ->
BUILD.TUPLE.run env code instr
| "STORE_SUBSCR" ->
STORE.SUBSCR.run env code instr
| "BINARY_SUBSCR" ->
Expand Down
92 changes: 92 additions & 0 deletions infer/src/python/unit/PyTransTest.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2640,6 +2640,98 @@ l[x] = 10
declare $builtins.python_float(float) : *PyFloat
declare $builtins.python_int(int) : *PyInt |}]
let%expect_test _ =
let source =
{|
t = (1, 2, 3) # will be a constant, not a BUILD_TUPLE
def f(x, y, z):
return (x, y, z) # should be BUILD_TUPLE
|}
in
test source ;
[%expect
{|
.source_language = "python"
define dummy.$toplevel() : *PyNone {
#b0:
store &dummy::t <- $builtins.python_tuple($builtins.python_int(1), $builtins.python_int(2), $builtins.python_int(3)):*PyTuple
n0 = $builtins.python_code("dummy.f")
ret null
}
define dummy.f(x: *PyObject, y: *PyObject, z: *PyObject) : *PyObject {
#b0:
n0:*PyObject = load &x
n1:*PyObject = load &y
n2:*PyObject = load &z
n3 = $builtins.python_build_tuple(n0, n1, n2)
ret n3
}
global dummy::t: *PyObject
global $python_implicit_names::__name__: *PyString
global $python_implicit_names::__file__: *PyString
declare $builtins.python_build_tuple(...) : *PyTuple
declare $builtins.python_code(*String) : *PyCode
declare $builtins.python_tuple(...) : *PyObject
declare $builtins.python_bytes(*Bytes) : *PyBytes
declare $builtins.python_string(*String) : *PyString
declare $builtins.python_bool(int) : *PyBool
declare $builtins.python_float(float) : *PyFloat
declare $builtins.python_int(int) : *PyInt |}]
let%expect_test _ =
let source = {|
s = {1, 2, 3}
|} in
test source ;
[%expect
{|
.source_language = "python"
define dummy.$toplevel() : *PyNone {
#b0:
n0 = $builtins.python_build_set($builtins.python_int(1), $builtins.python_int(2), $builtins.python_int(3))
store &dummy::s <- n0:*PySet
ret null
}
global dummy::s: *PyObject
global $python_implicit_names::__name__: *PyString
global $python_implicit_names::__file__: *PyString
declare $builtins.python_build_set(...) : *PySet
declare $builtins.python_tuple(...) : *PyObject
declare $builtins.python_bytes(*Bytes) : *PyBytes
declare $builtins.python_string(*String) : *PyString
declare $builtins.python_bool(int) : *PyBool
declare $builtins.python_float(float) : *PyFloat
declare $builtins.python_int(int) : *PyInt |}]
end )
Expand Down

0 comments on commit f0d9ccd

Please sign in to comment.