simplify the logic and document
This commit is contained in:
parent
110a9b3b1c
commit
f34909d68f
1 changed files with 31 additions and 35 deletions
|
@ -2,6 +2,7 @@
|
||||||
//! normal visitor, which just walks the entire body in one shot, the
|
//! normal visitor, which just walks the entire body in one shot, the
|
||||||
//! `ExprUseVisitor` determines how expressions are being used.
|
//! `ExprUseVisitor` determines how expressions are being used.
|
||||||
|
|
||||||
|
use hir::def::DefKind;
|
||||||
// Export these here so that Clippy can use them.
|
// Export these here so that Clippy can use them.
|
||||||
pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection};
|
pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection};
|
||||||
|
|
||||||
|
@ -14,7 +15,7 @@ use rustc_index::vec::Idx;
|
||||||
use rustc_infer::infer::InferCtxt;
|
use rustc_infer::infer::InferCtxt;
|
||||||
use rustc_middle::hir::place::ProjectionKind;
|
use rustc_middle::hir::place::ProjectionKind;
|
||||||
use rustc_middle::mir::FakeReadCause;
|
use rustc_middle::mir::FakeReadCause;
|
||||||
use rustc_middle::ty::{self, adjustment, TyCtxt};
|
use rustc_middle::ty::{self, adjustment, Ty, TyCtxt};
|
||||||
use rustc_target::abi::VariantIdx;
|
use rustc_target::abi::VariantIdx;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
|
@ -251,43 +252,34 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
||||||
needs_to_be_read = true;
|
needs_to_be_read = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PatKind::TupleStruct(..)
|
PatKind::Path(qpath) => {
|
||||||
| PatKind::Path(..)
|
// A `Path` pattern is just a name like `Foo`. This is either a
|
||||||
| PatKind::Struct(..)
|
// named constant or else it refers to an ADT variant
|
||||||
| PatKind::Tuple(..) => {
|
|
||||||
// If the PatKind is a TupleStruct, Path, Struct or Tuple then we want to check
|
|
||||||
// whether the Variant is a MultiVariant or a SingleVariant. We only want
|
|
||||||
// to borrow discr if it is a MultiVariant.
|
|
||||||
// If it is a SingleVariant and creates a binding we will handle that when
|
|
||||||
// this callback gets called again.
|
|
||||||
|
|
||||||
// Get the type of the Place after all projections have been applied
|
let res = self.mc.typeck_results.qpath_res(qpath, pat.hir_id);
|
||||||
let place_ty = place.place.ty();
|
match res {
|
||||||
|
Res::Def(DefKind::Const, _)
|
||||||
if let ty::Adt(def, _) = place_ty.kind() {
|
| Res::Def(DefKind::AssocConst, _) => {
|
||||||
if def.variants.len() > 1 {
|
// Named constants have to be equated with the value
|
||||||
|
// being matched, so that's a read of the value being matched.
|
||||||
needs_to_be_read = true;
|
needs_to_be_read = true;
|
||||||
} else if let Some(variant) = def.variants.iter().next() {
|
|
||||||
// We need to handle `const` in match arms slightly differently
|
|
||||||
// as they are not processed the same way as other match arms.
|
|
||||||
// Consider this const `const OP1: Opcode = Opcode(0x1)`, this
|
|
||||||
// will generate a pattern with kind Path while if use Opcode(0x1)
|
|
||||||
// this will generate pattern TupleStruct and Lit.
|
|
||||||
// When dealing with pat kind Path we need to make additional checks
|
|
||||||
// to ensure we have all the info needed to make a decision on whether
|
|
||||||
// to borrow discr.
|
|
||||||
//
|
|
||||||
// If the pat kind is a Path we want to check whether the
|
|
||||||
// variant contains at least one field. If that's the case,
|
|
||||||
// we want to borrow discr.
|
|
||||||
if matches!(pat.kind, PatKind::Path(..))
|
|
||||||
&& variant.fields.len() > 0
|
|
||||||
{
|
|
||||||
needs_to_be_read = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
_ => {
|
||||||
// If it is not ty::Adt, then it should be read
|
// Otherwise, this is a struct/enum variant, and so it's
|
||||||
|
// only a read if we need to read the discriminant.
|
||||||
|
needs_to_be_read = is_multivariant_adt(place.place.ty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PatKind::TupleStruct(..) | PatKind::Struct(..) | PatKind::Tuple(..) => {
|
||||||
|
// For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching
|
||||||
|
// against a multivariant enum or struct. In that case, we have to read
|
||||||
|
// the discriminant. Otherwise this kind of pattern doesn't actually
|
||||||
|
// read anything (we'll get invoked for the `...`, which may indeed
|
||||||
|
// perform some reads).
|
||||||
|
|
||||||
|
let place_ty = place.place.ty();
|
||||||
|
if is_multivariant_adt(place_ty) {
|
||||||
needs_to_be_read = true;
|
needs_to_be_read = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -854,3 +846,7 @@ fn delegate_consume<'a, 'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_multivariant_adt(ty: Ty<'tcx>) -> bool {
|
||||||
|
if let ty::Adt(def, _) = ty.kind() { def.variants.len() > 1 } else { false }
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue