Skip to content

Commit

Permalink
Rollup merge of rust-lang#114196 - compiler-errors:bubble-pls, r=lcnr
Browse files Browse the repository at this point in the history
Bubble up nested goals from equation in `predicates_for_object_candidate`

This used to be needed for rust-lang#114036 (comment), but since it's no longer, I'm opening this as a separate PR. This also fixes one ICEing UI test: (`tests/ui/unboxed-closures/issue-53448.rs`)

r? `@lcnr`
  • Loading branch information
matthiaskrgr authored Aug 7, 2023
2 parents bf40327 + 57407a3 commit 2a643b2
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 23 deletions.
16 changes: 6 additions & 10 deletions compiler/rustc_trait_selection/src/solve/assembly/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,16 +152,12 @@ pub(super) trait GoalKind<'tcx>:
let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
bug!("expected object type in `consider_object_bound_candidate`");
};
ecx.add_goals(
structural_traits::predicates_for_object_candidate(
&ecx,
goal.param_env,
goal.predicate.trait_ref(tcx),
bounds,
)
.into_iter()
.map(|pred| goal.with(tcx, pred)),
);
ecx.add_goals(structural_traits::predicates_for_object_candidate(
&ecx,
goal.param_env,
goal.predicate.trait_ref(tcx),
bounds,
));
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::{def_id::DefId, Movability, Mutability};
use rustc_infer::traits::query::NoSolution;
use rustc_middle::traits::solve::Goal;
use rustc_middle::ty::{
self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
};
Expand Down Expand Up @@ -345,7 +346,7 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>(
param_env: ty::ParamEnv<'tcx>,
trait_ref: ty::TraitRef<'tcx>,
object_bound: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
) -> Vec<ty::Clause<'tcx>> {
) -> Vec<Goal<'tcx, ty::Predicate<'tcx>>> {
let tcx = ecx.tcx();
let mut requirements = vec![];
requirements.extend(
Expand Down Expand Up @@ -376,17 +377,22 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>(
}
}

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

folder
.nested
.into_iter()
.chain(folded_requirements.into_iter().map(|clause| Goal::new(tcx, param_env, clause)))
.collect()
}

struct ReplaceProjectionWith<'a, 'tcx> {
ecx: &'a EvalCtxt<'a, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
mapping: FxHashMap<DefId, ty::PolyProjectionPredicate<'tcx>>,
nested: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
}

impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> {
Expand All @@ -402,13 +408,12 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> {
// 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 folder could be fallible?
let nested = self
.ecx
.eq_and_get_goals(self.param_env, alias_ty, proj.projection_ty)
.expect("expected to be able to unify goal projection with dyn's projection");
// FIXME: Technically we could register these too..
assert!(nested.is_empty(), "did not expect unification to have any nested goals");
// FIXME: Technically this equate could be fallible...
self.nested.extend(
self.ecx
.eq_and_get_goals(self.param_env, alias_ty, proj.projection_ty)
.expect("expected to be able to unify goal projection with dyn's projection"),
);
proj.term.ty().unwrap()
} else {
ty.super_fold_with(self)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// compile-flags: -Ztrait-solver=next
// ignore-test

trait Trait {
type Gat<'lt>;
}
impl Trait for u8 {
type Gat<'lt> = u8;
}

fn test<T: Trait, F: FnOnce(<T as Trait>::Gat<'_>) -> S + ?Sized, S>() {}

fn main() {
// Proving `dyn FnOnce: FnOnce` requires making sure that all of the supertraits
// of the trait and associated type bounds hold. We check this in
// `predicates_for_object_candidate`, and eagerly replace projections using equality
// which may generalize a type and emit a nested AliasRelate goal. Make sure that
// we don't ICE in that case, and bubble that goal up to the caller.
test::<u8, dyn FnOnce(<u8 as Trait>::Gat<'_>) + 'static, _>();
}

0 comments on commit 2a643b2

Please sign in to comment.