From f34909d68f1410c89e3a97bdee04d7e6e7cfbe5e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 27 Aug 2021 16:30:45 -0400 Subject: [PATCH] simplify the logic and document --- compiler/rustc_typeck/src/expr_use_visitor.rs | 68 +++++++++---------- 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 7c99a37f6e7..d999c17b579 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -2,6 +2,7 @@ //! normal visitor, which just walks the entire body in one shot, the //! `ExprUseVisitor` determines how expressions are being used. +use hir::def::DefKind; // Export these here so that Clippy can use them. pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection}; @@ -14,7 +15,7 @@ use rustc_infer::infer::InferCtxt; use rustc_middle::hir::place::ProjectionKind; 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 std::iter; @@ -251,43 +252,34 @@ pub fn walk_expr(&mut self, expr: &hir::Expr<'_>) { needs_to_be_read = true; } } - PatKind::TupleStruct(..) - | PatKind::Path(..) - | PatKind::Struct(..) - | 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 place_ty = place.place.ty(); - - if let ty::Adt(def, _) = place_ty.kind() { - if def.variants.len() > 1 { + PatKind::Path(qpath) => { + // A `Path` pattern is just a name like `Foo`. This is either a + // named constant or else it refers to an ADT variant + + let res = self.mc.typeck_results.qpath_res(qpath, pat.hir_id); + match res { + Res::Def(DefKind::Const, _) + | Res::Def(DefKind::AssocConst, _) => { + // 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; - } 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; } } @@ -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 } +} -- 2.44.0