mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Auto merge of #153869 - ShoyuVanilla:issue-153816, r=lcnr
Do not shallow resolve to root var while fudging Fixes https://github.com/rust-lang/rust/issues/153816 and fixes https://github.com/rust-lang/rust/issues/153849 In https://github.com/rust-lang/rust/pull/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
This commit is contained in:
@@ -1879,7 +1879,7 @@ fn check_expr_struct_fields(
|
||||
if !ocx.try_evaluate_obligations().is_empty() {
|
||||
return Err(TypeError::Mismatch);
|
||||
}
|
||||
Ok(self.resolve_vars_if_possible(adt_ty))
|
||||
Ok(adt_ty)
|
||||
})
|
||||
.ok()
|
||||
});
|
||||
|
||||
@@ -276,12 +276,7 @@ pub(in super::super) fn check_argument_types(
|
||||
|
||||
// Record all the argument types, with the args
|
||||
// produced from the above subtyping unification.
|
||||
Ok(Some(
|
||||
formal_input_tys
|
||||
.iter()
|
||||
.map(|&ty| self.resolve_vars_if_possible(ty))
|
||||
.collect(),
|
||||
))
|
||||
Ok(Some(formal_input_tys.to_vec()))
|
||||
})
|
||||
.ok()
|
||||
})
|
||||
|
||||
@@ -1250,6 +1250,36 @@ pub fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
||||
value.fold_with(&mut r)
|
||||
}
|
||||
|
||||
/// Normally, we shallow-resolve unresolved type variables to their root
|
||||
/// variables. This is mainly done for performance reasons, and in most
|
||||
/// cases resolving to the root variable (instead of the variable itself)
|
||||
/// does not affect type inference.
|
||||
///
|
||||
/// However, there is an exceptional case: *fudging*. Fudging is intended
|
||||
/// to guide inference rather than impose hard requirements. But our current
|
||||
/// handling here is somewhat janky.
|
||||
///
|
||||
/// In particular, inference variables that are considered equal within the
|
||||
/// fudging scope may not remain equal outside of it. This makes it observable
|
||||
/// which inference variable we resolve to. For backwards compatibility, we
|
||||
/// avoid resolving to the root variable by using this function inside the
|
||||
/// fudge instead of [`InferCtxt::resolve_vars_if_possible`].
|
||||
///
|
||||
/// See #153869 for more details.
|
||||
pub fn resolve_vars_if_possible_for_fudging<T>(&self, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
if let Err(guar) = value.error_reported() {
|
||||
self.set_tainted_by_errors(guar);
|
||||
}
|
||||
if !value.has_non_region_infer() {
|
||||
return value;
|
||||
}
|
||||
let mut r = resolve::OpportunisticVarResolver::new_for_fudging(self);
|
||||
value.fold_with(&mut r)
|
||||
}
|
||||
|
||||
pub fn resolve_numeric_literals_with_default<T>(&self, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
/// points for correctness.
|
||||
pub struct OpportunisticVarResolver<'a, 'tcx> {
|
||||
infcx: &'a InferCtxt<'tcx>,
|
||||
/// If true, we don't resolve ty/const vars to their roots.
|
||||
/// See comments on [`InferCtxt::resolve_vars_if_possible_for_fudging`]
|
||||
for_fudging: bool,
|
||||
/// We're able to use a cache here as the folder does
|
||||
/// not have any mutable state.
|
||||
cache: DelayedMap<Ty<'tcx>, Ty<'tcx>>,
|
||||
@@ -25,7 +28,12 @@ pub struct OpportunisticVarResolver<'a, 'tcx> {
|
||||
impl<'a, 'tcx> OpportunisticVarResolver<'a, 'tcx> {
|
||||
#[inline]
|
||||
pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
|
||||
OpportunisticVarResolver { infcx, cache: Default::default() }
|
||||
OpportunisticVarResolver { infcx, for_fudging: false, cache: Default::default() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new_for_fudging(infcx: &'a InferCtxt<'tcx>) -> Self {
|
||||
OpportunisticVarResolver { infcx, for_fudging: true, cache: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +51,7 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||
} else {
|
||||
let shallow = self.infcx.shallow_resolve(t);
|
||||
let res = shallow.super_fold_with(self);
|
||||
let res = if self.for_fudging && res.is_ty_var() { t } else { res };
|
||||
assert!(self.cache.insert(t, res));
|
||||
res
|
||||
}
|
||||
@@ -52,8 +61,11 @@ fn fold_const(&mut self, ct: Const<'tcx>) -> Const<'tcx> {
|
||||
if !ct.has_non_region_infer() {
|
||||
ct // micro-optimize -- if there is nothing in this const that this fold affects...
|
||||
} else {
|
||||
let ct = self.infcx.shallow_resolve_const(ct);
|
||||
ct.super_fold_with(self)
|
||||
let res = self.infcx.shallow_resolve_const(ct);
|
||||
if self.for_fudging && res.is_ct_infer() {
|
||||
return ct;
|
||||
};
|
||||
res.super_fold_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ pub fn fudge_inference_if_ok<T, E, F>(&self, f: F) -> Result<T, E>
|
||||
// going to be popped, so we will have to
|
||||
// eliminate any references to them.
|
||||
let snapshot_vars = SnapshotVarData::new(self, variable_lengths);
|
||||
Ok((snapshot_vars, self.resolve_vars_if_possible(value)))
|
||||
Ok((snapshot_vars, self.resolve_vars_if_possible_for_fudging(value)))
|
||||
})?;
|
||||
|
||||
// At this point, we need to replace any of the now-popped
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
//@ check-pass
|
||||
|
||||
// Regression test for <https://github.com/rust-lang/rust/issues/153816>
|
||||
|
||||
struct Inv<T, U>(*mut (T, U));
|
||||
|
||||
fn pass_through<F>(_: F) -> Inv<F, F> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn map(_: Inv<impl FnOnce(), impl Fn()>) {}
|
||||
|
||||
fn traverse() {
|
||||
map(pass_through(|| ()))
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,21 @@
|
||||
//@ check-pass
|
||||
|
||||
// Regression test for <https://github.com/rust-lang/rust/issues/153849>
|
||||
|
||||
#[expect(dead_code)]
|
||||
// Must be invariant
|
||||
pub struct Server<T>(*mut T);
|
||||
impl<T> Server<T> {
|
||||
fn new(_: T) -> Self
|
||||
where
|
||||
// Must be higher-ranked
|
||||
T: Fn(&mut i32),
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Must have a type annotation
|
||||
let _: Server<_> = Server::new(|_| ());
|
||||
}
|
||||
Reference in New Issue
Block a user