]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_const_eval/check_match.rs
Change for-loop desugar to not borrow the iterator during the loop
[rust.git] / src / librustc_const_eval / check_match.rs
index cd31290eb554c0fdce766f290657f32defc79bb6..e78ab0b234e2d03fee6089b7507ced4a98081071 100644 (file)
@@ -46,14 +46,13 @@ fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
                 b: hir::BodyId, s: Span, id: ast::NodeId) {
         intravisit::walk_fn(self, fk, fd, b, s, id);
 
-        let region_context = self.tcx.hir.local_def_id(id);
-        let region_maps = self.tcx.region_maps(region_context);
+        let def_id = self.tcx.hir.local_def_id(id);
 
         MatchVisitor {
             tcx: self.tcx,
             tables: self.tcx.body_tables(b),
-            region_maps: &region_maps,
-            param_env: &ty::ParameterEnvironment::for_item(self.tcx, id)
+            region_maps: &self.tcx.region_maps(def_id),
+            param_env: self.tcx.param_env(def_id)
         }.visit_body(self.tcx.hir.body(b));
     }
 }
@@ -70,8 +69,8 @@ fn create_e0004<'a>(sess: &'a Session, sp: Span, error_message: String) -> Diagn
 struct MatchVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     tables: &'a ty::TypeckTables<'tcx>,
-    param_env: &'a ty::ParameterEnvironment<'tcx>,
-    region_maps: &'a RegionMaps<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    region_maps: &'a RegionMaps,
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {
@@ -93,7 +92,10 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
     fn visit_local(&mut self, loc: &'tcx hir::Local) {
         intravisit::walk_local(self, loc);
 
-        self.check_irrefutable(&loc.pat, false);
+        self.check_irrefutable(&loc.pat, match loc.source {
+            hir::LocalSource::Normal => "local binding",
+            hir::LocalSource::ForLoopDesugar => "`for` loop binding",
+        });
 
         // Check legality of move bindings and `@` patterns.
         self.check_patterns(false, slice::ref_slice(&loc.pat));
@@ -103,7 +105,7 @@ fn visit_body(&mut self, body: &'tcx hir::Body) {
         intravisit::walk_body(self, body);
 
         for arg in &body.arguments {
-            self.check_irrefutable(&arg.pat, true);
+            self.check_irrefutable(&arg.pat, "function argument");
             self.check_patterns(false, slice::ref_slice(&arg.pat));
         }
     }
@@ -155,7 +157,7 @@ fn check_match(
             }
         }
 
-        let module = self.tcx.hir.local_def_id(self.tcx.hir.get_module_parent(scrut.id));
+        let module = self.tcx.hir.get_module_parent(scrut.id);
         MatchCheckCtxt::create_and_enter(self.tcx, module, |ref mut cx| {
             let mut have_errors = false;
 
@@ -183,7 +185,7 @@ fn check_match(
             // Then, if the match has no arms, check whether the scrutinee
             // is uninhabited.
             let pat_ty = self.tables.node_id_to_type(scrut.id);
-            let module = self.tcx.hir.local_def_id(self.tcx.hir.get_module_parent(scrut.id));
+            let module = self.tcx.hir.get_module_parent(scrut.id);
             if inlined_arms.is_empty() {
                 let scrutinee_is_uninhabited = if self.tcx.sess.features.borrow().never_type {
                     pat_ty.is_uninhabited_from(module, self.tcx)
@@ -212,7 +214,7 @@ fn check_match(
                 .map(|pat| vec![pat.0])
                 .collect();
             let scrut_ty = self.tables.node_id_to_type(scrut.id);
-            check_exhaustive(cx, scrut_ty, scrut.span, &matrix, source);
+            check_exhaustive(cx, scrut_ty, scrut.span, &matrix);
         })
     }
 
@@ -225,14 +227,8 @@ fn conservative_is_uninhabited(&self, scrutinee_ty: Ty<'tcx>) -> bool {
         }
     }
 
-    fn check_irrefutable(&self, pat: &Pat, is_fn_arg: bool) {
-        let origin = if is_fn_arg {
-            "function argument"
-        } else {
-            "local binding"
-        };
-
-        let module = self.tcx.hir.local_def_id(self.tcx.hir.get_module_parent(pat.id));
+    fn check_irrefutable(&self, pat: &Pat, origin: &str) {
+        let module = self.tcx.hir.get_module_parent(pat.id);
         MatchCheckCtxt::create_and_enter(self.tcx, module, |ref mut cx| {
             let mut patcx = PatternContext::new(self.tcx, self.tables);
             let pattern = patcx.lower_pattern(pat);
@@ -397,8 +393,7 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
 fn check_exhaustive<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
                               scrut_ty: Ty<'tcx>,
                               sp: Span,
-                              matrix: &Matrix<'a, 'tcx>,
-                              source: hir::MatchSource) {
+                              matrix: &Matrix<'a, 'tcx>) {
     let wild_pattern = Pattern {
         ty: scrut_ty,
         span: DUMMY_SP,
@@ -411,52 +406,32 @@ fn check_exhaustive<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
             } else {
                 pats.iter().map(|w| w.single_pattern()).collect()
             };
-            match source {
-                hir::MatchSource::ForLoopDesugar => {
-                    // `witnesses[0]` has the form `Some(<head>)`, peel off the `Some`
-                    let witness = match *witnesses[0].kind {
-                        PatternKind::Variant { ref subpatterns, .. } => match &subpatterns[..] {
-                            &[ref pat] => &pat.pattern,
-                            _ => bug!(),
-                        },
-                        _ => bug!(),
-                    };
-                    let pattern_string = witness.to_string();
-                    struct_span_err!(cx.tcx.sess, sp, E0297,
-                        "refutable pattern in `for` loop binding: \
-                                `{}` not covered",
-                                pattern_string)
-                        .span_label(sp, format!("pattern `{}` not covered", pattern_string))
-                        .emit();
+
+            const LIMIT: usize = 3;
+            let joined_patterns = match witnesses.len() {
+                0 => bug!(),
+                1 => format!("`{}`", witnesses[0]),
+                2...LIMIT => {
+                    let (tail, head) = witnesses.split_last().unwrap();
+                    let head: Vec<_> = head.iter().map(|w| w.to_string()).collect();
+                    format!("`{}` and `{}`", head.join("`, `"), tail)
                 },
                 _ => {
-                    const LIMIT: usize = 3;
-                    let joined_patterns = match witnesses.len() {
-                        0 => bug!(),
-                        1 => format!("`{}`", witnesses[0]),
-                        2...LIMIT => {
-                            let (tail, head) = witnesses.split_last().unwrap();
-                            let head: Vec<_> = head.iter().map(|w| w.to_string()).collect();
-                            format!("`{}` and `{}`", head.join("`, `"), tail)
-                        },
-                        _ => {
-                            let (head, tail) = witnesses.split_at(LIMIT);
-                            let head: Vec<_> = head.iter().map(|w| w.to_string()).collect();
-                            format!("`{}` and {} more", head.join("`, `"), tail.len())
-                        }
-                    };
-
-                    let label_text = match witnesses.len() {
-                        1 => format!("pattern {} not covered", joined_patterns),
-                        _ => format!("patterns {} not covered", joined_patterns)
-                    };
-                    create_e0004(cx.tcx.sess, sp,
-                                 format!("non-exhaustive patterns: {} not covered",
-                                         joined_patterns))
-                        .span_label(sp, label_text)
-                        .emit();
-                },
-            }
+                    let (head, tail) = witnesses.split_at(LIMIT);
+                    let head: Vec<_> = head.iter().map(|w| w.to_string()).collect();
+                    format!("`{}` and {} more", head.join("`, `"), tail.len())
+                }
+            };
+
+            let label_text = match witnesses.len() {
+                1 => format!("pattern {} not covered", joined_patterns),
+                _ => format!("patterns {} not covered", joined_patterns)
+            };
+            create_e0004(cx.tcx.sess, sp,
+                            format!("non-exhaustive patterns: {} not covered",
+                                    joined_patterns))
+                .span_label(sp, label_text)
+                .emit();
         }
         NotUseful => {
             // This is good, wildcard pattern isn't reachable
@@ -519,7 +494,7 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
 ///
 /// FIXME: this should be done by borrowck.
 fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Expr) {
-    cx.tcx.infer_ctxt((cx.tables, cx.param_env.clone()), Reveal::UserFacing).enter(|infcx| {
+    cx.tcx.infer_ctxt((cx.tables, cx.param_env), Reveal::UserFacing).enter(|infcx| {
         let mut checker = MutationChecker {
             cx: cx,
         };