Skip to content

Commit b023fcc

Browse files
committed
move checking for unsized target type into cast
It is odd to have this logic strewn about. This also means that all calls to `type_is_known_to_be_sized` are encapsulated in the cast code, in case we want to update that logic.
1 parent a4e0e6b commit b023fcc

File tree

2 files changed

+104
-98
lines changed

2 files changed

+104
-98
lines changed

src/librustc_typeck/check/cast.rs

+96-25
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+

src/librustc_typeck/check/mod.rs

+8-73
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)