]> git.lizzy.rs Git - rust.git/commitdiff
typeck/expr.rs: extract out check_expr_break.
authorMazdak Farrokhzad <twingoow@gmail.com>
Sat, 15 Jun 2019 00:06:02 +0000 (02:06 +0200)
committerMazdak Farrokhzad <twingoow@gmail.com>
Sat, 15 Jun 2019 00:06:02 +0000 (02:06 +0200)
src/librustc_typeck/check/expr.rs
src/librustc_typeck/lib.rs

index cb626da0294bbf052f940f7d6ad7c188a33cd520..bb8f331578a3d066feee782977f8db1ba7036620 100644 (file)
@@ -76,89 +76,7 @@ pub(super) fn check_expr_kind(
                 tcx.mk_unit()
             }
             ExprKind::Break(destination, ref expr_opt) => {
-                if let Ok(target_id) = destination.target_id {
-                    let (e_ty, cause);
-                    if let Some(ref e) = *expr_opt {
-                        // If this is a break with a value, we need to type-check
-                        // the expression. Get an expected type from the loop context.
-                        let opt_coerce_to = {
-                            let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
-                            enclosing_breakables.find_breakable(target_id)
-                                                .coerce
-                                                .as_ref()
-                                                .map(|coerce| coerce.expected_ty())
-                        };
-
-                        // If the loop context is not a `loop { }`, then break with
-                        // a value is illegal, and `opt_coerce_to` will be `None`.
-                        // Just set expectation to error in that case.
-                        let coerce_to = opt_coerce_to.unwrap_or(tcx.types.err);
-
-                        // Recurse without `enclosing_breakables` borrowed.
-                        e_ty = self.check_expr_with_hint(e, coerce_to);
-                        cause = self.misc(e.span);
-                    } else {
-                        // Otherwise, this is a break *without* a value. That's
-                        // always legal, and is equivalent to `break ()`.
-                        e_ty = tcx.mk_unit();
-                        cause = self.misc(expr.span);
-                    }
-
-                    // Now that we have type-checked `expr_opt`, borrow
-                    // the `enclosing_loops` field and let's coerce the
-                    // type of `expr_opt` into what is expected.
-                    let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
-                    let ctxt = enclosing_breakables.find_breakable(target_id);
-                    if let Some(ref mut coerce) = ctxt.coerce {
-                        if let Some(ref e) = *expr_opt {
-                            coerce.coerce(self, &cause, e, e_ty);
-                        } else {
-                            assert!(e_ty.is_unit());
-                            coerce.coerce_forced_unit(self, &cause, &mut |_| (), true);
-                        }
-                    } else {
-                        // If `ctxt.coerce` is `None`, we can just ignore
-                        // the type of the expresison.  This is because
-                        // either this was a break *without* a value, in
-                        // which case it is always a legal type (`()`), or
-                        // else an error would have been flagged by the
-                        // `loops` pass for using break with an expression
-                        // where you are not supposed to.
-                        assert!(expr_opt.is_none() || self.tcx.sess.err_count() > 0);
-                    }
-
-                    ctxt.may_break = true;
-
-                    // the type of a `break` is always `!`, since it diverges
-                    tcx.types.never
-                } else {
-                    // Otherwise, we failed to find the enclosing loop;
-                    // this can only happen if the `break` was not
-                    // inside a loop at all, which is caught by the
-                    // loop-checking pass.
-                    if self.tcx.sess.err_count() == 0 {
-                        self.tcx.sess.delay_span_bug(expr.span,
-                            "break was outside loop, but no error was emitted");
-                    }
-
-                    // We still need to assign a type to the inner expression to
-                    // prevent the ICE in #43162.
-                    if let Some(ref e) = *expr_opt {
-                        self.check_expr_with_hint(e, tcx.types.err);
-
-                        // ... except when we try to 'break rust;'.
-                        // ICE this expression in particular (see #43162).
-                        if let ExprKind::Path(QPath::Resolved(_, ref path)) = e.node {
-                            if path.segments.len() == 1 &&
-                               path.segments[0].ident.name == sym::rust {
-                                fatally_break_rust(self.tcx.sess);
-                            }
-                        }
-                    }
-                    // There was an error; make type-check fail.
-                    tcx.types.err
-                }
-
+                self.check_expr_break(destination, expr_opt.deref(), expr)
             }
             ExprKind::Continue(destination) => {
                 if destination.target_id.is_ok() {
@@ -725,4 +643,95 @@ fn check_expr_path(&self, qpath: &hir::QPath, expr: &'tcx hir::Expr) -> Ty<'tcx>
 
         ty
     }
+
+    fn check_expr_break(
+        &self,
+        destination: hir::Destination,
+        expr_opt: Option<&'tcx hir::Expr>,
+        expr: &'tcx hir::Expr,
+    ) -> Ty<'tcx> {
+        let tcx = self.tcx;
+        if let Ok(target_id) = destination.target_id {
+            let (e_ty, cause);
+            if let Some(ref e) = expr_opt {
+                // If this is a break with a value, we need to type-check
+                // the expression. Get an expected type from the loop context.
+                let opt_coerce_to = {
+                    let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
+                    enclosing_breakables.find_breakable(target_id)
+                                        .coerce
+                                        .as_ref()
+                                        .map(|coerce| coerce.expected_ty())
+                };
+
+                // If the loop context is not a `loop { }`, then break with
+                // a value is illegal, and `opt_coerce_to` will be `None`.
+                // Just set expectation to error in that case.
+                let coerce_to = opt_coerce_to.unwrap_or(tcx.types.err);
+
+                // Recurse without `enclosing_breakables` borrowed.
+                e_ty = self.check_expr_with_hint(e, coerce_to);
+                cause = self.misc(e.span);
+            } else {
+                // Otherwise, this is a break *without* a value. That's
+                // always legal, and is equivalent to `break ()`.
+                e_ty = tcx.mk_unit();
+                cause = self.misc(expr.span);
+            }
+
+            // Now that we have type-checked `expr_opt`, borrow
+            // the `enclosing_loops` field and let's coerce the
+            // type of `expr_opt` into what is expected.
+            let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
+            let ctxt = enclosing_breakables.find_breakable(target_id);
+            if let Some(ref mut coerce) = ctxt.coerce {
+                if let Some(ref e) = expr_opt {
+                    coerce.coerce(self, &cause, e, e_ty);
+                } else {
+                    assert!(e_ty.is_unit());
+                    coerce.coerce_forced_unit(self, &cause, &mut |_| (), true);
+                }
+            } else {
+                // If `ctxt.coerce` is `None`, we can just ignore
+                // the type of the expresison.  This is because
+                // either this was a break *without* a value, in
+                // which case it is always a legal type (`()`), or
+                // else an error would have been flagged by the
+                // `loops` pass for using break with an expression
+                // where you are not supposed to.
+                assert!(expr_opt.is_none() || self.tcx.sess.err_count() > 0);
+            }
+
+            ctxt.may_break = true;
+
+            // the type of a `break` is always `!`, since it diverges
+            tcx.types.never
+        } else {
+            // Otherwise, we failed to find the enclosing loop;
+            // this can only happen if the `break` was not
+            // inside a loop at all, which is caught by the
+            // loop-checking pass.
+            if self.tcx.sess.err_count() == 0 {
+                self.tcx.sess.delay_span_bug(expr.span,
+                    "break was outside loop, but no error was emitted");
+            }
+
+            // We still need to assign a type to the inner expression to
+            // prevent the ICE in #43162.
+            if let Some(ref e) = expr_opt {
+                self.check_expr_with_hint(e, tcx.types.err);
+
+                // ... except when we try to 'break rust;'.
+                // ICE this expression in particular (see #43162).
+                if let ExprKind::Path(QPath::Resolved(_, ref path)) = e.node {
+                    if path.segments.len() == 1 &&
+                        path.segments[0].ident.name == sym::rust {
+                        fatally_break_rust(self.tcx.sess);
+                    }
+                }
+            }
+            // There was an error; make type-check fail.
+            tcx.types.err
+        }
+    }
 }
index 79674e4baeba06014b72473cf3a1b4f6b3c1c9fb..cc6f7a07d9621c841099ca8045a359097be8bb47 100644 (file)
@@ -68,6 +68,7 @@
 #![feature(rustc_diagnostic_macros)]
 #![feature(slice_patterns)]
 #![feature(never_type)]
+#![feature(inner_deref)]
 
 #![recursion_limit="256"]