Skip to content

Commit bdeeb07

Browse files
committed
Prove obligations to termination instead of ignoring ambiguities.
Sometimes an obligation depends on a later one, so we can't just process them in order like it was done previously. This is not a problem in our test suite, but there may be ICEs out there and it will definitely be a problem with lazy TAIT.
1 parent 5c46002 commit bdeeb07

File tree

1 file changed

+42
-19
lines changed
  • compiler/rustc_trait_selection/src/traits/query/type_op

1 file changed

+42
-19
lines changed

compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs

+42-19
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ use crate::infer::canonical::{
44
use crate::infer::{InferCtxt, InferOk};
55
use crate::traits::query::Fallible;
66
use crate::traits::ObligationCause;
7-
use rustc_infer::infer::canonical::Canonical;
7+
use rustc_infer::infer::canonical::{Canonical, Certainty};
8+
use rustc_infer::traits::query::NoSolution;
9+
use rustc_infer::traits::PredicateObligations;
810
use rustc_middle::ty::fold::TypeFoldable;
911
use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
1012
use std::fmt;
@@ -17,7 +19,6 @@ pub mod implied_outlives_bounds;
1719
pub mod normalize;
1820
pub mod outlives;
1921
pub mod prove_predicate;
20-
use self::prove_predicate::ProvePredicate;
2122
pub mod subtype;
2223

2324
pub use rustc_middle::traits::query::type_op::*;
@@ -80,9 +81,14 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<'tcx> + 'tcx {
8081
query_key: ParamEnvAnd<'tcx, Self>,
8182
infcx: &InferCtxt<'_, 'tcx>,
8283
output_query_region_constraints: &mut QueryRegionConstraints<'tcx>,
83-
) -> Fallible<(Self::QueryResponse, Option<Canonical<'tcx, ParamEnvAnd<'tcx, Self>>>)> {
84+
) -> Fallible<(
85+
Self::QueryResponse,
86+
Option<Canonical<'tcx, ParamEnvAnd<'tcx, Self>>>,
87+
PredicateObligations<'tcx>,
88+
Certainty,
89+
)> {
8490
if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) {
85-
return Ok((result, None));
91+
return Ok((result, None, vec![], Certainty::Proven));
8692
}
8793

8894
// FIXME(#33684) -- We need to use
@@ -104,20 +110,7 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<'tcx> + 'tcx {
104110
output_query_region_constraints,
105111
)?;
106112

107-
// Typically, instantiating NLL query results does not
108-
// create obligations. However, in some cases there
109-
// are unresolved type variables, and unify them *can*
110-
// create obligations. In that case, we have to go
111-
// fulfill them. We do this via a (recursive) query.
112-
for obligation in obligations {
113-
let ((), _) = ProvePredicate::fully_perform_into(
114-
obligation.param_env.and(ProvePredicate::new(obligation.predicate)),
115-
infcx,
116-
output_query_region_constraints,
117-
)?;
118-
}
119-
120-
Ok((value, Some(canonical_self)))
113+
Ok((value, Some(canonical_self), obligations, canonical_result.value.certainty))
121114
}
122115
}
123116

@@ -129,9 +122,39 @@ where
129122

130123
fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
131124
let mut region_constraints = QueryRegionConstraints::default();
132-
let (output, canonicalized_query) =
125+
let (output, canonicalized_query, mut obligations, _) =
133126
Q::fully_perform_into(self, infcx, &mut region_constraints)?;
134127

128+
// Typically, instantiating NLL query results does not
129+
// create obligations. However, in some cases there
130+
// are unresolved type variables, and unify them *can*
131+
// create obligations. In that case, we have to go
132+
// fulfill them. We do this via a (recursive) query.
133+
while !obligations.is_empty() {
134+
trace!("{:#?}", obligations);
135+
let mut progress = false;
136+
for obligation in std::mem::take(&mut obligations) {
137+
let obligation = infcx.resolve_vars_if_possible(obligation);
138+
match ProvePredicate::fully_perform_into(
139+
obligation.param_env.and(ProvePredicate::new(obligation.predicate)),
140+
infcx,
141+
&mut region_constraints,
142+
) {
143+
Ok(((), _, new, certainty)) => {
144+
obligations.extend(new);
145+
progress = true;
146+
if let Certainty::Ambiguous = certainty {
147+
obligations.push(obligation);
148+
}
149+
}
150+
Err(_) => obligations.push(obligation),
151+
}
152+
}
153+
if !progress {
154+
return Err(NoSolution);
155+
}
156+
}
157+
135158
// Promote the final query-region-constraints into a
136159
// (optional) ref-counted vector:
137160
let region_constraints =

0 commit comments

Comments
 (0)