mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Rollup merge of #155096 - aerooneqq:delegation-user-specified-args-impl-traits, r=petrochenkov
delegation: support proper interaction of user-specified args and impl Traits
This PR supports usages of user-specified args with impl Traits. When there are user-specified args in child we still need to generate synthetic generic params and use them during signature inheritance:
```rust
fn foo<T, const N: usize>(f: impl FnOnce()) {}
reuse foo::<String, 123> as bar;
//desugaring
fn bar<TSynth: impl FnOnce()>(f: _) {
foo::<String, 123>(f)
}
```
When inheriting predicates we process impl Trait ones, so we need generic params to instantiate them. Other approach may involve not generating synthetic generic params and try to filter out those predicates, but fairly generating synthetic params seems more consistent?.
Fixes rust-lang/rust#154780, part of rust-lang/rust#118212.
r? @petrochenkov
This commit is contained in:
@@ -10,18 +10,38 @@
|
||||
|
||||
use crate::{LoweringContext, ResolverAstLoweringExt};
|
||||
|
||||
pub(super) enum DelegationGenerics<T> {
|
||||
#[derive(Clone, Copy)]
|
||||
pub(super) enum DelegationGenericsKind {
|
||||
/// User-specified args are present: `reuse foo::<String>;`.
|
||||
UserSpecified,
|
||||
/// The default case when no user-specified args are present: `reuse Trait::foo;`.
|
||||
Default(T),
|
||||
Default,
|
||||
/// In free-to-trait reuse, when user specified args for trait `reuse Trait::<i32>::foo;`
|
||||
/// in this case we need to both generate `Self` and process user args.
|
||||
SelfAndUserSpecified(T),
|
||||
SelfAndUserSpecified,
|
||||
/// In delegations from trait impl to other entities like free functions or trait functions,
|
||||
/// we want to generate a function whose generics matches generics of signature function
|
||||
/// in trait.
|
||||
TraitImpl(T, bool /* Has user-specified args */),
|
||||
TraitImpl(bool /* Has user-specified args */),
|
||||
}
|
||||
|
||||
pub(super) struct DelegationGenerics<T> {
|
||||
generics: T,
|
||||
kind: DelegationGenericsKind,
|
||||
}
|
||||
|
||||
impl<'hir> DelegationGenerics<&'hir [ty::GenericParamDef]> {
|
||||
fn default(generics: &'hir [ty::GenericParamDef]) -> Self {
|
||||
DelegationGenerics { generics, kind: DelegationGenericsKind::Default }
|
||||
}
|
||||
|
||||
fn user_specified(generics: &'hir [ty::GenericParamDef]) -> Self {
|
||||
DelegationGenerics { generics, kind: DelegationGenericsKind::UserSpecified }
|
||||
}
|
||||
|
||||
fn trait_impl(generics: &'hir [ty::GenericParamDef], user_specified: bool) -> Self {
|
||||
DelegationGenerics { generics, kind: DelegationGenericsKind::TraitImpl(user_specified) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Used for storing either ty generics or their uplifted HIR version. First we obtain
|
||||
@@ -54,20 +74,19 @@ pub(super) struct GenericArgsPropagationDetails {
|
||||
pub(super) use_args_in_sig_inheritance: bool,
|
||||
}
|
||||
|
||||
impl<T> DelegationGenerics<T> {
|
||||
fn args_propagation_details(&self) -> GenericArgsPropagationDetails {
|
||||
impl DelegationGenericsKind {
|
||||
fn args_propagation_details(self) -> GenericArgsPropagationDetails {
|
||||
match self {
|
||||
DelegationGenerics::UserSpecified | DelegationGenerics::SelfAndUserSpecified { .. } => {
|
||||
GenericArgsPropagationDetails {
|
||||
should_propagate: false,
|
||||
use_args_in_sig_inheritance: true,
|
||||
}
|
||||
}
|
||||
DelegationGenerics::TraitImpl(_, user_specified) => GenericArgsPropagationDetails {
|
||||
should_propagate: !*user_specified,
|
||||
DelegationGenericsKind::UserSpecified
|
||||
| DelegationGenericsKind::SelfAndUserSpecified => GenericArgsPropagationDetails {
|
||||
should_propagate: false,
|
||||
use_args_in_sig_inheritance: true,
|
||||
},
|
||||
DelegationGenericsKind::TraitImpl(user_specified) => GenericArgsPropagationDetails {
|
||||
should_propagate: !user_specified,
|
||||
use_args_in_sig_inheritance: false,
|
||||
},
|
||||
DelegationGenerics::Default(_) => GenericArgsPropagationDetails {
|
||||
DelegationGenericsKind::Default => GenericArgsPropagationDetails {
|
||||
should_propagate: true,
|
||||
use_args_in_sig_inheritance: false,
|
||||
},
|
||||
@@ -81,25 +100,9 @@ pub(super) fn into_hir_generics(
|
||||
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
|
||||
span: Span,
|
||||
) -> &mut HirOrTyGenerics<'hir> {
|
||||
if let HirOrTyGenerics::Ty(params) = self {
|
||||
let mut uplift_params = |generics: &'hir [ty::GenericParamDef]| {
|
||||
ctx.uplift_delegation_generic_params(span, generics)
|
||||
};
|
||||
|
||||
let hir_generics = match params {
|
||||
DelegationGenerics::UserSpecified => DelegationGenerics::UserSpecified,
|
||||
DelegationGenerics::Default(params) => {
|
||||
DelegationGenerics::Default(uplift_params(params))
|
||||
}
|
||||
DelegationGenerics::SelfAndUserSpecified(params) => {
|
||||
DelegationGenerics::SelfAndUserSpecified(uplift_params(params))
|
||||
}
|
||||
DelegationGenerics::TraitImpl(params, user_specified) => {
|
||||
DelegationGenerics::TraitImpl(uplift_params(params), *user_specified)
|
||||
}
|
||||
};
|
||||
|
||||
*self = HirOrTyGenerics::Hir(hir_generics);
|
||||
if let HirOrTyGenerics::Ty(ty) = self {
|
||||
let params = ctx.uplift_delegation_generic_params(span, ty.generics);
|
||||
*self = HirOrTyGenerics::Hir(DelegationGenerics { generics: params, kind: ty.kind });
|
||||
}
|
||||
|
||||
self
|
||||
@@ -108,12 +111,7 @@ pub(super) fn into_hir_generics(
|
||||
fn hir_generics_or_empty(&self) -> &'hir hir::Generics<'hir> {
|
||||
match self {
|
||||
HirOrTyGenerics::Ty(_) => hir::Generics::empty(),
|
||||
HirOrTyGenerics::Hir(hir_generics) => match hir_generics {
|
||||
DelegationGenerics::UserSpecified => hir::Generics::empty(),
|
||||
DelegationGenerics::Default(generics)
|
||||
| DelegationGenerics::SelfAndUserSpecified(generics)
|
||||
| DelegationGenerics::TraitImpl(generics, _) => generics,
|
||||
},
|
||||
HirOrTyGenerics::Hir(hir) => hir.generics,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,21 +125,16 @@ pub(super) fn into_generic_args(
|
||||
HirOrTyGenerics::Ty(_) => {
|
||||
bug!("Attempting to get generic args before uplifting to HIR")
|
||||
}
|
||||
HirOrTyGenerics::Hir(hir_generics) => match hir_generics {
|
||||
DelegationGenerics::UserSpecified => hir::GenericArgs::NONE,
|
||||
DelegationGenerics::Default(generics)
|
||||
| DelegationGenerics::SelfAndUserSpecified(generics)
|
||||
| DelegationGenerics::TraitImpl(generics, _) => {
|
||||
ctx.create_generics_args_from_params(generics.params, add_lifetimes, span)
|
||||
}
|
||||
},
|
||||
HirOrTyGenerics::Hir(hir) => {
|
||||
ctx.create_generics_args_from_params(hir.generics.params, add_lifetimes, span)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn args_propagation_details(&self) -> GenericArgsPropagationDetails {
|
||||
match self {
|
||||
HirOrTyGenerics::Ty(ty_generics) => ty_generics.args_propagation_details(),
|
||||
HirOrTyGenerics::Hir(hir_generics) => hir_generics.args_propagation_details(),
|
||||
HirOrTyGenerics::Ty(ty) => ty.kind.args_propagation_details(),
|
||||
HirOrTyGenerics::Hir(hir) => hir.kind.args_propagation_details(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -231,9 +224,10 @@ pub(super) fn uplift_delegation_generics(
|
||||
if matches!(delegation_parent_kind, DefKind::Impl { of_trait: true }) {
|
||||
// Considering parent generics, during signature inheritance
|
||||
// we will take those args that are in trait impl header trait ref.
|
||||
let parent = GenericsGenerationResult::new(DelegationGenerics::TraitImpl(&[], true));
|
||||
let parent = DelegationGenerics::trait_impl(&[], true);
|
||||
let parent = GenericsGenerationResult::new(parent);
|
||||
|
||||
let child = DelegationGenerics::TraitImpl(sig_params, child_user_specified);
|
||||
let child = DelegationGenerics::trait_impl(sig_params, child_user_specified);
|
||||
let child = GenericsGenerationResult::new(child);
|
||||
|
||||
return GenericsGenerationResults { parent, child };
|
||||
@@ -257,22 +251,28 @@ pub(super) fn uplift_delegation_generics(
|
||||
if segments[len - 2].args.is_some() {
|
||||
if generate_self {
|
||||
// Take only first Self parameter, it is trait so Self must be present.
|
||||
DelegationGenerics::SelfAndUserSpecified(&sig_parent_params[..1])
|
||||
DelegationGenerics {
|
||||
kind: DelegationGenericsKind::SelfAndUserSpecified,
|
||||
generics: &sig_parent_params[..1],
|
||||
}
|
||||
} else {
|
||||
DelegationGenerics::UserSpecified
|
||||
DelegationGenerics::user_specified(&[])
|
||||
}
|
||||
} else {
|
||||
let skip_self = usize::from(!generate_self);
|
||||
DelegationGenerics::Default(&sig_parent_params[skip_self..])
|
||||
DelegationGenerics::default(&sig_parent_params[skip_self..])
|
||||
}
|
||||
} else {
|
||||
DelegationGenerics::<&'hir [ty::GenericParamDef]>::Default(&[])
|
||||
DelegationGenerics::default(&[])
|
||||
};
|
||||
|
||||
let child_generics = if child_user_specified {
|
||||
DelegationGenerics::UserSpecified
|
||||
let synth_params_index =
|
||||
sig_params.iter().position(|p| p.kind.is_synthetic()).unwrap_or(sig_params.len());
|
||||
|
||||
DelegationGenerics::user_specified(&sig_params[synth_params_index..])
|
||||
} else {
|
||||
DelegationGenerics::Default(sig_params)
|
||||
DelegationGenerics::default(sig_params)
|
||||
};
|
||||
|
||||
GenericsGenerationResults {
|
||||
|
||||
@@ -318,11 +318,15 @@ fn create_generic_args<'tcx>(
|
||||
let (caller_kind, callee_kind) = (fn_kind(tcx, delegation_id), fn_kind(tcx, sig_id));
|
||||
|
||||
let delegation_args = ty::GenericArgs::identity_for_item(tcx, delegation_id);
|
||||
let delegation_parent_args_count = tcx.generics_of(delegation_id).parent_count;
|
||||
|
||||
let deleg_parent_args_without_self_count =
|
||||
get_delegation_parent_args_count_without_self(tcx, delegation_id, sig_id);
|
||||
|
||||
let delegation_generics = tcx.generics_of(delegation_id);
|
||||
let real_args_count = delegation_args.len() - delegation_generics.own_synthetic_params_count();
|
||||
let synth_args = &delegation_args[real_args_count..];
|
||||
let delegation_args = &delegation_args[..real_args_count];
|
||||
|
||||
let args = match (caller_kind, callee_kind) {
|
||||
(FnKind::Free, FnKind::Free)
|
||||
| (FnKind::Free, FnKind::AssocTrait)
|
||||
@@ -339,14 +343,15 @@ fn create_generic_args<'tcx>(
|
||||
|
||||
assert!(child_args.is_empty(), "Child args can not be used in trait impl case");
|
||||
|
||||
tcx.mk_args(&delegation_args[delegation_parent_args_count..])
|
||||
tcx.mk_args(&delegation_args[delegation_generics.parent_count..])
|
||||
}
|
||||
|
||||
(FnKind::AssocInherentImpl, FnKind::AssocTrait) => {
|
||||
let self_ty = tcx.type_of(tcx.local_parent(delegation_id)).instantiate_identity();
|
||||
|
||||
tcx.mk_args_from_iter(
|
||||
std::iter::once(ty::GenericArg::from(self_ty)).chain(delegation_args.iter()),
|
||||
std::iter::once(ty::GenericArg::from(self_ty))
|
||||
.chain(delegation_args.iter().copied()),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -411,7 +416,7 @@ fn create_generic_args<'tcx>(
|
||||
|
||||
new_args.extend_from_slice(&child_args[child_lifetimes_count..]);
|
||||
} else if !parent_args.is_empty() {
|
||||
let child_args = &delegation_args[delegation_parent_args_count..];
|
||||
let child_args = &delegation_args[delegation_generics.parent_count..];
|
||||
|
||||
let child_lifetimes_count =
|
||||
child_args.iter().take_while(|a| a.as_region().is_some()).count();
|
||||
@@ -424,6 +429,8 @@ fn create_generic_args<'tcx>(
|
||||
new_args.extend(&child_args[child_lifetimes_count + skip_self as usize..]);
|
||||
}
|
||||
|
||||
new_args.extend(synth_args);
|
||||
|
||||
new_args
|
||||
}
|
||||
|
||||
@@ -606,7 +613,8 @@ fn get_delegation_user_specified_args<'tcx>(
|
||||
.lower_generic_args_of_path(segment.ident.span, def_id, parent_args, segment, None)
|
||||
.0;
|
||||
|
||||
&args[parent_args.len()..]
|
||||
let synth_params_count = tcx.generics_of(def_id).own_synthetic_params_count();
|
||||
&args[parent_args.len()..args.len() - synth_params_count]
|
||||
});
|
||||
|
||||
(parent_args.unwrap_or_default(), child_args.unwrap_or_default())
|
||||
|
||||
@@ -747,7 +747,7 @@ fn inferred_kind(
|
||||
GenericParamDefKind::Lifetime => {
|
||||
self.lowerer.re_infer(self.span, RegionInferReason::Param(param)).into()
|
||||
}
|
||||
GenericParamDefKind::Type { has_default, .. } => {
|
||||
GenericParamDefKind::Type { has_default, synthetic } => {
|
||||
if !infer_args && has_default {
|
||||
// No type parameter provided, but a default exists.
|
||||
if let Some(prev) =
|
||||
@@ -763,6 +763,8 @@ fn inferred_kind(
|
||||
.type_of(param.def_id)
|
||||
.instantiate(tcx, preceding_args)
|
||||
.into()
|
||||
} else if synthetic {
|
||||
Ty::new_param(tcx, param.index, param.name).into()
|
||||
} else if infer_args {
|
||||
self.lowerer.ty_infer(Some(param), self.span).into()
|
||||
} else {
|
||||
|
||||
@@ -274,6 +274,10 @@ pub fn has_impl_trait(&'tcx self) -> bool {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn own_synthetic_params_count(&'tcx self) -> usize {
|
||||
self.own_params.iter().filter(|p| p.kind.is_synthetic()).count()
|
||||
}
|
||||
|
||||
/// Returns the args corresponding to the generic parameters
|
||||
/// of this item, excluding `Self`.
|
||||
///
|
||||
|
||||
@@ -9,14 +9,32 @@
|
||||
//! delegation parent if applicable. At some tests predicates are
|
||||
//! added. At some tests user-specified args are specified in reuse statement.
|
||||
|
||||
// Testing lifetimes + types + consts, reusing without
|
||||
// user args, checking predicates inheritance
|
||||
// Testing lifetimes + types + consts, reusing with(out)
|
||||
// user args, checking predicates inheritance, testing with impl Traits
|
||||
mod test_1 {
|
||||
fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>() {}
|
||||
trait Bound1 {}
|
||||
trait Bound2 {}
|
||||
trait Bound3 {}
|
||||
|
||||
struct X {}
|
||||
|
||||
impl Bound1 for X {}
|
||||
impl Bound2 for X {}
|
||||
impl Bound3 for X {}
|
||||
|
||||
fn foo<'a: 'a, 'b: 'b, T: Clone, U: Clone, const N: usize>(
|
||||
_x: impl Bound1 + Bound2 + Bound3,
|
||||
_f: impl FnOnce(T) -> U,
|
||||
) {
|
||||
}
|
||||
|
||||
pub fn check() {
|
||||
reuse foo as bar;
|
||||
bar::<i32, i32, 1>();
|
||||
bar::<i32, i32, 1>(X {}, |x| x);
|
||||
|
||||
reuse foo::<'static, 'static, usize, String, 132> as bar1;
|
||||
|
||||
bar1(X {}, |x| x.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,10 +10,10 @@
|
||||
//! added. At some tests user-specified args are specified in reuse statement.
|
||||
|
||||
// Testing lifetimes + types + consts in both parent and child, reusing in
|
||||
// a function without generic params
|
||||
// a function without generic params, with impl traits
|
||||
mod test_1 {
|
||||
trait Trait<'b, 'c, 'a, T, const N: usize>: Sized {
|
||||
fn foo<'d: 'd, U, const M: bool>(self) {}
|
||||
fn foo<'d: 'd, U, const M: bool>(self, _f: impl FnOnce() -> ()) {}
|
||||
}
|
||||
|
||||
impl Trait<'static, 'static, 'static, i32, 1> for u8 {}
|
||||
@@ -21,12 +21,12 @@ impl Trait<'static, 'static, 'static, i32, 1> for u8 {}
|
||||
pub fn check() {
|
||||
fn no_ctx() {
|
||||
reuse Trait::foo as bar;
|
||||
bar::<'static, 'static, 'static, 'static, u8, i32, 1, String, true>(123);
|
||||
bar::<'static, 'static, 'static, 'static, u8, i32, 1, String, true>(123, || ());
|
||||
}
|
||||
|
||||
fn with_ctx<'a, 'b, 'c, A, B, C, const N: usize, const M: bool>() {
|
||||
reuse Trait::foo as bar;
|
||||
bar::<'static, 'static, 'static, 'a, u8, i32, 1, A, M>(123);
|
||||
bar::<'static, 'static, 'static, 'a, u8, i32, 1, A, M>(123, || ());
|
||||
}
|
||||
|
||||
no_ctx();
|
||||
|
||||
@@ -10,19 +10,19 @@
|
||||
//! delegation parent if applicable. At some tests predicates are
|
||||
//! added. At some tests user-specified args are specified in reuse statement.
|
||||
|
||||
// Testing lifetimes + types/consts in child reuses,
|
||||
// Testing lifetimes + types/consts in child reuses, with impl traits,
|
||||
// with (un)specified user args with additional generic params in delegation parent
|
||||
mod test_1 {
|
||||
mod to_reuse {
|
||||
pub fn foo<'a: 'a, 'b: 'b, A, B, const N: usize>() {}
|
||||
pub fn bar<'a: 'a, 'b: 'b, A, B, const N: usize>(_x: &super::XX) {}
|
||||
pub fn bar<'a: 'a, 'b: 'b, A, B, const N: usize>(_x: &super::XX, _f: impl FnOnce(A) -> B) {}
|
||||
}
|
||||
|
||||
trait Trait<'a, 'b, 'c, A, B, const N: usize>: Sized {
|
||||
fn foo<'x: 'x, 'y: 'y, AA, BB, const NN: usize>() {}
|
||||
fn bar<'x: 'x, 'y: 'y, AA, BB, const NN: usize>(&self) {}
|
||||
fn bar<'x: 'x, 'y: 'y, AA, BB, const NN: usize>(&self, _f: impl FnOnce(AA) -> BB) {}
|
||||
fn oof() {}
|
||||
fn rab(&self) {}
|
||||
fn rab(&self, _f: impl FnOnce(A) -> B) {}
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // Fields are used instead of phantom data for generics use
|
||||
@@ -44,9 +44,9 @@ pub fn check() {
|
||||
<XX as Trait<'static, 'static, 'static, i32, i32, 1>>
|
||||
::foo::<'static, 'static, i8, i16, 123>();
|
||||
<XX as Trait<'static, 'static, 'static, i32, i32, 1>>
|
||||
::bar::<'static, 'static, String, i16, 123>(&x);
|
||||
::bar::<'static, 'static, String, i16, 123>(&x, |_| 123);
|
||||
<XX as Trait<'static, 'static, 'static, i32, i32, 1>>::oof();
|
||||
<XX as Trait<'static, 'static, 'static, i32, String, 1>>::rab(&x);
|
||||
<XX as Trait<'static, 'static, 'static, i32, String, 1>>::rab(&x, |_| 123.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,12 +12,12 @@
|
||||
|
||||
// Testing types in parent, types in child reuse,
|
||||
// testing predicates inheritance,
|
||||
// with additional generic params in delegation parent
|
||||
// with additional generic params in delegation parent, with impl traits
|
||||
mod test_1 {
|
||||
trait Trait0 {}
|
||||
|
||||
trait Trait1<T> {
|
||||
fn foo<U>(&self)
|
||||
fn foo<U>(&self, _f: impl FnOnce(T, U) -> (U, T))
|
||||
where
|
||||
T: Trait0,
|
||||
U: Trait0,
|
||||
@@ -39,7 +39,7 @@ impl Trait0 for u16 {}
|
||||
|
||||
pub fn check() {
|
||||
let s = S(F, &123, &123, &123);
|
||||
<S::<'static, 'static, 'static, i32, i32> as Trait1<u16>>::foo::<u16>(&s);
|
||||
<S::<'static, 'static, 'static, i32, i32> as Trait1<u16>>::foo::<u16>(&s, |x, y| (y, x));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
|
||||
// Testing lifetimes + types/consts OR types/consts OR none in delegation parent,
|
||||
// lifetimes + types/consts in child reuse,
|
||||
// with(out) user-specified args
|
||||
// with(out) user-specified args, with impl traits
|
||||
mod test_1 {
|
||||
mod to_reuse {
|
||||
pub fn foo<'a: 'a, 'b: 'b, A, B, const N: usize>() {}
|
||||
pub fn foo<'a: 'a, 'b: 'b, A, B, const N: usize>(_f: impl FnOnce(A, B) -> B) {}
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // Fields are used instead of phantom data for generics use
|
||||
@@ -39,14 +39,14 @@ impl X3 {
|
||||
|
||||
pub fn check() {
|
||||
X1::<'static, 'static, i32, i32, 1>
|
||||
::foo::<'static, 'static, String, String, 123>();
|
||||
X1::<'static, 'static, i32, i32, 1>::bar();
|
||||
::foo::<'static, 'static, String, String, 123>(|_, y| y);
|
||||
X1::<'static, 'static, i32, i32, 1>::bar(|_, y| y);
|
||||
|
||||
X2::<i32, i32, 1>::foo::<'static, 'static, String, String, 123>();
|
||||
X2::<i32, i32, 1>::bar();
|
||||
X2::<i32, i32, 1>::foo::<'static, 'static, String, String, 123>(|_, y| y);
|
||||
X2::<i32, i32, 1>::bar(|_, y| y);
|
||||
|
||||
X3::foo::<'static, 'static, String, String, 123>();
|
||||
X3::bar();
|
||||
X3::foo::<'static, 'static, String, String, 123>(|_, y| y);
|
||||
X3::bar(|_, y| y);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
|
||||
// Testing types in parent, none in child,
|
||||
// user-specified args in parent, checking predicates inheritance,
|
||||
// with additional generic params in delegation parent
|
||||
// with additional generic params in delegation parent, with impl traits
|
||||
mod test_1 {
|
||||
trait Trait<T: ToString> {
|
||||
fn foo(&self) {}
|
||||
fn foo(&self, _f: impl FnOnce(T) -> String) {}
|
||||
}
|
||||
|
||||
struct F;
|
||||
@@ -29,8 +29,8 @@ impl<'a, 'b, 'c, A, B> S<'a, 'b, 'c, A, B> {
|
||||
|
||||
pub fn check() {
|
||||
let s = S(F, &123, &123, &123);
|
||||
S::<'static, 'static, 'static, i32, i32>::foo(&s);
|
||||
s.foo();
|
||||
S::<'static, 'static, 'static, i32, i32>::foo(&s, |t| t.to_string());
|
||||
s.foo(|t| t.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,9 +10,10 @@
|
||||
//! added. At some tests user-specified args are specified in reuse statement.
|
||||
|
||||
// Testing lifetimes + types/consts in child, lifetimes + types/consts in delegation parent,
|
||||
// with(out) user-specified args
|
||||
// with(out) user-specified args, with impl traits
|
||||
mod test_1 {
|
||||
fn foo<'a: 'a, 'b: 'b, T: Clone + ToString, U: Clone, const N: usize>() {}
|
||||
fn foo<'a: 'a, 'b: 'b, T: Clone + ToString, U: Clone, const N: usize>(
|
||||
_f: impl FnOnce(T) -> (T, U)) {}
|
||||
|
||||
trait Trait<'a, A, B, C, const N: usize> {
|
||||
reuse foo;
|
||||
@@ -21,8 +22,10 @@ trait Trait<'a, A, B, C, const N: usize> {
|
||||
|
||||
impl Trait<'static, i32, i32, i32, 1> for u32 {}
|
||||
pub fn check() {
|
||||
<u32 as Trait<'static, i32, i32, i32, 1>>::foo::<'static, 'static, i32, String, 1>();
|
||||
<u32 as Trait<'static, i32, i32, i32, 1>>::bar();
|
||||
<u32 as Trait<'static, i32, i32, i32, 1>>
|
||||
::foo::<'static, 'static, i32, String, 1>(|t| (t, "".to_string()));
|
||||
<u32 as Trait<'static, i32, i32, i32, 1>>::bar(|t| (t, t.to_string()));
|
||||
u32::bar(|t| (t, t.to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
// lifetimes + types/consts in child,
|
||||
// in delegation parent with:
|
||||
// lifetimes + types OR none OR lifetimes OR types,
|
||||
// with(out) user-specified args, with different target expr
|
||||
// with(out) user-specified args, with different target expr, with impl traits
|
||||
mod test_1 {
|
||||
trait Trait<'b, 'c, 'a, T>: Sized {
|
||||
fn foo<'d: 'd, U, const M: bool>(&self) {}
|
||||
fn foo<'d: 'd, U, const M: bool>(&self, _f: impl FnOnce(T) -> U) {}
|
||||
}
|
||||
|
||||
impl<'b, 'c, 'a, T> Trait<'b, 'c, 'a, T> for u8 {}
|
||||
@@ -83,26 +83,26 @@ impl<X, Y, Z> Trait5<X, Y, Z> for u32 {}
|
||||
|
||||
pub fn check<'a: 'a>() {
|
||||
<u32 as Trait2<'static, 'static, 'static, i32, i32, i32>>
|
||||
::bar1::<'static, String, true>(&123);
|
||||
<u32 as Trait3>::bar1::<'static, String, true>(&123);
|
||||
<u32 as Trait4<'a, 'a, 'static>>::bar1::<'static, String, true>(&123);
|
||||
<u32 as Trait5<i32, u64, String>>::bar1::<'static, String, true>(&123);
|
||||
::bar1::<'static, String, true>(&123, |x| x.to_string());
|
||||
<u32 as Trait3>::bar1::<'static, String, true>(&123, |x| x.to_string());
|
||||
<u32 as Trait4<'a, 'a, 'static>>::bar1::<'static, String, true>(&123, |x| x.to_string());
|
||||
<u32 as Trait5<i32, u64, String>>::bar1::<'static, String, true>(&123, |x| x.to_string());
|
||||
|
||||
<u32 as Trait2<'static, 'static, 'static, i32, i32, i32>>::bar2(&123);
|
||||
<u32 as Trait3>::bar2(&123);
|
||||
<u32 as Trait4<'a, 'a, 'static>>::bar2(&123);
|
||||
<u32 as Trait5<i32, u64, String>>::bar2(&123);
|
||||
<u32 as Trait2<'static, 'static, 'static, i32, i32, i32>>::bar2(&123, |x| x.to_string());
|
||||
<u32 as Trait3>::bar2(&123, |x| x.to_string());
|
||||
<u32 as Trait4<'a, 'a, 'static>>::bar2(&123, |x| x.to_string());
|
||||
<u32 as Trait5<i32, u64, String>>::bar2(&123, |x| x.to_string());
|
||||
|
||||
<u32 as Trait2<'static, 'static, 'static, i32, i32, i32>>
|
||||
::bar3::<'static, String, true>(&123);
|
||||
<u32 as Trait3>::bar3::<'static, String, true>(&123);
|
||||
<u32 as Trait4<'a, 'a, 'static>>::bar3::<'static, String, true>(&123);
|
||||
<u32 as Trait5<i32, u64, String>>::bar3::<'static, String, true>(&123);
|
||||
::bar3::<'static, String, true>(&123, |x| x.to_string());
|
||||
<u32 as Trait3>::bar3::<'static, String, true>(&123, |x| x.to_string());
|
||||
<u32 as Trait4<'a, 'a, 'static>>::bar3::<'static, String, true>(&123, |x| x.to_string());
|
||||
<u32 as Trait5<i32, u64, String>>::bar3::<'static, String, true>(&123, |x| x.to_string());
|
||||
|
||||
<u32 as Trait2<'static, 'static, 'static, i32, i32, i32>>::bar4(&123);
|
||||
<u32 as Trait3>::bar4(&123);
|
||||
<u32 as Trait4<'a, 'a, 'static>>::bar4(&123);
|
||||
<u32 as Trait5<i32, u64, String>>::bar4(&123);
|
||||
<u32 as Trait2<'static, 'static, 'static, i32, i32, i32>>::bar4(&123, |x| x.to_string());
|
||||
<u32 as Trait3>::bar4(&123, |x| x.to_string());
|
||||
<u32 as Trait4<'a, 'a, 'static>>::bar4(&123, |x| x.to_string());
|
||||
<u32 as Trait5<i32, u64, String>>::bar4(&123, |x| x.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
//@ run-pass
|
||||
|
||||
#![feature(fn_delegation)]
|
||||
|
||||
// Almost original ICE with recursive delegation.
|
||||
mod test_1 {
|
||||
pub fn check() {
|
||||
fn foo<const N: usize, T, U>(f: impl FnOnce() -> usize) -> usize {
|
||||
f()
|
||||
}
|
||||
|
||||
reuse foo::<1, String, String> as bar;
|
||||
|
||||
reuse bar as bar2;
|
||||
|
||||
assert_eq!(bar(|| 123), 123);
|
||||
assert_eq!(bar2(|| 123), 123);
|
||||
}
|
||||
}
|
||||
|
||||
// Test recursive delegations through trait.
|
||||
mod test_2 {
|
||||
fn foo<'a, const B: bool, T, U>(_x: impl Trait<'a, T, B>, f: impl FnOnce() -> usize) -> usize {
|
||||
f()
|
||||
}
|
||||
|
||||
trait Trait<'a, A, const B: bool> {
|
||||
reuse foo;
|
||||
reuse foo::<'a, false, (), ()> as bar;
|
||||
}
|
||||
|
||||
struct X;
|
||||
impl<'a, A, const B: bool> Trait<'a, A, B> for X {}
|
||||
|
||||
reuse <X as Trait>::foo as foo2;
|
||||
reuse <X as Trait>::bar as bar2;
|
||||
|
||||
pub fn check() {
|
||||
assert_eq!(foo2::<'static, 'static, X, (), true, false, (), ()>(X, || 123), 123);
|
||||
assert_eq!(bar2::<'static, X, (), true>(X, || 123), 123);
|
||||
}
|
||||
}
|
||||
|
||||
// Testing impl Traits with SelfAndUserSpecified case.
|
||||
mod test_3 {
|
||||
trait Trait<'a, A, const B: bool> {
|
||||
fn foo<'b, const B2: bool, T, U>(&self, f: impl FnOnce() -> usize) -> usize {
|
||||
f()
|
||||
}
|
||||
}
|
||||
|
||||
struct X;
|
||||
impl<'a, A, const B: bool> Trait<'a, A, B> for X {}
|
||||
|
||||
reuse Trait::foo;
|
||||
reuse Trait::<'static, (), true>::foo::<true, (), ()> as bar;
|
||||
|
||||
pub fn check() {
|
||||
assert_eq!(foo::<'static, X, (), true, false, (), ()>(&X, || 123), 123);
|
||||
assert_eq!(bar::<X>(&X, || 123), 123);
|
||||
assert_eq!(bar(&X, || 123), 123);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(fn_delegation): rename Self generic param in recursive delegations
|
||||
// mod test_4 {
|
||||
// trait Trait<'a, A, const B: bool> {
|
||||
// fn foo<'b, const B2: bool, T, U>(&self, f: impl FnOnce() -> usize) -> usize {
|
||||
// f()
|
||||
// }
|
||||
// }
|
||||
|
||||
// struct X;
|
||||
// impl<'a, A, const B: bool> Trait<'a, A, B> for X {}
|
||||
|
||||
// reuse Trait::foo;
|
||||
// reuse Trait::<'static, (), true>::foo::<true, (), ()> as bar;
|
||||
|
||||
// trait Trait2 {
|
||||
// reuse foo;
|
||||
// reuse bar;
|
||||
// }
|
||||
|
||||
// reuse Trait2::foo as foo2;
|
||||
// reuse Trait2::foo::<'static, X, (), true, false, (), ()> as foo3;
|
||||
// reuse Trait2::bar as bar2;
|
||||
// reuse Trait2::bar::<X> as bar3;
|
||||
|
||||
// pub fn check() {
|
||||
// assert_eq!(foo::<'static, X, (), true, false, (), ()>(&X, || 123), 123);
|
||||
// assert_eq!(bar::<X>(&X, || 123), 123);
|
||||
// assert_eq!(bar(&X, || 123), 123);
|
||||
// }
|
||||
// }
|
||||
|
||||
fn main() {
|
||||
test_1::check();
|
||||
test_2::check();
|
||||
test_3::check();
|
||||
// test_4::check();
|
||||
}
|
||||
Reference in New Issue
Block a user