Skip to content

Rollup of 9 pull requests #139975

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
96984c0
add retry support to recursive_remove
Shourya742 Apr 15, 2025
003d633
add remove_and_create_dir_all in build_helper
Shourya742 Apr 15, 2025
d4eab8a
remove old remove_and_create_dir_all and use build_helpers remove_and…
Shourya742 Apr 15, 2025
b4b9cfb
Upgrade to `rustc-rayon-core` 0.5.1
cuviper Apr 16, 2025
3863018
Fix replacing supertrait aliases in ReplaceProjectionWith
compiler-errors Apr 16, 2025
e1936d2
Remove FIXME that is no longer relevant
compiler-errors Apr 14, 2025
9f548e2
Support inlined cross-crate re-exported trait aliases
fmease Apr 17, 2025
bf26963
bootstrap: enable zlib for LLVM when we compile it for profiling
ognevny Apr 17, 2025
62a104d
opt-dist: add a flag for running tests
ognevny Apr 17, 2025
289a23e
do not emit `OpaqueCast` projections with `-Znext-solver`
lcnr Apr 16, 2025
c85b5fc
check OpaqueCast tests with next-solver
lcnr Apr 17, 2025
857fe8f
Add tests for two untested cases of placeholder relations
amandasystems Apr 17, 2025
8562110
Hide unstable print kinds within emit_unknown_print_request_help in s…
xizheyin Apr 15, 2025
1965703
Rollup merge of #139774 - compiler-errors:supertrait-alias, r=lcnr
matthiaskrgr Apr 17, 2025
76c06b6
Rollup merge of #139850 - xizheyin:issue-138698, r=jieyouxu
matthiaskrgr Apr 17, 2025
db4e287
Rollup merge of #139870 - Shourya742:2025-04-15-add-retries-to-remove…
matthiaskrgr Apr 17, 2025
510d3bb
Rollup merge of #139902 - lcnr:no-opaque-cast-projection, r=oli-obk
matthiaskrgr Apr 17, 2025
d19a3c1
Rollup merge of #139931 - ognevny:bootstrap-llvm-zlib, r=Kobzol
matthiaskrgr Apr 17, 2025
d31489d
Rollup merge of #139935 - cuviper:rustc-rayon-core-0.5.1, r=lqd
matthiaskrgr Apr 17, 2025
54ea2d7
Rollup merge of #139943 - fmease:rustdoc-ixcre-trait-aliases, r=Guill…
matthiaskrgr Apr 17, 2025
36ac684
Rollup merge of #139960 - amandasystems:placeholder-ui-tests, r=lcnr
matthiaskrgr Apr 17, 2025
03c4a71
Rollup merge of #139962 - ognevny:opt-dist-tests, r=Kobzol
matthiaskrgr Apr 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3199,14 +3199,12 @@ dependencies = [

[[package]]
name = "rustc-rayon-core"
version = "0.5.0"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67668daaf00e359c126f6dcb40d652d89b458a008c8afa727a42a2d20fca0b7f"
checksum = "2f42932dcd3bcbe484b38a3ccf79b7906fac41c02d408b5b1bac26da3416efdb"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"num_cpus",
]

[[package]]
Expand Down
25 changes: 15 additions & 10 deletions compiler/rustc_hir_typeck/src/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1502,16 +1502,21 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
let mut projections = base_place.place.projections;

let node_ty = self.cx.typeck_results().node_type(node);
// Opaque types can't have field projections, but we can instead convert
// the current place in-place (heh) to the hidden type, and then apply all
// follow up projections on that.
if node_ty != place_ty
&& self
.cx
.try_structurally_resolve_type(self.cx.tcx().hir_span(base_place.hir_id), place_ty)
.is_impl_trait()
{
projections.push(Projection { kind: ProjectionKind::OpaqueCast, ty: node_ty });
if !self.cx.tcx().next_trait_solver_globally() {
// Opaque types can't have field projections, but we can instead convert
// the current place in-place (heh) to the hidden type, and then apply all
// follow up projections on that.
if node_ty != place_ty
&& self
.cx
.try_structurally_resolve_type(
self.cx.tcx().hir_span(base_place.hir_id),
place_ty,
)
.is_impl_trait()
{
projections.push(Projection { kind: ProjectionKind::OpaqueCast, ty: node_ty });
}
}
projections.push(Projection { kind, ty });
PlaceWithHirId::new(node, base_place.place.base_ty, base_place.place.base, projections)
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_middle/src/hir/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ pub enum ProjectionKind {

/// A conversion from an opaque type to its hidden type so we can
/// do further projections on it.
///
/// This is unused if `-Znext-solver` is enabled.
OpaqueCast,
}

Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_middle/src/mir/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1242,6 +1242,8 @@ pub enum ProjectionElem<V, T> {

/// Like an explicit cast from an opaque type to a concrete type, but without
/// requiring an intermediate variable.
///
/// This is unused with `-Znext-solver`.
OpaqueCast(T),

/// A transmute from an unsafe binder to the type that it wraps. This is a projection
Expand Down
25 changes: 14 additions & 11 deletions compiler/rustc_mir_build/src/builder/matches/match_pair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,18 +101,21 @@ impl<'tcx> MatchPairTree<'tcx> {
place_builder = resolved;
}

// Only add the OpaqueCast projection if the given place is an opaque type and the
// expected type from the pattern is not.
let may_need_cast = match place_builder.base() {
PlaceBase::Local(local) => {
let ty =
Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx).ty;
ty != pattern.ty && ty.has_opaque_types()
if !cx.tcx.next_trait_solver_globally() {
// Only add the OpaqueCast projection if the given place is an opaque type and the
// expected type from the pattern is not.
let may_need_cast = match place_builder.base() {
PlaceBase::Local(local) => {
let ty =
Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx)
.ty;
ty != pattern.ty && ty.has_opaque_types()
}
_ => true,
};
if may_need_cast {
place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty));
}
_ => true,
};
if may_need_cast {
place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty));
}

let place = place_builder.try_to_place(cx);
Expand Down
28 changes: 15 additions & 13 deletions compiler/rustc_mir_transform/src/post_analysis_normalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,22 @@ impl<'tcx> MutVisitor<'tcx> for PostAnalysisNormalizeVisitor<'tcx> {
_context: PlaceContext,
_location: Location,
) {
// Performance optimization: don't reintern if there is no `OpaqueCast` to remove.
if place.projection.iter().all(|elem| !matches!(elem, ProjectionElem::OpaqueCast(_))) {
return;
if !self.tcx.next_trait_solver_globally() {
// `OpaqueCast` projections are only needed if there are opaque types on which projections
// are performed. After the `PostAnalysisNormalize` pass, all opaque types are replaced with their
// hidden types, so we don't need these projections anymore.
//
// Performance optimization: don't reintern if there is no `OpaqueCast` to remove.
if place.projection.iter().any(|elem| matches!(elem, ProjectionElem::OpaqueCast(_))) {
place.projection = self.tcx.mk_place_elems(
&place
.projection
.into_iter()
.filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(_)))
.collect::<Vec<_>>(),
);
};
}
// `OpaqueCast` projections are only needed if there are opaque types on which projections
// are performed. After the `PostAnalysisNormalize` pass, all opaque types are replaced with their
// hidden types, so we don't need these projections anymore.
place.projection = self.tcx.mk_place_elems(
&place
.projection
.into_iter()
.filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(_)))
.collect::<Vec<_>>(),
);
self.super_place(place, _context, _location);
}

Expand Down
24 changes: 14 additions & 10 deletions compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,16 +92,20 @@ where
let ty::Dynamic(bounds, _, _) = goal.predicate.self_ty().kind() else {
panic!("expected object type in `probe_and_consider_object_bound_candidate`");
};
ecx.add_goals(
GoalSource::ImplWhereBound,
structural_traits::predicates_for_object_candidate(
ecx,
goal.param_env,
goal.predicate.trait_ref(cx),
bounds,
),
);
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
match structural_traits::predicates_for_object_candidate(
ecx,
goal.param_env,
goal.predicate.trait_ref(cx),
bounds,
) {
Ok(requirements) => {
ecx.add_goals(GoalSource::ImplWhereBound, requirements);
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
Err(_) => {
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
}
}
})
}

Expand Down
163 changes: 108 additions & 55 deletions compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ use derive_where::derive_where;
use rustc_type_ir::data_structures::HashMap;
use rustc_type_ir::inherent::*;
use rustc_type_ir::lang_items::TraitSolverLangItem;
use rustc_type_ir::solve::inspect::ProbeKind;
use rustc_type_ir::{
self as ty, Interner, Movability, Mutability, TypeFoldable, TypeFolder, TypeSuperFoldable,
Upcast as _, elaborate,
self as ty, FallibleTypeFolder, Interner, Movability, Mutability, TypeFoldable,
TypeSuperFoldable, Upcast as _, elaborate,
};
use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
use tracing::instrument;
Expand Down Expand Up @@ -822,22 +823,16 @@ pub(in crate::solve) fn const_conditions_for_destruct<I: Interner>(
/// impl Baz for dyn Foo<Item = Ty> {}
/// ```
///
/// However, in order to make such impls well-formed, we need to do an
/// However, in order to make such impls non-cyclical, we need to do an
/// additional step of eagerly folding the associated types in the where
/// clauses of the impl. In this example, that means replacing
/// `<Self as Foo>::Bar` with `Ty` in the first impl.
///
// FIXME: This is only necessary as `<Self as Trait>::Assoc: ItemBound`
// bounds in impls are trivially proven using the item bound candidates.
// This is unsound in general and once that is fixed, we don't need to
// normalize eagerly here. See https://github.com/lcnr/solver-woes/issues/9
// for more details.
pub(in crate::solve) fn predicates_for_object_candidate<D, I>(
ecx: &EvalCtxt<'_, D>,
ecx: &mut EvalCtxt<'_, D>,
param_env: I::ParamEnv,
trait_ref: ty::TraitRef<I>,
object_bounds: I::BoundExistentialPredicates,
) -> Vec<Goal<I, I::Predicate>>
) -> Result<Vec<Goal<I, I::Predicate>>, Ambiguous>
where
D: SolverDelegate<Interner = I>,
I: Interner,
Expand Down Expand Up @@ -871,72 +866,130 @@ where
.extend(cx.item_bounds(associated_type_def_id).iter_instantiated(cx, trait_ref.args));
}

let mut replace_projection_with = HashMap::default();
let mut replace_projection_with: HashMap<_, Vec<_>> = HashMap::default();
for bound in object_bounds.iter() {
if let ty::ExistentialPredicate::Projection(proj) = bound.skip_binder() {
// FIXME: We *probably* should replace this with a dummy placeholder,
// b/c don't want to replace literal instances of this dyn type that
// show up in the bounds, but just ones that come from substituting
// `Self` with the dyn type.
let proj = proj.with_self_ty(cx, trait_ref.self_ty());
let old_ty = replace_projection_with.insert(proj.def_id(), bound.rebind(proj));
assert_eq!(
old_ty,
None,
"{:?} has two generic parameters: {:?} and {:?}",
proj.projection_term,
proj.term,
old_ty.unwrap()
);
replace_projection_with.entry(proj.def_id()).or_default().push(bound.rebind(proj));
}
}

let mut folder =
ReplaceProjectionWith { ecx, param_env, mapping: replace_projection_with, nested: vec![] };
let folded_requirements = requirements.fold_with(&mut folder);
let mut folder = ReplaceProjectionWith {
ecx,
param_env,
self_ty: trait_ref.self_ty(),
mapping: &replace_projection_with,
nested: vec![],
};

folder
let requirements = requirements.try_fold_with(&mut folder)?;
Ok(folder
.nested
.into_iter()
.chain(folded_requirements.into_iter().map(|clause| Goal::new(cx, param_env, clause)))
.collect()
.chain(requirements.into_iter().map(|clause| Goal::new(cx, param_env, clause)))
.collect())
}

struct ReplaceProjectionWith<'a, D: SolverDelegate<Interner = I>, I: Interner> {
ecx: &'a EvalCtxt<'a, D>,
struct ReplaceProjectionWith<'a, 'b, I: Interner, D: SolverDelegate<Interner = I>> {
ecx: &'a mut EvalCtxt<'b, D>,
param_env: I::ParamEnv,
mapping: HashMap<I::DefId, ty::Binder<I, ty::ProjectionPredicate<I>>>,
self_ty: I::Ty,
mapping: &'a HashMap<I::DefId, Vec<ty::Binder<I, ty::ProjectionPredicate<I>>>>,
nested: Vec<Goal<I, I::Predicate>>,
}

impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I>
for ReplaceProjectionWith<'_, D, I>
impl<D, I> ReplaceProjectionWith<'_, '_, I, D>
where
D: SolverDelegate<Interner = I>,
I: Interner,
{
fn projection_may_match(
&mut self,
source_projection: ty::Binder<I, ty::ProjectionPredicate<I>>,
target_projection: ty::AliasTerm<I>,
) -> bool {
source_projection.item_def_id() == target_projection.def_id
&& self
.ecx
.probe(|_| ProbeKind::ProjectionCompatibility)
.enter(|ecx| -> Result<_, NoSolution> {
let source_projection = ecx.instantiate_binder_with_infer(source_projection);
ecx.eq(self.param_env, source_projection.projection_term, target_projection)?;
ecx.try_evaluate_added_goals()
})
.is_ok()
}

/// Try to replace an alias with the term present in the projection bounds of the self type.
/// Returns `Ok<None>` if this alias is not eligible to be replaced, or bail with
/// `Err(Ambiguous)` if it's uncertain which projection bound to replace the term with due
/// to multiple bounds applying.
fn try_eagerly_replace_alias(
&mut self,
alias_term: ty::AliasTerm<I>,
) -> Result<Option<I::Term>, Ambiguous> {
if alias_term.self_ty() != self.self_ty {
return Ok(None);
}

let Some(replacements) = self.mapping.get(&alias_term.def_id) else {
return Ok(None);
};

// This is quite similar to the `projection_may_match` we use in unsizing,
// but here we want to unify a projection predicate against an alias term
// so we can replace it with the the projection predicate's term.
let mut matching_projections = replacements
.iter()
.filter(|source_projection| self.projection_may_match(**source_projection, alias_term));
let Some(replacement) = matching_projections.next() else {
// This shouldn't happen.
panic!("could not replace {alias_term:?} with term from from {:?}", self.self_ty);
};
// FIXME: This *may* have issues with duplicated projections.
if matching_projections.next().is_some() {
// If there's more than one projection that we can unify here, then we
// need to stall until inference constrains things so that there's only
// one choice.
return Err(Ambiguous);
}

let replacement = self.ecx.instantiate_binder_with_infer(*replacement);
self.nested.extend(
self.ecx
.eq_and_get_goals(self.param_env, alias_term, replacement.projection_term)
.expect("expected to be able to unify goal projection with dyn's projection"),
);

Ok(Some(replacement.term))
}
}

/// Marker for bailing with ambiguity.
pub(crate) struct Ambiguous;

impl<D, I> FallibleTypeFolder<I> for ReplaceProjectionWith<'_, '_, I, D>
where
D: SolverDelegate<Interner = I>,
I: Interner,
{
type Error = Ambiguous;

fn cx(&self) -> I {
self.ecx.cx()
}

fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
fn try_fold_ty(&mut self, ty: I::Ty) -> Result<I::Ty, Ambiguous> {
if let ty::Alias(ty::Projection, alias_ty) = ty.kind() {
if let Some(replacement) = self.mapping.get(&alias_ty.def_id) {
// We may have a case where our object type's projection bound is higher-ranked,
// but the where clauses we instantiated are not. We can solve this by instantiating
// the binder at the usage site.
let proj = self.ecx.instantiate_binder_with_infer(*replacement);
// FIXME: Technically this equate could be fallible...
self.nested.extend(
self.ecx
.eq_and_get_goals(
self.param_env,
alias_ty,
proj.projection_term.expect_ty(self.ecx.cx()),
)
.expect(
"expected to be able to unify goal projection with dyn's projection",
),
);
proj.term.expect_ty()
} else {
ty.super_fold_with(self)
if let Some(term) = self.try_eagerly_replace_alias(alias_ty.into())? {
return Ok(term.expect_ty());
}
} else {
ty.super_fold_with(self)
}

ty.try_super_fold_with(self)
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -944,7 +944,7 @@ where
target_projection: ty::Binder<I, ty::ExistentialProjection<I>>| {
source_projection.item_def_id() == target_projection.item_def_id()
&& ecx
.probe(|_| ProbeKind::UpcastProjectionCompatibility)
.probe(|_| ProbeKind::ProjectionCompatibility)
.enter(|ecx| -> Result<_, NoSolution> {
ecx.enter_forall(target_projection, |ecx, target_projection| {
let source_projection =
Expand Down
Loading
Loading