Skip to content

Commit 3250240

Browse files
Rollup merge of #86506 - b-naber:gen_trait_impl_inconsistent, r=jackh726
Don't normalize xform_ret_ty during method candidate assembly Fixes #85671 Normalizing the return type of a method candidate together with the expected receiver type of the method can lead to valid method candidates being rejected during probing. Specifically in the example of the fixed issue we have a `self_ty` of the form `&A<&[Coef]>` whereas the `impl_ty` of the method would be `&A<_>`, if we normalize the projection in the return type we unify the inference variable with `Cont`, which will lead us to reject the candidate in the sup type check in `consider_probe`. Since we don't actually need the normalized return type during candidate assembly, we postpone the normalization until we consider candidates in `consider_probe`.
2 parents 87df4dd + 3215403 commit 3250240

File tree

6 files changed

+74
-14
lines changed

6 files changed

+74
-14
lines changed

compiler/rustc_typeck/src/check/method/probe.rs

+35-10
Original file line numberDiff line numberDiff line change
@@ -753,17 +753,27 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
753753
let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id);
754754
let impl_ty = impl_ty.subst(self.tcx, impl_substs);
755755

756+
debug!("impl_ty: {:?}", impl_ty);
757+
756758
// Determine the receiver type that the method itself expects.
757-
let xform_tys = self.xform_self_ty(&item, impl_ty, impl_substs);
759+
let (xform_self_ty, xform_ret_ty) = self.xform_self_ty(&item, impl_ty, impl_substs);
760+
debug!("xform_self_ty: {:?}, xform_ret_ty: {:?}", xform_self_ty, xform_ret_ty);
758761

759762
// We can't use normalize_associated_types_in as it will pollute the
760763
// fcx's fulfillment context after this probe is over.
764+
// Note: we only normalize `xform_self_ty` here since the normalization
765+
// of the return type can lead to inference results that prohibit
766+
// valid canidates from being found, see issue #85671
767+
// FIXME Postponing the normalization of the return type likely only hides a deeper bug,
768+
// which might be caused by the `param_env` itself. The clauses of the `param_env`
769+
// maybe shouldn't include `Param`s, but rather fresh variables or be canonicalized,
770+
// see isssue #89650
761771
let cause = traits::ObligationCause::misc(self.span, self.body_id);
762772
let selcx = &mut traits::SelectionContext::new(self.fcx);
763-
let traits::Normalized { value: (xform_self_ty, xform_ret_ty), obligations } =
764-
traits::normalize(selcx, self.param_env, cause, xform_tys);
773+
let traits::Normalized { value: xform_self_ty, obligations } =
774+
traits::normalize(selcx, self.param_env, cause, xform_self_ty);
765775
debug!(
766-
"assemble_inherent_impl_probe: xform_self_ty = {:?}/{:?}",
776+
"assemble_inherent_impl_probe after normalization: xform_self_ty = {:?}/{:?}",
767777
xform_self_ty, xform_ret_ty
768778
);
769779

@@ -1420,6 +1430,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
14201430
};
14211431

14221432
let mut result = ProbeResult::Match;
1433+
let mut xform_ret_ty = probe.xform_ret_ty;
1434+
debug!(?xform_ret_ty);
1435+
14231436
let selcx = &mut traits::SelectionContext::new(self);
14241437
let cause = traits::ObligationCause::misc(self.span, self.body_id);
14251438

@@ -1428,7 +1441,17 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
14281441
// match as well (or at least may match, sometimes we
14291442
// don't have enough information to fully evaluate).
14301443
match probe.kind {
1431-
InherentImplCandidate(substs, ref ref_obligations) => {
1444+
InherentImplCandidate(ref substs, ref ref_obligations) => {
1445+
// `xform_ret_ty` hasn't been normalized yet, only `xform_self_ty`,
1446+
// see the reasons mentioned in the comments in `assemble_inherent_impl_probe`
1447+
// for why this is necessary
1448+
let traits::Normalized {
1449+
value: normalized_xform_ret_ty,
1450+
obligations: normalization_obligations,
1451+
} = traits::normalize(selcx, self.param_env, cause.clone(), probe.xform_ret_ty);
1452+
xform_ret_ty = normalized_xform_ret_ty;
1453+
debug!("xform_ret_ty after normalization: {:?}", xform_ret_ty);
1454+
14321455
// Check whether the impl imposes obligations we have to worry about.
14331456
let impl_def_id = probe.item.container.id();
14341457
let impl_bounds = self.tcx.predicates_of(impl_def_id);
@@ -1442,7 +1465,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
14421465

14431466
let candidate_obligations = impl_obligations
14441467
.chain(norm_obligations.into_iter())
1445-
.chain(ref_obligations.iter().cloned());
1468+
.chain(ref_obligations.iter().cloned())
1469+
.chain(normalization_obligations.into_iter());
1470+
14461471
// Evaluate those obligations to see if they might possibly hold.
14471472
for o in candidate_obligations {
14481473
let o = self.resolve_vars_if_possible(o);
@@ -1527,9 +1552,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
15271552
}
15281553

15291554
if let ProbeResult::Match = result {
1530-
if let (Some(return_ty), Some(xform_ret_ty)) =
1531-
(self.return_type, probe.xform_ret_ty)
1532-
{
1555+
if let (Some(return_ty), Some(xform_ret_ty)) = (self.return_type, xform_ret_ty) {
15331556
let xform_ret_ty = self.resolve_vars_if_possible(xform_ret_ty);
15341557
debug!(
15351558
"comparing return_ty {:?} with xform ret ty {:?}",
@@ -1669,6 +1692,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
16691692
self.static_candidates.push(source);
16701693
}
16711694

1695+
#[instrument(level = "debug", skip(self))]
16721696
fn xform_self_ty(
16731697
&self,
16741698
item: &ty::AssocItem,
@@ -1683,9 +1707,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
16831707
}
16841708
}
16851709

1710+
#[instrument(level = "debug", skip(self))]
16861711
fn xform_method_sig(&self, method: DefId, substs: SubstsRef<'tcx>) -> ty::FnSig<'tcx> {
16871712
let fn_sig = self.tcx.fn_sig(method);
1688-
debug!("xform_self_ty(fn_sig={:?}, substs={:?})", fn_sig, substs);
1713+
debug!(?fn_sig);
16891714

16901715
assert!(!substs.has_escaping_bound_vars());
16911716

src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ LL | let _result = &Some(42).as_deref();
66
|
77
= note: the following trait bounds were not satisfied:
88
`{integer}: Deref`
9-
`<{integer} as Deref>::Target = _`
109

1110
error: aborting due to previous error
1211

src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ LL | let _result = &mut Some(42).as_deref_mut();
66
|
77
= note: the following trait bounds were not satisfied:
88
`{integer}: DerefMut`
9-
`<{integer} as Deref>::Target = _`
9+
`{integer}: Deref`
1010

1111
error: aborting due to previous error
1212

src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ LL | let _result = &Ok(42).as_deref();
66
|
77
= note: the following trait bounds were not satisfied:
88
`{integer}: Deref`
9-
`<{integer} as Deref>::Target = _`
109

1110
error: aborting due to previous error
1211

src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ LL | let _result = &mut Ok(42).as_deref_mut();
66
|
77
= note: the following trait bounds were not satisfied:
88
`{integer}: DerefMut`
9-
`<{integer} as Deref>::Target = _`
9+
`{integer}: Deref`
1010

1111
error: aborting due to previous error
1212

src/test/ui/resolve/issue-85671.rs

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// check-pass
2+
3+
// Some trait with a function that returns a slice:
4+
pub trait AsSlice {
5+
type Element;
6+
fn as_slice(&self) -> &[Self::Element];
7+
}
8+
9+
// Some type
10+
pub struct A<Cont>(Cont);
11+
12+
// Here we say that if A wraps a slice, then it implements AsSlice
13+
impl<'a, Element> AsSlice for A<&'a [Element]> {
14+
type Element = Element;
15+
fn as_slice(&self) -> &[Self::Element] {
16+
self.0
17+
}
18+
}
19+
20+
impl<Cont> A<Cont> {
21+
// We want this function to work
22+
pub fn failing<Coef>(&self)
23+
where
24+
Self: AsSlice<Element = Coef>,
25+
{
26+
self.as_ref_a().as_ref_a();
27+
}
28+
29+
pub fn as_ref_a<Coef>(&self) -> A<&[<Self as AsSlice>::Element]>
30+
where
31+
Self: AsSlice<Element = Coef>,
32+
{
33+
A(self.as_slice())
34+
}
35+
}
36+
37+
fn main() {}

0 commit comments

Comments
 (0)