summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits/structural_normalize.rs')
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_normalize.rs55
1 files changed, 55 insertions, 0 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
new file mode 100644
index 000000000..af8dd0da5
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
@@ -0,0 +1,55 @@
+use rustc_infer::infer::at::At;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::traits::{FulfillmentError, TraitEngine};
+use rustc_middle::ty::{self, Ty};
+
+use crate::traits::{query::evaluate_obligation::InferCtxtExt, NormalizeExt, Obligation};
+
+pub trait StructurallyNormalizeExt<'tcx> {
+ fn structurally_normalize(
+ &self,
+ ty: Ty<'tcx>,
+ fulfill_cx: &mut dyn TraitEngine<'tcx>,
+ ) -> Result<Ty<'tcx>, Vec<FulfillmentError<'tcx>>>;
+}
+
+impl<'tcx> StructurallyNormalizeExt<'tcx> for At<'_, 'tcx> {
+ fn structurally_normalize(
+ &self,
+ mut ty: Ty<'tcx>,
+ fulfill_cx: &mut dyn TraitEngine<'tcx>,
+ ) -> Result<Ty<'tcx>, Vec<FulfillmentError<'tcx>>> {
+ assert!(!ty.is_ty_var(), "should have resolved vars before calling");
+
+ if self.infcx.tcx.trait_solver_next() {
+ while let ty::Alias(ty::Projection, projection_ty) = *ty.kind() {
+ let new_infer_ty = self.infcx.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::NormalizeProjectionType,
+ span: self.cause.span,
+ });
+ let obligation = Obligation::new(
+ self.infcx.tcx,
+ self.cause.clone(),
+ self.param_env,
+ ty::Binder::dummy(ty::ProjectionPredicate {
+ projection_ty,
+ term: new_infer_ty.into(),
+ }),
+ );
+ if self.infcx.predicate_may_hold(&obligation) {
+ fulfill_cx.register_predicate_obligation(self.infcx, obligation);
+ let errors = fulfill_cx.select_where_possible(self.infcx);
+ if !errors.is_empty() {
+ return Err(errors);
+ }
+ ty = self.infcx.resolve_vars_if_possible(new_infer_ty);
+ } else {
+ break;
+ }
+ }
+ Ok(ty)
+ } else {
+ Ok(self.normalize(ty).into_value_registering_obligations(self.infcx, fulfill_cx))
+ }
+ }
+}