about summary refs log tree commit diff
path: root/compiler/rustc_hir_analysis/src
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2022-09-14 23:20:03 +0000
committerMichael Goulet <michael@errs.io>2022-10-14 04:27:01 +0000
commit76386bd65e650b5289b142daa310a4b98230c3db (patch)
treeb19f517615b9b5dcf35370d2ba8285a7f94f151d /compiler/rustc_hir_analysis/src
parentedabf59ca4646b3fc1a961c26431215001043f6a (diff)
downloadrust-76386bd65e650b5289b142daa310a4b98230c3db.tar.gz
rust-76386bd65e650b5289b142daa310a4b98230c3db.zip
Make dyn* cast into a coercion
Diffstat (limited to 'compiler/rustc_hir_analysis/src')
-rw-r--r--compiler/rustc_hir_analysis/src/check/cast.rs63
-rw-r--r--compiler/rustc_hir_analysis/src/check/coercion.rs50
-rw-r--r--compiler/rustc_hir_analysis/src/expr_use_visitor.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/mem_categorization.rs3
4 files changed, 60 insertions, 60 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/cast.rs b/compiler/rustc_hir_analysis/src/check/cast.rs
index 01badc133c9..75872830140 100644
--- a/compiler/rustc_hir_analysis/src/check/cast.rs
+++ b/compiler/rustc_hir_analysis/src/check/cast.rs
@@ -35,13 +35,12 @@ use crate::type_error_struct;
 use hir::def_id::LOCAL_CRATE;
 use rustc_errors::{struct_span_err, Applicability, DelayDm, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
-use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode};
 use rustc_middle::mir::Mutability;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::cast::{CastKind, CastTy};
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, Binder, Ty, TypeAndMut, TypeVisitable, VariantDef};
+use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable, VariantDef};
 use rustc_session::lint;
 use rustc_session::Session;
 use rustc_span::symbol::sym;
@@ -218,58 +217,10 @@ pub fn check_cast<'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, ty::DynStar) => (predicates, region),
-        _ => panic!("Invalid dyn* cast_ty"),
-    };
-
-    let cause = ObligationCause::new(
-        expr.span,
-        fcx.body_id,
-        // FIXME(dyn-star): 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));
+    match CastCheck::new(fcx, expr, expr_ty, cast_ty, cast_span, span) {
+        Ok(check) => CastCheckResult::Deferred(check),
+        Err(e) => CastCheckResult::Err(e),
     }
-
-    // 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
 }
 
 impl<'a, 'tcx> CastCheck<'tcx> {
@@ -934,11 +885,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
 
             (Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast),
 
-            // FIXME(dyn-star): this needs more conditions...
-            (_, DynStar) => Ok(CastKind::DynStarCast),
-
-            // FIXME(dyn-star): do we want to allow dyn* upcasting or other casts?
-            (DynStar, _) => Err(CastError::IllegalCast),
+            (_, DynStar) | (DynStar, _) => bug!("should be handled by `try_coerce`"),
         }
     }
 
diff --git a/compiler/rustc_hir_analysis/src/check/coercion.rs b/compiler/rustc_hir_analysis/src/check/coercion.rs
index cf87fe3c510..44e64382397 100644
--- a/compiler/rustc_hir_analysis/src/check/coercion.rs
+++ b/compiler/rustc_hir_analysis/src/check/coercion.rs
@@ -216,6 +216,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             ty::Ref(r_b, _, mutbl_b) => {
                 return self.coerce_borrowed_pointer(a, b, r_b, mutbl_b);
             }
+            ty::Dynamic(predicates, region, ty::DynStar) if self.tcx.features().dyn_star => {
+                return self.coerce_dyn_star(a, b, predicates, region);
+            }
             _ => {}
         }
 
@@ -745,6 +748,53 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         Ok(coercion)
     }
 
+    fn coerce_dyn_star(
+        &self,
+        a: Ty<'tcx>,
+        b: Ty<'tcx>,
+        predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
+        b_region: ty::Region<'tcx>,
+    ) -> CoerceResult<'tcx> {
+        if !self.tcx.features().dyn_star {
+            return Err(TypeError::Mismatch);
+        }
+
+        if let ty::Dynamic(a_data, _, _) = a.kind()
+            && let ty::Dynamic(b_data, _, _) = b.kind()
+        {
+            if a_data.principal_def_id() == b_data.principal_def_id() {
+                return self.unify_and(a, b, |_| vec![]);
+            } else {
+                bug!("dyn* trait upcasting is not supported");
+            }
+        }
+
+        let obligations = predicates
+            .iter()
+            .map(|predicate| {
+                // 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).
+                let predicate = predicate.with_self_ty(self.tcx, a);
+                Obligation::new(self.cause.clone(), self.param_env, predicate)
+            })
+            // Enforce the region bound `'static` (e.g., `usize: 'static`, in our example).
+            .chain([Obligation::new(
+                self.cause.clone(),
+                self.param_env,
+                self.tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::TypeOutlives(
+                    ty::OutlivesPredicate(a, b_region),
+                ))),
+            )])
+            .collect();
+
+        Ok(InferOk {
+            value: (vec![Adjustment { kind: Adjust::DynStar, target: b }], b),
+            obligations,
+        })
+    }
+
     fn coerce_from_safe_fn<F, G>(
         &self,
         a: Ty<'tcx>,
diff --git a/compiler/rustc_hir_analysis/src/expr_use_visitor.rs b/compiler/rustc_hir_analysis/src/expr_use_visitor.rs
index cbc3769901d..039c653e5bc 100644
--- a/compiler/rustc_hir_analysis/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_analysis/src/expr_use_visitor.rs
@@ -583,7 +583,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
         for adjustment in adjustments {
             debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
             match adjustment.kind {
-                adjustment::Adjust::NeverToAny | adjustment::Adjust::Pointer(_) => {
+                adjustment::Adjust::NeverToAny
+                | adjustment::Adjust::Pointer(_)
+                | adjustment::Adjust::DynStar => {
                     // Creating a closure/fn-pointer or unsizing consumes
                     // the input and stores it into the resulting rvalue.
                     self.delegate_consume(&place_with_id, place_with_id.hir_id);
diff --git a/compiler/rustc_hir_analysis/src/mem_categorization.rs b/compiler/rustc_hir_analysis/src/mem_categorization.rs
index b62c5b5e077..362f1c34300 100644
--- a/compiler/rustc_hir_analysis/src/mem_categorization.rs
+++ b/compiler/rustc_hir_analysis/src/mem_categorization.rs
@@ -292,7 +292,8 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
 
             adjustment::Adjust::NeverToAny
             | adjustment::Adjust::Pointer(_)
-            | adjustment::Adjust::Borrow(_) => {
+            | adjustment::Adjust::Borrow(_)
+            | adjustment::Adjust::DynStar => {
                 // Result is an rvalue.
                 Ok(self.cat_rvalue(expr.hir_id, expr.span, target))
             }