about summary refs log tree commit diff
path: root/compiler/rustc_hir_analysis/src/check/coercion.rs
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/check/coercion.rs
parentedabf59ca4646b3fc1a961c26431215001043f6a (diff)
downloadrust-76386bd65e650b5289b142daa310a4b98230c3db.tar.gz
rust-76386bd65e650b5289b142daa310a4b98230c3db.zip
Make dyn* cast into a coercion
Diffstat (limited to 'compiler/rustc_hir_analysis/src/check/coercion.rs')
-rw-r--r--compiler/rustc_hir_analysis/src/check/coercion.rs50
1 files changed, 50 insertions, 0 deletions
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>,