Skip to content

Commit 4c0ff95

Browse files
committed
Be more explicit about how and why we need fallback in targets of casts
1 parent 02084f3 commit 4c0ff95

File tree

3 files changed

+34
-21
lines changed

3 files changed

+34
-21
lines changed

src/librustc_typeck/check/cast.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
//! expression, `e as U2` is not necessarily so (in fact it will only be valid if
3939
//! `U1` coerces to `U2`).
4040
41-
use super::{Diverges, FnCtxt};
41+
use super::{Diverges, Fallback, FnCtxt};
4242

4343
use errors::DiagnosticBuilder;
4444
use hir::def_id::DefId;
@@ -392,7 +392,13 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
392392
}
393393

394394
pub fn check(mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) {
395-
self.expr_ty = fcx.resolved_type(self.span, self.expr_ty);
395+
self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty);
396+
// For backwards compatibility we apply numeric fallback here. This means that in:
397+
// `let x = 100; x as u8;`, we infer `x` to `i32` rather than `u8`.
398+
if self.expr_ty.is_ty_infer() {
399+
fcx.apply_fallback_if_possible(self.expr_ty, Fallback::Numeric);
400+
self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty);
401+
}
396402
self.cast_ty = fcx.structurally_resolved_type(self.span, self.cast_ty);
397403

398404
debug!("check_cast({}, {:?} as {:?})",

src/librustc_typeck/check/mod.rs

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1724,6 +1724,12 @@ enum TupleArgumentsFlag {
17241724
TupleArguments,
17251725
}
17261726

1727+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1728+
pub enum Fallback {
1729+
Full,
1730+
Numeric
1731+
}
1732+
17271733
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
17281734
pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>,
17291735
param_env: ty::ParamEnv<'tcx>,
@@ -2133,7 +2139,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
21332139
// unconstrained floats with f64.
21342140
// Defaulting inference variables becomes very dubious if we have
21352141
// encountered type-checking errors. In that case, fallback to TyError.
2136-
fn apply_fallback_if_possible(&self, ty: Ty<'tcx>) {
2142+
fn apply_fallback_if_possible(&self, ty: Ty<'tcx>, fallback: Fallback) {
21372143
use rustc::ty::error::UnconstrainedNumeric::Neither;
21382144
use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat};
21392145

@@ -2142,7 +2148,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
21422148
_ if self.is_tainted_by_errors() => self.tcx().types.err,
21432149
UnconstrainedInt => self.tcx.types.i32,
21442150
UnconstrainedFloat => self.tcx.types.f64,
2145-
Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(),
2151+
Neither if self.type_var_diverges(ty) && fallback == Fallback::Full
2152+
=> self.tcx.mk_diverging_default(),
21462153
Neither => return
21472154
};
21482155
debug!("default_type_parameters: defaulting `{:?}` to `{:?}`", ty, fallback);
@@ -2159,7 +2166,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
21592166
self.select_obligations_where_possible();
21602167

21612168
for ty in &self.unsolved_variables() {
2162-
self.apply_fallback_if_possible(ty);
2169+
self.apply_fallback_if_possible(ty, Fallback::Full);
21632170
}
21642171

21652172
let mut fulfillment_cx = self.fulfillment_cx.borrow_mut();
@@ -4937,22 +4944,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
49374944
}
49384945
}
49394946

4940-
// Same as `structurally_resolved_type` but also resolves numeric vars, with fallback.
4941-
pub fn resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
4942-
let mut ty = self.resolve_type_vars_with_obligations(ty);
4943-
if !ty.is_ty_infer() {
4944-
return ty;
4945-
} else {
4946-
self.apply_fallback_if_possible(ty);
4947-
ty = self.resolve_type_vars_with_obligations(ty);
4948-
if !ty.is_ty_infer() {
4949-
ty
4950-
} else { // Fallback failed, error.
4951-
self.must_be_known_in_context(sp, ty)
4952-
}
4953-
}
4954-
}
4955-
49564947
fn must_be_known_in_context(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
49574948
if !self.is_tainted_by_errors() {
49584949
type_error_struct!(self.tcx.sess, sp, ty, E0619,
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
pub fn main() {
12+
let cap = 512 * 512;
13+
cap as u8;
14+
// Assert `cap` did not get inferred to `u8` and overflowed.
15+
assert_ne!(cap, 0);
16+
}

0 commit comments

Comments
 (0)