]> 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 6ec5f38aa5bb529c94ac7d9edc7ba133e68c3b35..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);
@@ -258,7 +254,7 @@ fn check_irrefutable(&self, pat: &Pat, is_fn_arg: bool) {
                 "refutable pattern in {}: `{}` not covered",
                 origin, pattern_string
             );
-            diag.span_label(pat.span, &format!("pattern `{}` not covered", pattern_string));
+            diag.span_label(pat.span, format!("pattern `{}` not covered", pattern_string));
             diag.emit();
         });
     }
@@ -328,7 +324,7 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
                                 let span = first_pat.0.span;
                                 struct_span_err!(cx.tcx.sess, span, E0162,
                                                 "irrefutable if-let pattern")
-                                    .span_label(span, &format!("irrefutable pattern"))
+                                    .span_label(span, "irrefutable pattern")
                                     .emit();
                                 printed_if_let_err = true;
                             }
@@ -355,7 +351,7 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
                                 1 => {
                                     struct_span_err!(cx.tcx.sess, span, E0165,
                                                      "irrefutable while-let pattern")
-                                        .span_label(span, &format!("irrefutable pattern"))
+                                        .span_label(span, "irrefutable pattern")
                                         .emit();
                                 },
                                 _ => bug!(),
@@ -369,7 +365,7 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
                             diagnostic.set_span(pat.span);
                             // if we had a catchall pattern, hint at that
                             if let Some(catchall) = catchall {
-                                diagnostic.span_label(pat.span, &"this is an unreachable pattern");
+                                diagnostic.span_label(pat.span, "this is an unreachable pattern");
                                 diagnostic.span_note(catchall, "this pattern matches any value");
                             }
                             cx.tcx.sess.add_lint_diagnostic(lint::builtin::UNREACHABLE_PATTERNS,
@@ -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
@@ -485,18 +460,18 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
         if sub.map_or(false, |p| p.contains_bindings()) {
             struct_span_err!(cx.tcx.sess, p.span, E0007,
                              "cannot bind by-move with sub-bindings")
-                .span_label(p.span, &format!("binds an already bound by-move value by moving it"))
+                .span_label(p.span, "binds an already bound by-move value by moving it")
                 .emit();
         } else if has_guard {
             struct_span_err!(cx.tcx.sess, p.span, E0008,
                       "cannot bind by-move into a pattern guard")
-                .span_label(p.span, &format!("moves value into pattern guard"))
+                .span_label(p.span, "moves value into pattern guard")
                 .emit();
         } else if by_ref_span.is_some() {
             struct_span_err!(cx.tcx.sess, p.span, E0009,
                             "cannot bind by-move and by-ref in the same pattern")
-                    .span_label(p.span, &format!("by-move pattern here"))
-                    .span_label(by_ref_span.unwrap(), &format!("both by-ref and by-move used"))
+                    .span_label(p.span, "by-move pattern here")
+                    .span_label(by_ref_span.unwrap(), "both by-ref and by-move used")
                     .emit();
         }
     };
@@ -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,
         };
@@ -546,7 +521,7 @@ fn borrow(&mut self,
             ty::MutBorrow => {
                 struct_span_err!(self.cx.tcx.sess, span, E0301,
                           "cannot mutably borrow in a pattern guard")
-                    .span_label(span, &format!("borrowed mutably in pattern guard"))
+                    .span_label(span, "borrowed mutably in pattern guard")
                     .emit();
             }
             ty::ImmBorrow | ty::UniqueImmBorrow => {}
@@ -557,7 +532,7 @@ fn mutate(&mut self, _: ast::NodeId, span: Span, _: cmt, mode: MutateMode) {
         match mode {
             MutateMode::JustWrite | MutateMode::WriteAndRead => {
                 struct_span_err!(self.cx.tcx.sess, span, E0302, "cannot assign in a pattern guard")
-                    .span_label(span, &format!("assignment in pattern guard"))
+                    .span_label(span, "assignment in pattern guard")
                     .emit();
             }
             MutateMode::Init => {}
@@ -588,7 +563,7 @@ fn visit_pat(&mut self, pat: &Pat) {
                 if !self.bindings_allowed {
                     struct_span_err!(self.cx.tcx.sess, pat.span, E0303,
                                      "pattern bindings are not allowed after an `@`")
-                        .span_label(pat.span,  &format!("not allowed after `@`"))
+                        .span_label(pat.span,  "not allowed after `@`")
                         .emit();
                 }