about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2016-04-11 15:21:36 -0400
committerNiko Matsakis <niko@alum.mit.edu>2016-04-12 14:05:28 -0400
commitb023fcca3267fff93d91d559d3096e2defbc39fe (patch)
tree53a974842642862b54fc0a62d5361cd7d0cf40fc
parenta4e0e6bbf5835afc69ab5df383097a1d7b8293c5 (diff)
downloadrust-b023fcca3267fff93d91d559d3096e2defbc39fe.tar.gz
rust-b023fcca3267fff93d91d559d3096e2defbc39fe.zip
move checking for unsized target type into `cast`
It is odd to have this logic strewn about.  This also means that all
calls to `type_is_known_to_be_sized` are encapsulated in the
cast code, in case we want to update that logic.
-rw-r--r--src/librustc_typeck/check/cast.rs121
-rw-r--r--src/librustc_typeck/check/mod.rs81
2 files changed, 104 insertions, 98 deletions
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index ea872a92dcf..1765f5dc2f2 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -45,12 +45,13 @@ use super::structurally_resolved_type;
 
 use lint;
 use hir::def_id::DefId;
+use rustc::hir;
+use rustc::traits;
 use rustc::ty::{self, Ty, TypeFoldable};
 use rustc::ty::cast::{CastKind, CastTy};
-use syntax::codemap::Span;
-use rustc::hir;
 use syntax::ast;
-
+use syntax::codemap::Span;
+use util::common::ErrorReported;
 
 /// Reifies a cast check to be checked once we have full type information for
 /// a function context.
@@ -58,6 +59,7 @@ pub struct CastCheck<'tcx> {
     expr: &'tcx hir::Expr,
     expr_ty: Ty<'tcx>,
     cast_ty: Ty<'tcx>,
+    cast_span: Span,
     span: Span,
 }
 
@@ -111,37 +113,35 @@ enum CastError {
 }
 
 impl<'tcx> CastCheck<'tcx> {
-    pub fn new(expr: &'tcx hir::Expr, expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, span: Span)
-               -> CastCheck<'tcx> {
-        CastCheck {
+    pub fn new<'a>(fcx: &FnCtxt<'a, 'tcx>,
+                   expr: &'tcx hir::Expr,
+                   expr_ty: Ty<'tcx>,
+                   cast_ty: Ty<'tcx>,
+                   cast_span: Span,
+                   span: Span)
+                   -> Result<CastCheck<'tcx>, ErrorReported> {
+        let check = CastCheck {
             expr: expr,
             expr_ty: expr_ty,
             cast_ty: cast_ty,
+            cast_span: cast_span,
             span: span,
+        };
+
+        // For better error messages, we try to check whether the
+        // target type is known to be sized now (we will also check
+        // later, once inference is more complete done).
+        if !fcx.type_is_known_to_be_sized(cast_ty, span) {
+            check.report_cast_to_unsized_type(fcx);
+            return Err(ErrorReported);
         }
+
+        Ok(check)
     }
 
     fn report_cast_error<'a>(&self,
                              fcx: &FnCtxt<'a, 'tcx>,
                              e: CastError) {
-        // As a heuristic, don't report errors if there are unresolved
-        // inference variables floating around AND we've already
-        // reported some errors in this fn. It happens often that those
-        // inference variables are unresolved precisely *because* of
-        // the errors we've already reported. See #31997.
-        //
-        // Note: it's kind of annoying that we need this. Fallback is
-        // modified to push all unresolved inference variables to
-        // ty-err, but it's STILL possible to see fallback for
-        // integral/float variables, because those cannot be unified
-        // with ty-error.
-        if
-            fcx.infcx().is_tainted_by_errors() &&
-            (self.cast_ty.has_infer_types() || self.expr_ty.has_infer_types())
-        {
-            return;
-        }
-
         match e {
             CastError::NeedViaPtr |
             CastError::NeedViaThinPtr |
@@ -205,6 +205,61 @@ impl<'tcx> CastCheck<'tcx> {
         }
     }
 
+    fn report_cast_to_unsized_type<'a>(&self,
+                                       fcx: &FnCtxt<'a, 'tcx>) {
+        if
+            self.cast_ty.references_error() ||
+            self.expr_ty.references_error()
+        {
+            return;
+        }
+
+        let tstr = fcx.infcx().ty_to_string(self.cast_ty);
+        let mut err = fcx.type_error_struct(self.span, |actual| {
+            format!("cast to unsized type: `{}` as `{}`", actual, tstr)
+        }, self.expr_ty, None);
+        match self.expr_ty.sty {
+            ty::TyRef(_, ty::TypeAndMut { mutbl: mt, .. }) => {
+                let mtstr = match mt {
+                    hir::MutMutable => "mut ",
+                    hir::MutImmutable => ""
+                };
+                if self.cast_ty.is_trait() {
+                    match fcx.tcx().sess.codemap().span_to_snippet(self.cast_span) {
+                        Ok(s) => {
+                            err.span_suggestion(self.cast_span,
+                                                "try casting to a reference instead:",
+                                                format!("&{}{}", mtstr, s));
+                        },
+                        Err(_) =>
+                            span_help!(err, self.cast_span,
+                                       "did you mean `&{}{}`?", mtstr, tstr),
+                    }
+                } else {
+                    span_help!(err, self.span,
+                               "consider using an implicit coercion to `&{}{}` instead",
+                               mtstr, tstr);
+                }
+            }
+            ty::TyBox(..) => {
+                match fcx.tcx().sess.codemap().span_to_snippet(self.cast_span) {
+                    Ok(s) => {
+                        err.span_suggestion(self.cast_span,
+                                            "try casting to a `Box` instead:",
+                                            format!("Box<{}>", s));
+                    },
+                    Err(_) =>
+                        span_help!(err, self.cast_span, "did you mean `Box<{}>`?", tstr),
+                }
+            }
+            _ => {
+                span_help!(err, self.expr.span,
+                           "consider using a box or reference as appropriate");
+            }
+        }
+        err.emit();
+    }
+
     fn trivial_cast_lint<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) {
         let t_cast = self.cast_ty;
         let t_expr = self.expr_ty;
@@ -237,7 +292,9 @@ impl<'tcx> CastCheck<'tcx> {
         debug!("check_cast({}, {:?} as {:?})", self.expr.id, self.expr_ty,
                self.cast_ty);
 
-        if self.expr_ty.references_error() || self.cast_ty.references_error() {
+        if !fcx.type_is_known_to_be_sized(self.cast_ty, self.span) {
+            self.report_cast_to_unsized_type(fcx);
+        } else if self.expr_ty.references_error() || self.cast_ty.references_error() {
             // No sense in giving duplicate error messages
         } else if self.try_coercion_cast(fcx) {
             self.trivial_cast_lint(fcx);
@@ -422,3 +479,17 @@ impl<'tcx> CastCheck<'tcx> {
     }
 
 }
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    fn type_is_known_to_be_sized(&self,
+                                 ty: Ty<'tcx>,
+                                 span: Span)
+                                 -> bool
+    {
+        traits::type_known_to_meet_builtin_bound(self.infcx(),
+                                                 ty,
+                                                 ty::BoundSized,
+                                                 span)
+    }
+}
+
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 31458eac9ef..16d6aca07b5 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1076,64 +1076,6 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 }
 
-fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                         span: Span,
-                                         t_span: Span,
-                                         e_span: Span,
-                                         t_cast: Ty<'tcx>,
-                                         t_expr: Ty<'tcx>,
-                                         id: ast::NodeId) {
-    if t_cast.references_error() || t_expr.references_error() {
-        return;
-    }
-    let tstr = fcx.infcx().ty_to_string(t_cast);
-    let mut err = fcx.type_error_struct(span, |actual| {
-        format!("cast to unsized type: `{}` as `{}`", actual, tstr)
-    }, t_expr, None);
-    match t_expr.sty {
-        ty::TyRef(_, ty::TypeAndMut { mutbl: mt, .. }) => {
-            let mtstr = match mt {
-                hir::MutMutable => "mut ",
-                hir::MutImmutable => ""
-            };
-            if t_cast.is_trait() {
-                match fcx.tcx().sess.codemap().span_to_snippet(t_span) {
-                    Ok(s) => {
-                        err.span_suggestion(t_span,
-                                            "try casting to a reference instead:",
-                                            format!("&{}{}", mtstr, s));
-                    },
-                    Err(_) =>
-                        span_help!(err, t_span,
-                                   "did you mean `&{}{}`?", mtstr, tstr),
-                }
-            } else {
-                span_help!(err, span,
-                           "consider using an implicit coercion to `&{}{}` instead",
-                           mtstr, tstr);
-            }
-        }
-        ty::TyBox(..) => {
-            match fcx.tcx().sess.codemap().span_to_snippet(t_span) {
-                Ok(s) => {
-                    err.span_suggestion(t_span,
-                                        "try casting to a `Box` instead:",
-                                        format!("Box<{}>", s));
-                },
-                Err(_) =>
-                    span_help!(err, t_span, "did you mean `Box<{}>`?", tstr),
-            }
-        }
-        _ => {
-            span_help!(err, e_span,
-                       "consider using a box or reference as appropriate");
-        }
-    }
-    err.emit();
-    fcx.write_error(id);
-}
-
-
 impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
     fn tcx(&self) -> &TyCtxt<'tcx> { self.ccx.tcx }
 
@@ -1528,17 +1470,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.require_type_is_sized(self.expr_ty(expr), expr.span, code);
     }
 
-    pub fn type_is_known_to_be_sized(&self,
-                                     ty: Ty<'tcx>,
-                                     span: Span)
-                                     -> bool
-    {
-        traits::type_known_to_meet_builtin_bound(self.infcx(),
-                                                 ty,
-                                                 ty::BoundSized,
-                                                 span)
-    }
-
     pub fn register_builtin_bound(&self,
                                   ty: Ty<'tcx>,
                                   builtin_bound: ty::BuiltinBound,
@@ -3595,8 +3526,6 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         // Eagerly check for some obvious errors.
         if t_expr.references_error() || t_cast.references_error() {
             fcx.write_error(id);
-        } else if !fcx.type_is_known_to_be_sized(t_cast, expr.span) {
-            report_cast_to_unsized_type(fcx, expr.span, t.span, e.span, t_cast, t_expr, id);
         } else {
             // Write a type for the whole expression, assuming everything is going
             // to work out Ok.
@@ -3604,8 +3533,14 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 
             // Defer other checks until we're done type checking.
             let mut deferred_cast_checks = fcx.inh.deferred_cast_checks.borrow_mut();
-            let cast_check = cast::CastCheck::new(e, t_expr, t_cast, expr.span);
-            deferred_cast_checks.push(cast_check);
+            match cast::CastCheck::new(fcx, e, t_expr, t_cast, t.span, expr.span) {
+                Ok(cast_check) => {
+                    deferred_cast_checks.push(cast_check);
+                }
+                Err(ErrorReported) => {
+                    fcx.write_error(id);
+                }
+            }
         }
       }
       hir::ExprType(ref e, ref t) => {