Skip to content

Commit 1f7f8ea

Browse files
committed
Auto merge of #153869 - ShoyuVanilla:issue-153816, r=lcnr
Do not shallow resolve to root var while fudging Fixes #153816 and fixes #153849 In #151380, I thought that whether shallow resolve to root var or not wouldn't affect the actual type inferencing, but it isn't true for the fudge, in which we discard all newly created relationships between unresolved inference variables 😅 r? lcnr
2 parents 8b86f48 + b77739a commit 1f7f8ea

7 files changed

Lines changed: 86 additions & 11 deletions

File tree

compiler/rustc_hir_typeck/src/expr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1879,7 +1879,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18791879
if !ocx.try_evaluate_obligations().is_empty() {
18801880
return Err(TypeError::Mismatch);
18811881
}
1882-
Ok(self.resolve_vars_if_possible(adt_ty))
1882+
Ok(adt_ty)
18831883
})
18841884
.ok()
18851885
});

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -276,12 +276,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
276276

277277
// Record all the argument types, with the args
278278
// produced from the above subtyping unification.
279-
Ok(Some(
280-
formal_input_tys
281-
.iter()
282-
.map(|&ty| self.resolve_vars_if_possible(ty))
283-
.collect(),
284-
))
279+
Ok(Some(formal_input_tys.to_vec()))
285280
})
286281
.ok()
287282
})

compiler/rustc_infer/src/infer/mod.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,6 +1250,36 @@ impl<'tcx> InferCtxt<'tcx> {
12501250
value.fold_with(&mut r)
12511251
}
12521252

1253+
/// Normally, we shallow-resolve unresolved type variables to their root
1254+
/// variables. This is mainly done for performance reasons, and in most
1255+
/// cases resolving to the root variable (instead of the variable itself)
1256+
/// does not affect type inference.
1257+
///
1258+
/// However, there is an exceptional case: *fudging*. Fudging is intended
1259+
/// to guide inference rather than impose hard requirements. But our current
1260+
/// handling here is somewhat janky.
1261+
///
1262+
/// In particular, inference variables that are considered equal within the
1263+
/// fudging scope may not remain equal outside of it. This makes it observable
1264+
/// which inference variable we resolve to. For backwards compatibility, we
1265+
/// avoid resolving to the root variable by using this function inside the
1266+
/// fudge instead of [`InferCtxt::resolve_vars_if_possible`].
1267+
///
1268+
/// See #153869 for more details.
1269+
pub fn resolve_vars_if_possible_for_fudging<T>(&self, value: T) -> T
1270+
where
1271+
T: TypeFoldable<TyCtxt<'tcx>>,
1272+
{
1273+
if let Err(guar) = value.error_reported() {
1274+
self.set_tainted_by_errors(guar);
1275+
}
1276+
if !value.has_non_region_infer() {
1277+
return value;
1278+
}
1279+
let mut r = resolve::OpportunisticVarResolver::new_for_fudging(self);
1280+
value.fold_with(&mut r)
1281+
}
1282+
12531283
pub fn resolve_numeric_literals_with_default<T>(&self, value: T) -> T
12541284
where
12551285
T: TypeFoldable<TyCtxt<'tcx>>,

compiler/rustc_infer/src/infer/resolve.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ use crate::infer::TyOrConstInferVar;
1717
/// points for correctness.
1818
pub struct OpportunisticVarResolver<'a, 'tcx> {
1919
infcx: &'a InferCtxt<'tcx>,
20+
/// If true, we don't resolve ty/const vars to their roots.
21+
/// See comments on [`InferCtxt::resolve_vars_if_possible_for_fudging`]
22+
for_fudging: bool,
2023
/// We're able to use a cache here as the folder does
2124
/// not have any mutable state.
2225
cache: DelayedMap<Ty<'tcx>, Ty<'tcx>>,
@@ -25,7 +28,12 @@ pub struct OpportunisticVarResolver<'a, 'tcx> {
2528
impl<'a, 'tcx> OpportunisticVarResolver<'a, 'tcx> {
2629
#[inline]
2730
pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
28-
OpportunisticVarResolver { infcx, cache: Default::default() }
31+
OpportunisticVarResolver { infcx, for_fudging: false, cache: Default::default() }
32+
}
33+
34+
#[inline]
35+
pub fn new_for_fudging(infcx: &'a InferCtxt<'tcx>) -> Self {
36+
OpportunisticVarResolver { infcx, for_fudging: true, cache: Default::default() }
2937
}
3038
}
3139

@@ -43,6 +51,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for OpportunisticVarResolver<'a, 'tcx> {
4351
} else {
4452
let shallow = self.infcx.shallow_resolve(t);
4553
let res = shallow.super_fold_with(self);
54+
let res = if self.for_fudging && res.is_ty_var() { t } else { res };
4655
assert!(self.cache.insert(t, res));
4756
res
4857
}
@@ -52,8 +61,11 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for OpportunisticVarResolver<'a, 'tcx> {
5261
if !ct.has_non_region_infer() {
5362
ct // micro-optimize -- if there is nothing in this const that this fold affects...
5463
} else {
55-
let ct = self.infcx.shallow_resolve_const(ct);
56-
ct.super_fold_with(self)
64+
let res = self.infcx.shallow_resolve_const(ct);
65+
if self.for_fudging && res.is_ct_infer() {
66+
return ct;
67+
};
68+
res.super_fold_with(self)
5769
}
5870
}
5971

compiler/rustc_infer/src/infer/snapshot/fudge.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ impl<'tcx> InferCtxt<'tcx> {
101101
// going to be popped, so we will have to
102102
// eliminate any references to them.
103103
let snapshot_vars = SnapshotVarData::new(self, variable_lengths);
104-
Ok((snapshot_vars, self.resolve_vars_if_possible(value)))
104+
Ok((snapshot_vars, self.resolve_vars_if_possible_for_fudging(value)))
105105
})?;
106106

107107
// At this point, we need to replace any of the now-popped
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//@ check-pass
2+
3+
// Regression test for <https://github.com/rust-lang/rust/issues/153816>
4+
5+
struct Inv<T, U>(*mut (T, U));
6+
7+
fn pass_through<F>(_: F) -> Inv<F, F> {
8+
todo!()
9+
}
10+
11+
fn map(_: Inv<impl FnOnce(), impl Fn()>) {}
12+
13+
fn traverse() {
14+
map(pass_through(|| ()))
15+
}
16+
17+
fn main() {}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//@ check-pass
2+
3+
// Regression test for <https://github.com/rust-lang/rust/issues/153849>
4+
5+
#[expect(dead_code)]
6+
// Must be invariant
7+
pub struct Server<T>(*mut T);
8+
impl<T> Server<T> {
9+
fn new(_: T) -> Self
10+
where
11+
// Must be higher-ranked
12+
T: Fn(&mut i32),
13+
{
14+
todo!()
15+
}
16+
}
17+
18+
fn main() {
19+
// Must have a type annotation
20+
let _: Server<_> = Server::new(|_| ());
21+
}

0 commit comments

Comments
 (0)