about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection/src
diff options
context:
space:
mode:
authorOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2022-05-05 14:14:06 +0000
committerOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2022-05-10 07:20:00 +0000
commitf667e952f85911fb2983f98d0808d40242db7b47 (patch)
tree08d27fbabfe8ea77e4a273b0112c14fdcf61b0e3 /compiler/rustc_trait_selection/src
parent12d3f107c1634ed41a800e220ccf99b665d906d8 (diff)
downloadrust-f667e952f85911fb2983f98d0808d40242db7b47.tar.gz
rust-f667e952f85911fb2983f98d0808d40242db7b47.zip
Check hidden types for well formedness at the definition site instead of only at the opaque type itself
Diffstat (limited to 'compiler/rustc_trait_selection/src')
-rw-r--r--compiler/rustc_trait_selection/src/opaque_types.rs74
1 files changed, 71 insertions, 3 deletions
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index 4b949ff8b95..81a90e92b4f 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -1,11 +1,15 @@
 use crate::traits;
+use crate::traits::error_reporting::InferCtxtExt as _;
+use crate::traits::TraitEngineExt as _;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::DefId;
+use rustc_hir::OpaqueTyOrigin;
 use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
-use rustc_infer::infer::InferCtxt;
+use rustc_infer::infer::{InferCtxt, TyCtxtInferExt as _};
+use rustc_infer::traits::{Obligation, ObligationCause, TraitEngine};
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts};
-use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt};
+use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, ToPredicate, Ty, TyCtxt};
 use rustc_span::Span;
 
 pub trait InferCtxtExt<'tcx> {
@@ -13,6 +17,7 @@ pub trait InferCtxtExt<'tcx> {
         &self,
         opaque_type_key: OpaqueTypeKey<'tcx>,
         instantiated_ty: OpaqueHiddenType<'tcx>,
+        origin: OpaqueTyOrigin,
     ) -> Ty<'tcx>;
 }
 
@@ -45,6 +50,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         &self,
         opaque_type_key: OpaqueTypeKey<'tcx>,
         instantiated_ty: OpaqueHiddenType<'tcx>,
+        origin: OpaqueTyOrigin,
     ) -> Ty<'tcx> {
         if self.is_tainted_by_errors() {
             return self.tcx.ty_error();
@@ -76,7 +82,69 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         ));
         debug!(?definition_ty);
 
-        definition_ty
+        // Only check this for TAIT. RPIT already supports `src/test/ui/impl-trait/nested-return-type2.rs`
+        // on stable and we'd break that.
+        if let OpaqueTyOrigin::TyAlias = origin {
+            // This logic duplicates most of `check_opaque_meets_bounds`.
+            // FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely.
+            let param_env = self.tcx.param_env(def_id);
+            let body_id = self.tcx.local_def_id_to_hir_id(def_id.as_local().unwrap());
+            self.tcx.infer_ctxt().enter(move |infcx| {
+                // Require the hidden type to be well-formed with only the generics of the opaque type.
+                // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
+                // hidden type is well formed even without those bounds.
+                let predicate =
+                    ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()))
+                        .to_predicate(infcx.tcx);
+                let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
+
+                // Require that the hidden type actually fulfills all the bounds of the opaque type, even without
+                // the bounds that the function supplies.
+                match infcx.register_hidden_type(
+                    OpaqueTypeKey { def_id, substs: id_substs },
+                    ObligationCause::misc(instantiated_ty.span, body_id),
+                    param_env,
+                    definition_ty,
+                    origin,
+                ) {
+                    Ok(infer_ok) => {
+                        for obligation in infer_ok.obligations {
+                            fulfillment_cx.register_predicate_obligation(&infcx, obligation);
+                        }
+                    }
+                    Err(err) => {
+                        infcx
+                            .report_mismatched_types(
+                                &ObligationCause::misc(instantiated_ty.span, body_id),
+                                self.tcx.mk_opaque(def_id, id_substs),
+                                definition_ty,
+                                err,
+                            )
+                            .emit();
+                    }
+                }
+
+                fulfillment_cx.register_predicate_obligation(
+                    &infcx,
+                    Obligation::misc(instantiated_ty.span, body_id, param_env, predicate),
+                );
+
+                // Check that all obligations are satisfied by the implementation's
+                // version.
+                let errors = fulfillment_cx.select_all_or_error(&infcx);
+
+                let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+
+                if errors.is_empty() {
+                    definition_ty
+                } else {
+                    infcx.report_fulfillment_errors(&errors, None, false);
+                    self.tcx.ty_error()
+                }
+            })
+        } else {
+            definition_ty
+        }
     }
 }