Skip to content

Commit b5c46dc

Browse files
committed
Auto merge of rust-lang#120862 - matthiaskrgr:rollup-jzfab58, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - rust-lang#120584 (For a rigid projection, recursively look at the self type's item bounds to fix the `associated_type_bounds` feature) - rust-lang#120596 ([rustdoc] Correctly generate path for non-local items in source code pages) - rust-lang#120629 (Move some test files) - rust-lang#120846 (Update jobserver-rs to 0.1.28) - rust-lang#120850 (ast_lowering: Fix regression in `use ::{}` imports.) - rust-lang#120853 (Avoid a collection and iteration on empty passes) r? `@ghost` `@rustbot` modify labels: rollup
2 parents d44e3b9 + 8e1eadd commit b5c46dc

File tree

68 files changed

+565
-524
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+565
-524
lines changed

Cargo.lock

+2-2
Original file line numberDiff line numberDiff line change
@@ -2090,9 +2090,9 @@ dependencies = [
20902090

20912091
[[package]]
20922092
name = "jobserver"
2093-
version = "0.1.27"
2093+
version = "0.1.28"
20942094
source = "registry+https://github.com/rust-lang/crates.io-index"
2095-
checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d"
2095+
checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6"
20962096
dependencies = [
20972097
"libc",
20982098
]

compiler/rustc_ast_lowering/src/item.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
569569
});
570570
}
571571

572-
let path = if trees.is_empty() && !prefix.segments.is_empty() {
572+
// Condition should match `build_reduced_graph_for_use_tree`.
573+
let path = if trees.is_empty()
574+
&& !(prefix.segments.is_empty()
575+
|| prefix.segments.len() == 1
576+
&& prefix.segments[0].ident.name == kw::PathRoot)
577+
{
573578
// For empty lists we need to lower the prefix so it is checked for things
574579
// like stability later.
575580
let res = self.lower_import_res(id, span);

compiler/rustc_ast_lowering/src/lib.rs

+11-13
Original file line numberDiff line numberDiff line change
@@ -1092,24 +1092,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
10921092

10931093
// Piggy-back on the `impl Trait` context to figure out the correct behavior.
10941094
let desugar_kind = match itctx {
1095-
// We are in the return position:
1096-
//
1097-
// fn foo() -> impl Iterator<Item: Debug>
1098-
//
1099-
// so desugar to
1100-
//
1101-
// fn foo() -> impl Iterator<Item = impl Debug>
1102-
ImplTraitContext::ReturnPositionOpaqueTy { .. }
1103-
| ImplTraitContext::TypeAliasesOpaqueTy { .. } => DesugarKind::ImplTrait,
1104-
1105-
// We are in the argument position, but within a dyn type:
1095+
// in an argument, RPIT, or TAIT, if we are within a dyn type:
11061096
//
11071097
// fn foo(x: dyn Iterator<Item: Debug>)
11081098
//
1109-
// so desugar to
1099+
// then desugar to:
11101100
//
11111101
// fn foo(x: dyn Iterator<Item = impl Debug>)
1112-
ImplTraitContext::Universal if self.is_in_dyn_type => DesugarKind::ImplTrait,
1102+
//
1103+
// This is because dyn traits must have all of their associated types specified.
1104+
ImplTraitContext::ReturnPositionOpaqueTy { .. }
1105+
| ImplTraitContext::TypeAliasesOpaqueTy { .. }
1106+
| ImplTraitContext::Universal
1107+
if self.is_in_dyn_type =>
1108+
{
1109+
DesugarKind::ImplTrait
1110+
}
11131111

11141112
ImplTraitContext::Disallowed(position) if self.is_in_dyn_type => {
11151113
DesugarKind::Error(position)

compiler/rustc_codegen_ssa/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ ar_archive_writer = "0.1.5"
99
bitflags = "2.4.1"
1010
cc = "1.0.69"
1111
itertools = "0.11"
12-
jobserver = "0.1.27"
12+
jobserver = "0.1.28"
1313
pathdiff = "0.2.0"
1414
regex = "1.4"
1515
rustc_arena = { path = "../rustc_arena" }

compiler/rustc_data_structures/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ either = "1.0"
1111
elsa = "=1.7.1"
1212
ena = "0.14.2"
1313
indexmap = { version = "2.0.0" }
14-
jobserver_crate = { version = "0.1.27", package = "jobserver" }
14+
jobserver_crate = { version = "0.1.28", package = "jobserver" }
1515
libc = "0.2"
1616
measureme = "11"
1717
rustc-hash = "1.1.0"

compiler/rustc_data_structures/src/jobserver.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ static GLOBAL_CLIENT: LazyLock<Result<Client, String>> = LazyLock::new(|| {
2323

2424
if matches!(
2525
error.kind(),
26-
FromEnvErrorKind::NoEnvVar | FromEnvErrorKind::NoJobserver | FromEnvErrorKind::Unsupported
26+
FromEnvErrorKind::NoEnvVar
27+
| FromEnvErrorKind::NoJobserver
28+
| FromEnvErrorKind::NegativeFd
29+
| FromEnvErrorKind::Unsupported
2730
) {
2831
return Ok(default_client());
2932
}

compiler/rustc_lint/src/late.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -364,14 +364,11 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>(
364364
// Note: `passes` is often empty. In that case, it's faster to run
365365
// `builtin_lints` directly rather than bundling it up into the
366366
// `RuntimeCombinedLateLintPass`.
367-
let mut passes: Vec<_> = unerased_lint_store(tcx.sess)
368-
.late_module_passes
369-
.iter()
370-
.map(|mk_pass| (mk_pass)(tcx))
371-
.collect();
372-
if passes.is_empty() {
367+
let late_module_passes = &unerased_lint_store(tcx.sess).late_module_passes;
368+
if late_module_passes.is_empty() {
373369
late_lint_mod_inner(tcx, module_def_id, context, builtin_lints);
374370
} else {
371+
let mut passes: Vec<_> = late_module_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect();
375372
passes.push(Box::new(builtin_lints));
376373
let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] };
377374
late_lint_mod_inner(tcx, module_def_id, context, pass);

compiler/rustc_trait_selection/src/solve/assembly/mod.rs

+62-9
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,27 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
548548
goal: Goal<'tcx, G>,
549549
candidates: &mut Vec<Candidate<'tcx>>,
550550
) {
551-
let alias_ty = match goal.predicate.self_ty().kind() {
551+
let () = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| {
552+
ecx.assemble_alias_bound_candidates_recur(goal.predicate.self_ty(), goal, candidates);
553+
});
554+
}
555+
556+
/// For some deeply nested `<T>::A::B::C::D` rigid associated type,
557+
/// we should explore the item bounds for all levels, since the
558+
/// `associated_type_bounds` feature means that a parent associated
559+
/// type may carry bounds for a nested associated type.
560+
///
561+
/// If we have a projection, check that its self type is a rigid projection.
562+
/// If so, continue searching by recursively calling after normalization.
563+
// FIXME: This may recurse infinitely, but I can't seem to trigger it without
564+
// hitting another overflow error something. Add a depth parameter needed later.
565+
fn assemble_alias_bound_candidates_recur<G: GoalKind<'tcx>>(
566+
&mut self,
567+
self_ty: Ty<'tcx>,
568+
goal: Goal<'tcx, G>,
569+
candidates: &mut Vec<Candidate<'tcx>>,
570+
) {
571+
let (kind, alias_ty) = match *self_ty.kind() {
552572
ty::Bool
553573
| ty::Char
554574
| ty::Int(_)
@@ -573,23 +593,56 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
573593
| ty::Param(_)
574594
| ty::Placeholder(..)
575595
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
576-
| ty::Alias(ty::Inherent, _)
577-
| ty::Alias(ty::Weak, _)
578596
| ty::Error(_) => return,
579-
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
580-
| ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"),
581-
// Excluding IATs and type aliases here as they don't have meaningful item bounds.
582-
ty::Alias(ty::Projection | ty::Opaque, alias_ty) => alias_ty,
597+
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | ty::Bound(..) => {
598+
bug!("unexpected self type for `{goal:?}`")
599+
}
600+
601+
ty::Infer(ty::TyVar(_)) => {
602+
// If we hit infer when normalizing the self type of an alias,
603+
// then bail with ambiguity. We should never encounter this on
604+
// the *first* iteration of this recursive function.
605+
if let Ok(result) =
606+
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
607+
{
608+
candidates.push(Candidate { source: CandidateSource::AliasBound, result });
609+
}
610+
return;
611+
}
612+
613+
ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty),
614+
ty::Alias(ty::Inherent | ty::Weak, _) => {
615+
unreachable!("Weak and Inherent aliases should have been normalized away already")
616+
}
583617
};
584618

585619
for assumption in
586620
self.tcx().item_bounds(alias_ty.def_id).instantiate(self.tcx(), alias_ty.args)
587621
{
588622
match G::consider_alias_bound_candidate(self, goal, assumption) {
589623
Ok(result) => {
590-
candidates.push(Candidate { source: CandidateSource::AliasBound, result })
624+
candidates.push(Candidate { source: CandidateSource::AliasBound, result });
625+
}
626+
Err(NoSolution) => {}
627+
}
628+
}
629+
630+
if kind != ty::Projection {
631+
return;
632+
}
633+
634+
match self.try_normalize_ty(goal.param_env, alias_ty.self_ty()) {
635+
// Recurse on the self type of the projection.
636+
Some(next_self_ty) => {
637+
self.assemble_alias_bound_candidates_recur(next_self_ty, goal, candidates);
638+
}
639+
// Bail if we overflow when normalizing, adding an ambiguous candidate.
640+
None => {
641+
if let Ok(result) =
642+
self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW)
643+
{
644+
candidates.push(Candidate { source: CandidateSource::AliasBound, result });
591645
}
592-
Err(NoSolution) => (),
593646
}
594647
}
595648
}

compiler/rustc_trait_selection/src/traits/project.rs

+36-23
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt};
4040
use rustc_span::symbol::sym;
4141

4242
use std::collections::BTreeMap;
43+
use std::ops::ControlFlow;
4344

4445
pub use rustc_middle::traits::Reveal;
4546

@@ -1614,32 +1615,44 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
16141615
candidate_set: &mut ProjectionCandidateSet<'tcx>,
16151616
) {
16161617
debug!("assemble_candidates_from_trait_def(..)");
1618+
let mut ambiguous = false;
1619+
selcx.for_each_item_bound(
1620+
obligation.predicate.self_ty(),
1621+
|selcx, clause, _| {
1622+
let Some(clause) = clause.as_projection_clause() else {
1623+
return ControlFlow::Continue(());
1624+
};
16171625

1618-
let tcx = selcx.tcx();
1619-
// Check whether the self-type is itself a projection.
1620-
// If so, extract what we know from the trait and try to come up with a good answer.
1621-
let bounds = match *obligation.predicate.self_ty().kind() {
1622-
// Excluding IATs and type aliases here as they don't have meaningful item bounds.
1623-
ty::Alias(ty::Projection | ty::Opaque, ref data) => {
1624-
tcx.item_bounds(data.def_id).instantiate(tcx, data.args)
1625-
}
1626-
ty::Infer(ty::TyVar(_)) => {
1627-
// If the self-type is an inference variable, then it MAY wind up
1628-
// being a projected type, so induce an ambiguity.
1629-
candidate_set.mark_ambiguous();
1630-
return;
1631-
}
1632-
_ => return,
1633-
};
1626+
let is_match =
1627+
selcx.infcx.probe(|_| selcx.match_projection_projections(obligation, clause, true));
16341628

1635-
assemble_candidates_from_predicates(
1636-
selcx,
1637-
obligation,
1638-
candidate_set,
1639-
ProjectionCandidate::TraitDef,
1640-
bounds.iter(),
1641-
true,
1629+
match is_match {
1630+
ProjectionMatchesProjection::Yes => {
1631+
candidate_set.push_candidate(ProjectionCandidate::TraitDef(clause));
1632+
1633+
if !obligation.predicate.has_non_region_infer() {
1634+
// HACK: Pick the first trait def candidate for a fully
1635+
// inferred predicate. This is to allow duplicates that
1636+
// differ only in normalization.
1637+
return ControlFlow::Break(());
1638+
}
1639+
}
1640+
ProjectionMatchesProjection::Ambiguous => {
1641+
candidate_set.mark_ambiguous();
1642+
}
1643+
ProjectionMatchesProjection::No => {}
1644+
}
1645+
1646+
ControlFlow::Continue(())
1647+
},
1648+
// `ProjectionCandidateSet` is borrowed in the above closure,
1649+
// so just mark ambiguous outside of the closure.
1650+
|| ambiguous = true,
16421651
);
1652+
1653+
if ambiguous {
1654+
candidate_set.mark_ambiguous();
1655+
}
16431656
}
16441657

16451658
/// In the case of a trait object like

compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

+47-5
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,16 @@
66
//!
77
//! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly
88
9+
use std::ops::ControlFlow;
10+
911
use hir::def_id::DefId;
1012
use hir::LangItem;
13+
use rustc_data_structures::fx::FxHashSet;
1114
use rustc_hir as hir;
1215
use rustc_infer::traits::ObligationCause;
1316
use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError};
1417
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
15-
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
18+
use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt};
1619

1720
use crate::traits;
1821
use crate::traits::query::evaluate_obligation::InferCtxtExt;
@@ -158,11 +161,50 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
158161
_ => return,
159162
}
160163

161-
let result = self
162-
.infcx
163-
.probe(|_| self.match_projection_obligation_against_definition_bounds(obligation));
164+
self.infcx.probe(|_| {
165+
let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate);
166+
let placeholder_trait_predicate =
167+
self.infcx.enter_forall_and_leak_universe(poly_trait_predicate);
168+
debug!(?placeholder_trait_predicate);
169+
170+
// The bounds returned by `item_bounds` may contain duplicates after
171+
// normalization, so try to deduplicate when possible to avoid
172+
// unnecessary ambiguity.
173+
let mut distinct_normalized_bounds = FxHashSet::default();
174+
self.for_each_item_bound::<!>(
175+
placeholder_trait_predicate.self_ty(),
176+
|selcx, bound, idx| {
177+
let Some(bound) = bound.as_trait_clause() else {
178+
return ControlFlow::Continue(());
179+
};
180+
if bound.polarity() != placeholder_trait_predicate.polarity {
181+
return ControlFlow::Continue(());
182+
}
164183

165-
candidates.vec.extend(result.into_iter().map(|idx| ProjectionCandidate(idx)));
184+
selcx.infcx.probe(|_| {
185+
match selcx.match_normalize_trait_ref(
186+
obligation,
187+
bound.to_poly_trait_ref(),
188+
placeholder_trait_predicate.trait_ref,
189+
) {
190+
Ok(None) => {
191+
candidates.vec.push(ProjectionCandidate(idx));
192+
}
193+
Ok(Some(normalized_trait))
194+
if distinct_normalized_bounds.insert(normalized_trait) =>
195+
{
196+
candidates.vec.push(ProjectionCandidate(idx));
197+
}
198+
_ => {}
199+
}
200+
});
201+
202+
ControlFlow::Continue(())
203+
},
204+
// On ambiguity.
205+
|| candidates.ambiguous = true,
206+
);
207+
});
166208
}
167209

168210
/// Given an obligation like `<SomeTrait for T>`, searches the obligations that the caller

0 commit comments

Comments
 (0)