mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-27 09:14:20 +00:00
Rollup merge of #104258 - compiler-errors:tait-closure-deduce, r=oli-obk
Deduce closure signature from a type alias `impl Trait`'s supertraits r? `@oli-obk` Basically pass the TAIT's bounds through the same method that we're using to deduce a signature from infer var closure bounds. Does this need a new FCP? I see it as a logical extension of #101834, but happy to rfcbot a new one if it does.
This commit is contained in:
commit
34425c8c00
@ -173,34 +173,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
expected_ty: Ty<'tcx>,
|
expected_ty: Ty<'tcx>,
|
||||||
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
|
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
|
||||||
match *expected_ty.kind() {
|
match *expected_ty.kind() {
|
||||||
ty::Opaque(def_id, substs) => {
|
ty::Opaque(def_id, substs) => self.deduce_signature_from_predicates(
|
||||||
let bounds = self.tcx.bound_explicit_item_bounds(def_id);
|
self.tcx.bound_explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs),
|
||||||
let sig =
|
),
|
||||||
bounds.subst_iter_copied(self.tcx, substs).find_map(|(pred, span)| match pred
|
|
||||||
.kind()
|
|
||||||
.skip_binder()
|
|
||||||
{
|
|
||||||
ty::PredicateKind::Projection(proj_predicate) => self
|
|
||||||
.deduce_sig_from_projection(
|
|
||||||
Some(span),
|
|
||||||
pred.kind().rebind(proj_predicate),
|
|
||||||
),
|
|
||||||
_ => None,
|
|
||||||
});
|
|
||||||
|
|
||||||
let kind = bounds
|
|
||||||
.0
|
|
||||||
.iter()
|
|
||||||
.filter_map(|(pred, _)| match pred.kind().skip_binder() {
|
|
||||||
ty::PredicateKind::Trait(tp) => {
|
|
||||||
self.tcx.fn_trait_kind_from_lang_item(tp.def_id())
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur))));
|
|
||||||
trace!(?sig, ?kind);
|
|
||||||
(sig, kind)
|
|
||||||
}
|
|
||||||
ty::Dynamic(ref object_type, ..) => {
|
ty::Dynamic(ref object_type, ..) => {
|
||||||
let sig = object_type.projection_bounds().find_map(|pb| {
|
let sig = object_type.projection_bounds().find_map(|pb| {
|
||||||
let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self);
|
let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self);
|
||||||
@ -211,7 +186,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
.and_then(|did| self.tcx.fn_trait_kind_from_lang_item(did));
|
.and_then(|did| self.tcx.fn_trait_kind_from_lang_item(did));
|
||||||
(sig, kind)
|
(sig, kind)
|
||||||
}
|
}
|
||||||
ty::Infer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid),
|
ty::Infer(ty::TyVar(vid)) => self.deduce_signature_from_predicates(
|
||||||
|
self.obligations_for_self_ty(vid).map(|obl| (obl.predicate, obl.cause.span)),
|
||||||
|
),
|
||||||
ty::FnPtr(sig) => {
|
ty::FnPtr(sig) => {
|
||||||
let expected_sig = ExpectedSig { cause_span: None, sig };
|
let expected_sig = ExpectedSig { cause_span: None, sig };
|
||||||
(Some(expected_sig), Some(ty::ClosureKind::Fn))
|
(Some(expected_sig), Some(ty::ClosureKind::Fn))
|
||||||
@ -220,19 +197,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deduce_expectations_from_obligations(
|
fn deduce_signature_from_predicates(
|
||||||
&self,
|
&self,
|
||||||
expected_vid: ty::TyVid,
|
predicates: impl DoubleEndedIterator<Item = (ty::Predicate<'tcx>, Span)>,
|
||||||
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
|
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
|
||||||
let mut expected_sig = None;
|
let mut expected_sig = None;
|
||||||
let mut expected_kind = None;
|
let mut expected_kind = None;
|
||||||
|
|
||||||
for obligation in traits::elaborate_obligations(
|
for obligation in traits::elaborate_predicates_with_span(
|
||||||
self.tcx,
|
self.tcx,
|
||||||
// Reverse the obligations here, since `elaborate_*` uses a stack,
|
// Reverse the obligations here, since `elaborate_*` uses a stack,
|
||||||
// and we want to keep inference generally in the same order of
|
// and we want to keep inference generally in the same order of
|
||||||
// the registered obligations.
|
// the registered obligations.
|
||||||
self.obligations_for_self_ty(expected_vid).rev().collect(),
|
predicates.rev(),
|
||||||
) {
|
) {
|
||||||
debug!(?obligation.predicate);
|
debug!(?obligation.predicate);
|
||||||
let bound_predicate = obligation.predicate.kind();
|
let bound_predicate = obligation.predicate.kind();
|
||||||
|
@ -6,7 +6,6 @@ use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts};
|
|||||||
use crate::ty::visit::{TypeVisitable, TypeVisitor};
|
use crate::ty::visit::{TypeVisitable, TypeVisitor};
|
||||||
use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
|
use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
|
||||||
|
|
||||||
use rustc_data_structures::captures::Captures;
|
|
||||||
use rustc_data_structures::intern::{Interned, WithStableHash};
|
use rustc_data_structures::intern::{Interned, WithStableHash};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_macros::HashStable;
|
use rustc_macros::HashStable;
|
||||||
@ -19,7 +18,7 @@ use std::fmt;
|
|||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::{ControlFlow, Deref};
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
|
||||||
/// An entity in the Rust type system, which can be one of
|
/// An entity in the Rust type system, which can be one of
|
||||||
@ -562,25 +561,86 @@ impl<T, U> EarlyBinder<(T, U)> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, 's, T: IntoIterator<Item = I>, I: TypeFoldable<'tcx>> EarlyBinder<T> {
|
impl<'tcx, 's, I: IntoIterator> EarlyBinder<I>
|
||||||
|
where
|
||||||
|
I::Item: TypeFoldable<'tcx>,
|
||||||
|
{
|
||||||
pub fn subst_iter(
|
pub fn subst_iter(
|
||||||
self,
|
self,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
substs: &'s [GenericArg<'tcx>],
|
substs: &'s [GenericArg<'tcx>],
|
||||||
) -> impl Iterator<Item = I> + Captures<'s> + Captures<'tcx> {
|
) -> SubstIter<'s, 'tcx, I> {
|
||||||
self.0.into_iter().map(move |t| EarlyBinder(t).subst(tcx, substs))
|
SubstIter { it: self.0.into_iter(), tcx, substs }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, 's, 'a, T: IntoIterator<Item = &'a I>, I: Copy + TypeFoldable<'tcx> + 'a>
|
pub struct SubstIter<'s, 'tcx, I: IntoIterator> {
|
||||||
EarlyBinder<T>
|
it: I::IntoIter,
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
substs: &'s [GenericArg<'tcx>],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx, I: IntoIterator> Iterator for SubstIter<'_, 'tcx, I>
|
||||||
|
where
|
||||||
|
I::Item: TypeFoldable<'tcx>,
|
||||||
|
{
|
||||||
|
type Item = I::Item;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
Some(EarlyBinder(self.it.next()?).subst(self.tcx, self.substs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx, I: IntoIterator> DoubleEndedIterator for SubstIter<'_, 'tcx, I>
|
||||||
|
where
|
||||||
|
I::IntoIter: DoubleEndedIterator,
|
||||||
|
I::Item: TypeFoldable<'tcx>,
|
||||||
|
{
|
||||||
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
|
Some(EarlyBinder(self.it.next_back()?).subst(self.tcx, self.substs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx, 's, I: IntoIterator> EarlyBinder<I>
|
||||||
|
where
|
||||||
|
I::Item: Deref,
|
||||||
|
<I::Item as Deref>::Target: Copy + TypeFoldable<'tcx>,
|
||||||
{
|
{
|
||||||
pub fn subst_iter_copied(
|
pub fn subst_iter_copied(
|
||||||
self,
|
self,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
substs: &'s [GenericArg<'tcx>],
|
substs: &'s [GenericArg<'tcx>],
|
||||||
) -> impl Iterator<Item = I> + Captures<'s> + Captures<'tcx> + Captures<'a> {
|
) -> SubstIterCopied<'s, 'tcx, I> {
|
||||||
self.0.into_iter().map(move |t| EarlyBinder(*t).subst(tcx, substs))
|
SubstIterCopied { it: self.0.into_iter(), tcx, substs }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SubstIterCopied<'a, 'tcx, I: IntoIterator> {
|
||||||
|
it: I::IntoIter,
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
substs: &'a [GenericArg<'tcx>],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx, I: IntoIterator> Iterator for SubstIterCopied<'_, 'tcx, I>
|
||||||
|
where
|
||||||
|
I::Item: Deref,
|
||||||
|
<I::Item as Deref>::Target: Copy + TypeFoldable<'tcx>,
|
||||||
|
{
|
||||||
|
type Item = <I::Item as Deref>::Target;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
Some(EarlyBinder(*self.it.next()?).subst(self.tcx, self.substs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx, I: IntoIterator> DoubleEndedIterator for SubstIterCopied<'_, 'tcx, I>
|
||||||
|
where
|
||||||
|
I::IntoIter: DoubleEndedIterator,
|
||||||
|
I::Item: Deref,
|
||||||
|
<I::Item as Deref>::Target: Copy + TypeFoldable<'tcx>,
|
||||||
|
{
|
||||||
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
|
Some(EarlyBinder(*self.it.next_back()?).subst(self.tcx, self.substs))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
15
src/test/ui/impl-trait/deduce-signature-from-supertrait.rs
Normal file
15
src/test/ui/impl-trait/deduce-signature-from-supertrait.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
trait SuperExpectation: Fn(i32) {}
|
||||||
|
|
||||||
|
impl<T: Fn(i32)> SuperExpectation for T {}
|
||||||
|
|
||||||
|
type Foo = impl SuperExpectation;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _: Foo = |x| {
|
||||||
|
let _ = x.to_string();
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user