about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_typeck/check/cast.rs10
-rw-r--r--src/librustc_typeck/check/mod.rs29
-rw-r--r--src/test/run-pass/cast-does-fallback.rs16
3 files changed, 34 insertions, 21 deletions
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 631f7a740c4..8dde3d7ab98 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -38,7 +38,7 @@
 //! expression, `e as U2` is not necessarily so (in fact it will only be valid if
 //! `U1` coerces to `U2`).
 
-use super::{Diverges, FnCtxt};
+use super::{Diverges, Fallback, FnCtxt};
 
 use errors::DiagnosticBuilder;
 use hir::def_id::DefId;
@@ -392,7 +392,13 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
     }
 
     pub fn check(mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) {
-        self.expr_ty = fcx.resolved_type(self.span, self.expr_ty);
+        self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty);
+        // For backwards compatibility we apply numeric fallback here. This means that in:
+        // `let x = 100; x as u8;`, we infer `x` to `i32` rather than `u8`.
+        if self.expr_ty.is_ty_infer() {
+            fcx.apply_fallback_if_possible(self.expr_ty, Fallback::Numeric);
+            self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty);
+        }
         self.cast_ty = fcx.structurally_resolved_type(self.span, self.cast_ty);
 
         debug!("check_cast({}, {:?} as {:?})",
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 610510c5c74..e97de581173 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1724,6 +1724,12 @@ enum TupleArgumentsFlag {
     TupleArguments,
 }
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum Fallback {
+    Full,
+    Numeric
+}
+
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>,
                param_env: ty::ParamEnv<'tcx>,
@@ -2133,7 +2139,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     // unconstrained floats with f64.
     // Defaulting inference variables becomes very dubious if we have
     // encountered type-checking errors. In that case, fallback to TyError.
-    fn apply_fallback_if_possible(&self, ty: Ty<'tcx>) {
+    fn apply_fallback_if_possible(&self, ty: Ty<'tcx>, fallback: Fallback) {
         use rustc::ty::error::UnconstrainedNumeric::Neither;
         use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat};
 
@@ -2142,7 +2148,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             _ if self.is_tainted_by_errors() => self.tcx().types.err,
             UnconstrainedInt => self.tcx.types.i32,
             UnconstrainedFloat => self.tcx.types.f64,
-            Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(),
+            Neither if self.type_var_diverges(ty) && fallback == Fallback::Full
+                            => self.tcx.mk_diverging_default(),
             Neither => return
         };
         debug!("default_type_parameters: defaulting `{:?}` to `{:?}`", ty, fallback);
@@ -2159,7 +2166,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.select_obligations_where_possible();
 
         for ty in &self.unsolved_variables() {
-            self.apply_fallback_if_possible(ty);
+            self.apply_fallback_if_possible(ty, Fallback::Full);
         }
 
         let mut fulfillment_cx = self.fulfillment_cx.borrow_mut();
@@ -4937,22 +4944,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    // Same as `structurally_resolved_type` but also resolves numeric vars, with fallback.
-    pub fn resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
-        let mut ty = self.resolve_type_vars_with_obligations(ty);
-        if !ty.is_ty_infer() {
-            return ty;
-        } else {
-            self.apply_fallback_if_possible(ty);
-            ty = self.resolve_type_vars_with_obligations(ty);
-            if !ty.is_ty_infer() {
-                ty
-            } else { // Fallback failed, error.
-                self.must_be_known_in_context(sp, ty)
-            }
-        }
-    }
-
     fn must_be_known_in_context(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
         if !self.is_tainted_by_errors() {
             type_error_struct!(self.tcx.sess, sp, ty, E0619,
diff --git a/src/test/run-pass/cast-does-fallback.rs b/src/test/run-pass/cast-does-fallback.rs
new file mode 100644
index 00000000000..86d6e387b25
--- /dev/null
+++ b/src/test/run-pass/cast-does-fallback.rs
@@ -0,0 +1,16 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn main() {
+    let cap = 512 * 512;
+    cap as u8;
+    // Assert `cap` did not get inferred to `u8` and overflowed.
+    assert_ne!(cap, 0);
+}