diff options
| -rw-r--r-- | src/librustc_typeck/check/cast.rs | 10 | ||||
| -rw-r--r-- | src/librustc_typeck/check/mod.rs | 29 | ||||
| -rw-r--r-- | src/test/run-pass/cast-does-fallback.rs | 16 |
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); +} |
