Skip to content

Commit 7754ca8

Browse files
committed
consider opaque ty item bounds
1 parent 173ec7d commit 7754ca8

File tree

1 file changed

+60
-14
lines changed

1 file changed

+60
-14
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs

+60-14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::rustc_middle::ty::TypeVisitableExt;
12
use crate::FnCtxt;
23
use rustc_infer::traits::solve::Goal;
34
use rustc_infer::traits::{self, ObligationCause};
@@ -31,10 +32,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
3132
) -> bool {
3233
match predicate.kind().skip_binder() {
3334
ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
34-
self.self_type_matches_expected_vid(data.self_ty(), expected_vid)
35+
self.type_matches_expected_vid(expected_vid, data.self_ty())
3536
}
3637
ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
37-
self.self_type_matches_expected_vid(data.projection_ty.self_ty(), expected_vid)
38+
self.type_matches_expected_vid(expected_vid, data.projection_ty.self_ty())
3839
}
3940
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
4041
| ty::PredicateKind::Subtype(..)
@@ -52,11 +53,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
5253
}
5354

5455
#[instrument(level = "debug", skip(self), ret)]
55-
fn self_type_matches_expected_vid(&self, self_ty: Ty<'tcx>, expected_vid: ty::TyVid) -> bool {
56-
let self_ty = self.shallow_resolve(self_ty);
57-
debug!(?self_ty);
56+
fn type_matches_expected_vid(&self, expected_vid: ty::TyVid, ty: Ty<'tcx>) -> bool {
57+
let ty = self.shallow_resolve(ty);
58+
debug!(?ty);
5859

59-
match *self_ty.kind() {
60+
match *ty.kind() {
6061
ty::Infer(ty::TyVar(found_vid)) => expected_vid == self.root_var(found_vid),
6162
_ => false,
6263
}
@@ -67,6 +68,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
6768
self_ty: ty::TyVid,
6869
) -> Vec<traits::PredicateObligation<'tcx>> {
6970
let obligations = self.fulfillment_cx.borrow().pending_obligations();
71+
debug!(?obligations);
7072
let mut obligations_for_self_ty = vec![];
7173
for obligation in obligations {
7274
let mut visitor = NestedObligationsForSelfTy {
@@ -79,6 +81,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
7981
let goal = Goal::new(self.tcx, obligation.param_env, obligation.predicate);
8082
self.visit_proof_tree(goal, &mut visitor);
8183
}
84+
85+
obligations_for_self_ty.retain_mut(|obligation| {
86+
obligation.predicate = self.resolve_vars_if_possible(obligation.predicate);
87+
!obligation.predicate.has_placeholders()
88+
});
8289
obligations_for_self_ty
8390
}
8491
}
@@ -90,26 +97,65 @@ struct NestedObligationsForSelfTy<'a, 'tcx> {
9097
obligations_for_self_ty: &'a mut Vec<traits::PredicateObligation<'tcx>>,
9198
}
9299

100+
impl<'a, 'tcx> NestedObligationsForSelfTy<'a, 'tcx> {
101+
fn consider_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) {
102+
if self.fcx.predicate_has_self_ty(goal.predicate, self.ty_var_root) {
103+
self.obligations_for_self_ty.push(traits::Obligation::new(
104+
self.fcx.tcx,
105+
self.root_cause.clone(),
106+
goal.param_env,
107+
goal.predicate,
108+
));
109+
}
110+
}
111+
}
112+
93113
impl<'a, 'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'a, 'tcx> {
94114
type Result = ();
95115

96116
fn config(&self) -> InspectConfig {
97117
// Using an intentionally low depth to minimize the chance of future
98118
// breaking changes in case we adapt the approach later on. This also
99119
// avoids any hangs for exponentially growing proof trees.
100-
InspectConfig { max_depth: 3 }
120+
InspectConfig { max_depth: 5 }
101121
}
102122

103123
fn visit_goal(&mut self, inspect_goal: &InspectGoal<'_, 'tcx>) {
104124
let tcx = self.fcx.tcx;
105125
let goal = inspect_goal.goal();
106-
if self.fcx.predicate_has_self_ty(goal.predicate, self.ty_var_root) {
107-
self.obligations_for_self_ty.push(traits::Obligation::new(
108-
tcx,
109-
self.root_cause.clone(),
110-
goal.param_env,
111-
goal.predicate,
112-
));
126+
self.consider_goal(goal);
127+
128+
// HACK: When proving `NormalizesTo(oapque; ?infer)` we don't emit the
129+
// item bounds of the opaque as nested goals, so they never get picked up here.
130+
// Manually add these as obligations instead.
131+
//
132+
// Alternatively, we could change the solver to always emit the item bounds
133+
// as nested goals, even if the hidden type is an infer var. However, given that
134+
// these nested goals would always just fail with ambiguity, that would be
135+
// useless for everything apart from this exact `ProofTreeVisitor`, so we
136+
// do it here.
137+
match goal.predicate.kind().no_bound_vars() {
138+
Some(ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })) => {
139+
if alias.is_opaque(tcx) {
140+
let hidden_ty = term.ty().unwrap();
141+
if self.fcx.type_matches_expected_vid(self.ty_var_root, hidden_ty) {
142+
let mut obligations = vec![];
143+
self.fcx.add_item_bounds_for_hidden_type(
144+
alias.def_id,
145+
alias.args,
146+
self.root_cause.clone(),
147+
goal.param_env,
148+
hidden_ty,
149+
&mut obligations,
150+
);
151+
debug!(?obligations);
152+
for obl in obligations {
153+
self.consider_goal(obl.into());
154+
}
155+
}
156+
}
157+
}
158+
Some(_) | None => {}
113159
}
114160

115161
if let Some(candidate) = inspect_goal.unique_applicable_candidate() {

0 commit comments

Comments
 (0)