Skip to content

Commit da7529a

Browse files
committed
Split check_cast to a separate file
1 parent 1169693 commit da7529a

File tree

2 files changed

+184
-152
lines changed

2 files changed

+184
-152
lines changed

src/librustc_typeck/check/cast.rs

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
// Copyright 2015 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+
//! Code for type-checking cast expressions.
12+
13+
use super::coercion;
14+
use super::demand;
15+
use super::FnCtxt;
16+
use super::structurally_resolved_type;
17+
18+
use lint;
19+
use middle::infer;
20+
use middle::ty;
21+
use middle::ty::Ty;
22+
use syntax::ast;
23+
use syntax::codemap::Span;
24+
25+
/// Reifies a cast check to be checked once we have full type information for
26+
/// a function context.
27+
pub struct CastCheck<'tcx> {
28+
expr: ast::Expr,
29+
expr_ty: Ty<'tcx>,
30+
cast_ty: Ty<'tcx>,
31+
span: Span,
32+
}
33+
34+
impl<'tcx> CastCheck<'tcx> {
35+
pub fn new(expr: ast::Expr, expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, span: Span)
36+
-> CastCheck<'tcx> {
37+
CastCheck {
38+
expr: expr,
39+
expr_ty: expr_ty,
40+
cast_ty: cast_ty,
41+
span: span,
42+
}
43+
}
44+
}
45+
46+
pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) {
47+
fn cast_through_integer_err<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
48+
span: Span,
49+
t_1: Ty<'tcx>,
50+
t_e: Ty<'tcx>) {
51+
fcx.type_error_message(span, |actual| {
52+
format!("illegal cast; cast through an \
53+
integer first: `{}` as `{}`",
54+
actual,
55+
fcx.infcx().ty_to_string(t_1))
56+
}, t_e, None);
57+
}
58+
59+
let span = cast.span;
60+
let e = &cast.expr;
61+
let t_e = structurally_resolved_type(fcx, span, cast.expr_ty);
62+
let t_1 = structurally_resolved_type(fcx, span, cast.cast_ty);
63+
64+
// Check for trivial casts.
65+
if !ty::type_has_ty_infer(t_1) {
66+
if let Ok(()) = coercion::mk_assignty(fcx, e, t_e, t_1) {
67+
if ty::type_is_numeric(t_1) && ty::type_is_numeric(t_e) {
68+
fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS,
69+
e.id,
70+
span,
71+
format!("trivial numeric cast: `{}` as `{}`. Cast can be \
72+
replaced by coercion, this might require type \
73+
ascription or a temporary variable",
74+
fcx.infcx().ty_to_string(t_e),
75+
fcx.infcx().ty_to_string(t_1)));
76+
} else {
77+
fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_CASTS,
78+
e.id,
79+
span,
80+
format!("trivial cast: `{}` as `{}`. Cast can be \
81+
replaced by coercion, this might require type \
82+
ascription or a temporary variable",
83+
fcx.infcx().ty_to_string(t_e),
84+
fcx.infcx().ty_to_string(t_1)));
85+
}
86+
return;
87+
}
88+
}
89+
90+
let t_e_is_bare_fn_item = ty::type_is_bare_fn_item(t_e);
91+
let t_e_is_scalar = ty::type_is_scalar(t_e);
92+
let t_e_is_integral = ty::type_is_integral(t_e);
93+
let t_e_is_float = ty::type_is_floating_point(t_e);
94+
let t_e_is_c_enum = ty::type_is_c_like_enum(fcx.tcx(), t_e);
95+
96+
let t_1_is_scalar = ty::type_is_scalar(t_1);
97+
let t_1_is_char = ty::type_is_char(t_1);
98+
let t_1_is_bare_fn = ty::type_is_bare_fn(t_1);
99+
let t_1_is_float = ty::type_is_floating_point(t_1);
100+
101+
// casts to scalars other than `char` and `bare fn` are trivial
102+
let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn;
103+
104+
if t_e_is_bare_fn_item && t_1_is_bare_fn {
105+
demand::coerce(fcx, e.span, t_1, &e);
106+
} else if t_1_is_char {
107+
let t_e = fcx.infcx().shallow_resolve(t_e);
108+
if t_e.sty != ty::ty_uint(ast::TyU8) {
109+
fcx.type_error_message(span, |actual| {
110+
format!("only `u8` can be cast as `char`, not `{}`", actual)
111+
}, t_e, None);
112+
}
113+
} else if t_1.sty == ty::ty_bool {
114+
span_err!(fcx.tcx().sess, span, E0054,
115+
"cannot cast as `bool`, compare with zero instead");
116+
} else if t_1_is_float && (t_e_is_scalar || t_e_is_c_enum) && !(
117+
t_e_is_integral || t_e_is_float || t_e.sty == ty::ty_bool) {
118+
// Casts to float must go through an integer or boolean
119+
cast_through_integer_err(fcx, span, t_1, t_e)
120+
} else if t_e_is_c_enum && t_1_is_trivial {
121+
if ty::type_is_unsafe_ptr(t_1) {
122+
// ... and likewise with C enum -> *T
123+
cast_through_integer_err(fcx, span, t_1, t_e)
124+
}
125+
// casts from C-like enums are allowed
126+
} else if ty::type_is_region_ptr(t_e) && ty::type_is_unsafe_ptr(t_1) {
127+
fn types_compatible<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span,
128+
t1: Ty<'tcx>, t2: Ty<'tcx>) -> bool {
129+
match t1.sty {
130+
ty::ty_vec(_, Some(_)) => {}
131+
_ => return false
132+
}
133+
if ty::type_needs_infer(t2) {
134+
// This prevents this special case from going off when casting
135+
// to a type that isn't fully specified; e.g. `as *_`. (Issue
136+
// #14893.)
137+
return false
138+
}
139+
140+
let el = ty::sequence_element_type(fcx.tcx(), t1);
141+
infer::mk_eqty(fcx.infcx(),
142+
false,
143+
infer::Misc(sp),
144+
el,
145+
t2).is_ok()
146+
}
147+
148+
// Due to the limitations of LLVM global constants,
149+
// region pointers end up pointing at copies of
150+
// vector elements instead of the original values.
151+
// To allow unsafe pointers to work correctly, we
152+
// need to special-case obtaining an unsafe pointer
153+
// from a region pointer to a vector.
154+
155+
/* this cast is only allowed from &[T, ..n] to *T or
156+
&T to *T. */
157+
match (&t_e.sty, &t_1.sty) {
158+
(&ty::ty_rptr(_, ty::mt { ty: mt1, mutbl: ast::MutImmutable }),
159+
&ty::ty_ptr(ty::mt { ty: mt2, mutbl: ast::MutImmutable }))
160+
if types_compatible(fcx, e.span, mt1, mt2) => {
161+
/* this case is allowed */
162+
}
163+
_ => {
164+
demand::coerce(fcx, e.span, t_1, &e);
165+
}
166+
}
167+
} else if !(t_e_is_scalar && t_1_is_trivial) {
168+
/*
169+
If more type combinations should be supported than are
170+
supported here, then file an enhancement issue and
171+
record the issue number in this comment.
172+
*/
173+
fcx.type_error_message(span, |actual| {
174+
format!("non-scalar cast: `{}` as `{}`",
175+
actual,
176+
fcx.infcx().ty_to_string(t_1))
177+
}, t_e, None);
178+
}
179+
}

src/librustc_typeck/check/mod.rs

Lines changed: 5 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ pub mod demand;
139139
pub mod method;
140140
mod upvar;
141141
pub mod wf;
142+
mod cast;
142143
mod closure;
143144
mod callee;
144145
mod compare_method;
@@ -185,7 +186,7 @@ pub struct Inherited<'a, 'tcx: 'a> {
185186
// back and process them.
186187
deferred_call_resolutions: RefCell<DefIdMap<Vec<DeferredCallResolutionHandler<'tcx>>>>,
187188

188-
deferred_cast_checks: RefCell<Vec<CastCheck<'tcx>>>,
189+
deferred_cast_checks: RefCell<Vec<cast::CastCheck<'tcx>>>,
189190
}
190191

191192
trait DeferredCallResolution<'tcx> {
@@ -194,15 +195,6 @@ trait DeferredCallResolution<'tcx> {
194195

195196
type DeferredCallResolutionHandler<'tcx> = Box<DeferredCallResolution<'tcx>+'tcx>;
196197

197-
/// Reifies a cast check to be checked once we have full type information for
198-
/// a function context.
199-
struct CastCheck<'tcx> {
200-
expr: ast::Expr,
201-
expr_ty: Ty<'tcx>,
202-
cast_ty: Ty<'tcx>,
203-
span: Span,
204-
}
205-
206198
/// When type-checking an expression, we propagate downward
207199
/// whatever type hint we are able in the form of an `Expectation`.
208200
#[derive(Copy, Clone)]
@@ -1071,141 +1063,6 @@ fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
10711063
}
10721064

10731065

1074-
fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) {
1075-
fn cast_through_integer_err<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
1076-
span: Span,
1077-
t_1: Ty<'tcx>,
1078-
t_e: Ty<'tcx>) {
1079-
fcx.type_error_message(span, |actual| {
1080-
format!("illegal cast; cast through an \
1081-
integer first: `{}` as `{}`",
1082-
actual,
1083-
fcx.infcx().ty_to_string(t_1))
1084-
}, t_e, None);
1085-
}
1086-
1087-
let span = cast.span;
1088-
let e = &cast.expr;
1089-
let t_e = structurally_resolved_type(fcx, span, cast.expr_ty);
1090-
let t_1 = structurally_resolved_type(fcx, span, cast.cast_ty);
1091-
1092-
// Check for trivial casts.
1093-
if !ty::type_has_ty_infer(t_1) {
1094-
if let Ok(()) = coercion::mk_assignty(fcx, e, t_e, t_1) {
1095-
if ty::type_is_numeric(t_1) && ty::type_is_numeric(t_e) {
1096-
fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS,
1097-
e.id,
1098-
span,
1099-
format!("trivial numeric cast: `{}` as `{}`. Cast can be \
1100-
replaced by coercion, this might require type \
1101-
ascription or a temporary variable",
1102-
fcx.infcx().ty_to_string(t_e),
1103-
fcx.infcx().ty_to_string(t_1)));
1104-
} else {
1105-
fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_CASTS,
1106-
e.id,
1107-
span,
1108-
format!("trivial cast: `{}` as `{}`. Cast can be \
1109-
replaced by coercion, this might require type \
1110-
ascription or a temporary variable",
1111-
fcx.infcx().ty_to_string(t_e),
1112-
fcx.infcx().ty_to_string(t_1)));
1113-
}
1114-
return;
1115-
}
1116-
}
1117-
1118-
let t_e_is_bare_fn_item = ty::type_is_bare_fn_item(t_e);
1119-
let t_e_is_scalar = ty::type_is_scalar(t_e);
1120-
let t_e_is_integral = ty::type_is_integral(t_e);
1121-
let t_e_is_float = ty::type_is_floating_point(t_e);
1122-
let t_e_is_c_enum = ty::type_is_c_like_enum(fcx.tcx(), t_e);
1123-
1124-
let t_1_is_scalar = ty::type_is_scalar(t_1);
1125-
let t_1_is_char = ty::type_is_char(t_1);
1126-
let t_1_is_bare_fn = ty::type_is_bare_fn(t_1);
1127-
let t_1_is_float = ty::type_is_floating_point(t_1);
1128-
1129-
// casts to scalars other than `char` and `bare fn` are trivial
1130-
let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn;
1131-
1132-
if t_e_is_bare_fn_item && t_1_is_bare_fn {
1133-
demand::coerce(fcx, e.span, t_1, &e);
1134-
} else if t_1_is_char {
1135-
let t_e = fcx.infcx().shallow_resolve(t_e);
1136-
if t_e.sty != ty::ty_uint(ast::TyU8) {
1137-
fcx.type_error_message(span, |actual| {
1138-
format!("only `u8` can be cast as `char`, not `{}`", actual)
1139-
}, t_e, None);
1140-
}
1141-
} else if t_1.sty == ty::ty_bool {
1142-
span_err!(fcx.tcx().sess, span, E0054,
1143-
"cannot cast as `bool`, compare with zero instead");
1144-
} else if t_1_is_float && (t_e_is_scalar || t_e_is_c_enum) && !(
1145-
t_e_is_integral || t_e_is_float || t_e.sty == ty::ty_bool) {
1146-
// Casts to float must go through an integer or boolean
1147-
cast_through_integer_err(fcx, span, t_1, t_e)
1148-
} else if t_e_is_c_enum && t_1_is_trivial {
1149-
if ty::type_is_unsafe_ptr(t_1) {
1150-
// ... and likewise with C enum -> *T
1151-
cast_through_integer_err(fcx, span, t_1, t_e)
1152-
}
1153-
// casts from C-like enums are allowed
1154-
} else if ty::type_is_region_ptr(t_e) && ty::type_is_unsafe_ptr(t_1) {
1155-
fn types_compatible<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span,
1156-
t1: Ty<'tcx>, t2: Ty<'tcx>) -> bool {
1157-
match t1.sty {
1158-
ty::ty_vec(_, Some(_)) => {}
1159-
_ => return false
1160-
}
1161-
if ty::type_needs_infer(t2) {
1162-
// This prevents this special case from going off when casting
1163-
// to a type that isn't fully specified; e.g. `as *_`. (Issue
1164-
// #14893.)
1165-
return false
1166-
}
1167-
1168-
let el = ty::sequence_element_type(fcx.tcx(), t1);
1169-
infer::mk_eqty(fcx.infcx(),
1170-
false,
1171-
infer::Misc(sp),
1172-
el,
1173-
t2).is_ok()
1174-
}
1175-
1176-
// Due to the limitations of LLVM global constants,
1177-
// region pointers end up pointing at copies of
1178-
// vector elements instead of the original values.
1179-
// To allow unsafe pointers to work correctly, we
1180-
// need to special-case obtaining an unsafe pointer
1181-
// from a region pointer to a vector.
1182-
1183-
/* this cast is only allowed from &[T, ..n] to *T or
1184-
&T to *T. */
1185-
match (&t_e.sty, &t_1.sty) {
1186-
(&ty::ty_rptr(_, ty::mt { ty: mt1, mutbl: ast::MutImmutable }),
1187-
&ty::ty_ptr(ty::mt { ty: mt2, mutbl: ast::MutImmutable }))
1188-
if types_compatible(fcx, e.span, mt1, mt2) => {
1189-
/* this case is allowed */
1190-
}
1191-
_ => {
1192-
demand::coerce(fcx, e.span, t_1, &e);
1193-
}
1194-
}
1195-
} else if !(t_e_is_scalar && t_1_is_trivial) {
1196-
/*
1197-
If more type combinations should be supported than are
1198-
supported here, then file an enhancement issue and
1199-
record the issue number in this comment.
1200-
*/
1201-
fcx.type_error_message(span, |actual| {
1202-
format!("non-scalar cast: `{}` as `{}`",
1203-
actual,
1204-
fcx.infcx().ty_to_string(t_1))
1205-
}, t_e, None);
1206-
}
1207-
}
1208-
12091066
impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
12101067
fn tcx(&self) -> &ty::ctxt<'tcx> { self.ccx.tcx }
12111068

@@ -1925,7 +1782,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
19251782
fn check_casts(&self) {
19261783
let mut deferred_cast_checks = self.inh.deferred_cast_checks.borrow_mut();
19271784
for check in deferred_cast_checks.iter() {
1928-
check_cast(self, check);
1785+
cast::check_cast(self, check);
19291786
}
19301787

19311788
deferred_cast_checks.clear();
@@ -3531,12 +3388,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
35313388

35323389
// Defer other checks until we're done type checking.
35333390
let mut deferred_cast_checks = fcx.inh.deferred_cast_checks.borrow_mut();
3534-
deferred_cast_checks.push(CastCheck {
3535-
expr: (**e).clone(),
3536-
expr_ty: t_e,
3537-
cast_ty: t_1,
3538-
span: expr.span,
3539-
});
3391+
let cast_check = cast::CastCheck::new((**e).clone(), t_e, t_1, expr.span);
3392+
deferred_cast_checks.push(cast_check);
35403393
}
35413394
}
35423395
ast::ExprVec(ref args) => {

0 commit comments

Comments
 (0)