diff options
| author | Michael Goulet <michael@errs.io> | 2022-09-15 00:35:23 +0000 |
|---|---|---|
| committer | Michael Goulet <michael@errs.io> | 2022-11-03 15:52:38 +0000 |
| commit | caa701e3c190c4d77634c9075548746e4917e56d (patch) | |
| tree | 5d51fa43a97f2c9a3788be4170b5abdcb2be957d | |
| parent | 060d4392b1679fa4f7323ee702a7669af281d5db (diff) | |
| download | rust-caa701e3c190c4d77634c9075548746e4917e56d.tar.gz rust-caa701e3c190c4d77634c9075548746e4917e56d.zip | |
Elaborate supertrait obligations when deducing closure signature
4 files changed, 41 insertions, 35 deletions
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index cc1191d3245..4f8ac45d5a6 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -15,6 +15,7 @@ use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{self, Ty}; use rustc_span::source_map::Span; use rustc_target::spec::abi::Abi; +use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::ArgKind; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use std::cmp; @@ -226,27 +227,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_vid: ty::TyVid, ) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) { let mut expected_sig = None; - // Even if we can't infer the full signature, we may be able to - // infer the kind. This can occur when we elaborate a predicate - // like `F : Fn<A>`. Note that due to subtyping we could encounter - // many viable options, so pick the most restrictive. let mut expected_kind = None; - for obligation in self.obligations_for_self_ty(expected_vid) { + for obligation in traits::elaborate_obligations( + self.tcx, + self.obligations_for_self_ty(expected_vid).collect(), + ) { debug!(?obligation.predicate); let bound_predicate = obligation.predicate.kind(); + // Given a Projection predicate, we can potentially infer + // the complete signature. if expected_sig.is_none() && let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder() { - // Given a Projection predicate, we can potentially infer - // the complete signature. expected_sig = self.deduce_sig_from_projection( Some(obligation.cause.span), bound_predicate.rebind(proj_predicate), ); } + // Even if we can't infer the full signature, we may be able to + // infer the kind. This can occur when we elaborate a predicate + // like `F : Fn<A>`. Note that due to subtyping we could encounter + // many viable options, so pick the most restrictive. let trait_def_id = match bound_predicate.skip_binder() { ty::PredicateKind::Projection(data) => { Some(data.projection_ty.trait_def_id(self.tcx)) diff --git a/src/test/ui/closures/issue-23012-supertrait-signature-inference.rs b/src/test/ui/closures/issue-23012-supertrait-signature-inference.rs new file mode 100644 index 00000000000..5899b703e7c --- /dev/null +++ b/src/test/ui/closures/issue-23012-supertrait-signature-inference.rs @@ -0,0 +1,29 @@ +// check-pass +// Checks that we can infer a closure signature even if the `FnOnce` bound is +// a supertrait of the obligations we have currently registered for the Ty var. + +pub trait Receive<T, E>: FnOnce(Result<T, E>) { + fn receive(self, res: Result<T, E>); +} + +impl<T, E, F: FnOnce(Result<T, E>)> Receive<T, E> for F { + fn receive(self, res: Result<T, E>) { + self(res) + } +} + +pub trait Async<T, E> { + fn receive<F: Receive<T, E>>(self, f: F); +} + +impl<T, E> Async<T, E> for Result<T, E> { + fn receive<F: Receive<T, E>>(self, f: F) { + f(self) + } +} + +pub fn main() { + Ok::<u32, ()>(123).receive(|res| { + res.unwrap(); + }); +} diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs index 067ed7ea1e5..cad3e0f6677 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs @@ -1,7 +1,6 @@ +// check-pass // Regression test for issue #57611 // Ensures that we don't ICE -// FIXME: This should compile, but it currently doesn't -// known-bug: unknown #![feature(trait_alias)] #![feature(type_alias_impl_trait)] diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr deleted file mode 100644 index 6344f114a91..00000000000 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/issue-57611-trait-alias.rs:21:9 - | -LL | |x| x - | ^^^^^ one type is more general than the other - | - = note: expected trait `for<'a> Fn<(&'a X,)>` - found trait `Fn<(&X,)>` -note: this closure does not fulfill the lifetime requirements - --> $DIR/issue-57611-trait-alias.rs:21:9 - | -LL | |x| x - | ^^^ - -error: implementation of `FnOnce` is not general enough - --> $DIR/issue-57611-trait-alias.rs:21:9 - | -LL | |x| x - | ^^^^^ implementation of `FnOnce` is not general enough - | - = note: closure with signature `fn(&'2 X) -> &X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0308`. |
