mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Rollup merge of #86506 - b-naber:gen_trait_impl_inconsistent, r=jackh726
Don't normalize xform_ret_ty during method candidate assembly Fixes https://github.com/rust-lang/rust/issues/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`.
This commit is contained in:
commit
32502404e5
@ -753,17 +753,27 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id);
|
||||
let impl_ty = impl_ty.subst(self.tcx, impl_substs);
|
||||
|
||||
debug!("impl_ty: {:?}", impl_ty);
|
||||
|
||||
// Determine the receiver type that the method itself expects.
|
||||
let xform_tys = self.xform_self_ty(&item, impl_ty, impl_substs);
|
||||
let (xform_self_ty, xform_ret_ty) = self.xform_self_ty(&item, impl_ty, impl_substs);
|
||||
debug!("xform_self_ty: {:?}, xform_ret_ty: {:?}", xform_self_ty, xform_ret_ty);
|
||||
|
||||
// We can't use normalize_associated_types_in as it will pollute the
|
||||
// fcx's fulfillment context after this probe is over.
|
||||
// Note: we only normalize `xform_self_ty` here since the normalization
|
||||
// of the return type can lead to inference results that prohibit
|
||||
// valid canidates from being found, see issue #85671
|
||||
// FIXME Postponing the normalization of the return type likely only hides a deeper bug,
|
||||
// which might be caused by the `param_env` itself. The clauses of the `param_env`
|
||||
// maybe shouldn't include `Param`s, but rather fresh variables or be canonicalized,
|
||||
// see isssue #89650
|
||||
let cause = traits::ObligationCause::misc(self.span, self.body_id);
|
||||
let selcx = &mut traits::SelectionContext::new(self.fcx);
|
||||
let traits::Normalized { value: (xform_self_ty, xform_ret_ty), obligations } =
|
||||
traits::normalize(selcx, self.param_env, cause, xform_tys);
|
||||
let traits::Normalized { value: xform_self_ty, obligations } =
|
||||
traits::normalize(selcx, self.param_env, cause, xform_self_ty);
|
||||
debug!(
|
||||
"assemble_inherent_impl_probe: xform_self_ty = {:?}/{:?}",
|
||||
"assemble_inherent_impl_probe after normalization: xform_self_ty = {:?}/{:?}",
|
||||
xform_self_ty, xform_ret_ty
|
||||
);
|
||||
|
||||
@ -1420,6 +1430,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
};
|
||||
|
||||
let mut result = ProbeResult::Match;
|
||||
let mut xform_ret_ty = probe.xform_ret_ty;
|
||||
debug!(?xform_ret_ty);
|
||||
|
||||
let selcx = &mut traits::SelectionContext::new(self);
|
||||
let cause = traits::ObligationCause::misc(self.span, self.body_id);
|
||||
|
||||
@ -1428,7 +1441,17 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
// match as well (or at least may match, sometimes we
|
||||
// don't have enough information to fully evaluate).
|
||||
match probe.kind {
|
||||
InherentImplCandidate(substs, ref ref_obligations) => {
|
||||
InherentImplCandidate(ref substs, ref ref_obligations) => {
|
||||
// `xform_ret_ty` hasn't been normalized yet, only `xform_self_ty`,
|
||||
// see the reasons mentioned in the comments in `assemble_inherent_impl_probe`
|
||||
// for why this is necessary
|
||||
let traits::Normalized {
|
||||
value: normalized_xform_ret_ty,
|
||||
obligations: normalization_obligations,
|
||||
} = traits::normalize(selcx, self.param_env, cause.clone(), probe.xform_ret_ty);
|
||||
xform_ret_ty = normalized_xform_ret_ty;
|
||||
debug!("xform_ret_ty after normalization: {:?}", xform_ret_ty);
|
||||
|
||||
// Check whether the impl imposes obligations we have to worry about.
|
||||
let impl_def_id = probe.item.container.id();
|
||||
let impl_bounds = self.tcx.predicates_of(impl_def_id);
|
||||
@ -1442,7 +1465,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
|
||||
let candidate_obligations = impl_obligations
|
||||
.chain(norm_obligations.into_iter())
|
||||
.chain(ref_obligations.iter().cloned());
|
||||
.chain(ref_obligations.iter().cloned())
|
||||
.chain(normalization_obligations.into_iter());
|
||||
|
||||
// Evaluate those obligations to see if they might possibly hold.
|
||||
for o in candidate_obligations {
|
||||
let o = self.resolve_vars_if_possible(o);
|
||||
@ -1527,9 +1552,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
}
|
||||
|
||||
if let ProbeResult::Match = result {
|
||||
if let (Some(return_ty), Some(xform_ret_ty)) =
|
||||
(self.return_type, probe.xform_ret_ty)
|
||||
{
|
||||
if let (Some(return_ty), Some(xform_ret_ty)) = (self.return_type, xform_ret_ty) {
|
||||
let xform_ret_ty = self.resolve_vars_if_possible(xform_ret_ty);
|
||||
debug!(
|
||||
"comparing return_ty {:?} with xform ret ty {:?}",
|
||||
@ -1669,6 +1692,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
self.static_candidates.push(source);
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn xform_self_ty(
|
||||
&self,
|
||||
item: &ty::AssocItem,
|
||||
@ -1683,9 +1707,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn xform_method_sig(&self, method: DefId, substs: SubstsRef<'tcx>) -> ty::FnSig<'tcx> {
|
||||
let fn_sig = self.tcx.fn_sig(method);
|
||||
debug!("xform_self_ty(fn_sig={:?}, substs={:?})", fn_sig, substs);
|
||||
debug!(?fn_sig);
|
||||
|
||||
assert!(!substs.has_escaping_bound_vars());
|
||||
|
||||
|
@ -6,7 +6,6 @@ LL | let _result = &Some(42).as_deref();
|
||||
|
|
||||
= note: the following trait bounds were not satisfied:
|
||||
`{integer}: Deref`
|
||||
`<{integer} as Deref>::Target = _`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -6,7 +6,7 @@ LL | let _result = &mut Some(42).as_deref_mut();
|
||||
|
|
||||
= note: the following trait bounds were not satisfied:
|
||||
`{integer}: DerefMut`
|
||||
`<{integer} as Deref>::Target = _`
|
||||
`{integer}: Deref`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -6,7 +6,6 @@ LL | let _result = &Ok(42).as_deref();
|
||||
|
|
||||
= note: the following trait bounds were not satisfied:
|
||||
`{integer}: Deref`
|
||||
`<{integer} as Deref>::Target = _`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -6,7 +6,7 @@ LL | let _result = &mut Ok(42).as_deref_mut();
|
||||
|
|
||||
= note: the following trait bounds were not satisfied:
|
||||
`{integer}: DerefMut`
|
||||
`<{integer} as Deref>::Target = _`
|
||||
`{integer}: Deref`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
37
src/test/ui/resolve/issue-85671.rs
Normal file
37
src/test/ui/resolve/issue-85671.rs
Normal file
@ -0,0 +1,37 @@
|
||||
// check-pass
|
||||
|
||||
// Some trait with a function that returns a slice:
|
||||
pub trait AsSlice {
|
||||
type Element;
|
||||
fn as_slice(&self) -> &[Self::Element];
|
||||
}
|
||||
|
||||
// Some type
|
||||
pub struct A<Cont>(Cont);
|
||||
|
||||
// Here we say that if A wraps a slice, then it implements AsSlice
|
||||
impl<'a, Element> AsSlice for A<&'a [Element]> {
|
||||
type Element = Element;
|
||||
fn as_slice(&self) -> &[Self::Element] {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<Cont> A<Cont> {
|
||||
// We want this function to work
|
||||
pub fn failing<Coef>(&self)
|
||||
where
|
||||
Self: AsSlice<Element = Coef>,
|
||||
{
|
||||
self.as_ref_a().as_ref_a();
|
||||
}
|
||||
|
||||
pub fn as_ref_a<Coef>(&self) -> A<&[<Self as AsSlice>::Element]>
|
||||
where
|
||||
Self: AsSlice<Element = Coef>,
|
||||
{
|
||||
A(self.as_slice())
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Reference in New Issue
Block a user