From 22d582a38d3a25e9ec1a6062a91ae0d805e0cd26 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 1 Feb 2024 23:48:04 +0000 Subject: [PATCH 01/12] For a rigid projection, recursively look at the self type's item bounds --- .../src/solve/assembly/mod.rs | 129 ++++++++++++------ .../src/traits/project.rs | 61 +++++---- .../src/traits/select/candidate_assembly.rs | 54 +++++++- .../src/traits/select/confirmation.rs | 29 ++-- .../src/traits/select/mod.rs | 95 +++++-------- .../bad-bounds-on-assoc-in-trait.rs | 32 +---- .../bad-bounds-on-assoc-in-trait.stderr | 39 ------ .../bounds-on-assoc-in-trait.rs | 5 +- .../bounds-on-assoc-in-trait.stderr | 26 ---- tests/ui/associated-type-bounds/duplicate.rs | 3 - .../associated-type-bounds/duplicate.stderr | 50 ++----- .../hr-associated-type-bound-object.stderr | 4 + ...elf-auto-trait-issue-109924.current.stderr | 28 +--- ...g-self-auto-trait-issue-109924.next.stderr | 2 +- ...ormalizing-self-auto-trait-issue-109924.rs | 5 +- .../feature-gate-associated_type_bounds.rs | 1 - ...feature-gate-associated_type_bounds.stderr | 47 +++---- .../bugs/issue-88460.rs | 5 +- .../bugs/issue-88460.stderr | 29 ---- .../normalize-under-binder/issue-90950.rs | 3 +- .../normalize-under-binder/issue-90950.stderr | 29 ---- .../norm-before-method-resolution.rs | 3 +- .../norm-before-method-resolution.stderr | 23 ---- 23 files changed, 272 insertions(+), 430 deletions(-) delete mode 100644 tests/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr delete mode 100644 tests/ui/associated-type-bounds/bounds-on-assoc-in-trait.stderr delete mode 100644 tests/ui/generic-associated-types/bugs/issue-88460.stderr delete mode 100644 tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.stderr delete mode 100644 tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 239072dfc8e0e..150894ba83e05 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -542,50 +542,97 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, G>, candidates: &mut Vec>, ) { - let alias_ty = match goal.predicate.self_ty().kind() { - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Adt(_, _) - | ty::Foreign(_) - | ty::Str - | ty::Array(_, _) - | ty::Slice(_) - | ty::RawPtr(_) - | ty::Ref(_, _, _) - | ty::FnDef(_, _) - | ty::FnPtr(_) - | ty::Dynamic(..) - | ty::Closure(..) - | ty::CoroutineClosure(..) - | ty::Coroutine(..) - | ty::CoroutineWitness(..) - | ty::Never - | ty::Tuple(_) - | ty::Param(_) - | ty::Placeholder(..) - | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) - | ty::Alias(ty::Inherent, _) - | ty::Alias(ty::Weak, _) - | ty::Error(_) => return, - ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) - | ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"), - // Excluding IATs and type aliases here as they don't have meaningful item bounds. - ty::Alias(ty::Projection | ty::Opaque, alias_ty) => alias_ty, - }; + let _ = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| { + let mut self_ty = goal.predicate.self_ty(); + + // For some deeply nested `::A::B::C::D` rigid associated type, + // we should explore the item bounds for all levels, since the + // `associated_type_bounds` feature means that a parent associated + // type may carry bounds for a nested associated type. + loop { + let (kind, alias_ty) = match *self_ty.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(_) + | ty::Dynamic(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Never + | ty::Tuple(_) + | ty::Param(_) + | ty::Placeholder(..) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Error(_) => break, + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) + | ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"), + + // If we hit infer when normalizing the self type of an alias, + // then bail with ambiguity. + ty::Infer(ty::TyVar(_)) => { + if let Ok(result) = ecx + .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + { + candidates + .push(Candidate { source: CandidateSource::AliasBound, result }); + } + break; + } - for assumption in - self.tcx().item_bounds(alias_ty.def_id).instantiate(self.tcx(), alias_ty.args) - { - match G::consider_alias_bound_candidate(self, goal, assumption) { - Ok(result) => { - candidates.push(Candidate { source: CandidateSource::AliasBound, result }) + ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty), + ty::Alias(ty::Inherent | ty::Weak, _) => { + unreachable!("Weak and Inherent aliases should have been normalized away") + } + }; + + for assumption in + ecx.tcx().item_bounds(alias_ty.def_id).instantiate(ecx.tcx(), alias_ty.args) + { + match G::consider_alias_bound_candidate(ecx, goal, assumption) { + Ok(result) => { + candidates + .push(Candidate { source: CandidateSource::AliasBound, result }); + } + Err(NoSolution) => {} + } + } + + // If we have a projection, check that its self type is a rigid projection. + // If so, continue searching. + if kind == ty::Projection { + match ecx.try_normalize_ty(goal.param_env, alias_ty.self_ty()) { + Some(next_self_ty) => self_ty = next_self_ty, + None => { + if let Ok(result) = ecx + .evaluate_added_goals_and_make_canonical_response( + Certainty::OVERFLOW, + ) + { + candidates.push(Candidate { + source: CandidateSource::AliasBound, + result, + }); + } + break; + } + } + } else { + break; } - Err(NoSolution) => (), } - } + }); } /// Check that we are allowed to use an alias bound originating from the self diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index fd8306bbc0b69..8f47e45df0c6c 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -40,6 +40,7 @@ use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt}; use rustc_span::symbol::sym; use std::collections::BTreeMap; +use std::ops::ControlFlow; pub use rustc_middle::traits::Reveal; @@ -1614,32 +1615,46 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( candidate_set: &mut ProjectionCandidateSet<'tcx>, ) { debug!("assemble_candidates_from_trait_def(..)"); + let mut ambiguous = false; + selcx.for_each_item_bound( + obligation.predicate.self_ty(), + |selcx, clause, _| { + let Some(clause) = clause.as_projection_clause() else { + return ControlFlow::Continue(()); + }; - let tcx = selcx.tcx(); - // Check whether the self-type is itself a projection. - // If so, extract what we know from the trait and try to come up with a good answer. - let bounds = match *obligation.predicate.self_ty().kind() { - // Excluding IATs and type aliases here as they don't have meaningful item bounds. - ty::Alias(ty::Projection | ty::Opaque, ref data) => { - tcx.item_bounds(data.def_id).instantiate(tcx, data.args) - } - ty::Infer(ty::TyVar(_)) => { - // If the self-type is an inference variable, then it MAY wind up - // being a projected type, so induce an ambiguity. - candidate_set.mark_ambiguous(); - return; - } - _ => return, - }; + let is_match = + selcx.infcx.probe(|_| selcx.match_projection_projections(obligation, clause, true)); - assemble_candidates_from_predicates( - selcx, - obligation, - candidate_set, - ProjectionCandidate::TraitDef, - bounds.iter(), - true, + match is_match { + ProjectionMatchesProjection::Yes => { + candidate_set.push_candidate(ProjectionCandidate::TraitDef(clause)); + + if !obligation.predicate.has_non_region_infer() { + // HACK: Pick the first trait def candidate for a fully + // inferred predicate. This is to allow duplicates that + // differ only in normalization. + return ControlFlow::Break(()); + } + } + ProjectionMatchesProjection::Ambiguous => { + candidate_set.mark_ambiguous(); + } + ProjectionMatchesProjection::No => {} + } + + ControlFlow::Continue(()) + }, + || { + // `ProjectionCandidateSet` is borrowed in the above closure, + // so just mark ambiguous outside of the closure. + ambiguous = true; + }, ); + + if ambiguous { + candidate_set.mark_ambiguous(); + } } /// In the case of a trait object like diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index d056dd51f507e..248d75aaec713 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -6,13 +6,16 @@ //! //! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly +use std::ops::ControlFlow; + use hir::def_id::DefId; use hir::LangItem; +use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_infer::traits::ObligationCause; use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError}; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; -use rustc_middle::ty::{self, Ty, TypeVisitableExt}; +use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt}; use crate::traits; use crate::traits::query::evaluate_obligation::InferCtxtExt; @@ -158,11 +161,52 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { _ => return, } - let result = self - .infcx - .probe(|_| self.match_projection_obligation_against_definition_bounds(obligation)); + self.infcx.probe(|_| { + let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate); + let placeholder_trait_predicate = + self.infcx.enter_forall_and_leak_universe(poly_trait_predicate); + debug!(?placeholder_trait_predicate); + + // The bounds returned by `item_bounds` may contain duplicates after + // normalization, so try to deduplicate when possible to avoid + // unnecessary ambiguity. + let mut distinct_normalized_bounds = FxHashSet::default(); + self.for_each_item_bound::( + placeholder_trait_predicate.self_ty(), + |selcx, bound, idx| { + let Some(bound) = bound.as_trait_clause() else { + return ControlFlow::Continue(()); + }; + if bound.polarity() != placeholder_trait_predicate.polarity { + return ControlFlow::Continue(()); + } + + selcx.infcx.probe(|_| { + match selcx.match_normalize_trait_ref( + obligation, + bound.to_poly_trait_ref(), + placeholder_trait_predicate.trait_ref, + ) { + Ok(None) => { + candidates.vec.push(ProjectionCandidate(idx)); + } + Ok(Some(normalized_trait)) + if distinct_normalized_bounds.insert(normalized_trait) => + { + candidates.vec.push(ProjectionCandidate(idx)); + } + _ => {} + } + }); - candidates.vec.extend(result.into_iter().map(|idx| ProjectionCandidate(idx))); + ControlFlow::Continue(()) + }, + || { + // On ambiguity. + candidates.ambiguous = true; + }, + ); + }); } /// Given an obligation like ``, searches the obligations that the caller diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index f0c49253dbd7a..42074f4a079e2 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -162,20 +162,26 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.enter_forall_and_leak_universe(trait_predicate).trait_ref; let placeholder_self_ty = placeholder_trait_predicate.self_ty(); let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate); - let (def_id, args) = match *placeholder_self_ty.kind() { - // Excluding IATs and type aliases here as they don't have meaningful item bounds. - ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. }) => { - (def_id, args) - } - _ => bug!("projection candidate for unexpected type: {:?}", placeholder_self_ty), - }; - let candidate_predicate = - tcx.item_bounds(def_id).map_bound(|i| i[idx]).instantiate(tcx, args); + let candidate_predicate = self + .for_each_item_bound( + placeholder_self_ty, + |_, clause, clause_idx| { + if clause_idx == idx { + ControlFlow::Break(clause) + } else { + ControlFlow::Continue(()) + } + }, + || unreachable!(), + ) + .break_value() + .expect("expected to index into clause that exists"); let candidate = candidate_predicate .as_trait_clause() .expect("projection candidate is not a trait predicate") .map_bound(|t| t.trait_ref); + let mut obligations = Vec::new(); let candidate = normalize_with_depth_to( self, @@ -194,8 +200,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map_err(|_| Unimplemented) })?); - if let ty::Alias(ty::Projection, ..) = placeholder_self_ty.kind() { - let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, args); + // FIXME(compiler-errors): I don't think this is needed. + if let ty::Alias(ty::Projection, alias_ty) = placeholder_self_ty.kind() { + let predicates = tcx.predicates_of(alias_ty.def_id).instantiate_own(tcx, alias_ty.args); for (predicate, _) in predicates { let normalized = normalize_with_depth_to( self, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 5befff5372aa4..ac6cfcdeb5950 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -52,6 +52,7 @@ use std::cell::{Cell, RefCell}; use std::cmp; use std::fmt::{self, Display}; use std::iter; +use std::ops::ControlFlow; pub use rustc_middle::traits::select::*; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -1592,71 +1593,41 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.selection_cache.insert((param_env, pred), dep_node, candidate); } - /// Matches a predicate against the bounds of its self type. - /// - /// Given an obligation like `::Bar: Baz` where the self type is - /// a projection, look at the bounds of `T::Bar`, see if we can find a - /// `Baz` bound. We return indexes into the list returned by - /// `tcx.item_bounds` for any applicable bounds. - #[instrument(level = "debug", skip(self), ret)] - fn match_projection_obligation_against_definition_bounds( + /// Looks at the item bounds of the projection or opaque type. + /// If this is a nested rigid projection, such as + /// `<::Assoc as Tr2>::Assoc`, consider the item bounds + /// on both `Tr1::Assoc` and `Tr2::Assoc`, since we may encounter + /// relative bounds on both via the `associated_type_bounds` feature. + pub(super) fn for_each_item_bound( &mut self, - obligation: &PolyTraitObligation<'tcx>, - ) -> smallvec::SmallVec<[usize; 2]> { - let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate); - let placeholder_trait_predicate = - self.infcx.enter_forall_and_leak_universe(poly_trait_predicate); - debug!(?placeholder_trait_predicate); - - let tcx = self.infcx.tcx; - let (def_id, args) = match *placeholder_trait_predicate.trait_ref.self_ty().kind() { - ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. }) => { - (def_id, args) - } - _ => { - span_bug!( - obligation.cause.span, - "match_projection_obligation_against_definition_bounds() called \ - but self-ty is not a projection: {:?}", - placeholder_trait_predicate.trait_ref.self_ty() - ); - } - }; - let bounds = tcx.item_bounds(def_id).instantiate(tcx, args); + mut self_ty: Ty<'tcx>, + mut for_each: impl FnMut(&mut Self, ty::Clause<'tcx>, usize) -> ControlFlow, + on_ambiguity: impl FnOnce(), + ) -> ControlFlow { + let mut idx = 0; + loop { + let (kind, alias_ty) = match *self_ty.kind() { + ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty), + ty::Infer(ty::TyVar(_)) => { + on_ambiguity(); + return ControlFlow::Continue(()); + } + _ => return ControlFlow::Continue(()), + }; - // The bounds returned by `item_bounds` may contain duplicates after - // normalization, so try to deduplicate when possible to avoid - // unnecessary ambiguity. - let mut distinct_normalized_bounds = FxHashSet::default(); + for bound in + self.tcx().item_bounds(alias_ty.def_id).instantiate(self.tcx(), alias_ty.args) + { + for_each(self, bound, idx)?; + idx += 1; + } - bounds - .iter() - .enumerate() - .filter_map(|(idx, bound)| { - let bound_predicate = bound.kind(); - if let ty::ClauseKind::Trait(pred) = bound_predicate.skip_binder() { - let bound = bound_predicate.rebind(pred.trait_ref); - if self.infcx.probe(|_| { - match self.match_normalize_trait_ref( - obligation, - bound, - placeholder_trait_predicate.trait_ref, - ) { - Ok(None) => true, - Ok(Some(normalized_trait)) - if distinct_normalized_bounds.insert(normalized_trait) => - { - true - } - _ => false, - } - }) { - return Some(idx); - } - } - None - }) - .collect() + if kind == ty::Projection { + self_ty = alias_ty.self_ty(); + } else { + return ControlFlow::Continue(()); + } + } } /// Equates the trait in `obligation` with trait bound. If the two traits diff --git a/tests/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs b/tests/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs index d180de9be3bf3..1c48aadecceb9 100644 --- a/tests/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs +++ b/tests/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs @@ -1,5 +1,4 @@ -// NOTE: rustc cannot currently handle bounds of the form `for<'a> >::Assoc: Baz`. -// This should hopefully be fixed with Chalk. +// check-pass #![feature(associated_type_bounds)] @@ -24,9 +23,6 @@ impl<'a, 'b> Lam<&'a &'b u8> for L2 { trait Case1 { type C: Clone + Iterator Lam<&'a u8, App: Debug>> + Sync>; - //~^ ERROR `<::C as Iterator>::Item` is not an iterator - //~| ERROR `<::C as Iterator>::Item` cannot be sent between threads safely - //~| ERROR `<::C as Iterator>::Item` cannot be shared between threads safely } pub struct S1; @@ -35,33 +31,17 @@ impl Case1 for S1 { } fn assume_case1() { - fn assert_a<_0, A>() - where - A: Iterator, - _0: Debug, - { - } - assert_a::<_, T::A>(); - - fn assert_b<_0, B>() - where - B: Iterator, - _0: 'static, - { - } - assert_b::<_, T::B>(); - - fn assert_c<_0, _1, _2, C>() + fn assert_c<_1, _2, C>() where C: Clone + Iterator, _2: Send + Iterator, - _1: for<'a> Lam<&'a u8, App = _0>, - _0: Debug, + _1: for<'a> Lam<&'a u8>, + for<'a> <_1 as Lam<&'a u8>>::App: Debug, { } - assert_c::<_, _, _, T::C>(); + assert_c::<_, _, T::C>(); } fn main() { - assume_case1(S1); + assume_case1::(); } diff --git a/tests/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr b/tests/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr deleted file mode 100644 index c23e54594ee30..0000000000000 --- a/tests/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error[E0277]: `<::C as Iterator>::Item` cannot be sent between threads safely - --> $DIR/bad-bounds-on-assoc-in-trait.rs:26:36 - | -LL | type C: Clone + Iterator Lam<&'a u8, App: Debug>> + Sync>; - | ^^^^ `<::C as Iterator>::Item` cannot be sent between threads safely - | - = help: the trait `Send` is not implemented for `<::C as Iterator>::Item` -help: consider further restricting the associated type - | -LL | trait Case1 where <::C as Iterator>::Item: Send { - | ++++++++++++++++++++++++++++++++++++++++++++++++++ - -error[E0277]: `<::C as Iterator>::Item` is not an iterator - --> $DIR/bad-bounds-on-assoc-in-trait.rs:26:43 - | -LL | type C: Clone + Iterator Lam<&'a u8, App: Debug>> + Sync>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `<::C as Iterator>::Item` is not an iterator - | - = help: the trait `Iterator` is not implemented for `<::C as Iterator>::Item` -help: consider further restricting the associated type - | -LL | trait Case1 where <::C as Iterator>::Item: Iterator { - | ++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -error[E0277]: `<::C as Iterator>::Item` cannot be shared between threads safely - --> $DIR/bad-bounds-on-assoc-in-trait.rs:26:93 - | -LL | type C: Clone + Iterator Lam<&'a u8, App: Debug>> + Sync>; - | ^^^^ `<::C as Iterator>::Item` cannot be shared between threads safely - | - = help: the trait `Sync` is not implemented for `<::C as Iterator>::Item` -help: consider further restricting the associated type - | -LL | trait Case1 where <::C as Iterator>::Item: Sync { - | ++++++++++++++++++++++++++++++++++++++++++++++++++ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs b/tests/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs index 23be735010bf3..7bc2970ade9a2 100644 --- a/tests/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs +++ b/tests/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs @@ -1,3 +1,5 @@ +// check-pass + #![feature(associated_type_bounds)] use std::fmt::Debug; @@ -16,8 +18,6 @@ impl<'a, 'b> Lam<&'a &'b u8> for L2 { type App = u8; } trait Case1 { type A: Iterator; - //~^ ERROR `<::A as Iterator>::Item` doesn't implement `Debug` - type B: Iterator; } @@ -33,7 +33,6 @@ impl Case1 for S1 { // bounds of `Out`, but trait selection can't find the bound since it applies // to a type other than `Self::Out`. pub trait Foo { type Out: Baz; } -//~^ ERROR trait bound `<::Out as Baz>::Assoc: Default` is not satisfied pub trait Baz { type Assoc; } #[derive(Default)] diff --git a/tests/ui/associated-type-bounds/bounds-on-assoc-in-trait.stderr b/tests/ui/associated-type-bounds/bounds-on-assoc-in-trait.stderr deleted file mode 100644 index 4e2313bd4e4a9..0000000000000 --- a/tests/ui/associated-type-bounds/bounds-on-assoc-in-trait.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error[E0277]: `<::A as Iterator>::Item` doesn't implement `Debug` - --> $DIR/bounds-on-assoc-in-trait.rs:18:28 - | -LL | type A: Iterator; - | ^^^^^ `<::A as Iterator>::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` - | - = help: the trait `Debug` is not implemented for `<::A as Iterator>::Item` -help: consider further restricting the associated type - | -LL | trait Case1 where <::A as Iterator>::Item: Debug { - | +++++++++++++++++++++++++++++++++++++++++++++++++++ - -error[E0277]: the trait bound `<::Out as Baz>::Assoc: Default` is not satisfied - --> $DIR/bounds-on-assoc-in-trait.rs:35:38 - | -LL | pub trait Foo { type Out: Baz; } - | ^^^^^^^ the trait `Default` is not implemented for `<::Out as Baz>::Assoc` - | -help: consider further restricting the associated type - | -LL | pub trait Foo where <::Out as Baz>::Assoc: Default { type Out: Baz; } - | +++++++++++++++++++++++++++++++++++++++++++++++++ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-type-bounds/duplicate.rs b/tests/ui/associated-type-bounds/duplicate.rs index 160b524c881c9..036f8ede1b3b7 100644 --- a/tests/ui/associated-type-bounds/duplicate.rs +++ b/tests/ui/associated-type-bounds/duplicate.rs @@ -251,13 +251,10 @@ where trait TRA1 { type A: Iterator; //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - //~| ERROR `<::A as Iterator>::Item` cannot be sent between threads safely - //~| ERROR the trait bound `<::A as Iterator>::Item: Copy` is not satisfied } trait TRA2 { type A: Iterator; //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - //~| ERROR the trait bound `<::A as Iterator>::Item: Copy` is not satisfied } trait TRA3 { type A: Iterator; diff --git a/tests/ui/associated-type-bounds/duplicate.stderr b/tests/ui/associated-type-bounds/duplicate.stderr index accb366dd1552..bf6aab96dc726 100644 --- a/tests/ui/associated-type-bounds/duplicate.stderr +++ b/tests/ui/associated-type-bounds/duplicate.stderr @@ -7,7 +7,7 @@ LL | struct SI1> { | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:267:40 + --> $DIR/duplicate.rs:264:40 | LL | type TADyn1 = dyn Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -15,7 +15,7 @@ LL | type TADyn1 = dyn Iterator; | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:269:44 + --> $DIR/duplicate.rs:266:44 | LL | type TADyn2 = Box>; | ---------- ^^^^^^^^^^ re-bound here @@ -23,7 +23,7 @@ LL | type TADyn2 = Box>; | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:271:43 + --> $DIR/duplicate.rs:268:43 | LL | type TADyn3 = dyn Iterator; | ------------- ^^^^^^^^^^^^^ re-bound here @@ -523,7 +523,7 @@ LL | type A: Iterator; | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:258:34 + --> $DIR/duplicate.rs:256:34 | LL | type A: Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -531,7 +531,7 @@ LL | type A: Iterator; | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:263:37 + --> $DIR/duplicate.rs:260:37 | LL | type A: Iterator; | ------------- ^^^^^^^^^^^^^ re-bound here @@ -631,41 +631,7 @@ LL | Self: Iterator, | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0277]: the trait bound `<::A as Iterator>::Item: Copy` is not satisfied - --> $DIR/duplicate.rs:252:28 - | -LL | type A: Iterator; - | ^^^^ the trait `Copy` is not implemented for `<::A as Iterator>::Item` - | -help: consider further restricting the associated type - | -LL | trait TRA1 where <::A as Iterator>::Item: Copy { - | +++++++++++++++++++++++++++++++++++++++++++++++++ - -error[E0277]: `<::A as Iterator>::Item` cannot be sent between threads safely - --> $DIR/duplicate.rs:252:40 - | -LL | type A: Iterator; - | ^^^^ `<::A as Iterator>::Item` cannot be sent between threads safely - | - = help: the trait `Send` is not implemented for `<::A as Iterator>::Item` -help: consider further restricting the associated type - | -LL | trait TRA1 where <::A as Iterator>::Item: Send { - | +++++++++++++++++++++++++++++++++++++++++++++++++ - -error[E0277]: the trait bound `<::A as Iterator>::Item: Copy` is not satisfied - --> $DIR/duplicate.rs:258:28 - | -LL | type A: Iterator; - | ^^^^ the trait `Copy` is not implemented for `<::A as Iterator>::Item` - | -help: consider further restricting the associated type - | -LL | trait TRA2 where <::A as Iterator>::Item: Copy { - | +++++++++++++++++++++++++++++++++++++++++++++++++ - -error: aborting due to 78 previous errors +error: aborting due to 75 previous errors -Some errors have detailed explanations: E0277, E0282, E0719. -For more information about an error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0282, E0719. +For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/associated-types/hr-associated-type-bound-object.stderr b/tests/ui/associated-types/hr-associated-type-bound-object.stderr index 8c91211b964b4..87a048d0a134c 100644 --- a/tests/ui/associated-types/hr-associated-type-bound-object.stderr +++ b/tests/ui/associated-types/hr-associated-type-bound-object.stderr @@ -12,6 +12,10 @@ LL | trait X<'a> LL | where LL | for<'b> >::U: Clone, | ^^^^^ required by this bound in `X` +help: consider further restricting the associated type + | +LL | fn f<'a, T: X<'a> + ?Sized>(x: &>::U) where for<'b> >::U: Clone { + | ++++++++++++++++++++++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.current.stderr b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.current.stderr index d2db6abe3132c..2e82a3fcdb4c3 100644 --- a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.current.stderr +++ b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.current.stderr @@ -1,5 +1,5 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/normalizing-self-auto-trait-issue-109924.rs:7:12 + --> $DIR/normalizing-self-auto-trait-issue-109924.rs:6:12 | LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ @@ -7,29 +7,5 @@ LL | #![feature(return_type_notation)] = note: see issue #109417 for more information = note: `#[warn(incomplete_features)]` on by default -error[E0277]: `impl Future { <_ as Foo>::bar() }` cannot be sent between threads safely - --> $DIR/normalizing-self-auto-trait-issue-109924.rs:22:11 - | -LL | build(Bar); - | ----- ^^^ `impl Future { <_ as Foo>::bar() }` cannot be sent between threads safely - | | - | required by a bound introduced by this call - | - = help: the trait `for<'a> Send` is not implemented for `impl Future { <_ as Foo>::bar() }` -note: this is a known limitation of the trait solver that will be lifted in the future - --> $DIR/normalizing-self-auto-trait-issue-109924.rs:22:11 - | -LL | build(Bar); - | ------^^^- - | | | - | | the trait solver is unable to infer the generic types that should be inferred from this argument - | add turbofish arguments to this call to specify the types manually, even if it's redundant -note: required by a bound in `build` - --> $DIR/normalizing-self-auto-trait-issue-109924.rs:19:39 - | -LL | fn build(_: T) where T: Foo {} - | ^^^^ required by this bound in `build` - -error: aborting due to 1 previous error; 1 warning emitted +warning: 1 warning emitted -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.next.stderr b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.next.stderr index 4837815fad4ad..2e82a3fcdb4c3 100644 --- a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.next.stderr +++ b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.next.stderr @@ -1,5 +1,5 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/normalizing-self-auto-trait-issue-109924.rs:7:12 + --> $DIR/normalizing-self-auto-trait-issue-109924.rs:6:12 | LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs index 6097c7f1073ed..5341c39a975aa 100644 --- a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs +++ b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs @@ -1,11 +1,10 @@ +// check-pass // revisions: current next -//[current] known-bug: #109924 -//[next] check-pass //[next] compile-flags: -Znext-solver // edition:2021 #![feature(return_type_notation)] -//[next]~^ WARN the feature `return_type_notation` is incomplete +//~^ WARN the feature `return_type_notation` is incomplete trait Foo { async fn bar(&self); diff --git a/tests/ui/feature-gates/feature-gate-associated_type_bounds.rs b/tests/ui/feature-gates/feature-gate-associated_type_bounds.rs index 073599edad7b9..f87d3aab635c0 100644 --- a/tests/ui/feature-gates/feature-gate-associated_type_bounds.rs +++ b/tests/ui/feature-gates/feature-gate-associated_type_bounds.rs @@ -11,7 +11,6 @@ impl Tr1 for S1 { type As1 = S2; } trait _Tr3 { type A: Iterator; //~^ ERROR associated type bounds are unstable - //~| ERROR the trait bound `<::A as Iterator>::Item: Copy` is not satisfied type B: Iterator; //~^ ERROR associated type bounds are unstable diff --git a/tests/ui/feature-gates/feature-gate-associated_type_bounds.stderr b/tests/ui/feature-gates/feature-gate-associated_type_bounds.stderr index efab91f25f0d2..855a29953f1b0 100644 --- a/tests/ui/feature-gates/feature-gate-associated_type_bounds.stderr +++ b/tests/ui/feature-gates/feature-gate-associated_type_bounds.stderr @@ -9,7 +9,7 @@ LL | type A: Iterator; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:16:22 + --> $DIR/feature-gate-associated_type_bounds.rs:15:22 | LL | type B: Iterator; | ^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | type B: Iterator; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:20:20 + --> $DIR/feature-gate-associated_type_bounds.rs:19:20 | LL | struct _St1> { | ^^^^^^^^ @@ -29,7 +29,7 @@ LL | struct _St1> { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:27:18 + --> $DIR/feature-gate-associated_type_bounds.rs:26:18 | LL | enum _En1> { | ^^^^^^^^ @@ -39,7 +39,7 @@ LL | enum _En1> { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:34:19 + --> $DIR/feature-gate-associated_type_bounds.rs:33:19 | LL | union _Un1> { | ^^^^^^^^ @@ -49,7 +49,7 @@ LL | union _Un1> { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:41:37 + --> $DIR/feature-gate-associated_type_bounds.rs:40:37 | LL | type _TaWhere1 where T: Iterator = T; | ^^^^^^^^^^ @@ -59,7 +59,7 @@ LL | type _TaWhere1 where T: Iterator = T; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:44:22 + --> $DIR/feature-gate-associated_type_bounds.rs:43:22 | LL | fn _apit(_: impl Tr1) {} | ^^^^^^^^^ @@ -69,7 +69,7 @@ LL | fn _apit(_: impl Tr1) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:46:26 + --> $DIR/feature-gate-associated_type_bounds.rs:45:26 | LL | fn _apit_dyn(_: &dyn Tr1) {} | ^^^^^^^^^ @@ -79,7 +79,7 @@ LL | fn _apit_dyn(_: &dyn Tr1) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:49:24 + --> $DIR/feature-gate-associated_type_bounds.rs:48:24 | LL | fn _rpit() -> impl Tr1 { S1 } | ^^^^^^^^^ @@ -89,7 +89,7 @@ LL | fn _rpit() -> impl Tr1 { S1 } = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:52:31 + --> $DIR/feature-gate-associated_type_bounds.rs:51:31 | LL | fn _rpit_dyn() -> Box> { Box::new(S1) } | ^^^^^^^^^ @@ -99,7 +99,7 @@ LL | fn _rpit_dyn() -> Box> { Box::new(S1) } = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:55:23 + --> $DIR/feature-gate-associated_type_bounds.rs:54:23 | LL | const _cdef: impl Tr1 = S1; | ^^^^^^^^^ @@ -109,7 +109,7 @@ LL | const _cdef: impl Tr1 = S1; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:61:24 + --> $DIR/feature-gate-associated_type_bounds.rs:60:24 | LL | static _sdef: impl Tr1 = S1; | ^^^^^^^^^ @@ -119,7 +119,7 @@ LL | static _sdef: impl Tr1 = S1; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:68:21 + --> $DIR/feature-gate-associated_type_bounds.rs:67:21 | LL | let _: impl Tr1 = S1; | ^^^^^^^^^ @@ -129,7 +129,7 @@ LL | let _: impl Tr1 = S1; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0562]: `impl Trait` is not allowed in const types - --> $DIR/feature-gate-associated_type_bounds.rs:55:14 + --> $DIR/feature-gate-associated_type_bounds.rs:54:14 | LL | const _cdef: impl Tr1 = S1; | ^^^^^^^^^^^^^^^^^^^ @@ -137,7 +137,7 @@ LL | const _cdef: impl Tr1 = S1; = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in static types - --> $DIR/feature-gate-associated_type_bounds.rs:61:15 + --> $DIR/feature-gate-associated_type_bounds.rs:60:15 | LL | static _sdef: impl Tr1 = S1; | ^^^^^^^^^^^^^^^^^^^ @@ -145,25 +145,14 @@ LL | static _sdef: impl Tr1 = S1; = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in the type of variable bindings - --> $DIR/feature-gate-associated_type_bounds.rs:68:12 + --> $DIR/feature-gate-associated_type_bounds.rs:67:12 | LL | let _: impl Tr1 = S1; | ^^^^^^^^^^^^^^^^^^^ | = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0277]: the trait bound `<::A as Iterator>::Item: Copy` is not satisfied - --> $DIR/feature-gate-associated_type_bounds.rs:12:28 - | -LL | type A: Iterator; - | ^^^^ the trait `Copy` is not implemented for `<::A as Iterator>::Item` - | -help: consider further restricting the associated type - | -LL | trait _Tr3 where <::A as Iterator>::Item: Copy { - | +++++++++++++++++++++++++++++++++++++++++++++++++ - -error: aborting due to 17 previous errors +error: aborting due to 16 previous errors -Some errors have detailed explanations: E0277, E0562, E0658. -For more information about an error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0562, E0658. +For more information about an error, try `rustc --explain E0562`. diff --git a/tests/ui/generic-associated-types/bugs/issue-88460.rs b/tests/ui/generic-associated-types/bugs/issue-88460.rs index 224e696ad2c9c..3d2b225f0cd01 100644 --- a/tests/ui/generic-associated-types/bugs/issue-88460.rs +++ b/tests/ui/generic-associated-types/bugs/issue-88460.rs @@ -1,7 +1,4 @@ -// check-fail -// known-bug: #88460 - -// This should pass, but has a missed normalization due to HRTB. +// check-pass pub trait Marker {} diff --git a/tests/ui/generic-associated-types/bugs/issue-88460.stderr b/tests/ui/generic-associated-types/bugs/issue-88460.stderr deleted file mode 100644 index 74418a0c0bd52..0000000000000 --- a/tests/ui/generic-associated-types/bugs/issue-88460.stderr +++ /dev/null @@ -1,29 +0,0 @@ -error[E0277]: the trait bound `for<'a> <_ as Trait>::Assoc<'a>: Marker` is not satisfied - --> $DIR/issue-88460.rs:28:10 - | -LL | test(Foo); - | ---- ^^^ the trait `for<'a> Marker` is not implemented for `<_ as Trait>::Assoc<'a>` - | | - | required by a bound introduced by this call - | - = help: the trait `Marker` is implemented for `()` -note: this is a known limitation of the trait solver that will be lifted in the future - --> $DIR/issue-88460.rs:28:10 - | -LL | test(Foo); - | -----^^^- - | | | - | | the trait solver is unable to infer the generic types that should be inferred from this argument - | add turbofish arguments to this call to specify the types manually, even if it's redundant -note: required by a bound in `test` - --> $DIR/issue-88460.rs:15:27 - | -LL | fn test(value: T) - | ---- required by a bound in this function -... -LL | for<'a> T::Assoc<'a>: Marker, - | ^^^^^^ required by this bound in `test` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.rs index ab9d9a7ce6f08..7072f41066b3a 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.rs @@ -1,5 +1,4 @@ -// check-fail -// known-bug: #90950 +// check-pass trait Yokeable<'a>: 'static { type Output: 'a; diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.stderr deleted file mode 100644 index 075e422e29c0b..0000000000000 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.stderr +++ /dev/null @@ -1,29 +0,0 @@ -error[E0277]: the trait bound `for<'a> <_ as Yokeable<'a>>::Output: IsCovariant<'a>` is not satisfied - --> $DIR/issue-90950.rs:50:12 - | -LL | upcast(y) - | ------ ^ the trait `for<'a> IsCovariant<'a>` is not implemented for `<_ as Yokeable<'a>>::Output` - | | - | required by a bound introduced by this call - | - = help: the trait `IsCovariant<'a>` is implemented for `std::borrow::Cow<'a, T>` -note: this is a known limitation of the trait solver that will be lifted in the future - --> $DIR/issue-90950.rs:50:12 - | -LL | upcast(y) - | -------^- - | | | - | | the trait solver is unable to infer the generic types that should be inferred from this argument - | add turbofish arguments to this call to specify the types manually, even if it's redundant -note: required by a bound in `upcast` - --> $DIR/issue-90950.rs:27:42 - | -LL | fn upcast(x: Yoke) -> Yoke + 'static>> where - | ------ required by a bound in this function -LL | Y: for<'a> Yokeable<'a>, -LL | for<'a> >::Output: IsCovariant<'a> - | ^^^^^^^^^^^^^^^ required by this bound in `upcast` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.rs index 7693b11824762..58ca5b0c1874a 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.rs @@ -1,5 +1,4 @@ -// check-fail -// known-bug: #89196 +// check-pass // Should pass, but we normalize and check bounds before we resolve the generics // of the function (which we know because of the return type). diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr deleted file mode 100644 index f42fc59536c43..0000000000000 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0277]: the trait bound `for<'a> <_ as Trait<'a>>::Out: Copy` is not satisfied - --> $DIR/norm-before-method-resolution.rs:22:17 - | -LL | let _: () = weird_bound(); - | ^^^^^^^^^^^^^ the trait `for<'a> Copy` is not implemented for `<_ as Trait<'a>>::Out` - | -note: this is a known limitation of the trait solver that will be lifted in the future - --> $DIR/norm-before-method-resolution.rs:22:17 - | -LL | let _: () = weird_bound(); - | ^^^^^^^^^^^^^ try adding turbofish arguments to this expression to specify the types manually, even if it's redundant -note: required by a bound in `weird_bound` - --> $DIR/norm-before-method-resolution.rs:18:40 - | -LL | fn weird_bound() -> X - | ----------- required by a bound in this function -... -LL | for<'a> >::Out: Copy - | ^^^^ required by this bound in `weird_bound` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. From 548929dc5e7558880108065e088b56a4a7e11205 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 2 Feb 2024 00:41:26 +0000 Subject: [PATCH 02/12] Don't unnecessarily lower associated type bounds to impl trait --- compiler/rustc_ast_lowering/src/lib.rs | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index b570a0611c3f3..ee798aa85920f 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1094,24 +1094,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Piggy-back on the `impl Trait` context to figure out the correct behavior. let desugar_kind = match itctx { - // We are in the return position: - // - // fn foo() -> impl Iterator - // - // so desugar to - // - // fn foo() -> impl Iterator - ImplTraitContext::ReturnPositionOpaqueTy { .. } - | ImplTraitContext::TypeAliasesOpaqueTy { .. } => DesugarKind::ImplTrait, - - // We are in the argument position, but within a dyn type: + // in an argument, RPIT, or TAIT, if we are within a dyn type: // // fn foo(x: dyn Iterator) // - // so desugar to + // then desugar to: // // fn foo(x: dyn Iterator) - ImplTraitContext::Universal if self.is_in_dyn_type => DesugarKind::ImplTrait, + // + // This is because dyn traits must have all of their associated types specified. + ImplTraitContext::ReturnPositionOpaqueTy { .. } + | ImplTraitContext::TypeAliasesOpaqueTy { .. } + | ImplTraitContext::Universal + if self.is_in_dyn_type => + { + DesugarKind::ImplTrait + } ImplTraitContext::Disallowed(position) if self.is_in_dyn_type => { DesugarKind::Error(position) From 7a63d3f16a44ade84f7fd99a7257ff753eb1da1d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 2 Feb 2024 17:51:16 +0000 Subject: [PATCH 03/12] Add tests for untested capabilities --- .../associated-type-bounds/higher-ranked.rs | 17 +++++++++ ...sted-bounds-dont-eliminate-alias-bounds.rs | 37 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 tests/ui/associated-type-bounds/higher-ranked.rs create mode 100644 tests/ui/associated-type-bounds/nested-bounds-dont-eliminate-alias-bounds.rs diff --git a/tests/ui/associated-type-bounds/higher-ranked.rs b/tests/ui/associated-type-bounds/higher-ranked.rs new file mode 100644 index 0000000000000..2bd5f316811d9 --- /dev/null +++ b/tests/ui/associated-type-bounds/higher-ranked.rs @@ -0,0 +1,17 @@ +// check-pass + +#![feature(associated_type_bounds)] + +trait A<'a> { + type Assoc: ?Sized; +} + +impl<'a> A<'a> for () { + type Assoc = &'a (); +} + +fn hello() -> impl for<'a> A<'a, Assoc: Sized> { + () +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/nested-bounds-dont-eliminate-alias-bounds.rs b/tests/ui/associated-type-bounds/nested-bounds-dont-eliminate-alias-bounds.rs new file mode 100644 index 0000000000000..05e4e323d879d --- /dev/null +++ b/tests/ui/associated-type-bounds/nested-bounds-dont-eliminate-alias-bounds.rs @@ -0,0 +1,37 @@ +// check-pass + +#![feature(associated_type_bounds)] + +trait Trait1 { + type Assoc1: Bar; + + fn assoc(self) -> Self::Assoc1; +} + +impl Trait1 for () { + type Assoc1 = (); + fn assoc(self) {} +} + +trait Foo {} +impl Foo for () {} +trait Bar {} +impl Bar for () {} + +fn hello() -> impl Trait1 { + () +} + +fn world() { + // Tests that `Assoc1: Foo` bound in the RPIT doesn't disqualify + // the `Assoc1: Bar` bound in the item, as a nested RPIT desugaring + // would do. + + fn is_foo(_: impl Foo) {} + is_foo(hello().assoc()); + + fn is_bar(_: impl Bar) {} + is_bar(hello().assoc()); +} + +fn main() {} From 7057188c549cb38e72843c9c344f77659bf67bc9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 7 Feb 2024 00:19:12 +0000 Subject: [PATCH 04/12] make it recursive --- .../src/solve/assembly/mod.rs | 174 +++++++++--------- .../src/traits/project.rs | 8 +- .../src/traits/select/candidate_assembly.rs | 6 +- 3 files changed, 95 insertions(+), 93 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 150894ba83e05..380f7ac2d2da8 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -542,97 +542,103 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, G>, candidates: &mut Vec>, ) { - let _ = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| { - let mut self_ty = goal.predicate.self_ty(); - - // For some deeply nested `::A::B::C::D` rigid associated type, - // we should explore the item bounds for all levels, since the - // `associated_type_bounds` feature means that a parent associated - // type may carry bounds for a nested associated type. - loop { - let (kind, alias_ty) = match *self_ty.kind() { - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Adt(_, _) - | ty::Foreign(_) - | ty::Str - | ty::Array(_, _) - | ty::Slice(_) - | ty::RawPtr(_) - | ty::Ref(_, _, _) - | ty::FnDef(_, _) - | ty::FnPtr(_) - | ty::Dynamic(..) - | ty::Closure(..) - | ty::CoroutineClosure(..) - | ty::Coroutine(..) - | ty::CoroutineWitness(..) - | ty::Never - | ty::Tuple(_) - | ty::Param(_) - | ty::Placeholder(..) - | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) - | ty::Error(_) => break, - ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) - | ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"), - - // If we hit infer when normalizing the self type of an alias, - // then bail with ambiguity. - ty::Infer(ty::TyVar(_)) => { - if let Ok(result) = ecx - .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) - { - candidates - .push(Candidate { source: CandidateSource::AliasBound, result }); - } - break; - } + let () = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| { + ecx.assemble_alias_bound_candidates_recur(goal.predicate.self_ty(), goal, candidates); + }); + } - ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty), - ty::Alias(ty::Inherent | ty::Weak, _) => { - unreachable!("Weak and Inherent aliases should have been normalized away") - } - }; + /// For some deeply nested `::A::B::C::D` rigid associated type, + /// we should explore the item bounds for all levels, since the + /// `associated_type_bounds` feature means that a parent associated + /// type may carry bounds for a nested associated type. + /// + /// If we have a projection, check that its self type is a rigid projection. + /// If so, continue searching by recursively calling after normalization. + // FIXME: This may recurse infinitely, but I can't seem to trigger it without + // hitting another overflow error something. Add a depth parameter needed later. + fn assemble_alias_bound_candidates_recur>( + &mut self, + self_ty: Ty<'tcx>, + goal: Goal<'tcx, G>, + candidates: &mut Vec>, + ) { + let (kind, alias_ty) = match *self_ty.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(_) + | ty::Dynamic(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Never + | ty::Tuple(_) + | ty::Param(_) + | ty::Placeholder(..) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Error(_) => return, + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | ty::Bound(..) => { + bug!("unexpected self type for `{goal:?}`") + } - for assumption in - ecx.tcx().item_bounds(alias_ty.def_id).instantiate(ecx.tcx(), alias_ty.args) + ty::Infer(ty::TyVar(_)) => { + // If we hit infer when normalizing the self type of an alias, + // then bail with ambiguity. We should never encounter this on + // the *first* iteration of this recursive function. + if let Ok(result) = + self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) { - match G::consider_alias_bound_candidate(ecx, goal, assumption) { - Ok(result) => { - candidates - .push(Candidate { source: CandidateSource::AliasBound, result }); - } - Err(NoSolution) => {} - } + candidates.push(Candidate { source: CandidateSource::AliasBound, result }); } + return; + } - // If we have a projection, check that its self type is a rigid projection. - // If so, continue searching. - if kind == ty::Projection { - match ecx.try_normalize_ty(goal.param_env, alias_ty.self_ty()) { - Some(next_self_ty) => self_ty = next_self_ty, - None => { - if let Ok(result) = ecx - .evaluate_added_goals_and_make_canonical_response( - Certainty::OVERFLOW, - ) - { - candidates.push(Candidate { - source: CandidateSource::AliasBound, - result, - }); - } - break; - } - } - } else { - break; + ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty), + ty::Alias(ty::Inherent | ty::Weak, _) => { + unreachable!("Weak and Inherent aliases should have been normalized away already") + } + }; + + for assumption in + self.tcx().item_bounds(alias_ty.def_id).instantiate(self.tcx(), alias_ty.args) + { + match G::consider_alias_bound_candidate(self, goal, assumption) { + Ok(result) => { + candidates.push(Candidate { source: CandidateSource::AliasBound, result }); } + Err(NoSolution) => {} } - }); + } + + if kind != ty::Projection { + return; + } + + match self.try_normalize_ty(goal.param_env, alias_ty.self_ty()) { + // Recurse on the self type of the projection. + Some(next_self_ty) => { + self.assemble_alias_bound_candidates_recur(next_self_ty, goal, candidates); + } + // Bail if we overflow when normalizing, adding an ambiguous candidate. + None => { + if let Ok(result) = + self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW) + { + candidates.push(Candidate { source: CandidateSource::AliasBound, result }); + } + } + } } /// Check that we are allowed to use an alias bound originating from the self diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 8f47e45df0c6c..8cfbd7d3ce6af 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1645,11 +1645,9 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( ControlFlow::Continue(()) }, - || { - // `ProjectionCandidateSet` is borrowed in the above closure, - // so just mark ambiguous outside of the closure. - ambiguous = true; - }, + // `ProjectionCandidateSet` is borrowed in the above closure, + // so just mark ambiguous outside of the closure. + || ambiguous = true, ); if ambiguous { diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 248d75aaec713..27dbe0351da12 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -201,10 +201,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ControlFlow::Continue(()) }, - || { - // On ambiguity. - candidates.ambiguous = true; - }, + // On ambiguity. + || candidates.ambiguous = true, ); }); } From f0d002b890a3430e0c61a73cb4708f7fadee94f5 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 2 Feb 2024 17:13:22 +0100 Subject: [PATCH 05/12] Correctly generate path for non-local items in source code pages --- src/librustdoc/formats/item_type.rs | 37 ++++-- src/librustdoc/html/format.rs | 192 ++++++++++++++++++++-------- 2 files changed, 165 insertions(+), 64 deletions(-) diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs index e80da46adb4ca..f10c829bf4eed 100644 --- a/src/librustdoc/formats/item_type.rs +++ b/src/librustdoc/formats/item_type.rs @@ -4,7 +4,7 @@ use std::fmt; use serde::{Serialize, Serializer}; -use rustc_hir::def::DefKind; +use rustc_hir::def::{CtorOf, DefKind}; use rustc_span::hygiene::MacroKind; use crate::clean; @@ -115,7 +115,15 @@ impl<'a> From<&'a clean::Item> for ItemType { impl From for ItemType { fn from(other: DefKind) -> Self { - match other { + Self::from_def_kind(other, None) + } +} + +impl ItemType { + /// Depending on the parent kind, some variants have a different translation (like a `Method` + /// becoming a `TyMethod`). + pub(crate) fn from_def_kind(kind: DefKind, parent_kind: Option) -> Self { + match kind { DefKind::Enum => Self::Enum, DefKind::Fn => Self::Function, DefKind::Mod => Self::Module, @@ -131,30 +139,35 @@ impl From for ItemType { MacroKind::Attr => ItemType::ProcAttribute, MacroKind::Derive => ItemType::ProcDerive, }, - DefKind::ForeignTy - | DefKind::Variant - | DefKind::AssocTy - | DefKind::TyParam + DefKind::ForeignTy => Self::ForeignType, + DefKind::Variant => Self::Variant, + DefKind::Field => Self::StructField, + DefKind::AssocTy => Self::AssocType, + DefKind::AssocFn => { + if let Some(DefKind::Trait) = parent_kind { + Self::TyMethod + } else { + Self::Method + } + } + DefKind::Ctor(CtorOf::Struct, _) => Self::Struct, + DefKind::Ctor(CtorOf::Variant, _) => Self::Variant, + DefKind::AssocConst => Self::AssocConst, + DefKind::TyParam | DefKind::ConstParam - | DefKind::Ctor(..) - | DefKind::AssocFn - | DefKind::AssocConst | DefKind::ExternCrate | DefKind::Use | DefKind::ForeignMod | DefKind::AnonConst | DefKind::InlineConst | DefKind::OpaqueTy - | DefKind::Field | DefKind::LifetimeParam | DefKind::GlobalAsm | DefKind::Impl { .. } | DefKind::Closure => Self::ForeignType, } } -} -impl ItemType { pub(crate) fn as_str(&self) -> &'static str { match *self { ItemType::Module => "mod", diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 1923fc1511970..6c6d5384882b0 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -32,6 +32,7 @@ use crate::clean::{ self, types::ExternalLocation, utils::find_nearest_parent_module, ExternalCrate, ItemId, PrimitiveType, }; +use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; use crate::html::escape::Escape; use crate::html::render::Context; @@ -581,7 +582,7 @@ fn generate_macro_def_id_path( cx: &Context<'_>, root_path: Option<&str>, ) -> Result<(String, ItemType, Vec), HrefError> { - let tcx = cx.shared.tcx; + let tcx = cx.tcx(); let crate_name = tcx.crate_name(def_id.krate); let cache = cx.cache(); @@ -651,92 +652,179 @@ fn generate_macro_def_id_path( Ok((url, ItemType::Macro, fqp)) } +fn generate_item_def_id_path( + mut def_id: DefId, + original_def_id: DefId, + cx: &Context<'_>, + root_path: Option<&str>, + original_def_kind: DefKind, +) -> Result<(String, ItemType, Vec), HrefError> { + use crate::rustc_trait_selection::infer::TyCtxtInferExt; + use crate::rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; + use rustc_middle::traits::ObligationCause; + + let tcx = cx.tcx(); + let crate_name = tcx.crate_name(def_id.krate); + + // No need to try to infer the actual parent item if it's not an associated item from the `impl` + // block. + if def_id != original_def_id && matches!(tcx.def_kind(def_id), DefKind::Impl { .. }) { + let infcx = tcx.infer_ctxt().build(); + def_id = infcx + .at(&ObligationCause::dummy(), tcx.param_env(def_id)) + .query_normalize(ty::Binder::dummy(tcx.type_of(def_id).instantiate_identity())) + .map(|resolved| infcx.resolve_vars_if_possible(resolved.value)) + .ok() + .and_then(|normalized| normalized.skip_binder().ty_adt_def()) + .map(|adt| adt.did()) + .unwrap_or(def_id); + } + + let relative: Vec = tcx + .def_path(def_id) + .data + .into_iter() + .filter_map(|elem| { + // extern blocks (and a few others things) have an empty name. + match elem.data.get_opt_name() { + Some(s) if !s.is_empty() => Some(s), + _ => None, + } + }) + .collect(); + let fqp: Vec = once(crate_name).chain(relative).collect(); + + let def_kind = tcx.def_kind(def_id); + let shortty = def_kind.into(); + let module_fqp = to_module_fqp(shortty, &fqp); + let mut is_remote = false; + + let url_parts = url_parts(cx.cache(), def_id, &module_fqp, &cx.current, &mut is_remote)?; + let (url_parts, shortty, fqp) = make_href(root_path, shortty, url_parts, &fqp, is_remote)?; + if def_id == original_def_id { + return Ok((url_parts, shortty, fqp)); + } + let kind = ItemType::from_def_kind(original_def_kind, Some(def_kind)); + Ok((format!("{url_parts}#{kind}.{}", tcx.item_name(original_def_id)), shortty, fqp)) +} + +fn to_module_fqp(shortty: ItemType, fqp: &[Symbol]) -> &[Symbol] { + if shortty == ItemType::Module { fqp } else { &fqp[..fqp.len() - 1] } +} + +fn url_parts( + cache: &Cache, + def_id: DefId, + module_fqp: &[Symbol], + relative_to: &[Symbol], + is_remote: &mut bool, +) -> Result { + match cache.extern_locations[&def_id.krate] { + ExternalLocation::Remote(ref s) => { + *is_remote = true; + let s = s.trim_end_matches('/'); + let mut builder = UrlPartsBuilder::singleton(s); + builder.extend(module_fqp.iter().copied()); + Ok(builder) + } + ExternalLocation::Local => Ok(href_relative_parts(module_fqp, relative_to).collect()), + ExternalLocation::Unknown => Err(HrefError::DocumentationNotBuilt), + } +} + +fn make_href( + root_path: Option<&str>, + shortty: ItemType, + mut url_parts: UrlPartsBuilder, + fqp: &[Symbol], + is_remote: bool, +) -> Result<(String, ItemType, Vec), HrefError> { + if !is_remote && let Some(root_path) = root_path { + let root = root_path.trim_end_matches('/'); + url_parts.push_front(root); + } + debug!(?url_parts); + match shortty { + ItemType::Module => { + url_parts.push("index.html"); + } + _ => { + let prefix = shortty.as_str(); + let last = fqp.last().unwrap(); + url_parts.push_fmt(format_args!("{prefix}.{last}.html")); + } + } + Ok((url_parts.finish(), shortty, fqp.to_vec())) +} + pub(crate) fn href_with_root_path( - did: DefId, + original_did: DefId, cx: &Context<'_>, root_path: Option<&str>, ) -> Result<(String, ItemType, Vec), HrefError> { let tcx = cx.tcx(); - let def_kind = tcx.def_kind(did); + let def_kind = tcx.def_kind(original_did); let did = match def_kind { DefKind::AssocTy | DefKind::AssocFn | DefKind::AssocConst | DefKind::Variant => { // documented on their parent's page - tcx.parent(did) + tcx.parent(original_did) } + // If this a constructor, we get the parent (either a struct or a variant) and then + // generate the link for this item. + DefKind::Ctor(..) => return href_with_root_path(tcx.parent(original_did), cx, root_path), DefKind::ExternCrate => { // Link to the crate itself, not the `extern crate` item. - if let Some(local_did) = did.as_local() { + if let Some(local_did) = original_did.as_local() { tcx.extern_mod_stmt_cnum(local_did).unwrap_or(LOCAL_CRATE).as_def_id() } else { - did + original_did } } - _ => did, + _ => original_did, }; let cache = cx.cache(); let relative_to = &cx.current; - fn to_module_fqp(shortty: ItemType, fqp: &[Symbol]) -> &[Symbol] { - if shortty == ItemType::Module { fqp } else { &fqp[..fqp.len() - 1] } - } - if !did.is_local() - && !cache.effective_visibilities.is_directly_public(tcx, did) - && !cache.document_private - && !cache.primitive_locations.values().any(|&id| id == did) - { - return Err(HrefError::Private); + if !original_did.is_local() { + // If we are generating an href for the "jump to def" feature, then the only case we want + // to ignore is if the item is `doc(hidden)` because we can't link to it. + if root_path.is_some() { + if tcx.is_doc_hidden(original_did) { + return Err(HrefError::Private); + } + } else if !cache.effective_visibilities.is_directly_public(tcx, did) + && !cache.document_private + && !cache.primitive_locations.values().any(|&id| id == did) + { + return Err(HrefError::Private); + } } let mut is_remote = false; - let (fqp, shortty, mut url_parts) = match cache.paths.get(&did) { + let (fqp, shortty, url_parts) = match cache.paths.get(&did) { Some(&(ref fqp, shortty)) => (fqp, shortty, { let module_fqp = to_module_fqp(shortty, fqp.as_slice()); debug!(?fqp, ?shortty, ?module_fqp); href_relative_parts(module_fqp, relative_to).collect() }), None => { - if let Some(&(ref fqp, shortty)) = cache.external_paths.get(&did) { + // Associated items are handled differently with "jump to def". The anchor is generated + // directly here whereas for intra-doc links, we have some extra computation being + // performed there. + let def_id_to_get = if root_path.is_some() { original_did } else { did }; + if let Some(&(ref fqp, shortty)) = cache.external_paths.get(&def_id_to_get) { let module_fqp = to_module_fqp(shortty, fqp); - ( - fqp, - shortty, - match cache.extern_locations[&did.krate] { - ExternalLocation::Remote(ref s) => { - is_remote = true; - let s = s.trim_end_matches('/'); - let mut builder = UrlPartsBuilder::singleton(s); - builder.extend(module_fqp.iter().copied()); - builder - } - ExternalLocation::Local => { - href_relative_parts(module_fqp, relative_to).collect() - } - ExternalLocation::Unknown => return Err(HrefError::DocumentationNotBuilt), - }, - ) + (fqp, shortty, url_parts(cache, did, module_fqp, relative_to, &mut is_remote)?) } else if matches!(def_kind, DefKind::Macro(_)) { return generate_macro_def_id_path(did, cx, root_path); + } else if did.is_local() { + return Err(HrefError::Private); } else { - return Err(HrefError::NotInExternalCache); + return generate_item_def_id_path(did, original_did, cx, root_path, def_kind); } } }; - if !is_remote && let Some(root_path) = root_path { - let root = root_path.trim_end_matches('/'); - url_parts.push_front(root); - } - debug!(?url_parts); - match shortty { - ItemType::Module => { - url_parts.push("index.html"); - } - _ => { - let prefix = shortty.as_str(); - let last = fqp.last().unwrap(); - url_parts.push_fmt(format_args!("{prefix}.{last}.html")); - } - } - Ok((url_parts.finish(), shortty, fqp.to_vec())) + make_href(root_path, shortty, url_parts, fqp, is_remote) } pub(crate) fn href( From f3c24833c5af6686e4a1a18a46ed872f27b120ee Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 3 Feb 2024 01:28:08 +0100 Subject: [PATCH 06/12] Add regression test for non local items link generation --- tests/rustdoc/jump-to-non-local-method.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/rustdoc/jump-to-non-local-method.rs diff --git a/tests/rustdoc/jump-to-non-local-method.rs b/tests/rustdoc/jump-to-non-local-method.rs new file mode 100644 index 0000000000000..4f4252a584257 --- /dev/null +++ b/tests/rustdoc/jump-to-non-local-method.rs @@ -0,0 +1,15 @@ +// compile-flags: -Zunstable-options --generate-link-to-definition + +#![crate_name = "foo"] + +use std::sync::atomic::AtomicIsize; + +// @has 'src/foo/jump-to-non-local-method.rs.html' +// @has - '//a[@href="https://doc.rust-lang.org/nightly/core/sync/atomic/struct.AtomicIsize.html#method.new"]' 'AtomicIsize::new' + +pub fn bar() { + let _ = AtomicIsize::new(0); + b(); +} + +fn b() {} From 14e0dab96bb4038fe85930faf7c31227fbf95d61 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 3 Feb 2024 01:35:46 +0100 Subject: [PATCH 07/12] Unify item relative path computation in one function --- src/librustdoc/clean/inline.rs | 19 +++++++++-- src/librustdoc/html/format.rs | 26 ++------------ tests/rustdoc/jump-to-non-local-method.rs | 41 ++++++++++++++++++++--- 3 files changed, 55 insertions(+), 31 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index f65c09bf0e810..7ca4392233ed4 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -191,6 +191,20 @@ pub(crate) fn load_attrs<'hir>(cx: &DocContext<'hir>, did: DefId) -> &'hir [ast: cx.tcx.get_attrs_unchecked(did) } +pub(crate) fn item_relative_path(tcx: TyCtxt<'_>, def_id: DefId) -> Vec { + tcx.def_path(def_id) + .data + .into_iter() + .filter_map(|elem| { + // extern blocks (and a few others things) have an empty name. + match elem.data.get_opt_name() { + Some(s) if !s.is_empty() => Some(s), + _ => None, + } + }) + .collect() +} + /// Record an external fully qualified name in the external_paths cache. /// /// These names are used later on by HTML rendering to generate things like @@ -206,8 +220,7 @@ pub(crate) fn record_extern_fqn(cx: &mut DocContext<'_>, did: DefId, kind: ItemT let crate_name = cx.tcx.crate_name(did.krate); - let relative = - cx.tcx.def_path(did).data.into_iter().filter_map(|elem| elem.data.get_opt_name()); + let relative = item_relative_path(cx.tcx, did); let fqn = if let ItemType::Macro = kind { // Check to see if it is a macro 2.0 or built-in macro if matches!( @@ -218,7 +231,7 @@ pub(crate) fn record_extern_fqn(cx: &mut DocContext<'_>, did: DefId, kind: ItemT ) { once(crate_name).chain(relative).collect() } else { - vec![crate_name, relative.last().expect("relative was empty")] + vec![crate_name, *relative.last().expect("relative was empty")] } } else { once(crate_name).chain(relative).collect() diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 6c6d5384882b0..4ba1665bdc9f1 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -586,18 +586,7 @@ fn generate_macro_def_id_path( let crate_name = tcx.crate_name(def_id.krate); let cache = cx.cache(); - let fqp: Vec = tcx - .def_path(def_id) - .data - .into_iter() - .filter_map(|elem| { - // extern blocks (and a few others things) have an empty name. - match elem.data.get_opt_name() { - Some(s) if !s.is_empty() => Some(s), - _ => None, - } - }) - .collect(); + let fqp = clean::inline::item_relative_path(tcx, def_id); let mut relative = fqp.iter().copied(); let cstore = CStore::from_tcx(tcx); // We need this to prevent a `panic` when this function is used from intra doc links... @@ -680,18 +669,7 @@ fn generate_item_def_id_path( .unwrap_or(def_id); } - let relative: Vec = tcx - .def_path(def_id) - .data - .into_iter() - .filter_map(|elem| { - // extern blocks (and a few others things) have an empty name. - match elem.data.get_opt_name() { - Some(s) if !s.is_empty() => Some(s), - _ => None, - } - }) - .collect(); + let relative = clean::inline::item_relative_path(tcx, def_id); let fqp: Vec = once(crate_name).chain(relative).collect(); let def_kind = tcx.def_kind(def_id); diff --git a/tests/rustdoc/jump-to-non-local-method.rs b/tests/rustdoc/jump-to-non-local-method.rs index 4f4252a584257..7767b92fbe557 100644 --- a/tests/rustdoc/jump-to-non-local-method.rs +++ b/tests/rustdoc/jump-to-non-local-method.rs @@ -2,14 +2,47 @@ #![crate_name = "foo"] +// @has 'src/foo/jump-to-non-local-method.rs.html' + +// @has - '//a[@href="{{channel}}/core/sync/atomic/struct.AtomicIsize.html"]' 'std::sync::atomic::AtomicIsize' use std::sync::atomic::AtomicIsize; +// @has - '//a[@href="{{channel}}/std/io/trait.Read.html"]' 'std::io::Read' +use std::io::Read; +// @has - '//a[@href="{{channel}}/std/io/index.html"]' 'std::io' +use std::io; +// @has - '//a[@href="{{channel}}/std/process/fn.exit.html"]' 'std::process::exit' +use std::process::exit; +use std::cmp::Ordering; +use std::marker::PhantomData; -// @has 'src/foo/jump-to-non-local-method.rs.html' -// @has - '//a[@href="https://doc.rust-lang.org/nightly/core/sync/atomic/struct.AtomicIsize.html#method.new"]' 'AtomicIsize::new' +pub fn bar2(readable: T) { + // @has - '//a[@href="{{channel}}/std/io/trait.Read.html#tymethod.read"]' 'read' + let _ = readable.read(&mut []); +} pub fn bar() { + // @has - '//a[@href="{{channel}}/core/sync/atomic/struct.AtomicIsize.html#method.new"]' 'AtomicIsize::new' let _ = AtomicIsize::new(0); - b(); + // @has - '//a[@href="#48"]' 'local_private' + local_private(); +} + +pub fn extern_call() { + // @has - '//a[@href="{{channel}}/std/process/fn.exit.html"]' 'exit' + exit(0); +} + +pub fn macro_call() -> Result<(), ()> { + // @has - '//a[@href="{{channel}}/core/macro.try.html"]' 'try!' + try!(Err(())); + Ok(()) +} + +pub fn variant() { + // @has - '//a[@href="{{channel}}/core/cmp/enum.Ordering.html#variant.Less"]' 'Ordering::Less' + let _ = Ordering::Less; + // @has - '//a[@href="{{channel}}/core/marker/struct.PhantomData.html"]' 'PhantomData' + let _: PhantomData:: = PhantomData; } -fn b() {} +fn local_private() {} From 83f3bc42714250633cacadcde8b15da28bf443f0 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 9 Feb 2024 19:11:37 +0300 Subject: [PATCH 08/12] Update jobserver-rs to 0.1.28 --- Cargo.lock | 4 ++-- compiler/rustc_codegen_ssa/Cargo.toml | 2 +- compiler/rustc_data_structures/Cargo.toml | 2 +- compiler/rustc_data_structures/src/jobserver.rs | 5 ++++- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 29c8c7ef00404..9079d39c1edc4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2090,9 +2090,9 @@ dependencies = [ [[package]] name = "jobserver" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" dependencies = [ "libc", ] diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 7d2f5bb193a39..c4aaf421444ec 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -9,7 +9,7 @@ ar_archive_writer = "0.1.5" bitflags = "2.4.1" cc = "1.0.69" itertools = "0.11" -jobserver = "0.1.27" +jobserver = "0.1.28" pathdiff = "0.2.0" regex = "1.4" rustc_arena = { path = "../rustc_arena" } diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 08aa68ca54a7a..0635d8552ae55 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -11,7 +11,7 @@ either = "1.0" elsa = "=1.7.1" ena = "0.14.2" indexmap = { version = "2.0.0" } -jobserver_crate = { version = "0.1.27", package = "jobserver" } +jobserver_crate = { version = "0.1.28", package = "jobserver" } libc = "0.2" measureme = "11" rustc-hash = "1.1.0" diff --git a/compiler/rustc_data_structures/src/jobserver.rs b/compiler/rustc_data_structures/src/jobserver.rs index 412e33aaa6551..89088bc5c1b87 100644 --- a/compiler/rustc_data_structures/src/jobserver.rs +++ b/compiler/rustc_data_structures/src/jobserver.rs @@ -23,7 +23,10 @@ static GLOBAL_CLIENT: LazyLock> = LazyLock::new(|| { if matches!( error.kind(), - FromEnvErrorKind::NoEnvVar | FromEnvErrorKind::NoJobserver | FromEnvErrorKind::Unsupported + FromEnvErrorKind::NoEnvVar + | FromEnvErrorKind::NoJobserver + | FromEnvErrorKind::NegativeFd + | FromEnvErrorKind::Unsupported ) { return Ok(default_client()); } From 8b6b9c5efc6635a75bcd15899bc4314483c8e836 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 9 Feb 2024 19:52:41 +0300 Subject: [PATCH 09/12] ast_lowering: Fix regression in `use ::{}` imports. --- compiler/rustc_ast_lowering/src/item.rs | 7 ++++++- tests/ui/imports/empty-import-prefix-pass-2015.rs | 10 ++++++++++ tests/ui/imports/empty-import-prefix-pass.rs | 10 ++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 tests/ui/imports/empty-import-prefix-pass-2015.rs create mode 100644 tests/ui/imports/empty-import-prefix-pass.rs diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 75410323f97df..fb52f9cf58f26 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -569,7 +569,12 @@ impl<'hir> LoweringContext<'_, 'hir> { }); } - let path = if trees.is_empty() && !prefix.segments.is_empty() { + // Condition should match `build_reduced_graph_for_use_tree`. + let path = if trees.is_empty() + && !(prefix.segments.is_empty() + || prefix.segments.len() == 1 + && prefix.segments[0].ident.name == kw::PathRoot) + { // For empty lists we need to lower the prefix so it is checked for things // like stability later. let res = self.lower_import_res(id, span); diff --git a/tests/ui/imports/empty-import-prefix-pass-2015.rs b/tests/ui/imports/empty-import-prefix-pass-2015.rs new file mode 100644 index 0000000000000..a3278007c119a --- /dev/null +++ b/tests/ui/imports/empty-import-prefix-pass-2015.rs @@ -0,0 +1,10 @@ +// check-pass +// edition:2015 + +use {}; +use {{}}; + +use ::{}; +use {::{}}; + +fn main() {} diff --git a/tests/ui/imports/empty-import-prefix-pass.rs b/tests/ui/imports/empty-import-prefix-pass.rs new file mode 100644 index 0000000000000..d76c0da4bd8eb --- /dev/null +++ b/tests/ui/imports/empty-import-prefix-pass.rs @@ -0,0 +1,10 @@ +// check-pass +// edition:2018 + +use {}; +use {{}}; + +use ::{}; +use {::{}}; + +fn main() {} From e59d9b171ed276ede55765c63c75381b47549e07 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Fri, 9 Feb 2024 19:15:40 +0100 Subject: [PATCH 10/12] Avoid a collection and iteration on empty passes --- compiler/rustc_lint/src/late.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index caa015565914d..773baf2eaca96 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -364,14 +364,14 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>( // Note: `passes` is often empty. In that case, it's faster to run // `builtin_lints` directly rather than bundling it up into the // `RuntimeCombinedLateLintPass`. - let mut passes: Vec<_> = unerased_lint_store(tcx.sess) - .late_module_passes - .iter() - .map(|mk_pass| (mk_pass)(tcx)) - .collect(); - if passes.is_empty() { + let late_module_passes = &unerased_lint_store(tcx.sess).late_module_passes; + if late_module_passes.is_empty() { late_lint_mod_inner(tcx, module_def_id, context, builtin_lints); } else { + let mut passes: Vec<_> = late_module_passes + .iter() + .map(|mk_pass| (mk_pass)(tcx)) + .collect(); passes.push(Box::new(builtin_lints)); let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] }; late_lint_mod_inner(tcx, module_def_id, context, pass); From 4ef1790b4e593b02366f0eb5a0bfda6d825b2630 Mon Sep 17 00:00:00 2001 From: blyxyas Date: Fri, 9 Feb 2024 19:30:47 +0100 Subject: [PATCH 11/12] tidy --- compiler/rustc_lint/src/late.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index 773baf2eaca96..d3d7698e7f927 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -368,10 +368,7 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>( if late_module_passes.is_empty() { late_lint_mod_inner(tcx, module_def_id, context, builtin_lints); } else { - let mut passes: Vec<_> = late_module_passes - .iter() - .map(|mk_pass| (mk_pass)(tcx)) - .collect(); + let mut passes: Vec<_> = late_module_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect(); passes.push(Box::new(builtin_lints)); let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] }; late_lint_mod_inner(tcx, module_def_id, context, pass); From 69a5264a521f51ab3071da42e98cba476286a7d2 Mon Sep 17 00:00:00 2001 From: Caio Date: Fri, 9 Feb 2024 15:43:08 -0300 Subject: [PATCH 12/12] Move some tests --- src/tools/tidy/src/ui_tests.rs | 4 ++-- ...ssue-65634-raw-ident-suggestion.edition2015.stderr | 0 ...ssue-65634-raw-ident-suggestion.edition2018.stderr | 0 .../issue-65634-raw-ident-suggestion.rs | 0 tests/ui/{issues => binop}/issue-62375.rs | 0 tests/ui/{issues => binop}/issue-62375.stderr | 0 .../issue-82833-slice-miscompile.rs | 0 tests/ui/{issues => coercion}/issue-26905-rpass.rs | 0 tests/ui/{issues => coercion}/issue-26905.rs | 0 tests/ui/{issues => coercion}/issue-26905.stderr | 0 tests/ui/extern-mod-syntax.rs | 11 ----------- tests/ui/{issues => extern}/issue-16250.rs | 0 tests/ui/{issues => extern}/issue-16250.stderr | 0 tests/ui/{issues => extern}/issue-47725.rs | 0 tests/ui/{issues => extern}/issue-47725.stderr | 0 tests/ui/issues/issue-3878.rs | 9 --------- tests/ui/{ => macros}/auxiliary/hello_macro.rs | 0 tests/ui/{issues => macros}/issue-46438.rs | 0 tests/ui/{issues => macros}/issue-46438.stderr | 0 tests/ui/{ => macros}/macro-quote-test.rs | 0 tests/ui/{issues => pattern}/issue-28992-empty.rs | 0 tests/ui/{issues => pattern}/issue-28992-empty.stderr | 0 .../{issues => privacy}/auxiliary/private-trait-xc.rs | 0 tests/ui/{issues => privacy}/issue-11593.rs | 0 tests/ui/{issues => privacy}/issue-11593.stderr | 0 tests/ui/{issues => traits}/issue-33096.rs | 0 tests/ui/{issues => traits}/issue-40085.rs | 0 tests/ui/{issues => traits}/issue-58344.rs | 0 tests/ui/{issues => typeck}/issue-16338.rs | 0 tests/ui/{issues => typeck}/issue-16338.stderr | 0 30 files changed, 2 insertions(+), 22 deletions(-) rename tests/ui/{issues => async-await}/issue-65634-raw-ident-suggestion.edition2015.stderr (100%) rename tests/ui/{issues => async-await}/issue-65634-raw-ident-suggestion.edition2018.stderr (100%) rename tests/ui/{issues => async-await}/issue-65634-raw-ident-suggestion.rs (100%) rename tests/ui/{issues => binop}/issue-62375.rs (100%) rename tests/ui/{issues => binop}/issue-62375.stderr (100%) rename tests/ui/{issues => codegen}/issue-82833-slice-miscompile.rs (100%) rename tests/ui/{issues => coercion}/issue-26905-rpass.rs (100%) rename tests/ui/{issues => coercion}/issue-26905.rs (100%) rename tests/ui/{issues => coercion}/issue-26905.stderr (100%) delete mode 100644 tests/ui/extern-mod-syntax.rs rename tests/ui/{issues => extern}/issue-16250.rs (100%) rename tests/ui/{issues => extern}/issue-16250.stderr (100%) rename tests/ui/{issues => extern}/issue-47725.rs (100%) rename tests/ui/{issues => extern}/issue-47725.stderr (100%) delete mode 100644 tests/ui/issues/issue-3878.rs rename tests/ui/{ => macros}/auxiliary/hello_macro.rs (100%) rename tests/ui/{issues => macros}/issue-46438.rs (100%) rename tests/ui/{issues => macros}/issue-46438.stderr (100%) rename tests/ui/{ => macros}/macro-quote-test.rs (100%) rename tests/ui/{issues => pattern}/issue-28992-empty.rs (100%) rename tests/ui/{issues => pattern}/issue-28992-empty.stderr (100%) rename tests/ui/{issues => privacy}/auxiliary/private-trait-xc.rs (100%) rename tests/ui/{issues => privacy}/issue-11593.rs (100%) rename tests/ui/{issues => privacy}/issue-11593.stderr (100%) rename tests/ui/{issues => traits}/issue-33096.rs (100%) rename tests/ui/{issues => traits}/issue-40085.rs (100%) rename tests/ui/{issues => traits}/issue-58344.rs (100%) rename tests/ui/{issues => typeck}/issue-16338.rs (100%) rename tests/ui/{issues => typeck}/issue-16338.stderr (100%) diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index d5df05bacd93f..03f8a701627d3 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -14,8 +14,8 @@ use std::path::{Path, PathBuf}; // #73494. const ENTRY_LIMIT: usize = 900; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: usize = 1819; -const ROOT_ENTRY_LIMIT: usize = 872; +const ISSUES_ENTRY_LIMIT: usize = 1794; +const ROOT_ENTRY_LIMIT: usize = 870; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/ui/issues/issue-65634-raw-ident-suggestion.edition2015.stderr b/tests/ui/async-await/issue-65634-raw-ident-suggestion.edition2015.stderr similarity index 100% rename from tests/ui/issues/issue-65634-raw-ident-suggestion.edition2015.stderr rename to tests/ui/async-await/issue-65634-raw-ident-suggestion.edition2015.stderr diff --git a/tests/ui/issues/issue-65634-raw-ident-suggestion.edition2018.stderr b/tests/ui/async-await/issue-65634-raw-ident-suggestion.edition2018.stderr similarity index 100% rename from tests/ui/issues/issue-65634-raw-ident-suggestion.edition2018.stderr rename to tests/ui/async-await/issue-65634-raw-ident-suggestion.edition2018.stderr diff --git a/tests/ui/issues/issue-65634-raw-ident-suggestion.rs b/tests/ui/async-await/issue-65634-raw-ident-suggestion.rs similarity index 100% rename from tests/ui/issues/issue-65634-raw-ident-suggestion.rs rename to tests/ui/async-await/issue-65634-raw-ident-suggestion.rs diff --git a/tests/ui/issues/issue-62375.rs b/tests/ui/binop/issue-62375.rs similarity index 100% rename from tests/ui/issues/issue-62375.rs rename to tests/ui/binop/issue-62375.rs diff --git a/tests/ui/issues/issue-62375.stderr b/tests/ui/binop/issue-62375.stderr similarity index 100% rename from tests/ui/issues/issue-62375.stderr rename to tests/ui/binop/issue-62375.stderr diff --git a/tests/ui/issues/issue-82833-slice-miscompile.rs b/tests/ui/codegen/issue-82833-slice-miscompile.rs similarity index 100% rename from tests/ui/issues/issue-82833-slice-miscompile.rs rename to tests/ui/codegen/issue-82833-slice-miscompile.rs diff --git a/tests/ui/issues/issue-26905-rpass.rs b/tests/ui/coercion/issue-26905-rpass.rs similarity index 100% rename from tests/ui/issues/issue-26905-rpass.rs rename to tests/ui/coercion/issue-26905-rpass.rs diff --git a/tests/ui/issues/issue-26905.rs b/tests/ui/coercion/issue-26905.rs similarity index 100% rename from tests/ui/issues/issue-26905.rs rename to tests/ui/coercion/issue-26905.rs diff --git a/tests/ui/issues/issue-26905.stderr b/tests/ui/coercion/issue-26905.stderr similarity index 100% rename from tests/ui/issues/issue-26905.stderr rename to tests/ui/coercion/issue-26905.stderr diff --git a/tests/ui/extern-mod-syntax.rs b/tests/ui/extern-mod-syntax.rs deleted file mode 100644 index 65dfa6a0f5790..0000000000000 --- a/tests/ui/extern-mod-syntax.rs +++ /dev/null @@ -1,11 +0,0 @@ -// run-pass - -#![allow(unused_imports)] -#![no_std] - -extern crate std; -use std::ffi::c_void; - -pub fn main() { - std::println!("Hello world!"); -} diff --git a/tests/ui/issues/issue-16250.rs b/tests/ui/extern/issue-16250.rs similarity index 100% rename from tests/ui/issues/issue-16250.rs rename to tests/ui/extern/issue-16250.rs diff --git a/tests/ui/issues/issue-16250.stderr b/tests/ui/extern/issue-16250.stderr similarity index 100% rename from tests/ui/issues/issue-16250.stderr rename to tests/ui/extern/issue-16250.stderr diff --git a/tests/ui/issues/issue-47725.rs b/tests/ui/extern/issue-47725.rs similarity index 100% rename from tests/ui/issues/issue-47725.rs rename to tests/ui/extern/issue-47725.rs diff --git a/tests/ui/issues/issue-47725.stderr b/tests/ui/extern/issue-47725.stderr similarity index 100% rename from tests/ui/issues/issue-47725.stderr rename to tests/ui/extern/issue-47725.stderr diff --git a/tests/ui/issues/issue-3878.rs b/tests/ui/issues/issue-3878.rs deleted file mode 100644 index 6de3405af0d95..0000000000000 --- a/tests/ui/issues/issue-3878.rs +++ /dev/null @@ -1,9 +0,0 @@ -// run-pass -// pretty-expanded FIXME #23616 - -#![allow(path_statements)] - -pub fn main() { - let y: Box<_> = Box::new(1); - y; -} diff --git a/tests/ui/auxiliary/hello_macro.rs b/tests/ui/macros/auxiliary/hello_macro.rs similarity index 100% rename from tests/ui/auxiliary/hello_macro.rs rename to tests/ui/macros/auxiliary/hello_macro.rs diff --git a/tests/ui/issues/issue-46438.rs b/tests/ui/macros/issue-46438.rs similarity index 100% rename from tests/ui/issues/issue-46438.rs rename to tests/ui/macros/issue-46438.rs diff --git a/tests/ui/issues/issue-46438.stderr b/tests/ui/macros/issue-46438.stderr similarity index 100% rename from tests/ui/issues/issue-46438.stderr rename to tests/ui/macros/issue-46438.stderr diff --git a/tests/ui/macro-quote-test.rs b/tests/ui/macros/macro-quote-test.rs similarity index 100% rename from tests/ui/macro-quote-test.rs rename to tests/ui/macros/macro-quote-test.rs diff --git a/tests/ui/issues/issue-28992-empty.rs b/tests/ui/pattern/issue-28992-empty.rs similarity index 100% rename from tests/ui/issues/issue-28992-empty.rs rename to tests/ui/pattern/issue-28992-empty.rs diff --git a/tests/ui/issues/issue-28992-empty.stderr b/tests/ui/pattern/issue-28992-empty.stderr similarity index 100% rename from tests/ui/issues/issue-28992-empty.stderr rename to tests/ui/pattern/issue-28992-empty.stderr diff --git a/tests/ui/issues/auxiliary/private-trait-xc.rs b/tests/ui/privacy/auxiliary/private-trait-xc.rs similarity index 100% rename from tests/ui/issues/auxiliary/private-trait-xc.rs rename to tests/ui/privacy/auxiliary/private-trait-xc.rs diff --git a/tests/ui/issues/issue-11593.rs b/tests/ui/privacy/issue-11593.rs similarity index 100% rename from tests/ui/issues/issue-11593.rs rename to tests/ui/privacy/issue-11593.rs diff --git a/tests/ui/issues/issue-11593.stderr b/tests/ui/privacy/issue-11593.stderr similarity index 100% rename from tests/ui/issues/issue-11593.stderr rename to tests/ui/privacy/issue-11593.stderr diff --git a/tests/ui/issues/issue-33096.rs b/tests/ui/traits/issue-33096.rs similarity index 100% rename from tests/ui/issues/issue-33096.rs rename to tests/ui/traits/issue-33096.rs diff --git a/tests/ui/issues/issue-40085.rs b/tests/ui/traits/issue-40085.rs similarity index 100% rename from tests/ui/issues/issue-40085.rs rename to tests/ui/traits/issue-40085.rs diff --git a/tests/ui/issues/issue-58344.rs b/tests/ui/traits/issue-58344.rs similarity index 100% rename from tests/ui/issues/issue-58344.rs rename to tests/ui/traits/issue-58344.rs diff --git a/tests/ui/issues/issue-16338.rs b/tests/ui/typeck/issue-16338.rs similarity index 100% rename from tests/ui/issues/issue-16338.rs rename to tests/ui/typeck/issue-16338.rs diff --git a/tests/ui/issues/issue-16338.stderr b/tests/ui/typeck/issue-16338.stderr similarity index 100% rename from tests/ui/issues/issue-16338.stderr rename to tests/ui/typeck/issue-16338.stderr