diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2021-12-13 18:15:16 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-12-13 18:15:16 +0100 |
| commit | 84878336b05f1dcdff6f2a55b6b66d5fa6f2e82e (patch) | |
| tree | 922205b28a71aaf72812e55e06c181001d88d113 /compiler | |
| parent | f8de2f56e8628ec830d2bfd77a30f681f27bb46a (diff) | |
| parent | 48974158f1ce88dca7edd66c7bae81e759c2679d (diff) | |
| download | rust-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.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/wfcheck.rs | 54 |
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(), |
