提交 98525aee 编写于 作者: M Michael Goulet

Check object's supertrait and associated type bounds in new solver

上级 07c993eb
......@@ -99,6 +99,15 @@ fn consider_implied_clause(
requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
) -> QueryResult<'tcx>;
// Consider a clause specifically for a `dyn Trait` self type. This requires
// additionally checking all of the supertraits and object bounds to hold,
// since they're not implied by the well-formedness of the object type.
fn consider_object_bound_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
assumption: ty::Predicate<'tcx>,
) -> QueryResult<'tcx>;
fn consider_impl_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
......@@ -455,7 +464,7 @@ fn assemble_object_bound_candidates<G: GoalKind<'tcx>>(
for assumption in
elaborate_predicates(tcx, bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty)))
{
match G::consider_implied_clause(self, goal, assumption.predicate, []) {
match G::consider_object_bound_candidate(self, goal, assumption.predicate) {
Ok(result) => {
candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
}
......
......@@ -128,6 +128,50 @@ fn consider_implied_clause(
}
}
fn consider_object_bound_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
assumption: ty::Predicate<'tcx>,
) -> QueryResult<'tcx> {
if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred()
&& poly_projection_pred.projection_def_id() == goal.predicate.def_id()
{
ecx.probe(|ecx| {
let assumption_projection_pred =
ecx.instantiate_binder_with_infer(poly_projection_pred);
let mut nested_goals = ecx.eq(
goal.param_env,
goal.predicate.projection_ty,
assumption_projection_pred.projection_ty,
)?;
let tcx = ecx.tcx();
let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
bug!("expected object type in `consider_object_bound_candidate`");
};
nested_goals.extend(
structural_traits::predicates_for_object_candidate(
tcx,
goal.predicate.projection_ty.trait_ref(tcx),
bounds,
)
.into_iter()
.map(|pred| goal.with(tcx, pred)),
);
let subst_certainty = ecx.evaluate_all(nested_goals)?;
ecx.eq_term_and_make_canonical_response(
goal,
subst_certainty,
assumption_projection_pred.term,
)
})
} else {
Err(NoSolution)
}
}
fn consider_impl_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
......
......@@ -86,6 +86,45 @@ fn consider_implied_clause(
}
}
fn consider_object_bound_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
assumption: ty::Predicate<'tcx>,
) -> QueryResult<'tcx> {
if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred()
&& poly_trait_pred.def_id() == goal.predicate.def_id()
{
// FIXME: Constness and polarity
ecx.probe(|ecx| {
let assumption_trait_pred =
ecx.instantiate_binder_with_infer(poly_trait_pred);
let mut nested_goals = ecx.eq(
goal.param_env,
goal.predicate.trait_ref,
assumption_trait_pred.trait_ref,
)?;
let tcx = ecx.tcx();
let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
bug!("expected object type in `consider_object_bound_candidate`");
};
nested_goals.extend(
structural_traits::predicates_for_object_candidate(
tcx,
goal.predicate.trait_ref,
bounds,
)
.into_iter()
.map(|pred| goal.with(tcx, pred)),
);
ecx.evaluate_all_and_make_canonical_response(nested_goals)
})
} else {
Err(NoSolution)
}
}
fn consider_auto_trait_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
......
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::{Movability, Mutability};
use rustc_infer::traits::query::NoSolution;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable};
use crate::solve::EvalCtxt;
......@@ -233,3 +234,62 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
}
}
}
pub(crate) fn predicates_for_object_candidate<'tcx>(
tcx: TyCtxt<'tcx>,
trait_ref: ty::TraitRef<'tcx>,
object_bound: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
) -> Vec<ty::Predicate<'tcx>> {
let mut requirements = vec![];
requirements.extend(
tcx.super_predicates_of(trait_ref.def_id).instantiate(tcx, trait_ref.substs).predicates,
);
for item in tcx.associated_items(trait_ref.def_id).in_definition_order() {
if item.kind == ty::AssocKind::Type {
requirements.extend(tcx.item_bounds(item.def_id).subst(tcx, trait_ref.substs));
}
}
let mut replace_projection_with = FxHashMap::default();
for bound in object_bound {
let bound = bound.no_bound_vars().expect("higher-ranked projections not supported, yet");
if let ty::ExistentialPredicate::Projection(proj) = bound {
let proj = proj.with_self_ty(tcx, trait_ref.self_ty());
let old_ty = replace_projection_with.insert(
proj.projection_ty,
proj.term.ty().expect("expected only types in dyn right now"),
);
assert_eq!(
old_ty,
None,
"{} has two substitutions: {} and {}",
proj.projection_ty,
proj.term,
old_ty.unwrap()
);
}
}
requirements.fold_with(&mut ReplaceProjectionWith { tcx, mapping: replace_projection_with })
}
struct ReplaceProjectionWith<'tcx> {
tcx: TyCtxt<'tcx>,
mapping: FxHashMap<ty::AliasTy<'tcx>, Ty<'tcx>>,
}
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'tcx> {
fn interner(&self) -> TyCtxt<'tcx> {
self.tcx
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if let ty::Alias(ty::Projection, alias_ty) = *ty.kind()
&& let Some(replacement) = self.mapping.get(&alias_ty)
{
*replacement
} else {
ty.super_fold_with(self)
}
}
}
// compile-flags: -Ztrait-solver=next
trait Setup {
type From: Copy;
}
fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From {
*from
}
pub fn copy_any<T>(t: &T) -> T {
copy::<dyn Setup<From=T>>(t)
//~^ ERROR the trait bound `dyn Setup<From = T>: Setup` is not satisfied
}
fn main() {
let x = String::from("Hello, world");
let y = copy_any(&x);
println!("{y}");
}
error[E0277]: the trait bound `dyn Setup<From = T>: Setup` is not satisfied
--> $DIR/object-unsafety.rs:12:12
|
LL | copy::<dyn Setup<From=T>>(t)
| ^^^^^^^^^^^^^^^^^ the trait `Setup` is not implemented for `dyn Setup<From = T>`
|
note: required by a bound in `copy`
--> $DIR/object-unsafety.rs:7:12
|
LL | fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From {
| ^^^^^ required by this bound in `copy`
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
|
LL | pub fn copy_any<T>(t: &T) -> T where dyn Setup<From = T>: Setup {
| ++++++++++++++++++++++++++++++++
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册