Skip to content

Always record reference to binding in match if guards #78393

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions compiler/rustc_typeck/src/check/generator_interior.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,18 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
// The type table might not have information for this expression
// if it is in a malformed scope. (#66387)
if let Some(ty) = self.fcx.typeck_results.borrow().expr_ty_opt(expr) {
if guard_borrowing_from_pattern {
// Match guards create references to all the bindings in the pattern that are used
// in the guard, e.g. `y if is_even(y) => ...` becomes `is_even(*r_y)` where `r_y`
// is a reference to `y`, so we must record a reference to the type of the binding.
let tcx = self.fcx.tcx;
let ref_ty = tcx.mk_ref(
// Use `ReErased` as `resolve_interior` is going to replace all the regions anyway.
tcx.mk_region(ty::RegionKind::ReErased),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe someone with better knowledge about lifetimes in the compiler should double-check this makes sense.

ty::TypeAndMut { ty, mutbl: hir::Mutability::Not },
);
self.record(ref_ty, scope, Some(expr), expr.span, guard_borrowing_from_pattern);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is the only call to self.record that actually needs to ever pass true for guard_borrowing_from_pattern but I didn't want to make the recording of types any less cautious. If there are perf reasons to not want to record too many types in the generator witness we could rethink that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I think you're right. We could try disabling the others in a follow-up.

}
self.record(ty, scope, Some(expr), expr.span, guard_borrowing_from_pattern);
} else {
self.fcx.tcx.sess.delay_span_bug(expr.span, "no type for node");
Expand Down
21 changes: 20 additions & 1 deletion src/test/ui/generator/yielding-in-match-guards.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// check-pass
// build-pass
// edition:2018

// This test is derived from
Expand All @@ -11,6 +11,7 @@
// of the underlying generator.

async fn f() -> u8 { 1 }
async fn foo() -> [bool; 10] { [false; 10] }

pub async fn g(x: u8) {
match x {
Expand All @@ -19,6 +20,24 @@ pub async fn g(x: u8) {
}
}

// #78366: check the reference to the binding is recorded even if the binding is not autorefed

async fn h(x: usize) {
match x {
y if foo().await[y] => (),
_ => (),
}
}

async fn i(x: u8) {
match x {
y if f().await == y + 1 => (),
_ => (),
}
}

fn main() {
let _ = g(10);
let _ = h(9);
let _ = i(8);
}