Skip to content

Commit 6c282ca

Browse files
committed
---
yaml --- r: 277353 b: refs/heads/try c: b023fcc h: refs/heads/master i: 277351: f3685af
1 parent a85ee7c commit 6c282ca

File tree

3 files changed

+105
-99
lines changed

3 files changed

+105
-99
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
refs/heads/master: 6dbb0e86aec11050480beb76eade6fb805010ba7
33
refs/heads/snap-stage3: 235d77457d80b549dad3ac36d94f235208a1eafb
4-
refs/heads/try: a4e0e6bbf5835afc69ab5df383097a1d7b8293c5
4+
refs/heads/try: b023fcca3267fff93d91d559d3096e2defbc39fe
55
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
66
refs/tags/release-0.2: c870d2dffb391e14efb05aa27898f1f6333a9596
77
refs/tags/release-0.3: b5f0d0f648d9a6153664837026ba1be43d3e2503

branches/try/src/librustc_typeck/check/cast.rs

Lines changed: 96 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,21 @@ use super::structurally_resolved_type;
4545

4646
use lint;
4747
use hir::def_id::DefId;
48+
use rustc::hir;
49+
use rustc::traits;
4850
use rustc::ty::{self, Ty, TypeFoldable};
4951
use rustc::ty::cast::{CastKind, CastTy};
50-
use syntax::codemap::Span;
51-
use rustc::hir;
5252
use syntax::ast;
53-
53+
use syntax::codemap::Span;
54+
use util::common::ErrorReported;
5455

5556
/// Reifies a cast check to be checked once we have full type information for
5657
/// a function context.
5758
pub struct CastCheck<'tcx> {
5859
expr: &'tcx hir::Expr,
5960
expr_ty: Ty<'tcx>,
6061
cast_ty: Ty<'tcx>,
62+
cast_span: Span,
6163
span: Span,
6264
}
6365

@@ -111,37 +113,35 @@ enum CastError {
111113
}
112114

113115
impl<'tcx> CastCheck<'tcx> {
114-
pub fn new(expr: &'tcx hir::Expr, expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, span: Span)
115-
-> CastCheck<'tcx> {
116-
CastCheck {
116+
pub fn new<'a>(fcx: &FnCtxt<'a, 'tcx>,
117+
expr: &'tcx hir::Expr,
118+
expr_ty: Ty<'tcx>,
119+
cast_ty: Ty<'tcx>,
120+
cast_span: Span,
121+
span: Span)
122+
-> Result<CastCheck<'tcx>, ErrorReported> {
123+
let check = CastCheck {
117124
expr: expr,
118125
expr_ty: expr_ty,
119126
cast_ty: cast_ty,
127+
cast_span: cast_span,
120128
span: span,
129+
};
130+
131+
// For better error messages, we try to check whether the
132+
// target type is known to be sized now (we will also check
133+
// later, once inference is more complete done).
134+
if !fcx.type_is_known_to_be_sized(cast_ty, span) {
135+
check.report_cast_to_unsized_type(fcx);
136+
return Err(ErrorReported);
121137
}
138+
139+
Ok(check)
122140
}
123141

124142
fn report_cast_error<'a>(&self,
125143
fcx: &FnCtxt<'a, 'tcx>,
126144
e: CastError) {
127-
// As a heuristic, don't report errors if there are unresolved
128-
// inference variables floating around AND we've already
129-
// reported some errors in this fn. It happens often that those
130-
// inference variables are unresolved precisely *because* of
131-
// the errors we've already reported. See #31997.
132-
//
133-
// Note: it's kind of annoying that we need this. Fallback is
134-
// modified to push all unresolved inference variables to
135-
// ty-err, but it's STILL possible to see fallback for
136-
// integral/float variables, because those cannot be unified
137-
// with ty-error.
138-
if
139-
fcx.infcx().is_tainted_by_errors() &&
140-
(self.cast_ty.has_infer_types() || self.expr_ty.has_infer_types())
141-
{
142-
return;
143-
}
144-
145145
match e {
146146
CastError::NeedViaPtr |
147147
CastError::NeedViaThinPtr |
@@ -205,6 +205,61 @@ impl<'tcx> CastCheck<'tcx> {
205205
}
206206
}
207207

208+
fn report_cast_to_unsized_type<'a>(&self,
209+
fcx: &FnCtxt<'a, 'tcx>) {
210+
if
211+
self.cast_ty.references_error() ||
212+
self.expr_ty.references_error()
213+
{
214+
return;
215+
}
216+
217+
let tstr = fcx.infcx().ty_to_string(self.cast_ty);
218+
let mut err = fcx.type_error_struct(self.span, |actual| {
219+
format!("cast to unsized type: `{}` as `{}`", actual, tstr)
220+
}, self.expr_ty, None);
221+
match self.expr_ty.sty {
222+
ty::TyRef(_, ty::TypeAndMut { mutbl: mt, .. }) => {
223+
let mtstr = match mt {
224+
hir::MutMutable => "mut ",
225+
hir::MutImmutable => ""
226+
};
227+
if self.cast_ty.is_trait() {
228+
match fcx.tcx().sess.codemap().span_to_snippet(self.cast_span) {
229+
Ok(s) => {
230+
err.span_suggestion(self.cast_span,
231+
"try casting to a reference instead:",
232+
format!("&{}{}", mtstr, s));
233+
},
234+
Err(_) =>
235+
span_help!(err, self.cast_span,
236+
"did you mean `&{}{}`?", mtstr, tstr),
237+
}
238+
} else {
239+
span_help!(err, self.span,
240+
"consider using an implicit coercion to `&{}{}` instead",
241+
mtstr, tstr);
242+
}
243+
}
244+
ty::TyBox(..) => {
245+
match fcx.tcx().sess.codemap().span_to_snippet(self.cast_span) {
246+
Ok(s) => {
247+
err.span_suggestion(self.cast_span,
248+
"try casting to a `Box` instead:",
249+
format!("Box<{}>", s));
250+
},
251+
Err(_) =>
252+
span_help!(err, self.cast_span, "did you mean `Box<{}>`?", tstr),
253+
}
254+
}
255+
_ => {
256+
span_help!(err, self.expr.span,
257+
"consider using a box or reference as appropriate");
258+
}
259+
}
260+
err.emit();
261+
}
262+
208263
fn trivial_cast_lint<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) {
209264
let t_cast = self.cast_ty;
210265
let t_expr = self.expr_ty;
@@ -237,7 +292,9 @@ impl<'tcx> CastCheck<'tcx> {
237292
debug!("check_cast({}, {:?} as {:?})", self.expr.id, self.expr_ty,
238293
self.cast_ty);
239294

240-
if self.expr_ty.references_error() || self.cast_ty.references_error() {
295+
if !fcx.type_is_known_to_be_sized(self.cast_ty, self.span) {
296+
self.report_cast_to_unsized_type(fcx);
297+
} else if self.expr_ty.references_error() || self.cast_ty.references_error() {
241298
// No sense in giving duplicate error messages
242299
} else if self.try_coercion_cast(fcx) {
243300
self.trivial_cast_lint(fcx);
@@ -422,3 +479,17 @@ impl<'tcx> CastCheck<'tcx> {
422479
}
423480

424481
}
482+
483+
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
484+
fn type_is_known_to_be_sized(&self,
485+
ty: Ty<'tcx>,
486+
span: Span)
487+
-> bool
488+
{
489+
traits::type_known_to_meet_builtin_bound(self.infcx(),
490+
ty,
491+
ty::BoundSized,
492+
span)
493+
}
494+
}
495+

branches/try/src/librustc_typeck/check/mod.rs

Lines changed: 8 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1076,64 +1076,6 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
10761076
}
10771077
}
10781078

1079-
fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
1080-
span: Span,
1081-
t_span: Span,
1082-
e_span: Span,
1083-
t_cast: Ty<'tcx>,
1084-
t_expr: Ty<'tcx>,
1085-
id: ast::NodeId) {
1086-
if t_cast.references_error() || t_expr.references_error() {
1087-
return;
1088-
}
1089-
let tstr = fcx.infcx().ty_to_string(t_cast);
1090-
let mut err = fcx.type_error_struct(span, |actual| {
1091-
format!("cast to unsized type: `{}` as `{}`", actual, tstr)
1092-
}, t_expr, None);
1093-
match t_expr.sty {
1094-
ty::TyRef(_, ty::TypeAndMut { mutbl: mt, .. }) => {
1095-
let mtstr = match mt {
1096-
hir::MutMutable => "mut ",
1097-
hir::MutImmutable => ""
1098-
};
1099-
if t_cast.is_trait() {
1100-
match fcx.tcx().sess.codemap().span_to_snippet(t_span) {
1101-
Ok(s) => {
1102-
err.span_suggestion(t_span,
1103-
"try casting to a reference instead:",
1104-
format!("&{}{}", mtstr, s));
1105-
},
1106-
Err(_) =>
1107-
span_help!(err, t_span,
1108-
"did you mean `&{}{}`?", mtstr, tstr),
1109-
}
1110-
} else {
1111-
span_help!(err, span,
1112-
"consider using an implicit coercion to `&{}{}` instead",
1113-
mtstr, tstr);
1114-
}
1115-
}
1116-
ty::TyBox(..) => {
1117-
match fcx.tcx().sess.codemap().span_to_snippet(t_span) {
1118-
Ok(s) => {
1119-
err.span_suggestion(t_span,
1120-
"try casting to a `Box` instead:",
1121-
format!("Box<{}>", s));
1122-
},
1123-
Err(_) =>
1124-
span_help!(err, t_span, "did you mean `Box<{}>`?", tstr),
1125-
}
1126-
}
1127-
_ => {
1128-
span_help!(err, e_span,
1129-
"consider using a box or reference as appropriate");
1130-
}
1131-
}
1132-
err.emit();
1133-
fcx.write_error(id);
1134-
}
1135-
1136-
11371079
impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
11381080
fn tcx(&self) -> &TyCtxt<'tcx> { self.ccx.tcx }
11391081

@@ -1528,17 +1470,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15281470
self.require_type_is_sized(self.expr_ty(expr), expr.span, code);
15291471
}
15301472

1531-
pub fn type_is_known_to_be_sized(&self,
1532-
ty: Ty<'tcx>,
1533-
span: Span)
1534-
-> bool
1535-
{
1536-
traits::type_known_to_meet_builtin_bound(self.infcx(),
1537-
ty,
1538-
ty::BoundSized,
1539-
span)
1540-
}
1541-
15421473
pub fn register_builtin_bound(&self,
15431474
ty: Ty<'tcx>,
15441475
builtin_bound: ty::BuiltinBound,
@@ -3595,17 +3526,21 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
35953526
// Eagerly check for some obvious errors.
35963527
if t_expr.references_error() || t_cast.references_error() {
35973528
fcx.write_error(id);
3598-
} else if !fcx.type_is_known_to_be_sized(t_cast, expr.span) {
3599-
report_cast_to_unsized_type(fcx, expr.span, t.span, e.span, t_cast, t_expr, id);
36003529
} else {
36013530
// Write a type for the whole expression, assuming everything is going
36023531
// to work out Ok.
36033532
fcx.write_ty(id, t_cast);
36043533

36053534
// Defer other checks until we're done type checking.
36063535
let mut deferred_cast_checks = fcx.inh.deferred_cast_checks.borrow_mut();
3607-
let cast_check = cast::CastCheck::new(e, t_expr, t_cast, expr.span);
3608-
deferred_cast_checks.push(cast_check);
3536+
match cast::CastCheck::new(fcx, e, t_expr, t_cast, t.span, expr.span) {
3537+
Ok(cast_check) => {
3538+
deferred_cast_checks.push(cast_check);
3539+
}
3540+
Err(ErrorReported) => {
3541+
fcx.write_error(id);
3542+
}
3543+
}
36093544
}
36103545
}
36113546
hir::ExprType(ref e, ref t) => {

0 commit comments

Comments
 (0)