+pub enum CastCheckResult<'tcx> {
+ Ok,
+ Deferred(CastCheck<'tcx>),
+ Err(ErrorGuaranteed),
+}
+
+pub fn check_cast<'tcx>(
+ fcx: &FnCtxt<'_, 'tcx>,
+ expr: &'tcx hir::Expr<'tcx>,
+ expr_ty: Ty<'tcx>,
+ cast_ty: Ty<'tcx>,
+ cast_span: Span,
+ span: Span,
+) -> CastCheckResult<'tcx> {
+ if cast_ty.is_dyn_star() {
+ check_dyn_star_cast(fcx, expr, expr_ty, cast_ty)
+ } else {
+ match CastCheck::new(fcx, expr, expr_ty, cast_ty, cast_span, span) {
+ Ok(check) => CastCheckResult::Deferred(check),
+ Err(e) => CastCheckResult::Err(e),
+ }
+ }
+}
+
+fn check_dyn_star_cast<'tcx>(
+ fcx: &FnCtxt<'_, 'tcx>,
+ expr: &'tcx hir::Expr<'tcx>,
+ expr_ty: Ty<'tcx>,
+ cast_ty: Ty<'tcx>,
+) -> CastCheckResult<'tcx> {
+ // Find the bounds in the dyn*. For eaxmple, if we have
+ //
+ // let x = 22_usize as dyn* (Clone + Debug + 'static)
+ //
+ // this would return `existential_predicates = [?Self: Clone, ?Self: Debug]` and `region = 'static`.
+ let (existential_predicates, region) = match cast_ty.kind() {
+ ty::Dynamic(predicates, region, TraitObjectRepresentation::Sized) => (predicates, region),
+ _ => panic!("Invalid dyn* cast_ty"),
+ };
+
+ let cause = ObligationCause::new(
+ expr.span,
+ fcx.body_id,
+ // FIXME: Use a better obligation cause code
+ ObligationCauseCode::MiscObligation,
+ );
+
+ // For each existential predicate (e.g., `?Self: Clone`) substitute
+ // the type of the expression (e.g., `usize` in our example above)
+ // and then require that the resulting predicate (e.g., `usize: Clone`)
+ // holds (it does).
+ for existential_predicate in existential_predicates.iter() {
+ let predicate = existential_predicate.with_self_ty(fcx.tcx, expr_ty);
+ fcx.register_predicate(Obligation::new(cause.clone(), fcx.param_env, predicate));
+ }
+
+ // Enforce the region bound `'static` (e.g., `usize: 'static`, in our example).
+ fcx.register_predicate(Obligation::new(
+ cause,
+ fcx.param_env,
+ fcx.tcx.mk_predicate(Binder::dummy(ty::PredicateKind::TypeOutlives(
+ ty::OutlivesPredicate(expr_ty, *region),
+ ))),
+ ));
+
+ CastCheckResult::Ok
+}
+