Skip to content

Commit

Permalink
Add plumbing for send type inference
Browse files Browse the repository at this point in the history
Summary:
Here, we add the keys and bindings needed for send type inference.

The only thing that remains is:

In answers.rs for the   `Binding::SendTypeOfYield(_)`, we must lookup the return annotation and extract the send type from there if it exists.

The key would be                 `&KeyAnnotation::ReturnAnnotation(function_name.clone())`. However, using self.get to retrieve the annotation causes panic if the key is not found.

It looks like we can consider  `std::panic::catch_unwind` but it seems this is unsafe behavior.

Should we modify the `get` method to return an optional?

This is something to address next. Once we do this, the send type will be correctly inferred.

Reviewed By: stroxler

Differential Revision: D68468322

fbshipit-source-id: 4464a1159defed48062d5747ac4e63a237ae3a81
  • Loading branch information
migeed-z authored and facebook-github-bot committed Jan 22, 2025
1 parent 277952f commit ca8fa3d
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 208 deletions.
170 changes: 0 additions & 170 deletions pyre2/conformance/third_party/conformance.exp
Original file line number Diff line number Diff line change
Expand Up @@ -1648,16 +1648,6 @@
}
],
"annotations_generators.py": [
{
"code": -2,
"column": 9,
"concise_description": "TODO: ExprYield - Answers::expr_infer",
"description": "TODO: ExprYield - Answers::expr_infer",
"line": 46,
"name": "PyreError",
"stop_column": 18,
"stop_line": 46
},
{
"code": -2,
"column": 16,
Expand All @@ -1678,106 +1668,6 @@
"stop_column": 16,
"stop_line": 57
},
{
"code": -2,
"column": 9,
"concise_description": "TODO: ExprYield - Answers::expr_infer",
"description": "TODO: ExprYield - Answers::expr_infer",
"line": 57,
"name": "PyreError",
"stop_column": 16,
"stop_line": 57
},
{
"code": -2,
"column": 9,
"concise_description": "TODO: ExprYield - Answers::expr_infer",
"description": "TODO: ExprYield - Answers::expr_infer",
"line": 66,
"name": "PyreError",
"stop_column": 16,
"stop_line": 66
},
{
"code": -2,
"column": 5,
"concise_description": "TODO: ExprYield - Answers::expr_infer",
"description": "TODO: ExprYield - Answers::expr_infer",
"line": 70,
"name": "PyreError",
"stop_column": 14,
"stop_line": 70
},
{
"code": -2,
"column": 5,
"concise_description": "TODO: ExprYield - Answers::expr_infer",
"description": "TODO: ExprYield - Answers::expr_infer",
"line": 75,
"name": "PyreError",
"stop_column": 14,
"stop_line": 75
},
{
"code": -2,
"column": 5,
"concise_description": "TODO: ExprYield - Answers::expr_infer",
"description": "TODO: ExprYield - Answers::expr_infer",
"line": 79,
"name": "PyreError",
"stop_column": 10,
"stop_line": 79
},
{
"code": -2,
"column": 5,
"concise_description": "TODO: ExprYield - Answers::expr_infer",
"description": "TODO: ExprYield - Answers::expr_infer",
"line": 83,
"name": "PyreError",
"stop_column": 18,
"stop_line": 83
},
{
"code": -2,
"column": 5,
"concise_description": "TODO: ExprYield - Answers::expr_infer",
"description": "TODO: ExprYield - Answers::expr_infer",
"line": 87,
"name": "PyreError",
"stop_column": 15,
"stop_line": 87
},
{
"code": -2,
"column": 5,
"concise_description": "TODO: ExprYield - Answers::expr_infer",
"description": "TODO: ExprYield - Answers::expr_infer",
"line": 92,
"name": "PyreError",
"stop_column": 15,
"stop_line": 92
},
{
"code": -2,
"column": 5,
"concise_description": "TODO: ExprYield - Answers::expr_infer",
"description": "TODO: ExprYield - Answers::expr_infer",
"line": 101,
"name": "PyreError",
"stop_column": 12,
"stop_line": 101
},
{
"code": -2,
"column": 5,
"concise_description": "TODO: ExprYield - Answers::expr_infer",
"description": "TODO: ExprYield - Answers::expr_infer",
"line": 110,
"name": "PyreError",
"stop_column": 12,
"stop_line": 110
},
{
"code": -2,
"column": 5,
Expand Down Expand Up @@ -1828,16 +1718,6 @@
"stop_column": 19,
"stop_line": 119
},
{
"code": -2,
"column": 16,
"concise_description": "TODO: ExprYield - Answers::expr_infer",
"description": "TODO: ExprYield - Answers::expr_infer",
"line": 123,
"name": "PyreError",
"stop_column": 21,
"stop_line": 123
},
{
"code": -2,
"column": 5,
Expand All @@ -1858,16 +1738,6 @@
"stop_column": 29,
"stop_line": 127
},
{
"code": -2,
"column": 16,
"concise_description": "TODO: ExprYield - Answers::expr_infer",
"description": "TODO: ExprYield - Answers::expr_infer",
"line": 131,
"name": "PyreError",
"stop_column": 21,
"stop_line": 131
},
{
"code": -2,
"column": 5,
Expand All @@ -1888,26 +1758,6 @@
"stop_column": 29,
"stop_line": 135
},
{
"code": -2,
"column": 5,
"concise_description": "TODO: ExprYield - Answers::expr_infer",
"description": "TODO: ExprYield - Answers::expr_infer",
"line": 140,
"name": "PyreError",
"stop_column": 13,
"stop_line": 140
},
{
"code": -2,
"column": 5,
"concise_description": "TODO: ExprYield - Answers::expr_infer",
"description": "TODO: ExprYield - Answers::expr_infer",
"line": 145,
"name": "PyreError",
"stop_column": 13,
"stop_line": 145
},
{
"code": -2,
"column": 5,
Expand Down Expand Up @@ -1978,16 +1828,6 @@
"stop_column": 30,
"stop_line": 160
},
{
"code": -2,
"column": 9,
"concise_description": "TODO: ExprYield - Answers::expr_infer",
"description": "TODO: ExprYield - Answers::expr_infer",
"line": 161,
"name": "PyreError",
"stop_column": 35,
"stop_line": 161
},
{
"code": -2,
"column": 5,
Expand Down Expand Up @@ -2038,16 +1878,6 @@
"stop_column": 30,
"stop_line": 179
},
{
"code": -2,
"column": 5,
"concise_description": "TODO: ExprYield - Answers::expr_infer",
"description": "TODO: ExprYield - Answers::expr_infer",
"line": 187,
"name": "PyreError",
"stop_column": 10,
"stop_line": 187
},
{
"code": -2,
"column": 1,
Expand Down
17 changes: 5 additions & 12 deletions pyre2/conformance/third_party/conformance.result
Original file line number Diff line number Diff line change
Expand Up @@ -142,32 +142,25 @@
],
"annotations_generators.py": [
"Line 51: Expected 1 errors",
"Line 57: Expected 1 errors",
"Line 66: Expected 1 errors",
"Line 75: Expected 1 errors",
"Line 86: Expected 1 errors",
"Line 87: Expected 1 errors",
"Line 91: Expected 1 errors",
"Line 46: Unexpected errors ['TODO: ExprYield - Answers::expr_infer']",
"Line 92: Expected 1 errors",
"Line 56: Unexpected errors ['EXPECTED None <: C']",
"Line 70: Unexpected errors ['TODO: ExprYield - Answers::expr_infer']",
"Line 79: Unexpected errors ['TODO: ExprYield - Answers::expr_infer']",
"Line 83: Unexpected errors ['TODO: ExprYield - Answers::expr_infer']",
"Line 101: Unexpected errors ['TODO: ExprYield - Answers::expr_infer']",
"Line 110: Unexpected errors ['TODO: ExprYield - Answers::expr_infer']",
"Line 114: Unexpected errors ['EXPECTED None <: Iterator[A]', 'TODO: YieldFrom(ExprYieldFrom - Answers::expr_infer']",
"Line 123: Unexpected errors ['TODO: ExprYield - Answers::expr_infer']",
"Line 127: Unexpected errors ['EXPECTED None <: Generator[None, int, None]', 'TODO: YieldFrom(ExprYieldFrom - Answers::expr_infer']",
"Line 131: Unexpected errors ['TODO: ExprYield - Answers::expr_infer']",
"Line 140: Unexpected errors ['TODO: ExprYield - Answers::expr_infer']",
"Line 145: Unexpected errors ['TODO: ExprYield - Answers::expr_infer']",
"Line 149: Unexpected errors ['TODO: YieldFrom(ExprYieldFrom - Answers::expr_infer']",
"Line 150: Unexpected errors ['EXPECTED None <: Generator[int, None, None]', 'TODO: YieldFrom(ExprYieldFrom - Answers::expr_infer']",
"Line 154: Unexpected errors [\"Missing argument 'result'\", 'EXPECTED Literal[1] <: float']",
"Line 160: Unexpected errors [\"Missing argument 'result'\", 'EXPECTED Literal[1] <: float']",
"Line 161: Unexpected errors ['TODO: ExprYield - Answers::expr_infer']",
"Line 167: Unexpected errors ['assert_type(Coroutine[Any, Any, AsyncGenerator[str, None]], AsyncGenerator[str, None]) failed']",
"Line 168: Unexpected errors ['EXPECTED Coroutine[Unknown, Unknown, AsyncGenerator[str, None]] <: AsyncGenerator[str, None]']",
"Line 174: Unexpected errors ['assert_type(Coroutine[Any, Any, AsyncGenerator[str, None]], AsyncGenerator[str, None]) failed']",
"Line 175: Unexpected errors ['EXPECTED Coroutine[Unknown, Unknown, AsyncGenerator[str, None]] <: AsyncIterator[str]']",
"Line 179: Unexpected errors ['EXPECTED None <: AsyncIterator[int]']",
"Line 187: Unexpected errors ['TODO: ExprYield - Answers::expr_infer']",
"Line 190: Unexpected errors ['assert_type(Callable[[], Coroutine[Any, Any, AsyncIterator[int]]], Callable[[], AsyncIterator[int]]) failed']"
],
"annotations_methods.py": [
Expand Down
4 changes: 2 additions & 2 deletions pyre2/conformance/third_party/results.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"pass": 9,
"fail": 124,
"pass_rate": 0.07,
"differences": 1348,
"differences": 1341,
"passing": [
"annotations_coroutines.py",
"directives_no_type_check.py",
Expand All @@ -24,7 +24,7 @@
"aliases_typealiastype.py": 25,
"aliases_variance.py": 3,
"annotations_forward_refs.py": 10,
"annotations_generators.py": 28,
"annotations_generators.py": 21,
"annotations_methods.py": 9,
"annotations_typeexpr.py": 6,
"callables_annotation.py": 26,
Expand Down
2 changes: 2 additions & 0 deletions pyre2/pyre2/bin/alt/answers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1076,6 +1076,8 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
.generator(yield_type, Type::any_implicit(), return_type)
.to_type()
}
// TODO: Zeina, here we must construct a ReturnAnnotation key and look it up. The lookup will panic if key is not found. Figure out how to handle the failure.
Binding::SendTypeOfYield(_) => Type::any_explicit(),
Binding::ReturnExpr(ann, e, has_yields) => {
let ann = ann.map(|k| self.get_idx(k));
let hint = ann.as_ref().and_then(|x| x.ty.as_ref());
Expand Down
3 changes: 2 additions & 1 deletion pyre2/pyre2/bin/alt/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1086,7 +1086,8 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
None => self.error(x.range, "Expression is not awaitable".to_owned()),
}
}
Expr::Yield(x) => self.error_todo("Answers::expr_infer", x),
Expr::Yield(x) => self.get(&Key::SendTypeOfYield(x.range)).arc_clone(),

Expr::YieldFrom(_) => self.error_todo("Answers::expr_infer", x),
Expr::Compare(x) => {
let _ty = self.expr_infer(&x.left);
Expand Down
11 changes: 11 additions & 0 deletions pyre2/pyre2/bin/binding/binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ pub enum Key {
DecoratorApplication(TextRange),
/// I am the self type for a particular class.
SelfType(ShortIdentifier),
/// The send type of a yield expression.
SendTypeOfYield(TextRange),
/// The type at a specific return point.
ReturnExpression(ShortIdentifier, TextRange),
/// The type yielded inside of a specific yield expression inside a function.
Expand Down Expand Up @@ -139,6 +141,7 @@ impl Ranged for Key {
Self::Definition(x) => x.range(),
Self::DecoratorApplication(r) => r.range(),
Self::SelfType(x) => x.range(),
Self::SendTypeOfYield(x) => x.range(),
Self::ReturnExpression(_, r) => *r,
Self::YieldTypeOfYield(_, r) => *r,
Self::YieldTypeOfGenerator(x) => x.range(),
Expand All @@ -160,6 +163,9 @@ impl DisplayWith<ModuleInfo> for Key {
Self::Definition(x) => write!(f, "{} {:?}", ctx.display(x), x.range()),
Self::DecoratorApplication(r) => write!(f, "decorator {:?}", r),
Self::SelfType(x) => write!(f, "self {} {:?}", ctx.display(x), x.range()),
Self::SendTypeOfYield(x) => {
write!(f, "send type of yield {} {:?}", ctx.display(x), x.range())
}
Self::Usage(x) => write!(f, "use {} {:?}", ctx.display(x), x.range()),
Self::Anon(r) => write!(f, "anon {r:?}"),
Self::Expect(r) => write!(f, "expect {r:?}"),
Expand Down Expand Up @@ -336,6 +342,8 @@ pub enum Binding {
/// An expression returned from a function.
/// The `bool` is whether the function has `yield` within it.
ReturnExpr(Option<Idx<KeyAnnotation>>, Expr, bool),
/// An expression returned from a function.
SendTypeOfYield(ShortIdentifier),
/// A decorator application: the Key is the entity being decorated.
DecoratorApplication(Box<Decorator>, Idx<Key>),
/// A grouping of both the yield expression types and the return type.
Expand Down Expand Up @@ -449,6 +457,9 @@ impl DisplayWith<Bindings> for Binding {
iterable.display_with(ctx)
)
}
self::Binding::SendTypeOfYield(x) => {
write!(f, "send type of yield {} {:?}", m.display(x), x.range())
}
Self::IterableValue(None, x) => write!(f, "iter {}", m.display(x)),
Self::IterableValue(Some(k), x) => {
write!(f, "iter {}: {}", ctx.display(*k), m.display(x))
Expand Down
8 changes: 7 additions & 1 deletion pyre2/pyre2/bin/binding/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1233,9 +1233,15 @@ impl<'a> BindingsBuilder<'a> {
let key = self.table.insert(
Key::YieldTypeOfYield(ShortIdentifier::new(&func_name), x.range()),
// collect the value of the yield expression.
Binding::Expr(None, yield_expr(x)),
Binding::Expr(None, yield_expr(x.clone())),
);
yield_expr_keys.insert(key);

self.table.insert(
Key::SendTypeOfYield(x.range()),
// collect the value of the yield expression.
Binding::SendTypeOfYield(ShortIdentifier::new(&func_name)),
);
}
let yield_type = Binding::phi(yield_expr_keys);
self.table.insert(
Expand Down
Loading

0 comments on commit ca8fa3d

Please sign in to comment.