Skip to content

Commit b0a7de9

Browse files
shannonzhufacebook-github-bot
authored andcommitted
Store temporary annotations when refinement is disallowed
Summary: On assignment for globals, start storing temporary type data on otherwise non-refinable values. Also start clearing all temporary type data whenever we see a call expression. Future diffs will add temporary type data on attributes, asserts, etc. patterns that also can set local types. Reviewed By: grievejia Differential Revision: D30381727 fbshipit-source-id: 870cbc35e9b907510c0b9fb843c2a037540e37dc
1 parent 610292f commit b0a7de9

File tree

6 files changed

+235
-130
lines changed

6 files changed

+235
-130
lines changed

source/analysis/resolution.ml

Lines changed: 65 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -133,25 +133,30 @@ let partition_name resolution ~name =
133133

134134

135135
let set_local
136+
?(temporary = false)
136137
({ annotation_store = { annotations; temporary_annotations }; _ } as resolution)
137138
~reference
138139
~annotation
139140
=
140-
{
141-
resolution with
142-
annotation_store =
143-
{
144-
annotations =
145-
Map.set
146-
annotations
147-
~key:reference
148-
~data:(RefinementUnit.create () |> RefinementUnit.set_base ~base:annotation);
149-
temporary_annotations;
150-
};
151-
}
141+
let annotations, temporary_annotations =
142+
if temporary then
143+
( annotations,
144+
Map.set
145+
temporary_annotations
146+
~key:reference
147+
~data:(RefinementUnit.create () |> RefinementUnit.set_base ~base:annotation) )
148+
else
149+
( Map.set
150+
annotations
151+
~key:reference
152+
~data:(RefinementUnit.create () |> RefinementUnit.set_base ~base:annotation),
153+
temporary_annotations )
154+
in
155+
{ resolution with annotation_store = { annotations; temporary_annotations } }
152156

153157

154158
let set_local_with_attributes
159+
?(temporary = false)
155160
({ annotation_store = { annotations; temporary_annotations }; _ } as resolution)
156161
~name
157162
~annotation
@@ -162,30 +167,41 @@ let set_local_with_attributes
162167
| None, Some base -> RefinementUnit.set_base refinement_unit ~base
163168
| _ -> refinement_unit
164169
in
165-
{
166-
resolution with
167-
annotation_store =
168-
{
169-
annotations =
170-
Map.set
171-
annotations
172-
~key:object_reference
173-
~data:
174-
(Map.find annotations object_reference
175-
|> Option.value ~default:(RefinementUnit.create ())
176-
|> RefinementUnit.add_attribute_refinement ~reference:attribute_path ~base:annotation
177-
|> set_base ~base);
178-
temporary_annotations;
179-
};
180-
}
170+
let annotations, temporary_annotations =
171+
if temporary then
172+
( annotations,
173+
Map.set
174+
temporary_annotations
175+
~key:object_reference
176+
~data:
177+
(Map.find temporary_annotations object_reference
178+
|> (fun existing -> Option.first_some existing (Map.find annotations object_reference))
179+
|> Option.value ~default:(RefinementUnit.create ())
180+
|> RefinementUnit.add_attribute_refinement ~reference:attribute_path ~base:annotation
181+
|> set_base ~base) )
182+
else
183+
( Map.set
184+
annotations
185+
~key:object_reference
186+
~data:
187+
(Map.find annotations object_reference
188+
|> Option.value ~default:(RefinementUnit.create ())
189+
|> RefinementUnit.add_attribute_refinement ~reference:attribute_path ~base:annotation
190+
|> set_base ~base),
191+
temporary_annotations )
192+
in
193+
{ resolution with annotation_store = { annotations; temporary_annotations } }
181194

182195

183196
let get_local
184197
?(global_fallback = true)
185198
~reference
186-
({ annotation_store = { annotations; _ }; global_resolution; _ } as resolution)
199+
({ annotation_store = { annotations; temporary_annotations }; global_resolution; _ } as
200+
resolution)
187201
=
188-
match Map.find annotations reference with
202+
match
203+
Option.first_some (Map.find temporary_annotations reference) (Map.find annotations reference)
204+
with
189205
| Some result when global_fallback || not (is_global resolution ~reference) ->
190206
RefinementUnit.base result
191207
| _ when global_fallback ->
@@ -197,10 +213,15 @@ let get_local
197213
let get_local_with_attributes
198214
?(global_fallback = true)
199215
~name
200-
({ annotation_store = { annotations; _ }; global_resolution; _ } as resolution)
216+
({ annotation_store = { annotations; temporary_annotations }; global_resolution; _ } as
217+
resolution)
201218
=
202219
let object_reference, attribute_path, _ = partition_name resolution ~name in
203-
match Map.find annotations object_reference with
220+
match
221+
Option.first_some
222+
(Map.find temporary_annotations object_reference)
223+
(Map.find annotations object_reference)
224+
with
204225
| Some result when global_fallback || not (is_global resolution ~reference:object_reference) ->
205226
RefinementUnit.annotation result ~reference:attribute_path
206227
| _ when global_fallback ->
@@ -217,7 +238,18 @@ let unset_local
217238
=
218239
{
219240
resolution with
220-
annotation_store = { annotations = Map.remove annotations reference; temporary_annotations };
241+
annotation_store =
242+
{
243+
annotations = Map.remove annotations reference;
244+
temporary_annotations = Map.remove temporary_annotations reference;
245+
};
246+
}
247+
248+
249+
let clear_temporary_annotations ({ annotation_store; _ } as resolution) =
250+
{
251+
resolution with
252+
annotation_store = { annotation_store with temporary_annotations = Reference.Map.empty };
221253
}
222254

223255

source/analysis/resolution.mli

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,14 @@ val resolve_attribute_access : t -> base_type:Type.t -> attribute:string -> Type
5555

5656
val partition_name : t -> name:Expression.Name.t -> Reference.t * Reference.t * Annotation.t option
5757

58-
val set_local : t -> reference:Reference.t -> annotation:Annotation.t -> t
58+
val set_local : ?temporary:bool -> t -> reference:Reference.t -> annotation:Annotation.t -> t
5959

60-
val set_local_with_attributes : t -> name:Expression.Name.t -> annotation:Annotation.t -> t
60+
val set_local_with_attributes
61+
: ?temporary:bool ->
62+
t ->
63+
name:Expression.Name.t ->
64+
annotation:Annotation.t ->
65+
t
6166

6267
val get_local : ?global_fallback:bool -> reference:Reference.t -> t -> Annotation.t option
6368

@@ -69,6 +74,8 @@ val get_local_with_attributes
6974

7075
val unset_local : t -> reference:Reference.t -> t
7176

77+
val clear_temporary_annotations : t -> t
78+
7279
val is_global : t -> reference:Reference.t -> bool
7380

7481
val add_type_variable : t -> variable:Type.Variable.t -> t

source/analysis/test/integration/annotationTest.ml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -743,10 +743,7 @@ let test_check_immutable_annotations context =
743743
constant: str
744744
constant = "hi"
745745
|}
746-
[
747-
"Incompatible variable type [9]: constant is declared to have type `int` but is used as type \
748-
`str`.";
749-
];
746+
[];
750747
assert_type_errors
751748
{|
752749
import typing

source/analysis/test/integration/refinementTest.ml

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,10 @@ let test_check_global_refinement context =
386386
if x is not None:
387387
reveal_type(x)
388388
|}
389-
["Revealed type [-1]: Revealed type for `x` is `typing.Optional[int]`."]
389+
[
390+
"Revealed type [-1]: Revealed type for `x` is `typing.Optional[int]` (inferred: \
391+
`typing_extensions.Literal[1]`).";
392+
]
390393

391394

392395
let test_check_local_refinement context =
@@ -1018,6 +1021,32 @@ let test_check_final_attribute_refinement context =
10181021
()
10191022

10201023

1024+
let test_check_temporary_refinement context =
1025+
let assert_type_errors = assert_type_errors ~context in
1026+
assert_type_errors
1027+
{|
1028+
MY_GLOBAL = 1.0
1029+
1030+
def arbitrary_call() -> None:
1031+
pass
1032+
1033+
def test() -> None:
1034+
reveal_type(MY_GLOBAL)
1035+
global MY_GLOBAL
1036+
MY_GLOBAL = 1
1037+
reveal_type(MY_GLOBAL)
1038+
arbitrary_call()
1039+
reveal_type(MY_GLOBAL)
1040+
|}
1041+
[
1042+
"Revealed type [-1]: Revealed type for `MY_GLOBAL` is `float`.";
1043+
"Revealed type [-1]: Revealed type for `MY_GLOBAL` is `float` (inferred: \
1044+
`typing_extensions.Literal[1]`).";
1045+
"Revealed type [-1]: Revealed type for `MY_GLOBAL` is `float`.";
1046+
];
1047+
()
1048+
1049+
10211050
let () =
10221051
"refinement"
10231052
>::: [
@@ -1029,5 +1058,6 @@ let () =
10291058
"check_assert_contains_none" >:: test_assert_contains_none;
10301059
"check_callable" >:: test_check_callable;
10311060
"check_final_attribute_refinement" >:: test_check_final_attribute_refinement;
1061+
"check_temporary_refinement" >:: test_check_temporary_refinement;
10321062
]
10331063
|> Test.run

source/analysis/test/integration/revealTypeTest.ml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,10 @@ let test_reveal_type context =
126126
x = 1
127127
reveal_type(x)
128128
|}
129-
["Revealed type [-1]: Revealed type for `x` is `float`."];
129+
[
130+
"Revealed type [-1]: Revealed type for `x` is `float` (inferred: \
131+
`typing_extensions.Literal[1]`).";
132+
];
130133
assert_type_errors
131134
{|
132135
import typing

0 commit comments

Comments
 (0)