2019-06-22 21:31:14 +00:00
|
|
|
// Regression test for broken MIR error (#61442)
|
|
|
|
// Due to the two possible evaluation orders for
|
|
|
|
// a '+=' expression (depending on whether or not the 'AddAssign' trait
|
|
|
|
// is being used), we were failing to account for all types that might
|
|
|
|
// possibly be live across a yield point.
|
|
|
|
|
2019-06-05 23:54:34 +00:00
|
|
|
#![feature(generators)]
|
|
|
|
|
|
|
|
fn foo() {
|
|
|
|
let _x = static || {
|
|
|
|
let mut s = String::new();
|
|
|
|
s += { yield; "" };
|
|
|
|
};
|
Change how we compute yield_in_scope
Compound operators (e.g. 'a += b') have two different possible
evaluation orders. When the left-hand side is a primitive type, the
expression is evaluated right-to-left. However, when the left-hand side
is a non-primitive type, the expression is evaluated left-to-right.
This causes problems when we try to determine if a type is live across a
yield point. Since we need to perform this computation before typecheck
has run, we can't simply check the types of the operands.
This commit calculates the most 'pessimistic' scenario - that is,
erring on the side of treating more types as live, rather than fewer.
This is perfectly safe - in fact, this initial liveness computation is
already overly conservative (e.g. issue #57478). The important thing is
that we compute a superset of the types that are actually live across
yield points. When we generate MIR, we'll determine which types actually
need to stay live across a given yield point, and which ones cam
actually be dropped.
Concretely, we force the computed HIR traversal index for
right-hand-side yield expression to be equal to the maximum index for
the left-hand side. This covers both possible execution orders:
* If the expression is evalauted right-to-left, our 'pessismitic' index
is unecessary, but safe. We visit the expressions in an
ExprKind::AssignOp from right to left, so it actually would have been
safe to do nothing. However, while increasing the index of a yield point
might cause the compiler to reject code that could actually compile, it
will never cause incorrect code to be accepted.
* If the expression is evaluated left-to-right, our 'pessimistic' index
correctly ensures that types in the left-hand-side are seen as occuring
before the yield - which is exactly what we want
2019-06-07 02:23:28 +00:00
|
|
|
|
|
|
|
let _y = static || {
|
|
|
|
let x = &mut 0;
|
|
|
|
*{ yield; x } += match String::new() { _ => 0 };
|
|
|
|
};
|
|
|
|
|
|
|
|
// Please don't ever actually write something like this
|
|
|
|
let _z = static || {
|
|
|
|
let x = &mut 0;
|
|
|
|
*{
|
|
|
|
let inner = &mut 1;
|
|
|
|
*{ yield (); inner } += match String::new() { _ => 1};
|
|
|
|
yield;
|
|
|
|
x
|
|
|
|
} += match String::new() { _ => 2 };
|
|
|
|
};
|
2019-06-05 23:54:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
foo()
|
|
|
|
}
|