Skip to content

Commit 7d5a892

Browse files
committed
ExprUseVisitor: remove maybe_read_scrutinee
The split between walk_pat and maybe_read_scrutinee has now become redundant. Due to this change, one testcase within the testsuite has become similar enough to a known ICE to also break. I am leaving this as future work, as it requires feature(type_alias_impl_trait)
1 parent 8ed61e4 commit 7d5a892

File tree

9 files changed

+93
-231
lines changed

9 files changed

+93
-231
lines changed

compiler/rustc_hir_typeck/src/expr_use_visitor.rs

+23-147
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77
88
use std::cell::{Ref, RefCell};
99
use std::ops::Deref;
10-
use std::slice::from_ref;
1110

12-
use hir::Expr;
1311
use hir::def::DefKind;
1412
use hir::pat_util::EnumerateAndAdjustIterator as _;
1513
use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
@@ -312,7 +310,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
312310

313311
let param_place = self.cat_rvalue(param.hir_id, param_ty);
314312

315-
self.walk_irrefutable_pat(&param_place, param.pat)?;
313+
self.fake_read_scrutinee(&param_place, false)?;
314+
self.walk_pat(&param_place, param.pat, false)?;
316315
}
317316

318317
self.consume_expr(body.value)?;
@@ -454,13 +453,9 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
454453

455454
hir::ExprKind::Match(discr, arms, _) => {
456455
let discr_place = self.cat_expr(discr)?;
457-
self.maybe_read_scrutinee(
458-
discr,
459-
discr_place.clone(),
460-
arms.iter().map(|arm| arm.pat),
461-
)?;
456+
self.fake_read_scrutinee(&discr_place, true)?;
457+
self.walk_expr(discr)?;
462458

463-
// treatment of the discriminant is handled while walking the arms.
464459
for arm in arms {
465460
self.walk_arm(&discr_place, arm)?;
466461
}
@@ -597,115 +592,25 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
597592
Ok(())
598593
}
599594

600-
fn maybe_read_scrutinee<'t>(
595+
#[instrument(skip(self), level = "debug")]
596+
fn fake_read_scrutinee(
601597
&self,
602-
discr: &Expr<'_>,
603-
discr_place: PlaceWithHirId<'tcx>,
604-
pats: impl Iterator<Item = &'t hir::Pat<'t>>,
598+
discr_place: &PlaceWithHirId<'tcx>,
599+
refutable: bool,
605600
) -> Result<(), Cx::Error> {
606-
// Matching should not always be considered a use of the place, hence
607-
// discr does not necessarily need to be borrowed.
608-
// We only want to borrow discr if the pattern contain something other
609-
// than wildcards.
610-
let mut needs_to_be_read = false;
611-
for pat in pats {
612-
self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| {
613-
match &pat.kind {
614-
PatKind::Binding(.., opt_sub_pat) => {
615-
// If the opt_sub_pat is None, then the binding does not count as
616-
// a wildcard for the purpose of borrowing discr.
617-
if opt_sub_pat.is_none() {
618-
needs_to_be_read = true;
619-
}
620-
}
621-
PatKind::Never => {
622-
// A never pattern reads the value.
623-
// FIXME(never_patterns): does this do what I expect?
624-
needs_to_be_read = true;
625-
}
626-
PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => {
627-
// A `Path` pattern is just a name like `Foo`. This is either a
628-
// named constant or else it refers to an ADT variant
629-
630-
let res = self.cx.typeck_results().qpath_res(qpath, *hir_id);
631-
match res {
632-
Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => {
633-
// Named constants have to be equated with the value
634-
// being matched, so that's a read of the value being matched.
635-
//
636-
// FIXME: We don't actually reads for ZSTs.
637-
needs_to_be_read = true;
638-
}
639-
_ => {
640-
// Otherwise, this is a struct/enum variant, and so it's
641-
// only a read if we need to read the discriminant.
642-
needs_to_be_read |=
643-
self.is_multivariant_adt(place.place.ty(), *span);
644-
}
645-
}
646-
}
647-
PatKind::TupleStruct(..) | PatKind::Struct(..) | PatKind::Tuple(..) => {
648-
// For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching
649-
// against a multivariant enum or struct. In that case, we have to read
650-
// the discriminant. Otherwise this kind of pattern doesn't actually
651-
// read anything (we'll get invoked for the `...`, which may indeed
652-
// perform some reads).
653-
654-
let place_ty = place.place.ty();
655-
needs_to_be_read |= self.is_multivariant_adt(place_ty, pat.span);
656-
}
657-
PatKind::Expr(_) | PatKind::Range(..) => {
658-
// If the PatKind is a Lit or a Range then we want
659-
// to borrow discr.
660-
needs_to_be_read = true;
661-
}
662-
PatKind::Slice(lhs, wild, rhs) => {
663-
// We don't need to test the length if the pattern is `[..]`
664-
if matches!((lhs, wild, rhs), (&[], Some(_), &[]))
665-
// Arrays have a statically known size, so
666-
// there is no need to read their length
667-
|| place.place.ty().peel_refs().is_array()
668-
{
669-
} else {
670-
needs_to_be_read = true;
671-
}
672-
}
673-
PatKind::Or(_)
674-
| PatKind::Box(_)
675-
| PatKind::Deref(_)
676-
| PatKind::Ref(..)
677-
| PatKind::Guard(..)
678-
| PatKind::Wild
679-
| PatKind::Err(_) => {
680-
// If the PatKind is Or, Box, or Ref, the decision is made later
681-
// as these patterns contains subpatterns
682-
// If the PatKind is Wild or Err, the decision is made based on the other patterns
683-
// being examined
684-
}
685-
}
686-
687-
Ok(())
688-
})?
689-
}
601+
let closure_def_id = match discr_place.place.base {
602+
PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id),
603+
_ => None,
604+
};
690605

691-
if needs_to_be_read {
692-
self.borrow_expr(discr, BorrowKind::Immutable)?;
606+
let cause = if refutable {
607+
FakeReadCause::ForMatchedPlace(closure_def_id)
693608
} else {
694-
let closure_def_id = match discr_place.place.base {
695-
PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id),
696-
_ => None,
697-
};
609+
FakeReadCause::ForLet(closure_def_id)
610+
};
698611

699-
self.delegate.borrow_mut().fake_read(
700-
&discr_place,
701-
FakeReadCause::ForMatchedPlace(closure_def_id),
702-
discr_place.hir_id,
703-
);
612+
self.delegate.borrow_mut().fake_read(discr_place, cause, discr_place.hir_id);
704613

705-
// We always want to walk the discriminant. We want to make sure, for instance,
706-
// that the discriminant has been initialized.
707-
self.walk_expr(discr)?;
708-
}
709614
Ok(())
710615
}
711616

@@ -722,12 +627,11 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
722627
self.walk_expr(expr)?;
723628
let expr_place = self.cat_expr(expr)?;
724629
f()?;
630+
self.fake_read_scrutinee(&expr_place, els.is_some())?;
631+
self.walk_pat(&expr_place, pat, false)?;
725632
if let Some(els) = els {
726-
// borrowing because we need to test the discriminant
727-
self.maybe_read_scrutinee(expr, expr_place.clone(), from_ref(pat).iter())?;
728633
self.walk_block(els)?;
729634
}
730-
self.walk_irrefutable_pat(&expr_place, pat)?;
731635
Ok(())
732636
}
733637

@@ -899,16 +803,6 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
899803
discr_place: &PlaceWithHirId<'tcx>,
900804
arm: &hir::Arm<'_>,
901805
) -> Result<(), Cx::Error> {
902-
let closure_def_id = match discr_place.place.base {
903-
PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id),
904-
_ => None,
905-
};
906-
907-
self.delegate.borrow_mut().fake_read(
908-
discr_place,
909-
FakeReadCause::ForMatchedPlace(closure_def_id),
910-
discr_place.hir_id,
911-
);
912806
self.walk_pat(discr_place, arm.pat, arm.guard.is_some())?;
913807

914808
if let Some(ref e) = arm.guard {
@@ -919,27 +813,6 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
919813
Ok(())
920814
}
921815

922-
/// Walks a pat that occurs in isolation (i.e., top-level of fn argument or
923-
/// let binding, and *not* a match arm or nested pat.)
924-
fn walk_irrefutable_pat(
925-
&self,
926-
discr_place: &PlaceWithHirId<'tcx>,
927-
pat: &hir::Pat<'_>,
928-
) -> Result<(), Cx::Error> {
929-
let closure_def_id = match discr_place.place.base {
930-
PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id),
931-
_ => None,
932-
};
933-
934-
self.delegate.borrow_mut().fake_read(
935-
discr_place,
936-
FakeReadCause::ForLet(closure_def_id),
937-
discr_place.hir_id,
938-
);
939-
self.walk_pat(discr_place, pat, false)?;
940-
Ok(())
941-
}
942-
943816
/// The core driver for walking a pattern
944817
///
945818
/// This should mirror how pattern-matching gets lowered to MIR, as
@@ -1928,8 +1801,11 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
19281801
/// Here, we cannot perform such an accurate checks, because querying
19291802
/// whether a type is inhabited requires that it has been fully inferred,
19301803
/// which cannot be guaranteed at this point.
1804+
#[instrument(skip(self, span), level = "debug")]
19311805
fn is_multivariant_adt(&self, ty: Ty<'tcx>, span: Span) -> bool {
1932-
if let ty::Adt(def, _) = self.cx.try_structurally_resolve_type(span, ty).kind() {
1806+
let ty = self.cx.try_structurally_resolve_type(span, ty);
1807+
debug!(?ty, "is_multivariant_adt: resolved");
1808+
if let ty::Adt(def, _) = ty.kind() {
19331809
// Note that if a non-exhaustive SingleVariant is defined in another crate, we need
19341810
// to assume that more cases will be added to the variant in the future. This mean
19351811
// that we should handle non-exhaustive SingleVariant the same way we would handle

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1447,6 +1447,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14471447
pub(crate) fn try_structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
14481448
let ty = self.resolve_vars_with_obligations(ty);
14491449

1450+
debug!("next_solver = {:?}", self.next_trait_solver());
14501451
if self.next_trait_solver()
14511452
&& let ty::Alias(..) = ty.kind()
14521453
{
File renamed without changes.

tests/crashes/119786-2.rs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//@ known-bug: #119786
2+
//@ edition:2021
3+
4+
fn enum_upvar() {
5+
type T = impl Copy;
6+
let foo: T = Some((1u32, 2u32));
7+
let x = move || {
8+
match foo {
9+
None => (),
10+
Some(_) => (),
11+
}
12+
};
13+
}
14+
15+
pub fn main() {}

tests/crashes/119786-3.rs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//@ known-bug: #119786
2+
//@ edition:2021
3+
4+
fn enum_upvar() {
5+
type T = impl Copy;
6+
let foo: T = Some((1u32, 2u32));
7+
let x = move || {
8+
match foo {
9+
None => (),
10+
Some((a, b)) => (),
11+
}
12+
};
13+
}
14+
15+
pub fn main() {}

tests/ui/closures/2229_closure_analysis/match/match-edge-cases_2.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error[E0505]: cannot move out of `ts` because it is borrowed
44
LL | let _b = || { match ts {
55
| -- -- borrow occurs due to use in closure
66
| |
7-
| borrow of `ts` occurs here
7+
| borrow of `ts.x` occurs here
88
...
99
LL | let mut mut_ts = ts;
1010
| ^^ move out of `ts` occurs here

tests/ui/closures/2229_closure_analysis/match/patterns-capture-analysis.rs

+8-14
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ fn test_1_should_capture() {
1414
//~| Min Capture analysis includes:
1515
match variant {
1616
//~^ NOTE: Capturing variant[] -> Immutable
17-
//~| NOTE: Capturing variant[] -> Immutable
1817
//~| NOTE: Min Capture variant[] -> Immutable
1918
Some(_) => {}
2019
_ => {}
@@ -65,9 +64,8 @@ fn test_6_should_capture_single_variant() {
6564
//~^ First Pass analysis includes:
6665
//~| Min Capture analysis includes:
6766
match variant {
68-
//~^ NOTE: Capturing variant[] -> Immutable
69-
//~| NOTE: Capturing variant[(0, 0)] -> Immutable
70-
//~| NOTE: Min Capture variant[] -> Immutable
67+
//~^ NOTE: Capturing variant[(0, 0)] -> Immutable
68+
//~| NOTE: Min Capture variant[(0, 0)] -> Immutable
7169
SingleVariant::Points(a) => {
7270
println!("{:?}", a);
7371
}
@@ -133,7 +131,6 @@ fn test_5_should_capture_multi_variant() {
133131
//~| Min Capture analysis includes:
134132
match variant {
135133
//~^ NOTE: Capturing variant[] -> Immutable
136-
//~| NOTE: Capturing variant[] -> Immutable
137134
//~| NOTE: Min Capture variant[] -> Immutable
138135
MVariant::A => {}
139136
_ => {}
@@ -151,9 +148,8 @@ fn test_7_should_capture_slice_len() {
151148
//~^ First Pass analysis includes:
152149
//~| Min Capture analysis includes:
153150
match slice {
154-
//~^ NOTE: Capturing slice[] -> Immutable
155-
//~| NOTE: Capturing slice[Deref] -> Immutable
156-
//~| NOTE: Min Capture slice[] -> Immutable
151+
//~^ NOTE: Capturing slice[Deref] -> Immutable
152+
//~| NOTE: Min Capture slice[Deref] -> Immutable
157153
[_,_,_] => {},
158154
_ => {}
159155
}
@@ -164,9 +160,8 @@ fn test_7_should_capture_slice_len() {
164160
//~^ First Pass analysis includes:
165161
//~| Min Capture analysis includes:
166162
match slice {
167-
//~^ NOTE: Capturing slice[] -> Immutable
168-
//~| NOTE: Capturing slice[Deref] -> Immutable
169-
//~| NOTE: Min Capture slice[] -> Immutable
163+
//~^ NOTE: Capturing slice[Deref] -> Immutable
164+
//~| NOTE: Min Capture slice[Deref] -> Immutable
170165
[] => {},
171166
_ => {}
172167
}
@@ -177,9 +172,8 @@ fn test_7_should_capture_slice_len() {
177172
//~^ First Pass analysis includes:
178173
//~| Min Capture analysis includes:
179174
match slice {
180-
//~^ NOTE: Capturing slice[] -> Immutable
181-
//~| NOTE: Capturing slice[Deref] -> Immutable
182-
//~| NOTE: Min Capture slice[] -> Immutable
175+
//~^ NOTE: Capturing slice[Deref] -> Immutable
176+
//~| NOTE: Min Capture slice[Deref] -> Immutable
183177
[_, .. ,_] => {},
184178
_ => {}
185179
}

0 commit comments

Comments
 (0)