Skip to content

Commit 6718ea1

Browse files
committed
Auto merge of #101834 - compiler-errors:super-deduce-closure-sig, r=lcnr
Elaborate supertrait obligations when deducing closure signatures We elaborate the supertrait obligations of any registered predicates for a closure to see if we can infer a closure signature. This is not as general of a fix as it *could* be, since we just elaborate supertrait bounds instead of doing a theoretical walk of _all_ registered predicates that might cause us to deduce `Fn` trait information for a closure infer var. I don't even know how to come up with an example that fails here but would work with a more general system. Fixes #23012 Also fixes the existing compile failure in #57611 r? `@ghost` for now until I do a perf run cc `@nikomatsakis` since you commented on #23012 (comment)
2 parents 215e3cd + bc3516d commit 6718ea1

File tree

5 files changed

+125
-102
lines changed

5 files changed

+125
-102
lines changed

compiler/rustc_hir_typeck/src/closure.rs

+45-27
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use rustc_middle::ty::visit::TypeVisitable;
1515
use rustc_middle::ty::{self, Ty};
1616
use rustc_span::source_map::Span;
1717
use rustc_target::spec::abi::Abi;
18+
use rustc_trait_selection::traits;
1819
use rustc_trait_selection::traits::error_reporting::ArgKind;
1920
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
2021
use std::cmp;
@@ -225,33 +226,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
225226
&self,
226227
expected_vid: ty::TyVid,
227228
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
228-
let expected_sig =
229-
self.obligations_for_self_ty(expected_vid).find_map(|(_, obligation)| {
230-
debug!(?obligation.predicate);
231-
232-
let bound_predicate = obligation.predicate.kind();
233-
if let ty::PredicateKind::Projection(proj_predicate) =
234-
obligation.predicate.kind().skip_binder()
235-
{
236-
// Given a Projection predicate, we can potentially infer
237-
// the complete signature.
238-
self.deduce_sig_from_projection(
239-
Some(obligation.cause.span),
240-
bound_predicate.rebind(proj_predicate),
241-
)
242-
} else {
243-
None
244-
}
245-
});
229+
let mut expected_sig = None;
230+
let mut expected_kind = None;
231+
232+
for obligation in traits::elaborate_obligations(
233+
self.tcx,
234+
// Reverse the obligations here, since `elaborate_*` uses a stack,
235+
// and we want to keep inference generally in the same order of
236+
// the registered obligations.
237+
self.obligations_for_self_ty(expected_vid).rev().collect(),
238+
) {
239+
debug!(?obligation.predicate);
240+
let bound_predicate = obligation.predicate.kind();
241+
242+
// Given a Projection predicate, we can potentially infer
243+
// the complete signature.
244+
if expected_sig.is_none()
245+
&& let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder()
246+
{
247+
expected_sig = self.deduce_sig_from_projection(
248+
Some(obligation.cause.span),
249+
bound_predicate.rebind(proj_predicate),
250+
);
251+
}
246252

247-
// Even if we can't infer the full signature, we may be able to
248-
// infer the kind. This can occur when we elaborate a predicate
249-
// like `F : Fn<A>`. Note that due to subtyping we could encounter
250-
// many viable options, so pick the most restrictive.
251-
let expected_kind = self
252-
.obligations_for_self_ty(expected_vid)
253-
.filter_map(|(tr, _)| self.tcx.fn_trait_kind_from_lang_item(tr.def_id()))
254-
.fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur))));
253+
// Even if we can't infer the full signature, we may be able to
254+
// infer the kind. This can occur when we elaborate a predicate
255+
// like `F : Fn<A>`. Note that due to subtyping we could encounter
256+
// many viable options, so pick the most restrictive.
257+
let trait_def_id = match bound_predicate.skip_binder() {
258+
ty::PredicateKind::Projection(data) => {
259+
Some(data.projection_ty.trait_def_id(self.tcx))
260+
}
261+
ty::PredicateKind::Trait(data) => Some(data.def_id()),
262+
_ => None,
263+
};
264+
if let Some(closure_kind) =
265+
trait_def_id.and_then(|def_id| self.tcx.fn_trait_kind_from_lang_item(def_id))
266+
{
267+
expected_kind = Some(
268+
expected_kind
269+
.map_or_else(|| closure_kind, |current| cmp::min(current, closure_kind)),
270+
);
271+
}
272+
}
255273

256274
(expected_sig, expected_kind)
257275
}
@@ -689,7 +707,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
689707

690708
let output_ty = match *ret_ty.kind() {
691709
ty::Infer(ty::TyVar(ret_vid)) => {
692-
self.obligations_for_self_ty(ret_vid).find_map(|(_, obligation)| {
710+
self.obligations_for_self_ty(ret_vid).find_map(|obligation| {
693711
get_future_output(obligation.predicate, obligation.cause.span)
694712
})?
695713
}

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

+50-47
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMut
2121
use rustc_middle::ty::fold::TypeFoldable;
2222
use rustc_middle::ty::visit::TypeVisitable;
2323
use rustc_middle::ty::{
24-
self, AdtKind, CanonicalUserType, DefIdTree, EarlyBinder, GenericParamDefKind, ToPolyTraitRef,
25-
ToPredicate, Ty, UserType,
24+
self, AdtKind, CanonicalUserType, DefIdTree, EarlyBinder, GenericParamDefKind, ToPredicate, Ty,
25+
UserType,
2626
};
2727
use rustc_middle::ty::{GenericArgKind, InternalSubsts, SubstsRef, UserSelfTy, UserSubsts};
2828
use rustc_session::lint;
@@ -650,12 +650,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
650650
}
651651

652652
#[instrument(skip(self), level = "debug")]
653-
fn self_type_matches_expected_vid(
654-
&self,
655-
trait_ref: ty::PolyTraitRef<'tcx>,
656-
expected_vid: ty::TyVid,
657-
) -> bool {
658-
let self_ty = self.shallow_resolve(trait_ref.skip_binder().self_ty());
653+
fn self_type_matches_expected_vid(&self, self_ty: Ty<'tcx>, expected_vid: ty::TyVid) -> bool {
654+
let self_ty = self.shallow_resolve(self_ty);
659655
debug!(?self_ty);
660656

661657
match *self_ty.kind() {
@@ -674,54 +670,61 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
674670
pub(in super::super) fn obligations_for_self_ty<'b>(
675671
&'b self,
676672
self_ty: ty::TyVid,
677-
) -> impl Iterator<Item = (ty::PolyTraitRef<'tcx>, traits::PredicateObligation<'tcx>)>
678-
+ Captures<'tcx>
679-
+ 'b {
673+
) -> impl DoubleEndedIterator<Item = traits::PredicateObligation<'tcx>> + Captures<'tcx> + 'b
674+
{
680675
// FIXME: consider using `sub_root_var` here so we
681676
// can see through subtyping.
682677
let ty_var_root = self.root_var(self_ty);
683678
trace!("pending_obligations = {:#?}", self.fulfillment_cx.borrow().pending_obligations());
684679

685-
self.fulfillment_cx
686-
.borrow()
687-
.pending_obligations()
688-
.into_iter()
689-
.filter_map(move |obligation| {
690-
let bound_predicate = obligation.predicate.kind();
691-
match bound_predicate.skip_binder() {
692-
ty::PredicateKind::Projection(data) => Some((
693-
bound_predicate.rebind(data).required_poly_trait_ref(self.tcx),
694-
obligation,
695-
)),
696-
ty::PredicateKind::Trait(data) => {
697-
Some((bound_predicate.rebind(data).to_poly_trait_ref(), obligation))
698-
}
699-
ty::PredicateKind::Subtype(..) => None,
700-
ty::PredicateKind::Coerce(..) => None,
701-
ty::PredicateKind::RegionOutlives(..) => None,
702-
ty::PredicateKind::TypeOutlives(..) => None,
703-
ty::PredicateKind::WellFormed(..) => None,
704-
ty::PredicateKind::ObjectSafe(..) => None,
705-
ty::PredicateKind::ConstEvaluatable(..) => None,
706-
ty::PredicateKind::ConstEquate(..) => None,
707-
// N.B., this predicate is created by breaking down a
708-
// `ClosureType: FnFoo()` predicate, where
709-
// `ClosureType` represents some `Closure`. It can't
710-
// possibly be referring to the current closure,
711-
// because we haven't produced the `Closure` for
712-
// this closure yet; this is exactly why the other
713-
// code is looking for a self type of an unresolved
714-
// inference variable.
715-
ty::PredicateKind::ClosureKind(..) => None,
716-
ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
680+
self.fulfillment_cx.borrow().pending_obligations().into_iter().filter_map(
681+
move |obligation| match &obligation.predicate.kind().skip_binder() {
682+
ty::PredicateKind::Projection(data)
683+
if self.self_type_matches_expected_vid(
684+
data.projection_ty.self_ty(),
685+
ty_var_root,
686+
) =>
687+
{
688+
Some(obligation)
717689
}
718-
})
719-
.filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root))
690+
ty::PredicateKind::Trait(data)
691+
if self.self_type_matches_expected_vid(data.self_ty(), ty_var_root) =>
692+
{
693+
Some(obligation)
694+
}
695+
696+
ty::PredicateKind::Trait(..)
697+
| ty::PredicateKind::Projection(..)
698+
| ty::PredicateKind::Subtype(..)
699+
| ty::PredicateKind::Coerce(..)
700+
| ty::PredicateKind::RegionOutlives(..)
701+
| ty::PredicateKind::TypeOutlives(..)
702+
| ty::PredicateKind::WellFormed(..)
703+
| ty::PredicateKind::ObjectSafe(..)
704+
| ty::PredicateKind::ConstEvaluatable(..)
705+
| ty::PredicateKind::ConstEquate(..)
706+
// N.B., this predicate is created by breaking down a
707+
// `ClosureType: FnFoo()` predicate, where
708+
// `ClosureType` represents some `Closure`. It can't
709+
// possibly be referring to the current closure,
710+
// because we haven't produced the `Closure` for
711+
// this closure yet; this is exactly why the other
712+
// code is looking for a self type of an unresolved
713+
// inference variable.
714+
| ty::PredicateKind::ClosureKind(..)
715+
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
716+
},
717+
)
720718
}
721719

722720
pub(in super::super) fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool {
723-
self.obligations_for_self_ty(self_ty)
724-
.any(|(tr, _)| Some(tr.def_id()) == self.tcx.lang_items().sized_trait())
721+
let sized_did = self.tcx.lang_items().sized_trait();
722+
self.obligations_for_self_ty(self_ty).any(|obligation| {
723+
match obligation.predicate.kind().skip_binder() {
724+
ty::PredicateKind::Trait(data) => Some(data.def_id()) == sized_did,
725+
_ => false,
726+
}
727+
})
725728
}
726729

727730
pub(in super::super) fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// check-pass
2+
// Checks that we can infer a closure signature even if the `FnOnce` bound is
3+
// a supertrait of the obligations we have currently registered for the Ty var.
4+
5+
pub trait Receive<T, E>: FnOnce(Result<T, E>) {
6+
fn receive(self, res: Result<T, E>);
7+
}
8+
9+
impl<T, E, F: FnOnce(Result<T, E>)> Receive<T, E> for F {
10+
fn receive(self, res: Result<T, E>) {
11+
self(res)
12+
}
13+
}
14+
15+
pub trait Async<T, E> {
16+
fn receive<F: Receive<T, E>>(self, f: F);
17+
}
18+
19+
impl<T, E> Async<T, E> for Result<T, E> {
20+
fn receive<F: Receive<T, E>>(self, f: F) {
21+
f(self)
22+
}
23+
}
24+
25+
pub fn main() {
26+
Ok::<u32, ()>(123).receive(|res| {
27+
res.unwrap();
28+
});
29+
}

src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1+
// check-pass
12
// Regression test for issue #57611
23
// Ensures that we don't ICE
3-
// FIXME: This should compile, but it currently doesn't
4-
// known-bug: unknown
54

65
#![feature(trait_alias)]
76
#![feature(type_alias_impl_trait)]

src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr

-26
This file was deleted.

0 commit comments

Comments
 (0)