From 4c0ff95e6ecd861741e868cc729afe0339a4b8c7 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Thu, 21 Dec 2017 07:40:54 -0200 Subject: [PATCH] Be more explicit about how and why we need fallback in targets of casts --- src/librustc_typeck/check/cast.rs | 10 +++++++-- src/librustc_typeck/check/mod.rs | 29 +++++++++---------------- src/test/run-pass/cast-does-fallback.rs | 16 ++++++++++++++ 3 files changed, 34 insertions(+), 21 deletions(-) create mode 100644 src/test/run-pass/cast-does-fallback.rs diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 631f7a740c4b..8dde3d7ab98a 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 610510c5c74e..e97de581173d 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 000000000000..86d6e387b255 --- /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 or the MIT license +// , 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); +}