Skip to content

Commit

Permalink
Auto merge of rust-lang#120861 - matthiaskrgr:rollup-pkbbh0r, r=matth…
Browse files Browse the repository at this point in the history
…iaskrgr

Rollup of 7 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#120589 (std::thread::available_parallelism merging linux/android/freebsd version)
 - 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)

Failed merges:

 - rust-lang#120549 (modify alias-relate to also normalize ambiguous opaques)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Feb 9, 2024
2 parents d44e3b9 + 0b6980b commit 036b1d1
Show file tree
Hide file tree
Showing 69 changed files with 576 additions and 546 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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",
]
Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
24 changes: 11 additions & 13 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1092,24 +1092,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<Item: Debug>
//
// so desugar to
//
// fn foo() -> impl Iterator<Item = impl Debug>
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<Item: Debug>)
//
// so desugar to
// then desugar to:
//
// fn foo(x: dyn Iterator<Item = impl Debug>)
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)
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_data_structures/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_data_structures/src/jobserver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ static GLOBAL_CLIENT: LazyLock<Result<Client, String>> = LazyLock::new(|| {

if matches!(
error.kind(),
FromEnvErrorKind::NoEnvVar | FromEnvErrorKind::NoJobserver | FromEnvErrorKind::Unsupported
FromEnvErrorKind::NoEnvVar
| FromEnvErrorKind::NoJobserver
| FromEnvErrorKind::NegativeFd
| FromEnvErrorKind::Unsupported
) {
return Ok(default_client());
}
Expand Down
9 changes: 3 additions & 6 deletions compiler/rustc_lint/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,14 +364,11 @@ 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);
Expand Down
71 changes: 62 additions & 9 deletions compiler/rustc_trait_selection/src/solve/assembly/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,27 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
goal: Goal<'tcx, G>,
candidates: &mut Vec<Candidate<'tcx>>,
) {
let alias_ty = match goal.predicate.self_ty().kind() {
let () = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| {
ecx.assemble_alias_bound_candidates_recur(goal.predicate.self_ty(), goal, candidates);
});
}

/// For some deeply nested `<T>::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<G: GoalKind<'tcx>>(
&mut self,
self_ty: Ty<'tcx>,
goal: Goal<'tcx, G>,
candidates: &mut Vec<Candidate<'tcx>>,
) {
let (kind, alias_ty) = match *self_ty.kind() {
ty::Bool
| ty::Char
| ty::Int(_)
Expand All @@ -573,23 +593,56 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
| 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,
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | ty::Bound(..) => {
bug!("unexpected self type for `{goal:?}`")
}

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)
{
candidates.push(Candidate { source: CandidateSource::AliasBound, result });
}
return;
}

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 })
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 });
}
Err(NoSolution) => (),
}
}
}
Expand Down
59 changes: 36 additions & 23 deletions compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -1614,32 +1615,44 @@ 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -158,11 +161,50 @@ 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(());
}

candidates.vec.extend(result.into_iter().map(|idx| ProjectionCandidate(idx)));
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));
}
_ => {}
}
});

ControlFlow::Continue(())
},
// On ambiguity.
|| candidates.ambiguous = true,
);
});
}

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

0 comments on commit 036b1d1

Please sign in to comment.