]> git.lizzy.rs Git - rust.git/commitdiff
improve infer var handling for implied bounds
authorlcnr <rust@lcnr.de>
Mon, 19 Sep 2022 12:59:52 +0000 (14:59 +0200)
committerlcnr <rust@lcnr.de>
Mon, 19 Sep 2022 13:13:34 +0000 (15:13 +0200)
compiler/rustc_infer/src/infer/outlives/env.rs
compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
compiler/rustc_traits/src/implied_outlives_bounds.rs
compiler/rustc_typeck/src/check/compare_method.rs

index 872886da3626108ca370bfb942d650bced1a1775..9922b156ebf96d0c5765f6d192a4e0be058c580a 100644 (file)
@@ -53,6 +53,7 @@ pub struct OutlivesEnvironment<'tcx> {
 }
 
 /// Builder of OutlivesEnvironment.
+#[derive(Debug)]
 struct OutlivesEnvironmentBuilder<'tcx> {
     param_env: ty::ParamEnv<'tcx>,
     region_relation: TransitiveRelationBuilder<Region<'tcx>>,
@@ -109,6 +110,7 @@ pub fn region_bound_pairs(&self) -> &RegionBoundPairs<'tcx> {
 
 impl<'a, 'tcx> OutlivesEnvironmentBuilder<'tcx> {
     #[inline]
+    #[instrument(level = "debug")]
     fn build(self) -> OutlivesEnvironment<'tcx> {
         OutlivesEnvironment {
             param_env: self.param_env,
index a4b540182280b601b0115adfa63090fba8035d60..3008dfcadde9e3c7eccd56081bd06a34b7f36ee1 100644 (file)
@@ -46,7 +46,7 @@ impl<'a, 'cx, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'cx, 'tcx> {
     ///   Note that this may cause outlives obligations to be injected
     ///   into the inference context with this body-id.
     /// - `ty`, the type that we are supposed to assume is WF.
-    #[instrument(level = "debug", skip(self, param_env, body_id))]
+    #[instrument(level = "debug", skip(self, param_env, body_id), ret)]
     fn implied_outlives_bounds(
         &self,
         param_env: ty::ParamEnv<'tcx>,
@@ -71,6 +71,7 @@ fn implied_outlives_bounds(
         let TypeOpOutput { output, constraints, .. } = result;
 
         if let Some(constraints) = constraints {
+            debug!(?constraints);
             // Instantiation may have produced new inference variables and constraints on those
             // variables. Process these constraints.
             let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(self.tcx);
index e3e78f70b15ef9014ba115a63405fde35b50a283..691b79f10533dd813579d7a9afa72c76b647ce00 100644 (file)
@@ -49,7 +49,8 @@ fn compute_implied_outlives_bounds<'tcx>(
     let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default();
     let mut wf_args = vec![ty.into()];
 
-    let mut implied_bounds = vec![];
+    let mut outlives_bounds: Vec<ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>> =
+        vec![];
 
     let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx);
 
@@ -65,30 +66,17 @@ fn compute_implied_outlives_bounds<'tcx>(
         // than the ultimate set. (Note: normally there won't be
         // unresolved inference variables here anyway, but there might be
         // during typeck under some circumstances.)
+        //
+        // FIXME(@lcnr): It's not really "always fine", having fewer implied
+        // bounds can be backward incompatible, e.g. #101951 was caused by
+        // us not dealing with inference vars in `TypeOutlives` predicates.
         let obligations = wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, 0, arg, DUMMY_SP)
             .unwrap_or_default();
 
-        // N.B., all of these predicates *ought* to be easily proven
-        // true. In fact, their correctness is (mostly) implied by
-        // other parts of the program. However, in #42552, we had
-        // an annoying scenario where:
-        //
-        // - Some `T::Foo` gets normalized, resulting in a
-        //   variable `_1` and a `T: Trait<Foo=_1>` constraint
-        //   (not sure why it couldn't immediately get
-        //   solved). This result of `_1` got cached.
-        // - These obligations were dropped on the floor here,
-        //   rather than being registered.
-        // - Then later we would get a request to normalize
-        //   `T::Foo` which would result in `_1` being used from
-        //   the cache, but hence without the `T: Trait<Foo=_1>`
-        //   constraint. As a result, `_1` never gets resolved,
-        //   and we get an ICE (in dropck).
-        //
-        // Therefore, we register any predicates involving
-        // inference variables. We restrict ourselves to those
-        // involving inference variables both for efficiency and
-        // to avoids duplicate errors that otherwise show up.
+        // While these predicates should all be implied by other parts of
+        // the program, they are still relevant as they may constrain
+        // inference variables, which is necessary to add the correct
+        // implied bounds in some cases, mostly when dealing with projections.
         fulfill_cx.register_predicate_obligations(
             infcx,
             obligations.iter().filter(|o| o.predicate.has_infer_types_or_consts()).cloned(),
@@ -96,10 +84,10 @@ fn compute_implied_outlives_bounds<'tcx>(
 
         // From the full set of obligations, just filter down to the
         // region relationships.
-        implied_bounds.extend(obligations.into_iter().flat_map(|obligation| {
+        outlives_bounds.extend(obligations.into_iter().filter_map(|obligation| {
             assert!(!obligation.has_escaping_bound_vars());
             match obligation.predicate.kind().no_bound_vars() {
-                None => vec![],
+                None => None,
                 Some(pred) => match pred {
                     ty::PredicateKind::Trait(..)
                     | ty::PredicateKind::Subtype(..)
@@ -109,21 +97,18 @@ fn compute_implied_outlives_bounds<'tcx>(
                     | ty::PredicateKind::ObjectSafe(..)
                     | ty::PredicateKind::ConstEvaluatable(..)
                     | ty::PredicateKind::ConstEquate(..)
-                    | ty::PredicateKind::TypeWellFormedFromEnv(..) => vec![],
+                    | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
                     ty::PredicateKind::WellFormed(arg) => {
                         wf_args.push(arg);
-                        vec![]
+                        None
                     }
 
                     ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
-                        vec![OutlivesBound::RegionSubRegion(r_b, r_a)]
+                        Some(ty::OutlivesPredicate(r_a.into(), r_b))
                     }
 
                     ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, r_b)) => {
-                        let ty_a = infcx.resolve_vars_if_possible(ty_a);
-                        let mut components = smallvec![];
-                        push_outlives_components(tcx, ty_a, &mut components);
-                        implied_bounds_from_components(r_b, components)
+                        Some(ty::OutlivesPredicate(ty_a.into(), r_b))
                     }
                 },
             }
@@ -133,9 +118,27 @@ fn compute_implied_outlives_bounds<'tcx>(
     // Ensure that those obligations that we had to solve
     // get solved *here*.
     match fulfill_cx.select_all_or_error(infcx).as_slice() {
-        [] => Ok(implied_bounds),
-        _ => Err(NoSolution),
+        [] => (),
+        _ => return Err(NoSolution),
     }
+
+    // We lazily compute the outlives components as
+    // `select_all_or_error` constrains inference variables.
+    let implied_bounds = outlives_bounds
+        .into_iter()
+        .flat_map(|ty::OutlivesPredicate(a, r_b)| match a.unpack() {
+            ty::GenericArgKind::Lifetime(r_a) => vec![OutlivesBound::RegionSubRegion(r_b, r_a)],
+            ty::GenericArgKind::Type(ty_a) => {
+                let ty_a = infcx.resolve_vars_if_possible(ty_a);
+                let mut components = smallvec![];
+                push_outlives_components(tcx, ty_a, &mut components);
+                implied_bounds_from_components(r_b, components)
+            }
+            ty::GenericArgKind::Const(_) => unreachable!(),
+        })
+        .collect();
+
+    Ok(implied_bounds)
 }
 
 /// When we have an implied bound that `T: 'a`, we can further break
index 0c6d8f26f1d6340e939df2abc18afe8fffc3c175..59d591acdc445ce962238e1cba3d83b84db8268b 100644 (file)
@@ -140,6 +140,7 @@ pub(crate) fn compare_impl_method<'tcx>(
 ///
 /// Finally we register each of these predicates as an obligation and check that
 /// they hold.
+#[instrument(level = "debug", skip(tcx, impl_m_span, impl_trait_ref))]
 fn compare_predicate_entailment<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_m: &AssocItem,