about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2021-12-13 18:15:16 +0100
committerGitHub <noreply@github.com>2021-12-13 18:15:16 +0100
commit84878336b05f1dcdff6f2a55b6b66d5fa6f2e82e (patch)
tree922205b28a71aaf72812e55e06c181001d88d113 /compiler
parentf8de2f56e8628ec830d2bfd77a30f681f27bb46a (diff)
parent48974158f1ce88dca7edd66c7bae81e759c2679d (diff)
downloadrust-84878336b05f1dcdff6f2a55b6b66d5fa6f2e82e.tar.gz
rust-84878336b05f1dcdff6f2a55b6b66d5fa6f2e82e.zip
Rollup merge of #91849 - jackh726:gats-outlives-lint-part2, r=nikomatsakis
GATs outlives lint: Try to prove bounds

Fixes #91036
Fixes #90888
Fixes #91348 (better error + documentation to be added to linked issue)

Instead of checking for bounds directly, try to prove them in the associated type environment.

Also, add a bit of extra information to the error, including a link to the relevant discussion issue (#87479). That should be edited to include a brief summary of the current state of the outlives lint, including a brief background. It also might or might not be worth it to bump this to a full error code at some point.

r? ``@nikomatsakis``
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_infer/src/infer/free_regions.rs2
-rw-r--r--compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs2
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs54
3 files changed, 48 insertions, 10 deletions
diff --git a/compiler/rustc_infer/src/infer/free_regions.rs b/compiler/rustc_infer/src/infer/free_regions.rs
index 4814b65e320..e93cdf79421 100644
--- a/compiler/rustc_infer/src/infer/free_regions.rs
+++ b/compiler/rustc_infer/src/infer/free_regions.rs
@@ -11,7 +11,7 @@ use rustc_middle::ty::{self, Lift, Region, TyCtxt};
 ///
 /// This stuff is a bit convoluted and should be refactored, but as we
 /// transition to NLL, it'll all go away anyhow.
-pub struct RegionRelations<'a, 'tcx> {
+pub(crate) struct RegionRelations<'a, 'tcx> {
     pub tcx: TyCtxt<'tcx>,
 
     /// The context used for debug messages
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index 85ee6d2cdc2..a5ec84a4f14 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -28,7 +28,7 @@ use std::fmt;
 /// assuming such values can be found. It returns the final values of
 /// all the variables as well as a set of errors that must be reported.
 #[instrument(level = "debug", skip(region_rels, var_infos, data))]
-pub fn resolve<'tcx>(
+pub(crate) fn resolve<'tcx>(
     region_rels: &RegionRelations<'_, 'tcx>,
     var_infos: VarInfos,
     data: RegionConstraintData<'tcx>,
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 3fd3284d8b1..1404bc27167 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -426,22 +426,48 @@ fn check_gat_where_clauses(
         }
     }
 
-    // If there are any missing clauses, emit an error
-    let mut clauses = clauses.unwrap_or_default();
+    // If there are any clauses that aren't provable, emit an error
+    let clauses = clauses.unwrap_or_default();
     debug!(?clauses);
     if !clauses.is_empty() {
-        let written_predicates: ty::GenericPredicates<'_> =
-            tcx.explicit_predicates_of(trait_item.def_id);
+        let param_env = tcx.param_env(trait_item.def_id);
+
         let mut clauses: Vec<_> = clauses
-            .drain_filter(|clause| !written_predicates.predicates.iter().any(|p| &p.0 == clause))
+            .into_iter()
+            .filter(|clause| match clause.kind().skip_binder() {
+                ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => {
+                    !region_known_to_outlive(
+                        tcx,
+                        trait_item.hir_id(),
+                        param_env,
+                        &FxHashSet::default(),
+                        a,
+                        b,
+                    )
+                }
+                ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
+                    !ty_known_to_outlive(
+                        tcx,
+                        trait_item.hir_id(),
+                        param_env,
+                        &FxHashSet::default(),
+                        a,
+                        b,
+                    )
+                }
+                _ => bug!("Unexpected PredicateKind"),
+            })
             .map(|clause| format!("{}", clause))
             .collect();
+
         // We sort so that order is predictable
         clauses.sort();
+
         if !clauses.is_empty() {
+            let plural = if clauses.len() > 1 { "s" } else { "" };
             let mut err = tcx.sess.struct_span_err(
                 trait_item.span,
-                &format!("Missing required bounds on {}", trait_item.ident),
+                &format!("missing required bound{} on `{}`", plural, trait_item.ident),
             );
 
             let suggestion = format!(
@@ -455,11 +481,22 @@ fn check_gat_where_clauses(
             );
             err.span_suggestion(
                 trait_item.generics.where_clause.tail_span_for_suggestion(),
-                "add the required where clauses",
+                &format!("add the required where clause{}", plural),
                 suggestion,
                 Applicability::MachineApplicable,
             );
 
+            let bound = if clauses.len() > 1 { "these bounds are" } else { "this bound is" };
+            err.note(&format!(
+                "{} currently required to ensure that impls have maximum flexibility",
+                bound
+            ));
+            err.note(
+                "we are soliciting feedback, see issue #87479 \
+                 <https://github.com/rust-lang/rust/issues/87479> \
+                 for more information",
+            );
+
             err.emit()
         }
     }
@@ -541,7 +578,8 @@ fn region_known_to_outlive<'tcx>(
         });
 
         use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate;
-        (&infcx).push_sub_region_constraint(origin, region_a, region_b);
+        // `region_a: region_b` -> `region_b <= region_a`
+        (&infcx).push_sub_region_constraint(origin, region_b, region_a);
 
         let errors = infcx.resolve_regions(
             id.expect_owner().to_def_id(),