@@ -35,12 +35,15 @@ use crate::type_error_struct;
3535use hir:: def_id:: LOCAL_CRATE ;
3636use rustc_errors:: { struct_span_err, Applicability , DiagnosticBuilder , ErrorGuaranteed } ;
3737use rustc_hir as hir;
38+ use rustc_infer:: traits:: { Obligation , ObligationCause , ObligationCauseCode } ;
3839use rustc_middle:: mir:: Mutability ;
3940use rustc_middle:: ty:: adjustment:: AllowTwoPhase ;
4041use rustc_middle:: ty:: cast:: { CastKind , CastTy } ;
4142use rustc_middle:: ty:: error:: TypeError ;
4243use rustc_middle:: ty:: subst:: SubstsRef ;
43- use rustc_middle:: ty:: { self , Ty , TypeAndMut , TypeVisitable , VariantDef } ;
44+ use rustc_middle:: ty:: {
45+ self , Binder , TraitObjectRepresentation , Ty , TypeAndMut , TypeVisitable , VariantDef ,
46+ } ;
4447use rustc_session:: lint;
4548use rustc_session:: Session ;
4649use rustc_span:: symbol:: sym;
@@ -52,9 +55,12 @@ use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
5255/// a function context.
5356#[ derive( Debug ) ]
5457pub struct CastCheck < ' tcx > {
58+ /// The expression whose value is being casted
5559 expr : & ' tcx hir:: Expr < ' tcx > ,
60+ /// The source type for the cast expression
5661 expr_ty : Ty < ' tcx > ,
5762 expr_span : Span ,
63+ /// The target type. That is, the type we are casting to.
5864 cast_ty : Ty < ' tcx > ,
5965 cast_span : Span ,
6066 span : Span ,
@@ -199,8 +205,76 @@ fn make_invalid_casting_error<'a, 'tcx>(
199205 )
200206}
201207
208+ pub enum CastCheckResult < ' tcx > {
209+ Ok ,
210+ Deferred ( CastCheck < ' tcx > ) ,
211+ Err ( ErrorGuaranteed ) ,
212+ }
213+
214+ pub fn check_cast < ' tcx > (
215+ fcx : & FnCtxt < ' _ , ' tcx > ,
216+ expr : & ' tcx hir:: Expr < ' tcx > ,
217+ expr_ty : Ty < ' tcx > ,
218+ cast_ty : Ty < ' tcx > ,
219+ cast_span : Span ,
220+ span : Span ,
221+ ) -> CastCheckResult < ' tcx > {
222+ if cast_ty. is_dyn_star ( ) {
223+ check_dyn_star_cast ( fcx, expr, expr_ty, cast_ty)
224+ } else {
225+ match CastCheck :: new ( fcx, expr, expr_ty, cast_ty, cast_span, span) {
226+ Ok ( check) => CastCheckResult :: Deferred ( check) ,
227+ Err ( e) => CastCheckResult :: Err ( e) ,
228+ }
229+ }
230+ }
231+
232+ fn check_dyn_star_cast < ' tcx > (
233+ fcx : & FnCtxt < ' _ , ' tcx > ,
234+ expr : & ' tcx hir:: Expr < ' tcx > ,
235+ expr_ty : Ty < ' tcx > ,
236+ cast_ty : Ty < ' tcx > ,
237+ ) -> CastCheckResult < ' tcx > {
238+ // Find the bounds in the dyn*. For eaxmple, if we have
239+ //
240+ // let x = 22_usize as dyn* (Clone + Debug + 'static)
241+ //
242+ // this would return `existential_predicates = [?Self: Clone, ?Self: Debug]` and `region = 'static`.
243+ let ( existential_predicates, region) = match cast_ty. kind ( ) {
244+ ty:: Dynamic ( predicates, region, TraitObjectRepresentation :: Sized ) => ( predicates, region) ,
245+ _ => panic ! ( "Invalid dyn* cast_ty" ) ,
246+ } ;
247+
248+ let cause = ObligationCause :: new (
249+ expr. span ,
250+ fcx. body_id ,
251+ // FIXME: Use a better obligation cause code
252+ ObligationCauseCode :: MiscObligation ,
253+ ) ;
254+
255+ // For each existential predicate (e.g., `?Self: Clone`) substitute
256+ // the type of the expression (e.g., `usize` in our example above)
257+ // and then require that the resulting predicate (e.g., `usize: Clone`)
258+ // holds (it does).
259+ for existential_predicate in existential_predicates. iter ( ) {
260+ let predicate = existential_predicate. with_self_ty ( fcx. tcx , expr_ty) ;
261+ fcx. register_predicate ( Obligation :: new ( cause. clone ( ) , fcx. param_env , predicate) ) ;
262+ }
263+
264+ // Enforce the region bound `'static` (e.g., `usize: 'static`, in our example).
265+ fcx. register_predicate ( Obligation :: new (
266+ cause,
267+ fcx. param_env ,
268+ fcx. tcx . mk_predicate ( Binder :: dummy ( ty:: PredicateKind :: TypeOutlives (
269+ ty:: OutlivesPredicate ( expr_ty, * region) ,
270+ ) ) ) ,
271+ ) ) ;
272+
273+ CastCheckResult :: Ok
274+ }
275+
202276impl < ' a , ' tcx > CastCheck < ' tcx > {
203- pub fn new (
277+ fn new (
204278 fcx : & FnCtxt < ' a , ' tcx > ,
205279 expr : & ' tcx hir:: Expr < ' tcx > ,
206280 expr_ty : Ty < ' tcx > ,
@@ -215,7 +289,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
215289 // cases now. We do a more thorough check at the end, once
216290 // inference is more completely known.
217291 match cast_ty. kind ( ) {
218- ty:: Dynamic ( .. ) | ty:: Slice ( ..) => {
292+ ty:: Dynamic ( _ , _ , TraitObjectRepresentation :: Unsized ) | ty:: Slice ( ..) => {
219293 let reported = check. report_cast_to_unsized_type ( fcx) ;
220294 Err ( reported)
221295 }
0 commit comments