Skip to content

Commit ae4d89d

Browse files
committed
Auto merge of #106742 - compiler-errors:new-solver-make-it-not-ice, r=lcnr
Implement some FIXME methods in the new trait solver Implement just enough of the solver's response logic to make it not ICE. Also, fix a bug with `no_bound_vars` call failing due to canonical bound vars. r? `@lcnr`
2 parents fc11ee0 + 1de196f commit ae4d89d

File tree

6 files changed

+186
-41
lines changed

6 files changed

+186
-41
lines changed

compiler/rustc_middle/src/ty/sty.rs

+88-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ use crate::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
77
use crate::ty::visit::ValidateBoundVars;
88
use crate::ty::InferTy::*;
99
use crate::ty::{
10-
self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable,
11-
TypeVisitor,
10+
self, AdtDef, DefIdTree, Discr, FallibleTypeFolder, Term, Ty, TyCtxt, TypeFlags, TypeFoldable,
11+
TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor,
1212
};
1313
use crate::ty::{List, ParamEnv};
1414
use hir::def::DefKind;
@@ -1106,6 +1106,17 @@ impl<'tcx, T> Binder<'tcx, T> {
11061106
if self.0.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) }
11071107
}
11081108

1109+
pub fn no_bound_vars_ignoring_escaping(self, tcx: TyCtxt<'tcx>) -> Option<T>
1110+
where
1111+
T: TypeFoldable<'tcx>,
1112+
{
1113+
if !self.0.has_escaping_bound_vars() {
1114+
Some(self.skip_binder())
1115+
} else {
1116+
self.0.try_fold_with(&mut SkipBindersAt { index: ty::INNERMOST, tcx }).ok()
1117+
}
1118+
}
1119+
11091120
/// Splits the contents into two things that share the same binder
11101121
/// level as the original, returning two distinct binders.
11111122
///
@@ -1135,6 +1146,81 @@ impl<'tcx, T: IntoIterator> Binder<'tcx, T> {
11351146
}
11361147
}
11371148

1149+
struct SkipBindersAt<'tcx> {
1150+
tcx: TyCtxt<'tcx>,
1151+
index: ty::DebruijnIndex,
1152+
}
1153+
1154+
impl<'tcx> FallibleTypeFolder<'tcx> for SkipBindersAt<'tcx> {
1155+
type Error = ();
1156+
1157+
fn tcx(&self) -> TyCtxt<'tcx> {
1158+
self.tcx
1159+
}
1160+
1161+
fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error>
1162+
where
1163+
T: ty::TypeFoldable<'tcx>,
1164+
{
1165+
self.index.shift_in(1);
1166+
let value = t.try_map_bound(|t| t.try_fold_with(self));
1167+
self.index.shift_out(1);
1168+
value
1169+
}
1170+
1171+
fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
1172+
if !ty.has_escaping_bound_vars() {
1173+
Ok(ty)
1174+
} else if let ty::Bound(index, bv) = *ty.kind() {
1175+
if index == self.index {
1176+
Err(())
1177+
} else {
1178+
Ok(self.tcx().mk_ty(ty::Bound(index.shifted_out(1), bv)))
1179+
}
1180+
} else {
1181+
ty.try_super_fold_with(self)
1182+
}
1183+
}
1184+
1185+
fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
1186+
if !r.has_escaping_bound_vars() {
1187+
Ok(r)
1188+
} else if let ty::ReLateBound(index, bv) = r.kind() {
1189+
if index == self.index {
1190+
Err(())
1191+
} else {
1192+
Ok(self.tcx().mk_region(ty::ReLateBound(index.shifted_out(1), bv)))
1193+
}
1194+
} else {
1195+
r.try_super_fold_with(self)
1196+
}
1197+
}
1198+
1199+
fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
1200+
if !ct.has_escaping_bound_vars() {
1201+
Ok(ct)
1202+
} else if let ty::ConstKind::Bound(index, bv) = ct.kind() {
1203+
if index == self.index {
1204+
Err(())
1205+
} else {
1206+
Ok(self.tcx().mk_const(
1207+
ty::ConstKind::Bound(index.shifted_out(1), bv),
1208+
ct.ty().try_fold_with(self)?,
1209+
))
1210+
}
1211+
} else {
1212+
ct.try_super_fold_with(self)
1213+
}
1214+
}
1215+
1216+
fn try_fold_predicate(
1217+
&mut self,
1218+
p: ty::Predicate<'tcx>,
1219+
) -> Result<ty::Predicate<'tcx>, Self::Error> {
1220+
if !p.has_escaping_bound_vars() { Ok(p) } else { p.try_super_fold_with(self) }
1221+
}
1222+
}
1223+
11381224
/// Represents the projection of an associated type.
11391225
///
11401226
/// For a projection, this would be `<Ty as Trait<...>>::N`.

compiler/rustc_trait_selection/src/solve/assembly.rs

+4-7
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
33
use super::infcx_ext::InferCtxtExt;
44
use super::{
5-
fixme_instantiate_canonical_query_response, CanonicalGoal, CanonicalResponse, Certainty,
6-
EvalCtxt, Goal,
5+
instantiate_canonical_query_response, CanonicalGoal, CanonicalResponse, Certainty, EvalCtxt,
6+
Goal,
77
};
88
use rustc_hir::def_id::DefId;
99
use rustc_infer::infer::TyCtxtInferExt;
@@ -121,11 +121,8 @@ impl<'a, 'tcx, G: GoalKind<'tcx>> AssemblyCtxt<'a, 'tcx, G> {
121121
// canonical wrt the caller.
122122
for Candidate { source, result } in normalized_candidates {
123123
self.infcx.probe(|_| {
124-
let candidate_certainty = fixme_instantiate_canonical_query_response(
125-
&self.infcx,
126-
&orig_values,
127-
result,
128-
);
124+
let candidate_certainty =
125+
instantiate_canonical_query_response(&self.infcx, &orig_values, result);
129126

130127
// FIXME: This is a bit scary if the `normalizes_to_goal` overflows.
131128
//

compiler/rustc_trait_selection/src/solve/cache.rs

+44-10
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@
99
//! FIXME(@lcnr): Write that section, feel free to ping me if you need help here
1010
//! before then or if I still haven't done that before January 2023.
1111
use super::overflow::OverflowData;
12-
use super::CanonicalGoal;
12+
use super::{CanonicalGoal, Certainty, MaybeCause, Response};
1313
use super::{EvalCtxt, QueryResult};
1414

1515
use rustc_data_structures::fx::FxHashMap;
16-
use rustc_middle::ty::TyCtxt;
16+
use rustc_infer::infer::canonical::{Canonical, CanonicalVarKind, CanonicalVarValues};
17+
use rustc_middle::ty::{self, TyCtxt};
1718
use std::{cmp::Ordering, collections::hash_map::Entry};
1819

1920
#[derive(Debug, Clone)]
@@ -111,11 +112,11 @@ impl<'tcx> EvalCtxt<'tcx> {
111112
// No entry, simply push this goal on the stack after dealing with overflow.
112113
Entry::Vacant(v) => {
113114
if self.overflow_data.has_overflow(cache.stack.len()) {
114-
return Err(self.deal_with_overflow());
115+
return Err(self.deal_with_overflow(goal));
115116
}
116117

117118
v.insert(ProvisionalEntry {
118-
response: fixme_response_yes_no_constraints(),
119+
response: response_no_constraints(self.tcx, goal, Certainty::Yes),
119120
depth: cache.stack.len(),
120121
});
121122
cache.stack.push(StackElem { goal, has_been_used: false });
@@ -150,7 +151,11 @@ impl<'tcx> EvalCtxt<'tcx> {
150151
{
151152
Err(entry.response)
152153
} else {
153-
Err(fixme_response_maybe_no_constraints())
154+
Err(response_no_constraints(
155+
self.tcx,
156+
goal,
157+
Certainty::Maybe(MaybeCause::Ambiguity),
158+
))
154159
}
155160
}
156161
}
@@ -248,10 +253,39 @@ impl<'tcx> EvalCtxt<'tcx> {
248253
}
249254
}
250255

251-
fn fixme_response_yes_no_constraints<'tcx>() -> QueryResult<'tcx> {
252-
unimplemented!()
253-
}
256+
pub(super) fn response_no_constraints<'tcx>(
257+
tcx: TyCtxt<'tcx>,
258+
goal: Canonical<'tcx, impl Sized>,
259+
certainty: Certainty,
260+
) -> QueryResult<'tcx> {
261+
let var_values = goal
262+
.variables
263+
.iter()
264+
.enumerate()
265+
.map(|(i, info)| match info.kind {
266+
CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => {
267+
tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i).into())).into()
268+
}
269+
CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => {
270+
let br = ty::BoundRegion {
271+
var: ty::BoundVar::from_usize(i),
272+
kind: ty::BrAnon(i as u32, None),
273+
};
274+
tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
275+
}
276+
CanonicalVarKind::Const(_, ty) | CanonicalVarKind::PlaceholderConst(_, ty) => tcx
277+
.mk_const(ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i)), ty)
278+
.into(),
279+
})
280+
.collect();
254281

255-
fn fixme_response_maybe_no_constraints<'tcx>() -> QueryResult<'tcx> {
256-
unimplemented!()
282+
Ok(Canonical {
283+
max_universe: goal.max_universe,
284+
variables: goal.variables,
285+
value: Response {
286+
var_values: CanonicalVarValues { var_values },
287+
external_constraints: Default::default(),
288+
certainty,
289+
},
290+
})
257291
}

compiler/rustc_trait_selection/src/solve/fulfill.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
6262
let mut errors = Vec::new();
6363
for i in 0.. {
6464
if !infcx.tcx.recursion_limit().value_within_limit(i) {
65-
unimplemented!("overflow")
65+
unimplemented!("overflowed on pending obligations: {:?}", self.obligations);
6666
}
6767

6868
let mut has_changed = false;

compiler/rustc_trait_selection/src/solve/mod.rs

+42-15
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,19 @@
1919

2020
use std::mem;
2121

22-
use rustc_infer::infer::canonical::OriginalQueryValues;
23-
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
22+
use rustc_infer::infer::canonical::{OriginalQueryValues, QueryRegionConstraints, QueryResponse};
23+
use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
2424
use rustc_infer::traits::query::NoSolution;
2525
use rustc_infer::traits::Obligation;
26+
use rustc_middle::infer::canonical::Certainty as OldCertainty;
2627
use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
2728
use rustc_middle::ty::{self, Ty, TyCtxt};
2829
use rustc_middle::ty::{RegionOutlivesPredicate, ToPredicate, TypeOutlivesPredicate};
2930
use rustc_span::DUMMY_SP;
3031

32+
use crate::traits::ObligationCause;
33+
34+
use self::cache::response_no_constraints;
3135
use self::infcx_ext::InferCtxtExt;
3236

3337
mod assembly;
@@ -119,7 +123,7 @@ pub enum MaybeCause {
119123
}
120124

121125
/// Additional constraints returned on success.
122-
#[derive(Debug, PartialEq, Eq, Clone, Hash, TypeFoldable, TypeVisitable)]
126+
#[derive(Debug, PartialEq, Eq, Clone, Hash, TypeFoldable, TypeVisitable, Default)]
123127
pub struct ExternalConstraints<'tcx> {
124128
// FIXME: implement this.
125129
regions: (),
@@ -175,7 +179,7 @@ impl<'tcx> EvalCtxt<'tcx> {
175179
let canonical_response = self.evaluate_canonical_goal(canonical_goal)?;
176180
Ok((
177181
true, // FIXME: check whether `var_values` are an identity substitution.
178-
fixme_instantiate_canonical_query_response(infcx, &orig_values, canonical_response),
182+
instantiate_canonical_query_response(infcx, &orig_values, canonical_response),
179183
))
180184
}
181185

@@ -208,7 +212,8 @@ impl<'tcx> EvalCtxt<'tcx> {
208212
// of `PredicateKind` this is the case and it is and faster than instantiating and
209213
// recanonicalizing.
210214
let Goal { param_env, predicate } = canonical_goal.value;
211-
if let Some(kind) = predicate.kind().no_bound_vars() {
215+
216+
if let Some(kind) = predicate.kind().no_bound_vars_ignoring_escaping(self.tcx) {
212217
match kind {
213218
ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => self.compute_trait_goal(
214219
canonical_goal.unchecked_rebind(Goal { param_env, predicate }),
@@ -234,7 +239,10 @@ impl<'tcx> EvalCtxt<'tcx> {
234239
| ty::PredicateKind::ConstEvaluatable(_)
235240
| ty::PredicateKind::ConstEquate(_, _)
236241
| ty::PredicateKind::TypeWellFormedFromEnv(_)
237-
| ty::PredicateKind::Ambiguous => unimplemented!(),
242+
| ty::PredicateKind::Ambiguous => {
243+
// FIXME
244+
response_no_constraints(self.tcx, canonical_goal, Certainty::Yes)
245+
}
238246
}
239247
} else {
240248
let (infcx, goal, var_values) =
@@ -248,16 +256,18 @@ impl<'tcx> EvalCtxt<'tcx> {
248256

249257
fn compute_type_outlives_goal(
250258
&mut self,
251-
_goal: CanonicalGoal<'tcx, TypeOutlivesPredicate<'tcx>>,
259+
goal: CanonicalGoal<'tcx, TypeOutlivesPredicate<'tcx>>,
252260
) -> QueryResult<'tcx> {
253-
todo!()
261+
// FIXME
262+
response_no_constraints(self.tcx, goal, Certainty::Yes)
254263
}
255264

256265
fn compute_region_outlives_goal(
257266
&mut self,
258-
_goal: CanonicalGoal<'tcx, RegionOutlivesPredicate<'tcx>>,
267+
goal: CanonicalGoal<'tcx, RegionOutlivesPredicate<'tcx>>,
259268
) -> QueryResult<'tcx> {
260-
todo!()
269+
// FIXME
270+
response_no_constraints(self.tcx, goal, Certainty::Yes)
261271
}
262272
}
263273

@@ -300,10 +310,27 @@ impl<'tcx> EvalCtxt<'tcx> {
300310
}
301311
}
302312

303-
fn fixme_instantiate_canonical_query_response<'tcx>(
304-
_: &InferCtxt<'tcx>,
305-
_: &OriginalQueryValues<'tcx>,
306-
_: CanonicalResponse<'tcx>,
313+
fn instantiate_canonical_query_response<'tcx>(
314+
infcx: &InferCtxt<'tcx>,
315+
original_values: &OriginalQueryValues<'tcx>,
316+
response: CanonicalResponse<'tcx>,
307317
) -> Certainty {
308-
unimplemented!()
318+
let Ok(InferOk { value, obligations }) = infcx
319+
.instantiate_query_response_and_region_obligations(
320+
&ObligationCause::dummy(),
321+
ty::ParamEnv::empty(),
322+
original_values,
323+
&response.unchecked_map(|resp| QueryResponse {
324+
var_values: resp.var_values,
325+
region_constraints: QueryRegionConstraints::default(),
326+
certainty: match resp.certainty {
327+
Certainty::Yes => OldCertainty::Proven,
328+
Certainty::Maybe(_) => OldCertainty::Ambiguous,
329+
},
330+
opaque_types: resp.external_constraints.opaque_types,
331+
value: resp.certainty,
332+
}),
333+
) else { bug!(); };
334+
assert!(obligations.is_empty());
335+
value
309336
}

compiler/rustc_trait_selection/src/solve/overflow.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
use rustc_infer::infer::canonical::Canonical;
12
use rustc_infer::traits::query::NoSolution;
23
use rustc_middle::ty::TyCtxt;
34
use rustc_session::Limit;
45

6+
use super::cache::response_no_constraints;
57
use super::{Certainty, EvalCtxt, MaybeCause, QueryResult};
68

79
/// When detecting a solver overflow, we return ambiguity. Overflow can be
@@ -49,9 +51,12 @@ impl OverflowData {
4951
}
5052

5153
impl<'tcx> EvalCtxt<'tcx> {
52-
pub(super) fn deal_with_overflow(&mut self) -> QueryResult<'tcx> {
54+
pub(super) fn deal_with_overflow(
55+
&mut self,
56+
goal: Canonical<'tcx, impl Sized>,
57+
) -> QueryResult<'tcx> {
5358
self.overflow_data.deal_with_overflow();
54-
fixme_response_overflow_no_constraints()
59+
response_no_constraints(self.tcx, goal, Certainty::Maybe(MaybeCause::Overflow))
5560
}
5661

5762
/// A `while`-loop which tracks overflow.
@@ -74,7 +79,3 @@ impl<'tcx> EvalCtxt<'tcx> {
7479
Ok(Certainty::Maybe(MaybeCause::Overflow))
7580
}
7681
}
77-
78-
fn fixme_response_overflow_no_constraints<'tcx>() -> QueryResult<'tcx> {
79-
unimplemented!()
80-
}

0 commit comments

Comments
 (0)