Skip to content

Commit 8901d71

Browse files
stroxlerfacebook-github-bot
authored andcommitted
Rework some of the target.rs plumbing
Summary: This diff doesn't actually do anything, but it pushes the decision about whether to operate on a `Binding` vs an `ExprOrBinding` a bit closer to the caller (without changing any of the public APIs) This will eventually be portant for determinism: I eventually need `bind_targets_with_value` to pass a callback rather than a raw value, because that's the only way that I'll be able to make the `ensure_expr` actually track usage for first-usage-based type inference There's a sort of silly thing going on here where we wrap the result of `make_binding` in a `BindingOrExpr` and then unwrap it again, which is needed because the mutual recursion for unpacked targets combined with our best-effort attempt at contextual typing for attr and subscript assignments requires us to design `bind_target_impl` around the general case. This is a little messy but not a real problem, the wrapping and unwrapping is very cheap. Reviewed By: yangdanny97 Differential Revision: D75422385 fbshipit-source-id: b1a485a966d37c4d89ee37190dc5c6c42d3da2ca
1 parent 5126edf commit 8901d71

File tree

1 file changed

+17
-23
lines changed

1 file changed

+17
-23
lines changed

pyrefly/lib/binding/target.rs

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,7 @@ impl<'a> BindingsBuilder<'a> {
176176
fn bind_target_impl(
177177
&mut self,
178178
target: &mut Expr,
179-
make_binding: &dyn Fn(Option<Idx<KeyAnnotation>>) -> Binding,
180-
value: Option<&Expr>,
179+
make_assigned_value: &dyn Fn(Option<Idx<KeyAnnotation>>) -> ExprOrBinding,
181180
is_aug_assign: bool,
182181
) {
183182
if is_aug_assign && let Expr::Name(name) = target {
@@ -191,18 +190,13 @@ impl<'a> BindingsBuilder<'a> {
191190
// a mutation.
192191
self.ensure_expr(target);
193192
}
193+
let make_binding = &|ann| match make_assigned_value(ann) {
194+
ExprOrBinding::Expr(e) => Binding::Expr(ann, e),
195+
ExprOrBinding::Binding(b) => b,
196+
};
194197
match target {
195198
Expr::Name(name) => self.bind_assign(name, make_binding, FlowStyle::None),
196199
Expr::Attribute(x) => {
197-
// `make_binding` will give us a binding for inferring the value type, which we
198-
// *might* use to compute the attribute type if there are no explicit annotations.
199-
let make_assigned_value = |ann| {
200-
if let Some(value) = value {
201-
ExprOrBinding::Expr(value.clone())
202-
} else {
203-
ExprOrBinding::Binding(make_binding(ann))
204-
}
205-
};
206200
// Create a binding to verify that the assignment is valid and potentially narrow
207201
// the name assigned to.
208202
let attr_value = self.bind_attr_assign(x.clone(), make_assigned_value);
@@ -211,13 +205,6 @@ impl<'a> BindingsBuilder<'a> {
211205
self.scopes.record_self_attr_assign(x, attr_value, None);
212206
}
213207
Expr::Subscript(x) => {
214-
let make_assigned_value = |ann| {
215-
if let Some(value) = value {
216-
ExprOrBinding::Expr(value.clone())
217-
} else {
218-
ExprOrBinding::Binding(make_binding(ann))
219-
}
220-
};
221208
// Create a binding to verify that the assignment is valid and potentially narrow
222209
// the name assigned to.
223210
self.bind_subscript_assign(x.clone(), make_assigned_value);
@@ -234,7 +221,7 @@ impl<'a> BindingsBuilder<'a> {
234221
"Starred assignment target must be in a list or tuple".to_owned(),
235222
ErrorKind::InvalidSyntax,
236223
);
237-
self.bind_target_impl(&mut x.value, make_binding, value, false);
224+
self.bind_target_impl(&mut x.value, make_assigned_value, false);
238225
}
239226
illegal_target => {
240227
// Most structurally invalid targets become errors in the parser, which we propagate so there
@@ -250,7 +237,10 @@ impl<'a> BindingsBuilder<'a> {
250237
target: &mut Expr,
251238
make_binding: &dyn Fn(Option<Idx<KeyAnnotation>>) -> Binding,
252239
) {
253-
self.bind_target_impl(target, make_binding, None, false);
240+
// TODO(stroxler): Clean this up: we're wrapping the binding and then just unwrapping it later.
241+
// Forcing all callers to produce an `ExprOrBinding` will also help us improve contextual typing.
242+
let make_assigned_value = &|ann| ExprOrBinding::Binding(make_binding(ann));
243+
self.bind_target_impl(target, make_assigned_value, false);
254244
}
255245

256246
/// Similar to `bind_target`, but specifically for assignments:
@@ -260,9 +250,10 @@ impl<'a> BindingsBuilder<'a> {
260250
/// a method (like descriptor attribute assigns and `__setitem__` calls).
261251
pub fn bind_targets_with_value(&mut self, targets: &mut Vec<Expr>, value: &mut Expr) {
262252
self.ensure_expr(value);
263-
let make_binding = |ann: Option<Idx<KeyAnnotation>>| Binding::Expr(ann, value.clone());
253+
let make_assigned_value =
254+
&|_: Option<Idx<KeyAnnotation>>| ExprOrBinding::Expr(value.clone());
264255
for target in targets {
265-
self.bind_target_impl(target, &make_binding, Some(value), false);
256+
self.bind_target_impl(target, make_assigned_value, false);
266257
}
267258
}
268259

@@ -271,6 +262,9 @@ impl<'a> BindingsBuilder<'a> {
271262
target: &mut Expr,
272263
make_binding: &dyn Fn(Option<Idx<KeyAnnotation>>) -> Binding,
273264
) {
265+
// TODO(stroxler): Clean this up: we're wrapping the binding and then just unwrapping it later.
266+
// Forcing all callers to produce an `ExprOrBinding` will also help us improve contextual typing.
267+
let make_assigned_value = &|ann| ExprOrBinding::Binding(make_binding(ann));
274268
// A normal target should not ensure top level `Name`, since it will *define*
275269
// that name (overwriting any previous value) but an `AugAssign` is a mutation
276270
// (possibly in place, possibly overwriting) of an existing value so we do
@@ -279,7 +273,7 @@ impl<'a> BindingsBuilder<'a> {
279273
// AugAssign cannot be used with multi-target assignment so it does not interact
280274
// with the `bind_unpacking` recursion (if a user attempts to do so, we'll throw
281275
// an error and otherwise treat it as a normal assignment from a binding standpoint).
282-
self.bind_target_impl(target, make_binding, None, true);
276+
self.bind_target_impl(target, make_assigned_value, true);
283277
}
284278

285279
pub fn bind_assign(

0 commit comments

Comments
 (0)