From baf4bb7100e770fb4cf052c07d408a9dd97d6e96 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 3 Dec 2024 18:42:09 +0100 Subject: [PATCH 01/11] remove unnecessary `eval_verify_bound` --- .../rustc_borrowck/src/region_infer/mod.rs | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 0eecf98a6ede5..fd58de6497d53 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -973,7 +973,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { propagated_outlives_requirements: &mut Vec>, ) -> bool { let tcx = infcx.tcx; - let TypeTest { generic_kind, lower_bound, span: blame_span, ref verify_bound } = *type_test; + let TypeTest { generic_kind, lower_bound, span: blame_span, verify_bound: _ } = *type_test; let generic_ty = generic_kind.to_ty(tcx); let Some(subject) = self.try_promote_type_test_subject(infcx, generic_ty) else { @@ -1013,23 +1013,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { // `ClosureOutlivesRequirement`. for ur in self.scc_values.universal_regions_outlived_by(r_scc) { debug!("universal_region_outlived_by ur={:?}", ur); - // Check whether we can already prove that the "subject" outlives `ur`. - // If so, we don't have to propagate this requirement to our caller. - // - // To continue the example from the function, if we are trying to promote - // a requirement that `T: 'X`, and we know that `'X = '1 + '2` (i.e., the union - // `'1` and `'2`), then in this loop `ur` will be `'1` (and `'2`). So here - // we check whether `T: '1` is something we *can* prove. If so, no need - // to propagate that requirement. - // - // This is needed because -- particularly in the case - // where `ur` is a local bound -- we are sometimes in a - // position to prove things that our caller cannot. See - // #53570 for an example. - if self.eval_verify_bound(infcx, generic_ty, ur, &verify_bound) { - continue; - } - let non_local_ub = self.universal_region_relations.non_local_upper_bounds(ur); debug!(?non_local_ub); From 1228b38cbd1dfd2252fd89eb5badb1e123f0849a Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 4 Dec 2024 17:12:57 +0100 Subject: [PATCH 02/11] add assert --- compiler/rustc_borrowck/src/region_infer/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index fd58de6497d53..035c52101071d 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1011,7 +1011,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { // For each region outlived by lower_bound find a non-local, // universal region (it may be the same region) and add it to // `ClosureOutlivesRequirement`. + let mut found_outlived_universal_region = false; for ur in self.scc_values.universal_regions_outlived_by(r_scc) { + found_outlived_universal_region = true; debug!("universal_region_outlived_by ur={:?}", ur); let non_local_ub = self.universal_region_relations.non_local_upper_bounds(ur); debug!(?non_local_ub); @@ -1034,6 +1036,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { propagated_outlives_requirements.push(requirement); } } + // If we succeed to promote the subject, i.e. it only contains non-local regions, + // and fail to prove the type test inside of the closure, the `lower_bound` has to + // also be at least as large as some universal region, as the type test is otherwise + // trivial. + assert!(found_outlived_universal_region); true } From b579c36224d9143a5721e4427d95f60e82cce6a6 Mon Sep 17 00:00:00 2001 From: Max Niederman Date: Sat, 24 Aug 2024 21:56:12 -0700 Subject: [PATCH 03/11] add guard patterns to HIR and implement lowering --- compiler/rustc_ast_lowering/src/pat.rs | 5 +++-- compiler/rustc_hir/src/hir.rs | 7 +++++-- compiler/rustc_hir/src/intravisit.rs | 4 ++++ compiler/rustc_hir_analysis/src/check/region.rs | 5 ++++- compiler/rustc_hir_pretty/src/lib.rs | 6 ++++++ compiler/rustc_hir_typeck/src/expr.rs | 3 +++ compiler/rustc_hir_typeck/src/expr_use_visitor.rs | 3 ++- compiler/rustc_hir_typeck/src/pat.rs | 9 ++++++++- compiler/rustc_mir_build/src/thir/pattern/mod.rs | 3 +++ compiler/rustc_passes/src/input_stats.rs | 1 + src/librustdoc/clean/utils.rs | 1 + 11 files changed, 40 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index a4ab2561b721b..40e7d6430fde5 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -120,8 +120,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.lower_range_end(end, e2.is_some()), ); } - // FIXME(guard_patterns): lower pattern guards to HIR - PatKind::Guard(inner, _) => pattern = inner, + PatKind::Guard(inner, cond) => { + break hir::PatKind::Guard(self.lower_pat(inner), self.lower_expr(cond)); + } PatKind::Slice(pats) => break self.lower_pat_slice(pats), PatKind::Rest => { // If we reach here the `..` pattern is not semantically allowed. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 5ea3bcef9ba3b..21367e0acbc16 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1385,7 +1385,7 @@ impl<'hir> Pat<'hir> { use PatKind::*; match self.kind { Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => true, - Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_short_(it), + Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_short_(it), Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)), TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)), Slice(before, slice, after) => { @@ -1412,7 +1412,7 @@ impl<'hir> Pat<'hir> { use PatKind::*; match self.kind { Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => {} - Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_(it), + Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_(it), Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)), TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)), Slice(before, slice, after) => { @@ -1564,6 +1564,9 @@ pub enum PatKind<'hir> { /// A literal. Lit(&'hir Expr<'hir>), + /// A guard pattern (e.g., `x if guard(x)`). + Guard(&'hir Pat<'hir>, &'hir Expr<'hir>), + /// A range pattern (e.g., `1..=2` or `1..2`). Range(Option<&'hir Expr<'hir>>, Option<&'hir Expr<'hir>>, RangeEnd), diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 387a195cb2981..be73b513db232 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -696,6 +696,10 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V: visit_opt!(visitor, visit_pat, slice_pattern); walk_list!(visitor, visit_pat, postpatterns); } + PatKind::Guard(subpat, condition) => { + try_visit!(visitor.visit_pat(subpat)); + try_visit!(visitor.visit_expr(condition)); + } } V::Result::output() } diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index ca6729a5bbdf6..ffc0657eebf1d 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -654,6 +654,7 @@ fn resolve_local<'tcx>( /// | ( ..., P&, ... ) /// | ... "|" P& "|" ... /// | box P& + /// | P& if ... /// ``` fn is_binding_pat(pat: &hir::Pat<'_>) -> bool { // Note that the code below looks for *explicit* refs only, that is, it won't @@ -694,7 +695,9 @@ fn resolve_local<'tcx>( | PatKind::TupleStruct(_, subpats, _) | PatKind::Tuple(subpats, _) => subpats.iter().any(|p| is_binding_pat(p)), - PatKind::Box(subpat) | PatKind::Deref(subpat) => is_binding_pat(subpat), + PatKind::Box(subpat) | PatKind::Deref(subpat) | PatKind::Guard(subpat, _) => { + is_binding_pat(subpat) + } PatKind::Ref(_, _) | PatKind::Binding(hir::BindingMode(hir::ByRef::No, _), ..) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 5c1c58921907e..3717119c2ddc5 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1999,6 +1999,12 @@ impl<'a> State<'a> { self.commasep(Inconsistent, after, |s, p| s.print_pat(p)); self.word("]"); } + PatKind::Guard(inner, cond) => { + self.print_pat(inner); + self.space(); + self.word_space("if"); + self.print_expr(cond); + } PatKind::Err(_) => { self.popen(); self.word("/*ERROR*/"); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index a7d12cae7b5f3..9170ecb13616c 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -457,6 +457,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Does not constitute a read. hir::PatKind::Wild => false, + // Might not constitute a read, since the condition might be false. + hir::PatKind::Guard(_, _) => true, + // This is unnecessarily restrictive when the pattern that doesn't // constitute a read is unreachable. // diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index ecbae6ac72fa2..ad764e5563b94 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -615,6 +615,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx | PatKind::Box(_) | PatKind::Deref(_) | PatKind::Ref(..) + | PatKind::Guard(..) | PatKind::Wild | PatKind::Err(_) => { // If the PatKind is Or, Box, or Ref, the decision is made later @@ -1737,7 +1738,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx } } - PatKind::Binding(.., Some(subpat)) => { + PatKind::Binding(.., Some(subpat)) | PatKind::Guard(subpat, _) => { self.cat_pattern(place_with_id, subpat, op)?; } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 98b28240f4cb9..5c6fdc81a4931 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -284,6 +284,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PatKind::Struct(ref qpath, fields, has_rest_pat) => { self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, pat_info) } + PatKind::Guard(pat, _) => { + self.check_pat(pat, expected, pat_info); + expected + } PatKind::Or(pats) => { for pat in pats { self.check_pat(pat, expected, pat_info); @@ -422,7 +426,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // An OR-pattern just propagates to each individual alternative. // This is maximally flexible, allowing e.g., `Some(mut x) | &Some(mut x)`. // In that example, `Some(mut x)` results in `Peel` whereas `&Some(mut x)` in `Reset`. - | PatKind::Or(_) => AdjustMode::Pass, + | PatKind::Or(_) + // Like or-patterns, guard patterns just propogate to their subpatterns. + | PatKind::Guard(..) => AdjustMode::Pass, } } @@ -901,6 +907,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Or(..) + | PatKind::Guard(..) | PatKind::Tuple(..) | PatKind::Slice(..) => "binding", diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index bdf243c87b6f1..54510faf2e182 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -435,6 +435,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { hir::PatKind::Or(pats) => PatKind::Or { pats: self.lower_patterns(pats) }, + // FIXME(guard_patterns): implement guard pattern lowering + hir::PatKind::Guard(pat, _) => self.lower_pattern(pat).kind, + hir::PatKind::Err(guar) => PatKind::Error(guar), }; diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs index f9cb8c9b92716..88d69eb36788d 100644 --- a/compiler/rustc_passes/src/input_stats.rs +++ b/compiler/rustc_passes/src/input_stats.rs @@ -305,6 +305,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { Deref, Ref, Lit, + Guard, Range, Slice, Err diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 8aeebdde7bb45..1fb35750c15f5 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -320,6 +320,7 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol { ); return Symbol::intern("()"); } + PatKind::Guard(p, _) => return name_from_pat(&*p), PatKind::Range(..) => return kw::Underscore, PatKind::Slice(begin, ref mid, end) => { let begin = begin.iter().map(|p| name_from_pat(p).to_string()); From 087b8721dbaab3a607601e95a2c11779715c0603 Mon Sep 17 00:00:00 2001 From: Max Niederman Date: Sun, 15 Sep 2024 00:25:08 -0700 Subject: [PATCH 04/11] typecheck guard pattern conditions --- compiler/rustc_hir_typeck/src/pat.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 5c6fdc81a4931..4870e6193c3f1 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -284,8 +284,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PatKind::Struct(ref qpath, fields, has_rest_pat) => { self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, pat_info) } - PatKind::Guard(pat, _) => { + PatKind::Guard(pat, cond) => { self.check_pat(pat, expected, pat_info); + self.check_expr_has_type_or_error(cond, self.tcx.types.bool, |_| {}); expected } PatKind::Or(pats) => { From c3132e77caffb7691ecd7734505ae5661baf0a42 Mon Sep 17 00:00:00 2001 From: Max Niederman Date: Tue, 31 Dec 2024 17:36:49 -0800 Subject: [PATCH 05/11] allow irrefutable let patterns in feature gate test --- .../feature-gate-guard-patterns.rs | 4 +-- .../feature-gate-guard-patterns.stderr | 35 +++++-------------- 2 files changed, 10 insertions(+), 29 deletions(-) diff --git a/tests/ui/feature-gates/feature-gate-guard-patterns.rs b/tests/ui/feature-gates/feature-gate-guard-patterns.rs index 929e8ef3181f9..52ed89e668b1f 100644 --- a/tests/ui/feature-gates/feature-gate-guard-patterns.rs +++ b/tests/ui/feature-gates/feature-gate-guard-patterns.rs @@ -1,3 +1,5 @@ +#![allow(irrefutable_let_patterns)] + fn match_guards_still_work() { match 0 { 0 if guard(0) => {}, @@ -24,11 +26,9 @@ fn other_guards_dont() { if let (x if guard(x)) = 0 {} //~^ ERROR: guard patterns are experimental - //~| WARN: irrefutable while let (x if guard(x)) = 0 {} //~^ ERROR: guard patterns are experimental - //~| WARN: irrefutable #[cfg(FALSE)] while let (x if guard(x)) = 0 {} diff --git a/tests/ui/feature-gates/feature-gate-guard-patterns.stderr b/tests/ui/feature-gates/feature-gate-guard-patterns.stderr index 0613b5c95a413..8b85b663889f7 100644 --- a/tests/ui/feature-gates/feature-gate-guard-patterns.stderr +++ b/tests/ui/feature-gates/feature-gate-guard-patterns.stderr @@ -1,5 +1,5 @@ error: unexpected parentheses surrounding `match` arm pattern - --> $DIR/feature-gate-guard-patterns.rs:10:9 + --> $DIR/feature-gate-guard-patterns.rs:12:9 | LL | (0 if guard(0)) => {}, | ^ ^ @@ -11,7 +11,7 @@ LL + 0 if guard(0) => {}, | error[E0425]: cannot find value `x` in this scope - --> $DIR/feature-gate-guard-patterns.rs:21:22 + --> $DIR/feature-gate-guard-patterns.rs:23:22 | LL | let ((x if guard(x)) | x) = 0; | ^ not found in this scope @@ -23,13 +23,13 @@ LL | fn even_as_function_parameters(((x if guard(x), _) | (_, x)): (i32, i32)) { | ^ | help: the binding `x` is available in a different scope in the same function - --> $DIR/feature-gate-guard-patterns.rs:21:11 + --> $DIR/feature-gate-guard-patterns.rs:23:11 | LL | let ((x if guard(x)) | x) = 0; | ^ error[E0658]: guard patterns are experimental - --> $DIR/feature-gate-guard-patterns.rs:16:15 + --> $DIR/feature-gate-guard-patterns.rs:18:15 | LL | (0 if guard(0)) | 1 => {}, | ^^^^^^^^ @@ -40,7 +40,7 @@ LL | (0 if guard(0)) | 1 => {}, = help: consider using match arm guards error[E0658]: guard patterns are experimental - --> $DIR/feature-gate-guard-patterns.rs:21:16 + --> $DIR/feature-gate-guard-patterns.rs:23:16 | LL | let ((x if guard(x)) | x) = 0; | ^^^^^^^^ @@ -51,7 +51,7 @@ LL | let ((x if guard(x)) | x) = 0; = help: consider using match arm guards error[E0658]: guard patterns are experimental - --> $DIR/feature-gate-guard-patterns.rs:25:18 + --> $DIR/feature-gate-guard-patterns.rs:27:18 | LL | if let (x if guard(x)) = 0 {} | ^^^^^^^^ @@ -62,7 +62,7 @@ LL | if let (x if guard(x)) = 0 {} = help: consider using match arm guards error[E0658]: guard patterns are experimental - --> $DIR/feature-gate-guard-patterns.rs:29:21 + --> $DIR/feature-gate-guard-patterns.rs:30:21 | LL | while let (x if guard(x)) = 0 {} | ^^^^^^^^ @@ -94,26 +94,7 @@ LL | fn even_as_function_parameters(((x if guard(x), _) | (_, x)): (i32, i32)) { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = help: consider using match arm guards -warning: irrefutable `if let` pattern - --> $DIR/feature-gate-guard-patterns.rs:25:8 - | -LL | if let (x if guard(x)) = 0 {} - | ^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this pattern will always match, so the `if let` is useless - = help: consider replacing the `if let` with a `let` - = note: `#[warn(irrefutable_let_patterns)]` on by default - -warning: irrefutable `while let` pattern - --> $DIR/feature-gate-guard-patterns.rs:29:11 - | -LL | while let (x if guard(x)) = 0 {} - | ^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this pattern will always match, so the loop will never exit - = help: consider instead using a `loop { ... }` with a `let` inside it - -error: aborting due to 9 previous errors; 2 warnings emitted +error: aborting due to 9 previous errors Some errors have detailed explanations: E0425, E0658. For more information about an error, try `rustc --explain E0425`. From 8cefc0a05b4d7f66c2d1975b283c55daaa292144 Mon Sep 17 00:00:00 2001 From: Max Niederman Date: Sat, 5 Oct 2024 22:09:20 -0700 Subject: [PATCH 06/11] cover guard patterns in clippy lints --- src/tools/clippy/clippy_lints/src/equatable_if_let.rs | 2 +- .../clippy/clippy_lints/src/matches/match_same_arms.rs | 8 +++++--- src/tools/clippy/clippy_lints/src/matches/single_match.rs | 4 ++++ src/tools/clippy/clippy_lints/src/utils/author.rs | 6 ++++++ src/tools/clippy/clippy_utils/src/hir_utils.rs | 4 ++++ src/tools/clippy/clippy_utils/src/lib.rs | 2 +- 6 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs index fb9f2b1526e38..9c8edfd6113f6 100644 --- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs +++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs @@ -55,7 +55,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool { | PatKind::Err(_) => false, PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)), PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a), - PatKind::Ref(x, _) | PatKind::Box(x) | PatKind::Deref(x) => unary_pattern(x), + PatKind::Ref(x, _) | PatKind::Box(x) | PatKind::Deref(x) | PatKind::Guard(x, _) => unary_pattern(x), PatKind::Path(_) | PatKind::Lit(_) => true, } } diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs index b72a61a438499..4b731d759723c 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs @@ -254,9 +254,11 @@ impl<'a> NormalizedPat<'a> { fn from_pat(cx: &LateContext<'_>, arena: &'a DroplessArena, pat: &'a Pat<'_>) -> Self { match pat.kind { PatKind::Wild | PatKind::Binding(.., None) => Self::Wild, - PatKind::Binding(.., Some(pat)) | PatKind::Box(pat) | PatKind::Deref(pat) | PatKind::Ref(pat, _) => { - Self::from_pat(cx, arena, pat) - }, + PatKind::Binding(.., Some(pat)) + | PatKind::Box(pat) + | PatKind::Deref(pat) + | PatKind::Ref(pat, _) + | PatKind::Guard(pat, _) => Self::from_pat(cx, arena, pat), PatKind::Never => Self::Never, PatKind::Struct(ref path, fields, _) => { let fields = diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs index 3ca20479f8e00..10ca6832d9c12 100644 --- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs @@ -343,6 +343,10 @@ impl<'a> PatState<'a> { matches!(self, Self::Wild) }, + PatKind::Guard(..) => { + matches!(self, Self::Wild) + } + // Patterns for things which can only contain a single sub-pattern. PatKind::Binding(_, _, _, Some(pat)) | PatKind::Ref(pat, _) | PatKind::Box(pat) | PatKind::Deref(pat) => { self.add_pat(cx, pat) diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index d2970c93f8e91..c2dcb5ae1f9e5 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -712,6 +712,12 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { kind!("Ref({pat}, Mutability::{muta:?})"); self.pat(pat); }, + PatKind::Guard(pat, cond) => { + bind!(self, pat, cond); + kind!("Guard({pat}, {cond})"); + self.pat(pat); + self.expr(cond); + } PatKind::Lit(lit_expr) => { bind!(self, lit_expr); kind!("Lit({lit_expr})"); diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index ed52c481de124..7c4e834f8416f 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1104,6 +1104,10 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_pat(pat); std::mem::discriminant(&mu).hash(&mut self.s); }, + PatKind::Guard(pat, guard) => { + self.hash_pat(pat); + self.hash_expr(guard); + }, PatKind::Slice(l, m, r) => { for pat in l { self.hash_pat(pat); diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 77c597f853489..4c4e942b2792c 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1777,7 +1777,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { }, } }, - PatKind::Lit(..) | PatKind::Range(..) | PatKind::Err(_) | PatKind::Deref(_) => true, + PatKind::Lit(..) | PatKind::Range(..) | PatKind::Err(_) | PatKind::Deref(_) | PatKind::Guard(..) => true, } } From ab07e78092bf8f370b9a61266d40c3a444b59608 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 6 Jan 2025 06:01:14 +0000 Subject: [PATCH 07/11] Failing test --- .../ui/symbol-names/normalize-in-param-env.rs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 tests/ui/symbol-names/normalize-in-param-env.rs diff --git a/tests/ui/symbol-names/normalize-in-param-env.rs b/tests/ui/symbol-names/normalize-in-param-env.rs new file mode 100644 index 0000000000000..a1453eb13eff5 --- /dev/null +++ b/tests/ui/symbol-names/normalize-in-param-env.rs @@ -0,0 +1,38 @@ +//@ revisions: legacy v0 +//@[v0] compile-flags: -C symbol-mangling-version=v0 +//@[legacy] compile-flags: -C symbol-mangling-version=legacy -Zunstable-options +//@ build-pass + +pub struct Vec2; + +pub trait Point { + type S; +} +impl Point for Vec2 { + type S = f32; +} + +pub trait Point2: Point { + type S2; +} +impl Point2 for Vec2 { + type S2 = Self::S; +} + +trait MyFrom { + fn my_from(); +} +impl MyFrom for P { + fn my_from() { + // This is just a really dumb way to force the legacy symbol mangling to + // mangle the closure's parent impl def path *with* args. Otherwise, + // legacy symbol mangling will strip the args from the instance, meaning + // that we don't trigger the bug. + let c = || {}; + let x = Box::new(c) as Box; + } +} + +fn main() { + >::my_from(); +} From 86d8b79d0dc800e9aacd455c31836c1a72dc676f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 6 Jan 2025 06:10:36 +0000 Subject: [PATCH 08/11] Use a post-monomorphization typing env when mangling components that come from impls --- compiler/rustc_middle/src/ty/print/mod.rs | 40 ++++++++++---------- compiler/rustc_symbol_mangling/src/legacy.rs | 29 ++++++++++---- compiler/rustc_symbol_mangling/src/v0.rs | 30 ++++++++++----- 3 files changed, 61 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index b0150bc11920b..72f353f06ff52 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -45,10 +45,25 @@ pub trait Printer<'tcx>: Sized { &mut self, impl_def_id: DefId, args: &'tcx [GenericArg<'tcx>], - self_ty: Ty<'tcx>, - trait_ref: Option>, ) -> Result<(), PrintError> { - self.default_print_impl_path(impl_def_id, args, self_ty, trait_ref) + let tcx = self.tcx(); + let self_ty = tcx.type_of(impl_def_id); + let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); + let (self_ty, impl_trait_ref) = if tcx.generics_of(impl_def_id).count() <= args.len() { + ( + self_ty.instantiate(tcx, args), + impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(tcx, args)), + ) + } else { + // We are probably printing a nested item inside of an impl. + // Use the identity substitutions for the impl. + ( + self_ty.instantiate_identity(), + impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()), + ) + }; + + self.default_print_impl_path(impl_def_id, self_ty, impl_trait_ref) } fn print_region(&mut self, region: ty::Region<'tcx>) -> Result<(), PrintError>; @@ -107,23 +122,7 @@ pub trait Printer<'tcx>: Sized { self.path_crate(def_id.krate) } - DefPathData::Impl => { - let generics = self.tcx().generics_of(def_id); - let self_ty = self.tcx().type_of(def_id); - let impl_trait_ref = self.tcx().impl_trait_ref(def_id); - let (self_ty, impl_trait_ref) = if args.len() >= generics.count() { - ( - self_ty.instantiate(self.tcx(), args), - impl_trait_ref.map(|i| i.instantiate(self.tcx(), args)), - ) - } else { - ( - self_ty.instantiate_identity(), - impl_trait_ref.map(|i| i.instantiate_identity()), - ) - }; - self.print_impl_path(def_id, args, self_ty, impl_trait_ref) - } + DefPathData::Impl => self.print_impl_path(def_id, args), _ => { let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id }; @@ -201,7 +200,6 @@ pub trait Printer<'tcx>: Sized { fn default_print_impl_path( &mut self, impl_def_id: DefId, - _args: &'tcx [GenericArg<'tcx>], self_ty: Ty<'tcx>, impl_trait_ref: Option>, ) -> Result<(), PrintError> { diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 0d6d8488a23ca..333ea0214eb3f 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -8,6 +8,7 @@ use rustc_middle::bug; use rustc_middle::ty::print::{PrettyPrinter, Print, PrintError, Printer}; use rustc_middle::ty::{ self, GenericArg, GenericArgKind, Instance, ReifyReason, Ty, TyCtxt, TypeVisitableExt, + TypingEnv, }; use tracing::debug; @@ -383,14 +384,26 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> { &mut self, impl_def_id: DefId, args: &'tcx [GenericArg<'tcx>], - mut self_ty: Ty<'tcx>, - mut impl_trait_ref: Option>, ) -> Result<(), PrintError> { - let mut typing_env = ty::TypingEnv::post_analysis(self.tcx, impl_def_id); - if !args.is_empty() { - typing_env.param_env = - ty::EarlyBinder::bind(typing_env.param_env).instantiate(self.tcx, args); - } + let self_ty = self.tcx.type_of(impl_def_id); + let impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id); + let (typing_env, mut self_ty, mut impl_trait_ref) = + if self.tcx.generics_of(impl_def_id).count() <= args.len() { + ( + TypingEnv::fully_monomorphized(), + self_ty.instantiate(self.tcx, args), + impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(self.tcx, args)), + ) + } else { + // We are probably printing a nested item inside of an impl. + // Use the identity substitutions for the impl. We also need + // a well-formed param-env, so let's use post-analysis. + ( + TypingEnv::post_analysis(self.tcx, impl_def_id), + self_ty.instantiate_identity(), + impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()), + ) + }; match &mut impl_trait_ref { Some(impl_trait_ref) => { @@ -403,7 +416,7 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> { } } - self.default_print_impl_path(impl_def_id, args, self_ty, impl_trait_ref) + self.default_print_impl_path(impl_def_id, self_ty, impl_trait_ref) } } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 0ca47eba5e81e..b77ad209e2bd8 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -14,8 +14,8 @@ use rustc_middle::bug; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::print::{Print, PrintError, Printer}; use rustc_middle::ty::{ - self, EarlyBinder, FloatTy, GenericArg, GenericArgKind, Instance, IntTy, ReifyReason, Ty, - TyCtxt, TypeVisitable, TypeVisitableExt, UintTy, + self, FloatTy, GenericArg, GenericArgKind, Instance, IntTy, ReifyReason, Ty, TyCtxt, + TypeVisitable, TypeVisitableExt, UintTy, }; use rustc_span::kw; @@ -227,17 +227,29 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { &mut self, impl_def_id: DefId, args: &'tcx [GenericArg<'tcx>], - mut self_ty: Ty<'tcx>, - mut impl_trait_ref: Option>, ) -> Result<(), PrintError> { let key = self.tcx.def_key(impl_def_id); let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id }; - let mut typing_env = ty::TypingEnv::post_analysis(self.tcx, impl_def_id); - if !args.is_empty() { - typing_env.param_env = - EarlyBinder::bind(typing_env.param_env).instantiate(self.tcx, args); - } + let self_ty = self.tcx.type_of(impl_def_id); + let impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id); + let (typing_env, mut self_ty, mut impl_trait_ref) = + if self.tcx.generics_of(impl_def_id).count() <= args.len() { + ( + ty::TypingEnv::fully_monomorphized(), + self_ty.instantiate(self.tcx, args), + impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(self.tcx, args)), + ) + } else { + // We are probably printing a nested item inside of an impl. + // Use the identity substitutions for the impl. We also need + // a well-formed param-env, so let's use post-analysis. + ( + ty::TypingEnv::post_analysis(self.tcx, impl_def_id), + self_ty.instantiate_identity(), + impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()), + ) + }; match &mut impl_trait_ref { Some(impl_trait_ref) => { From 5a566005c1c0ef62c9af88e645d86ab28971af04 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 25 Dec 2024 02:43:27 +0000 Subject: [PATCH 09/11] Normalize each signature input/output in typeck_with_fallback with its own span --- compiler/rustc_hir_typeck/src/lib.rs | 19 +++++++++++++-- .../associated-types-for-unimpl-trait.stderr | 5 ++-- .../associated-types-no-suitable-bound.stderr | 5 ++-- ...ated-types-no-suitable-supertrait-2.stderr | 5 ++-- ...ciated-types-no-suitable-supertrait.stderr | 10 ++++---- tests/ui/associated-types/issue-59324.stderr | 5 ++-- tests/ui/auto-traits/issue-83857-ub.stderr | 12 +++------- tests/ui/error-codes/E0229.stderr | 4 ++-- tests/ui/issues/issue-18611.stderr | 10 ++++---- tests/ui/issues/issue-35570.stderr | 11 +++------ tests/ui/proc-macro/bad-projection.stderr | 5 ++-- ...ions-implied-bounds-projection-gap-hr-1.rs | 2 +- ...-implied-bounds-projection-gap-hr-1.stderr | 8 +++---- .../min_specialization/issue-79224.stderr | 9 +++---- .../generic_underconstrained.stderr | 12 ++++------ .../generic_underconstrained2.stderr | 24 +++++++------------ 16 files changed, 69 insertions(+), 77 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 5a0a855147deb..a406ec9a8fbb4 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -147,8 +147,23 @@ fn typeck_with_fallback<'tcx>( check_abi(tcx, span, fn_sig.abi()); // Compute the function signature from point of view of inside the fn. - let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig); - let fn_sig = fcx.normalize(body.value.span, fn_sig); + let mut fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig); + + // Normalize the input and output types one at a time, using a different + // `WellFormedLoc` for each. We cannot call `normalize_associated_types` + // on the entire `FnSig`, since this would use the same `WellFormedLoc` + // for each type, preventing the HIR wf check from generating + // a nice error message. + let arg_span = + |idx| decl.inputs.get(idx).map_or(decl.output.span(), |arg: &hir::Ty<'_>| arg.span); + + fn_sig.inputs_and_output = tcx.mk_type_list_from_iter( + fn_sig + .inputs_and_output + .iter() + .enumerate() + .map(|(idx, ty)| fcx.normalize(arg_span(idx), ty)), + ); check_fn(&mut fcx, fn_sig, None, decl, def_id, body, tcx.features().unsized_fn_params()); } else { diff --git a/tests/ui/associated-types/associated-types-for-unimpl-trait.stderr b/tests/ui/associated-types/associated-types-for-unimpl-trait.stderr index 4cba3990049a5..db18cdf7d5aad 100644 --- a/tests/ui/associated-types/associated-types-for-unimpl-trait.stderr +++ b/tests/ui/associated-types/associated-types-for-unimpl-trait.stderr @@ -10,11 +10,12 @@ LL | fn uhoh(&self, foo: U, bar: ::Value) where Self: S | +++++++++++ error[E0277]: the trait bound `Self: Get` is not satisfied - --> $DIR/associated-types-for-unimpl-trait.rs:11:81 + --> $DIR/associated-types-for-unimpl-trait.rs:11:41 | LL | fn uhoh(&self, foo: U, bar: ::Value) where Self: Sized {} - | ^^ the trait `Get` is not implemented for `Self` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self` | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider further restricting `Self` | LL | fn uhoh(&self, foo: U, bar: ::Value) where Self: Sized, Self: Get {} diff --git a/tests/ui/associated-types/associated-types-no-suitable-bound.stderr b/tests/ui/associated-types/associated-types-no-suitable-bound.stderr index 4f951ee4b4e62..b0598b3810ca4 100644 --- a/tests/ui/associated-types/associated-types-no-suitable-bound.stderr +++ b/tests/ui/associated-types/associated-types-no-suitable-bound.stderr @@ -10,11 +10,12 @@ LL | fn uhoh(foo: ::Value) {} | +++++ error[E0277]: the trait bound `T: Get` is not satisfied - --> $DIR/associated-types-no-suitable-bound.rs:11:40 + --> $DIR/associated-types-no-suitable-bound.rs:11:21 | LL | fn uhoh(foo: ::Value) {} - | ^^ the trait `Get` is not implemented for `T` + | ^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `T` | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider restricting type parameter `T` with trait `Get` | LL | fn uhoh(foo: ::Value) {} diff --git a/tests/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr b/tests/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr index c5dcfc00925d7..fce8c7ed384d6 100644 --- a/tests/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr +++ b/tests/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr @@ -10,11 +10,12 @@ LL | fn uhoh(&self, foo: U, bar: ::Value) where Self: Ge | +++++++++++++++ error[E0277]: the trait bound `Self: Get` is not satisfied - --> $DIR/associated-types-no-suitable-supertrait-2.rs:17:62 + --> $DIR/associated-types-no-suitable-supertrait-2.rs:17:40 | LL | fn uhoh(&self, foo: U, bar: ::Value) {} - | ^^ the trait `Get` is not implemented for `Self` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self` | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider further restricting `Self` | LL | fn uhoh(&self, foo: U, bar: ::Value) where Self: Get {} diff --git a/tests/ui/associated-types/associated-types-no-suitable-supertrait.stderr b/tests/ui/associated-types/associated-types-no-suitable-supertrait.stderr index 46cebda078e46..b7d528025bd14 100644 --- a/tests/ui/associated-types/associated-types-no-suitable-supertrait.stderr +++ b/tests/ui/associated-types/associated-types-no-suitable-supertrait.stderr @@ -34,27 +34,29 @@ LL | fn uhoh(&self, foo: U, bar: ::Value) where Self: Ge | +++++++++++++++ error[E0277]: the trait bound `Self: Get` is not satisfied - --> $DIR/associated-types-no-suitable-supertrait.rs:17:62 + --> $DIR/associated-types-no-suitable-supertrait.rs:17:40 | LL | fn uhoh(&self, foo: U, bar: ::Value) {} - | ^^ the trait `Get` is not implemented for `Self` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self` | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider further restricting `Self` | LL | fn uhoh(&self, foo: U, bar: ::Value) where Self: Get {} | +++++++++++++++ error[E0277]: the trait bound `(T, U): Get` is not satisfied - --> $DIR/associated-types-no-suitable-supertrait.rs:23:64 + --> $DIR/associated-types-no-suitable-supertrait.rs:23:40 | LL | fn uhoh(&self, foo: U, bar: <(T, U) as Get>::Value) {} - | ^^ the trait `Get` is not implemented for `(T, U)` + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `(T, U)` | help: this trait has no implementations, consider adding one --> $DIR/associated-types-no-suitable-supertrait.rs:12:1 | LL | trait Get { | ^^^^^^^^^ + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 5 previous errors diff --git a/tests/ui/associated-types/issue-59324.stderr b/tests/ui/associated-types/issue-59324.stderr index 805c3e60bb6a8..2abe337b69ae3 100644 --- a/tests/ui/associated-types/issue-59324.stderr +++ b/tests/ui/associated-types/issue-59324.stderr @@ -65,16 +65,17 @@ LL | pub trait ThriftService: | +++++ error[E0277]: the trait bound `(): Foo` is not satisfied - --> $DIR/issue-59324.rs:23:52 + --> $DIR/issue-59324.rs:23:29 | LL | fn with_factory(factory: dyn ThriftService<()>) {} - | ^^ the trait `Foo` is not implemented for `()` + | ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()` | help: this trait has no implementations, consider adding one --> $DIR/issue-59324.rs:3:1 | LL | pub trait Foo: NotFoo { | ^^^^^^^^^^^^^^^^^^^^^ + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the size for values of type `(dyn ThriftService<(), AssocType = _> + 'static)` cannot be known at compilation time --> $DIR/issue-59324.rs:23:29 diff --git a/tests/ui/auto-traits/issue-83857-ub.stderr b/tests/ui/auto-traits/issue-83857-ub.stderr index 7c437b7e6c84d..3536450c75b12 100644 --- a/tests/ui/auto-traits/issue-83857-ub.stderr +++ b/tests/ui/auto-traits/issue-83857-ub.stderr @@ -18,16 +18,10 @@ LL | fn generic(v: Foo, f: fn( as WithAssoc>::Output) -> i | +++++++++++++++++++++ error[E0277]: `Foo` cannot be sent between threads safely - --> $DIR/issue-83857-ub.rs:21:80 + --> $DIR/issue-83857-ub.rs:21:35 | -LL | fn generic(v: Foo, f: fn( as WithAssoc>::Output) -> i32) { - | ________________________________________________________________________________^ -LL | | -LL | | -LL | | f(foo(v)); -LL | | -LL | | } - | |_^ `Foo` cannot be sent between threads safely +LL | fn generic(v: Foo, f: fn( as WithAssoc>::Output) -> i32) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be sent between threads safely | = help: the trait `Send` is not implemented for `Foo` note: required for `Foo` to implement `WithAssoc` diff --git a/tests/ui/error-codes/E0229.stderr b/tests/ui/error-codes/E0229.stderr index ab2536cc0c9d5..7c967e89ddbc1 100644 --- a/tests/ui/error-codes/E0229.stderr +++ b/tests/ui/error-codes/E0229.stderr @@ -48,10 +48,10 @@ LL | fn baz(x: &>::A) {} | +++++ error[E0277]: the trait bound `I: Foo` is not satisfied - --> $DIR/E0229.rs:13:39 + --> $DIR/E0229.rs:13:14 | LL | fn baz(x: &>::A) {} - | ^^ the trait `Foo` is not implemented for `I` + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `I` | help: consider restricting type parameter `I` with trait `Foo` | diff --git a/tests/ui/issues/issue-18611.stderr b/tests/ui/issues/issue-18611.stderr index 918654215b372..4fa699de63527 100644 --- a/tests/ui/issues/issue-18611.stderr +++ b/tests/ui/issues/issue-18611.stderr @@ -11,19 +11,17 @@ LL | trait HasState { | ^^^^^^^^^^^^^^ error[E0277]: the trait bound `isize: HasState` is not satisfied - --> $DIR/issue-18611.rs:1:46 + --> $DIR/issue-18611.rs:1:18 | -LL | fn add_state(op: ::State) { - | ______________________________________________^ -... | -LL | | } - | |_^ the trait `HasState` is not implemented for `isize` +LL | fn add_state(op: ::State) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasState` is not implemented for `isize` | help: this trait has no implementations, consider adding one --> $DIR/issue-18611.rs:6:1 | LL | trait HasState { | ^^^^^^^^^^^^^^ + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-35570.stderr b/tests/ui/issues/issue-35570.stderr index 0aa6b5e402e44..b39b15fdf4b10 100644 --- a/tests/ui/issues/issue-35570.stderr +++ b/tests/ui/issues/issue-35570.stderr @@ -11,15 +11,10 @@ LL | trait Trait2<'a> { | ^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `for<'a> (): Trait2<'a>` is not satisfied - --> $DIR/issue-35570.rs:8:66 + --> $DIR/issue-35570.rs:8:16 | -LL | fn _ice(param: Box Trait1<<() as Trait2<'a>>::Ty>>) { - | __________________________________________________________________^ -LL | | -LL | | -LL | | let _e: (usize, usize) = unsafe{mem::transmute(param)}; -LL | | } - | |_^ the trait `for<'a> Trait2<'a>` is not implemented for `()` +LL | fn _ice(param: Box Trait1<<() as Trait2<'a>>::Ty>>) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Trait2<'a>` is not implemented for `()` | help: this trait has no implementations, consider adding one --> $DIR/issue-35570.rs:4:1 diff --git a/tests/ui/proc-macro/bad-projection.stderr b/tests/ui/proc-macro/bad-projection.stderr index 2e8668f60de74..aa6b3da6da995 100644 --- a/tests/ui/proc-macro/bad-projection.stderr +++ b/tests/ui/proc-macro/bad-projection.stderr @@ -48,16 +48,17 @@ LL | trait Project { | ^^^^^^^^^^^^^ error[E0277]: the trait bound `(): Project` is not satisfied - --> $DIR/bad-projection.rs:14:40 + --> $DIR/bad-projection.rs:14:17 | LL | pub fn uwu() -> <() as Project>::Assoc {} - | ^^ the trait `Project` is not implemented for `()` + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `Project` is not implemented for `()` | help: this trait has no implementations, consider adding one --> $DIR/bad-projection.rs:9:1 | LL | trait Project { | ^^^^^^^^^^^^^ + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 5 previous errors diff --git a/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.rs b/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.rs index 4d77a551f6472..1106352037a08 100644 --- a/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.rs +++ b/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.rs @@ -20,8 +20,8 @@ trait Trait2<'a, 'b> { // do not infer that. fn callee<'x, 'y, T>(t: &'x dyn for<'z> Trait1< >::Foo >) //~^ ERROR the trait bound `for<'z> T: Trait2<'y, 'z>` is not satisfied + //~| ERROR the trait bound `for<'z> T: Trait2<'y, 'z>` is not satisfied { - //~^ ERROR the trait bound `for<'z> T: Trait2<'y, 'z>` is not satisfied } fn main() { } diff --git a/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr b/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr index 87f0f47f2401e..643746ed46fcf 100644 --- a/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr +++ b/tests/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr @@ -10,12 +10,10 @@ LL | fn callee<'x, 'y, T: for<'z> Trait2<'y, 'z>>(t: &'x dyn for<'z> Trait1< T: Trait2<'y, 'z>` is not satisfied - --> $DIR/regions-implied-bounds-projection-gap-hr-1.rs:23:1 + --> $DIR/regions-implied-bounds-projection-gap-hr-1.rs:21:25 | -LL | / { -LL | | -LL | | } - | |_^ the trait `for<'z> Trait2<'y, 'z>` is not implemented for `T` +LL | fn callee<'x, 'y, T>(t: &'x dyn for<'z> Trait1< >::Foo >) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'z> Trait2<'y, 'z>` is not implemented for `T` | help: consider restricting type parameter `T` with trait `Trait2` | diff --git a/tests/ui/specialization/min_specialization/issue-79224.stderr b/tests/ui/specialization/min_specialization/issue-79224.stderr index b2118ccd81b67..2ed614f1857d4 100644 --- a/tests/ui/specialization/min_specialization/issue-79224.stderr +++ b/tests/ui/specialization/min_specialization/issue-79224.stderr @@ -35,13 +35,10 @@ LL | impl Display for Cow<'_, B> { | +++++++++++++++++++ error[E0277]: the trait bound `B: Clone` is not satisfied - --> $DIR/issue-79224.rs:30:62 + --> $DIR/issue-79224.rs:30:12 | -LL | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - | ______________________________________________________________^ -... | -LL | | } - | |_____^ the trait `Clone` is not implemented for `B` +LL | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + | ^^^^^ the trait `Clone` is not implemented for `B` | = note: required for `B` to implement `ToOwned` help: consider further restricting type parameter `B` with trait `Clone` diff --git a/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr b/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr index 98f99cdbfbd65..c24f8fd867fb3 100644 --- a/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr +++ b/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr @@ -15,21 +15,17 @@ LL | fn underconstrain(_: T) -> Underconstrained { | +++++++ error[E0277]: the trait bound `T: Trait` is not satisfied - --> $DIR/generic_underconstrained.rs:9:51 + --> $DIR/generic_underconstrained.rs:9:31 | -LL | fn underconstrain(_: T) -> Underconstrained { - | ___________________________________________________^ -LL | | -LL | | -LL | | unimplemented!() -LL | | } - | |_^ the trait `Trait` is not implemented for `T` +LL | fn underconstrain(_: T) -> Underconstrained { + | ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` | note: required by a bound on the type alias `Underconstrained` --> $DIR/generic_underconstrained.rs:6:26 | LL | type Underconstrained = impl Send; | ^^^^^ required by this bound + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider restricting type parameter `T` with trait `Trait` | LL | fn underconstrain(_: T) -> Underconstrained { diff --git a/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr b/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr index 5506977a3e702..93df5ddca796f 100644 --- a/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr +++ b/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr @@ -31,42 +31,34 @@ LL | fn underconstrained2(_: U, _: V) -> Underconstrained | +++++++++++++++++ error[E0277]: `U` doesn't implement `Debug` - --> $DIR/generic_underconstrained2.rs:8:53 + --> $DIR/generic_underconstrained2.rs:8:33 | -LL | fn underconstrained(_: U) -> Underconstrained { - | _____________________________________________________^ -LL | | -LL | | -LL | | 5u32 -LL | | } - | |_^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` +LL | fn underconstrained(_: U) -> Underconstrained { + | ^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` | note: required by a bound on the type alias `Underconstrained` --> $DIR/generic_underconstrained2.rs:5:26 | LL | type Underconstrained = impl Send; | ^^^^^^^^^^^^^^^ required by this bound + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider restricting type parameter `U` with trait `Debug` | LL | fn underconstrained(_: U) -> Underconstrained { | +++++++++++++++++ error[E0277]: `V` doesn't implement `Debug` - --> $DIR/generic_underconstrained2.rs:17:64 + --> $DIR/generic_underconstrained2.rs:17:43 | -LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { - | ________________________________________________________________^ -LL | | -LL | | -LL | | 5u32 -LL | | } - | |_^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug` +LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { + | ^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug` | note: required by a bound on the type alias `Underconstrained2` --> $DIR/generic_underconstrained2.rs:14:27 | LL | type Underconstrained2 = impl Send; | ^^^^^^^^^^^^^^^ required by this bound + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider restricting type parameter `V` with trait `Debug` | LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { From c7a806ad081947c77b415c0097cbbd3925ac759b Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 6 Jan 2025 11:56:13 -0700 Subject: [PATCH 10/11] rustdoc: use stable paths as preferred canonical paths This accomplishes something like 16a4ad7d7b0d163f7be6803c786c3b83d42913bb, but with the `rustc_allowed_through_unstable_modules` attribute instead of the path length. --- src/librustdoc/formats/cache.rs | 8 +++- .../fully-stable-path-is-better.rs | 40 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 tests/rustdoc/inline_local/fully-stable-path-is-better.rs diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index e64baca974dab..7a95d33723e50 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -1,5 +1,6 @@ use std::mem; +use rustc_attr_parsing::StabilityLevel; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet}; use rustc_middle::ty::{self, TyCtxt}; @@ -306,7 +307,12 @@ impl DocFolder for CacheBuilder<'_, '_> { | clean::ProcMacroItem(..) | clean::VariantItem(..) => { use rustc_data_structures::fx::IndexEntry as Entry; - if !self.cache.stripped_mod { + if !self.cache.stripped_mod + && !matches!( + item.stability.map(|stab| stab.level), + Some(StabilityLevel::Stable { allowed_through_unstable_modules: true, .. }) + ) + { // Re-exported items mean that the same id can show up twice // in the rustdoc ast that we're looking at. We know, // however, that a re-exported item doesn't show up in the diff --git a/tests/rustdoc/inline_local/fully-stable-path-is-better.rs b/tests/rustdoc/inline_local/fully-stable-path-is-better.rs new file mode 100644 index 0000000000000..88b0b0d57b084 --- /dev/null +++ b/tests/rustdoc/inline_local/fully-stable-path-is-better.rs @@ -0,0 +1,40 @@ +//! Test case for [134702] +//! +//! [134702]: https://github.com/rust-lang/rust/issues/134702 +#![crate_name = "foo"] +#![stable(since = "1.0", feature = "v1")] + +#![feature(staged_api, rustc_attrs)] + +#[stable(since = "1.0", feature = "stb1")] +pub mod stb1 { + #[doc(inline)] + #[stable(since = "1.0", feature = "stb1")] + pub use crate::uns::Inside1; +} + +#[unstable(feature = "uns", issue = "135003")] +pub mod uns { + #[stable(since = "1.0", feature = "stb1")] + #[rustc_allowed_through_unstable_modules] + pub struct Inside1; + #[stable(since = "1.0", feature = "stb2")] + #[rustc_allowed_through_unstable_modules] + pub struct Inside2; +} + +#[stable(since = "1.0", feature = "stb2")] +pub mod stb2 { + #[doc(inline)] + #[stable(since = "1.0", feature = "stb2")] + pub use crate::uns::Inside2; +} + +#[stable(since = "1.0", feature = "nested")] +pub mod nested { + //! [Inside1] [Inside2] + //@ has foo/nested/index.html '//a[@href="../stb1/struct.Inside1.html"]' 'Inside1' + //@ has foo/nested/index.html '//a[@href="../stb2/struct.Inside2.html"]' 'Inside2' + use crate::stb1::Inside1; + use crate::stb2::Inside2; +} From b77eb96baad4ad5c90cce09e4d649e8974d445c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= <39484203+jieyouxu@users.noreply.github.com> Date: Tue, 7 Jan 2025 20:49:29 +0800 Subject: [PATCH 11/11] rustfmt: drop nightly-gating of the `--style-edition` flag registration --- src/tools/rustfmt/src/bin/main.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tools/rustfmt/src/bin/main.rs b/src/tools/rustfmt/src/bin/main.rs index 4078484ff10fe..34984798ae60e 100644 --- a/src/tools/rustfmt/src/bin/main.rs +++ b/src/tools/rustfmt/src/bin/main.rs @@ -161,6 +161,12 @@ fn make_opts() -> Options { "Set options from command line. These settings take priority over .rustfmt.toml", "[key1=val1,key2=val2...]", ); + opts.optopt( + "", + "style-edition", + "The edition of the Style Guide.", + "[2015|2018|2021|2024]", + ); if is_nightly { opts.optflag( @@ -186,12 +192,6 @@ fn make_opts() -> Options { "skip-children", "Don't reformat child modules (unstable).", ); - opts.optopt( - "", - "style-edition", - "The edition of the Style Guide (unstable).", - "[2015|2018|2021|2024]", - ); } opts.optflag("v", "verbose", "Print verbose output");