-
Notifications
You must be signed in to change notification settings - Fork 13.3k
[DRAFT] Make alias bounds sound in the new solver #110628
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
Changes from all commits
a01d3b1
2fadce5
b39846f
6da9e7f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ use rustc_data_structures::fx::FxIndexSet; | |
use rustc_hir::def_id::DefId; | ||
use rustc_infer::traits::query::NoSolution; | ||
use rustc_infer::traits::util::elaborate; | ||
use rustc_infer::traits::Reveal; | ||
use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult}; | ||
use rustc_middle::ty::fast_reject::TreatProjections; | ||
use rustc_middle::ty::TypeFoldable; | ||
|
@@ -87,7 +88,9 @@ pub(super) enum CandidateSource { | |
} | ||
|
||
/// Methods used to assemble candidates for either trait or projection goals. | ||
pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq { | ||
pub(super) trait GoalKind<'tcx>: | ||
TypeFoldable<TyCtxt<'tcx>> + Copy + Eq + std::fmt::Display | ||
{ | ||
fn self_ty(self) -> Ty<'tcx>; | ||
|
||
fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx>; | ||
|
@@ -106,10 +109,17 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq { | |
requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>, | ||
) -> QueryResult<'tcx>; | ||
|
||
// Consider a clause specifically for a `dyn Trait` self type. This requires | ||
fn consider_alias_bound_clause( | ||
ecx: &mut EvalCtxt<'_, 'tcx>, | ||
goal: Goal<'tcx, Self>, | ||
assumption: ty::Predicate<'tcx>, | ||
) -> QueryResult<'tcx>; | ||
|
||
// FIXME: better wording here. | ||
// Consider a clause that is spooky and we cannot trust. 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( | ||
// since they're not implied by the well-formedness of anything necessarily. | ||
fn consider_non_wf_assumption( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a version of Naming bikeshed I guess. |
||
ecx: &mut EvalCtxt<'_, 'tcx>, | ||
goal: Goal<'tcx, Self>, | ||
assumption: ty::Predicate<'tcx>, | ||
|
@@ -463,7 +473,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | |
|
||
for assumption in self.tcx().item_bounds(alias_ty.def_id).subst(self.tcx(), alias_ty.substs) | ||
{ | ||
match G::consider_implied_clause(self, goal, assumption, []) { | ||
match G::consider_alias_bound_clause(self, goal, assumption) { | ||
Ok(result) => { | ||
candidates.push(Candidate { source: CandidateSource::AliasBound, result }) | ||
} | ||
|
@@ -529,7 +539,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | |
continue; | ||
} | ||
|
||
match G::consider_object_bound_candidate(self, goal, assumption) { | ||
match G::consider_non_wf_assumption(self, goal, assumption) { | ||
Ok(result) => { | ||
candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result }) | ||
} | ||
|
@@ -602,4 +612,61 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | |
} | ||
self.flounder(&responses) | ||
} | ||
|
||
#[instrument(level = "debug", skip(self), ret)] | ||
pub(super) fn evaluate_alias_bound_self_is_well_formed<G: GoalKind<'tcx>>( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the logic we had discussed before, essentially that an alias bound only holds if the trait ref of the alias is satisfied via a param-env candidate. |
||
&mut self, | ||
goal: Goal<'tcx, G>, | ||
) -> QueryResult<'tcx> { | ||
match *goal.predicate.self_ty().kind() { | ||
ty::Alias(ty::Projection, projection_ty) => { | ||
let mut param_env_candidates = vec![]; | ||
let projection_trait_ref = projection_ty.trait_ref(self.tcx()); | ||
|
||
if projection_trait_ref.self_ty().is_ty_var() { | ||
return self | ||
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); | ||
} | ||
|
||
let trait_goal = goal.with( | ||
self.tcx(), | ||
ty::TraitPredicate { | ||
trait_ref: projection_trait_ref, | ||
constness: ty::BoundConstness::NotConst, | ||
polarity: ty::ImplPolarity::Positive, | ||
}, | ||
); | ||
|
||
// FIXME: We probably need some sort of recursion depth incr here. | ||
// Can't come up with an example yet, though, and the worst case | ||
// we can have is a compiler stack overflow... | ||
self.assemble_param_env_candidates(trait_goal, &mut param_env_candidates); | ||
self.assemble_alias_bound_candidates(trait_goal, &mut param_env_candidates); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to consider nested alias bounds here I think - https://hackmd.io/frHMYxD5S4-rWlxkx_eWNw#3-Nested-alias-bound-candidates |
||
|
||
// FIXME: Bad bad bad bad bad !!!!! | ||
let lang_items = self.tcx().lang_items(); | ||
let trait_def_id = projection_trait_ref.def_id; | ||
let funky_built_in_res = if lang_items.pointee_trait() == Some(trait_def_id) { | ||
G::consider_builtin_pointee_candidate(self, goal) | ||
} else if lang_items.discriminant_kind_trait() == Some(trait_def_id) { | ||
G::consider_builtin_discriminant_kind_candidate(self, goal) | ||
} else { | ||
Err(NoSolution) | ||
}; | ||
if let Ok(result) = funky_built_in_res { | ||
param_env_candidates | ||
.push(Candidate { source: CandidateSource::BuiltinImpl, result }); | ||
} | ||
Comment on lines
+646
to
+659
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
||
self.merge_candidates(param_env_candidates) | ||
} | ||
ty::Alias(ty::Opaque, _opaque_ty) => match goal.param_env.reveal() { | ||
Reveal::UserFacing => { | ||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) | ||
} | ||
Reveal::All => return Err(NoSolution), | ||
}, | ||
_ => bug!("we shouldn't have gotten here!"), | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See https://hackmd.io/frHMYxD5S4-rWlxkx_eWNw#2-Coinduction-is-necessary-for-this-to-work