]> git.lizzy.rs Git - rust.git/commitdiff
simplify the logic and document
authorNiko Matsakis <niko@alum.mit.edu>
Fri, 27 Aug 2021 20:30:45 +0000 (16:30 -0400)
committerNiko Matsakis <niko@alum.mit.edu>
Fri, 27 Aug 2021 20:30:45 +0000 (16:30 -0400)
compiler/rustc_typeck/src/expr_use_visitor.rs

index 7c99a37f6e7f814fa4364de4b51e9d54e79ff6a9..d999c17b579bb353b1b5b9d7b66df909b0742fe5 100644 (file)
@@ -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 }
+}