From d87d7b94f8fb2125dbbe8359d3cb084cff17c365 Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Thu, 12 Mar 2026 17:25:05 +0300 Subject: [PATCH] Always generate generics that match trait in trait impl scenario --- compiler/rustc_ast_lowering/src/delegation.rs | 6 +- .../src/delegation/generics.rs | 81 +++++++-- compiler/rustc_hir_analysis/src/delegation.rs | 8 +- .../generics/impl-trait-wrong-args-count.rs | 40 ----- .../impl-trait-wrong-args-count.stderr | 74 --------- .../generics/trait-impl-wrong-args-count.rs | 111 +++++++++++++ .../trait-impl-wrong-args-count.stderr | 156 ++++++++++++++++++ 7 files changed, 340 insertions(+), 136 deletions(-) delete mode 100644 tests/ui/delegation/generics/impl-trait-wrong-args-count.rs delete mode 100644 tests/ui/delegation/generics/impl-trait-wrong-args-count.stderr create mode 100644 tests/ui/delegation/generics/trait-impl-wrong-args-count.rs create mode 100644 tests/ui/delegation/generics/trait-impl-wrong-args-count.stderr diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 1d634c03255ea..fa11e04763404 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -724,9 +724,11 @@ impl<'hir> LoweringContext<'_, 'hir> { result: &mut GenericsGenerationResult<'hir>, add_lifetimes: bool, ) -> hir::PathSegment<'hir> { + let details = result.generics.args_propagation_details(); + // The first condition is needed when there is SelfAndUserSpecified case, // we don't want to propagate generics params in this situation. - let segment = if !result.generics.is_user_specified() + let segment = if details.should_propagate && let Some(args) = result .generics .into_hir_generics(self, item_id, span) @@ -737,7 +739,7 @@ impl<'hir> LoweringContext<'_, 'hir> { segment.clone() }; - if result.generics.is_user_specified() { + if details.use_args_in_sig_inheritance { result.args_segment_id = Some(segment.hir_id); } diff --git a/compiler/rustc_ast_lowering/src/delegation/generics.rs b/compiler/rustc_ast_lowering/src/delegation/generics.rs index 9e7ec04d38fb7..6bfe73fb0d8fa 100644 --- a/compiler/rustc_ast_lowering/src/delegation/generics.rs +++ b/compiler/rustc_ast_lowering/src/delegation/generics.rs @@ -20,6 +20,10 @@ pub(super) enum DelegationGenerics { /// In free-to-trait reuse, when user specified args for trait `reuse Trait::::foo;` /// in this case we need to both generate `Self` and process user args. SelfAndUserSpecified(Option), + /// 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(Option, bool /* Has user-specified args */), } /// Used for storing either AST generics or their lowered HIR version. Firstly we obtain @@ -48,12 +52,29 @@ pub(super) struct GenericsGenerationResults<'hir> { pub(super) child: GenericsGenerationResult<'hir>, } +pub(super) struct GenericArgsPropagationDetails { + pub(super) should_propagate: bool, + pub(super) use_args_in_sig_inheritance: bool, +} + impl DelegationGenerics { - fn is_user_specified(&self) -> bool { - matches!( - self, - DelegationGenerics::UserSpecified | DelegationGenerics::SelfAndUserSpecified { .. } - ) + 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, + use_args_in_sig_inheritance: false, + }, + DelegationGenerics::Default(_) => GenericArgsPropagationDetails { + should_propagate: true, + use_args_in_sig_inheritance: false, + }, + } } } @@ -77,6 +98,12 @@ impl<'hir> HirOrAstGenerics<'hir> { DelegationGenerics::SelfAndUserSpecified(generics) => { DelegationGenerics::SelfAndUserSpecified(generics.as_mut().map(process_params)) } + DelegationGenerics::TraitImpl(generics, user_specified) => { + DelegationGenerics::TraitImpl( + generics.as_mut().map(process_params), + *user_specified, + ) + } }; *self = HirOrAstGenerics::Hir(hir_generics); @@ -91,7 +118,8 @@ impl<'hir> HirOrAstGenerics<'hir> { HirOrAstGenerics::Hir(hir_generics) => match hir_generics { DelegationGenerics::UserSpecified => hir::Generics::empty(), DelegationGenerics::Default(generics) - | DelegationGenerics::SelfAndUserSpecified(generics) => { + | DelegationGenerics::SelfAndUserSpecified(generics) + | DelegationGenerics::TraitImpl(generics, _) => { generics.unwrap_or(hir::Generics::empty()) } }, @@ -111,17 +139,18 @@ impl<'hir> HirOrAstGenerics<'hir> { HirOrAstGenerics::Hir(hir_generics) => match hir_generics { DelegationGenerics::UserSpecified => None, DelegationGenerics::Default(generics) - | DelegationGenerics::SelfAndUserSpecified(generics) => generics.map(|generics| { + | DelegationGenerics::SelfAndUserSpecified(generics) + | DelegationGenerics::TraitImpl(generics, _) => generics.map(|generics| { ctx.create_generics_args_from_params(generics.params, add_lifetimes, span) }), }, } } - pub(super) fn is_user_specified(&self) -> bool { + pub(super) fn args_propagation_details(&self) -> GenericArgsPropagationDetails { match self { - HirOrAstGenerics::Ast(ast_generics) => ast_generics.is_user_specified(), - HirOrAstGenerics::Hir(hir_generics) => hir_generics.is_user_specified(), + HirOrAstGenerics::Ast(ast_generics) => ast_generics.args_propagation_details(), + HirOrAstGenerics::Hir(hir_generics) => hir_generics.args_propagation_details(), } } } @@ -215,10 +244,29 @@ impl<'hir> LoweringContext<'_, 'hir> { item_id: NodeId, span: Span, ) -> GenericsGenerationResults<'hir> { - let delegation_in_free_ctx = !matches!( - self.tcx.def_kind(self.tcx.local_parent(self.local_def_id(item_id))), - DefKind::Trait | DefKind::Impl { .. } - ); + let delegation_parent_kind = + self.tcx.def_kind(self.tcx.local_parent(self.local_def_id(item_id))); + + let segments = &delegation.path.segments; + let len = segments.len(); + let child_user_specified = segments[len - 1].args.is_some(); + + // If we are in trait impl always generate function whose generics matches + // those that are defined in trait. + 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::Default(None)); + + let generics = self.get_fn_like_generics(root_fn_id, span); + let child = DelegationGenerics::TraitImpl(generics, child_user_specified); + let child = GenericsGenerationResult::new(child); + + return GenericsGenerationResults { parent, child }; + } + + let delegation_in_free_ctx = + !matches!(delegation_parent_kind, DefKind::Trait | DefKind::Impl { .. }); let root_function_in_trait = matches!(self.tcx.def_kind(self.tcx.parent(root_fn_id)), DefKind::Trait); @@ -234,9 +282,6 @@ impl<'hir> LoweringContext<'_, 'hir> { ) }; - let segments = &delegation.path.segments; - let len = segments.len(); - let can_add_generics_to_parent = len >= 2 && self.get_resolution_id(segments[len - 2].id).is_some_and(|def_id| { matches!(self.tcx.def_kind(def_id), DefKind::Trait | DefKind::TraitAlias) @@ -256,7 +301,7 @@ impl<'hir> LoweringContext<'_, 'hir> { DelegationGenerics::Default(None) }; - let child_generics = if segments[len - 1].args.is_some() { + let child_generics = if child_user_specified { DelegationGenerics::UserSpecified } else { DelegationGenerics::Default(self.get_fn_like_generics(root_fn_id, span)) diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs index 3392a72daec14..64cf9cb6403e9 100644 --- a/compiler/rustc_hir_analysis/src/delegation.rs +++ b/compiler/rustc_hir_analysis/src/delegation.rs @@ -338,10 +338,14 @@ fn create_generic_args<'tcx>( | (FnKind::AssocTrait, FnKind::AssocTrait) => delegation_args, (FnKind::AssocTraitImpl, FnKind::AssocTrait) => { - // Special case, as user specifies Trait args in impl trait header, we want to treat - // them as parent args. + // Special case, as user specifies Trait args in trait impl header, we want to treat + // them as parent args. We always generate a function whose generics match + // child generics in trait. let parent = tcx.local_parent(delegation_id); parent_args = tcx.impl_trait_header(parent).trait_ref.instantiate_identity().args; + + assert!(child_args.is_empty(), "Child args can not be used in trait impl case"); + tcx.mk_args(&delegation_args[delegation_parent_args_count..]) } diff --git a/tests/ui/delegation/generics/impl-trait-wrong-args-count.rs b/tests/ui/delegation/generics/impl-trait-wrong-args-count.rs deleted file mode 100644 index 8c9b7d5a9e4e9..0000000000000 --- a/tests/ui/delegation/generics/impl-trait-wrong-args-count.rs +++ /dev/null @@ -1,40 +0,0 @@ -#![feature(fn_delegation)] -#![allow(incomplete_features)] - -mod to_reuse { - pub fn bar<'a: 'a, 'b: 'b, A, B>(x: &super::XX) {} - pub fn bar1(x: &super::XX) {} - pub fn bar2(x: &super::XX) {} -} - -trait Trait<'a, 'b, 'c, A, B, const N: usize>: Sized { - fn bar<'x: 'x, 'y: 'y, AA, BB, const NN: usize>(&self) {} - fn bar1<'x: 'x, 'y: 'y, AA, BB, const NN: usize>(&self) {} - fn bar2(&self) {} - fn bar3(&self) {} - fn bar4(&self) {} -} - -struct X<'x1, 'x2, 'x3, 'x4, X1, X2, const X3: usize>( - &'x1 X1, &'x2 X2, &'x3 X1, &'x4 [usize; X3]); -type XX = X::<'static, 'static, 'static, 'static, i32, i32, 3>; - -impl<'a, 'b, 'c, A, B, const N: usize> Trait<'a, 'b, 'c, A, B, N> for XX { - reuse to_reuse::bar; - //~^ ERROR: function takes at most 2 generic arguments but 3 generic arguments were supplied - - reuse to_reuse::bar1; - //~^ ERROR: function takes 0 generic arguments but 3 generic arguments were supplied - - reuse to_reuse::bar2; - //~^ ERROR: type annotations needed - //~| ERROR: type annotations needed - - reuse to_reuse::bar2:: as bar3; - - reuse to_reuse::bar2:: as bar4; - //~^ ERROR: method `bar4` has 0 type parameters but its trait declaration has 3 type parameters -} - -fn main() { -} diff --git a/tests/ui/delegation/generics/impl-trait-wrong-args-count.stderr b/tests/ui/delegation/generics/impl-trait-wrong-args-count.stderr deleted file mode 100644 index 2a94ac0bfe03f..0000000000000 --- a/tests/ui/delegation/generics/impl-trait-wrong-args-count.stderr +++ /dev/null @@ -1,74 +0,0 @@ -error[E0049]: method `bar4` has 0 type parameters but its trait declaration has 3 type parameters - --> $DIR/impl-trait-wrong-args-count.rs:35:21 - | -LL | fn bar4(&self) {} - | - - - - | | - | expected 3 type parameters -... -LL | reuse to_reuse::bar2:: as bar4; - | ^^^^ found 0 type parameters - -error[E0107]: function takes at most 2 generic arguments but 3 generic arguments were supplied - --> $DIR/impl-trait-wrong-args-count.rs:23:21 - | -LL | fn bar<'x: 'x, 'y: 'y, AA, BB, const NN: usize>(&self) {} - | ----------------- help: remove the unnecessary generic argument -... -LL | reuse to_reuse::bar; - | ^^^ expected at most 2 generic arguments - | -note: function defined here, with at most 2 generic parameters: `A`, `B` - --> $DIR/impl-trait-wrong-args-count.rs:5:12 - | -LL | pub fn bar<'a: 'a, 'b: 'b, A, B>(x: &super::XX) {} - | ^^^ - - - -error[E0107]: function takes 0 generic arguments but 3 generic arguments were supplied - --> $DIR/impl-trait-wrong-args-count.rs:26:21 - | -LL | reuse to_reuse::bar1; - | ^^^^ expected 0 generic arguments - | -note: function defined here, with 0 generic parameters - --> $DIR/impl-trait-wrong-args-count.rs:6:12 - | -LL | pub fn bar1(x: &super::XX) {} - | ^^^^ - -error[E0284]: type annotations needed - --> $DIR/impl-trait-wrong-args-count.rs:29:21 - | -LL | reuse to_reuse::bar2; - | ^^^^ cannot infer the value of the const parameter `X` declared on the function `bar2` - | -note: required by a const generic parameter in `bar2` - --> $DIR/impl-trait-wrong-args-count.rs:7:35 - | -LL | pub fn bar2(x: &super::XX) {} - | ^^^^^^^^^^^^^^ required by this const generic parameter in `bar2` -help: consider specifying the generic arguments - | -LL | reuse to_reuse::bar2::; - | ++++++++++++++++++++++++++ - -error[E0284]: type annotations needed - --> $DIR/impl-trait-wrong-args-count.rs:29:21 - | -LL | reuse to_reuse::bar2; - | ^^^^ cannot infer the value of the const parameter `Y` declared on the function `bar2` - | -note: required by a const generic parameter in `bar2` - --> $DIR/impl-trait-wrong-args-count.rs:7:51 - | -LL | pub fn bar2(x: &super::XX) {} - | ^^^^^^^^^^^^^ required by this const generic parameter in `bar2` -help: consider specifying the generic arguments - | -LL | reuse to_reuse::bar2::; - | ++++++++++++++++++++++++++ - -error: aborting due to 5 previous errors - -Some errors have detailed explanations: E0049, E0107, E0284. -For more information about an error, try `rustc --explain E0049`. diff --git a/tests/ui/delegation/generics/trait-impl-wrong-args-count.rs b/tests/ui/delegation/generics/trait-impl-wrong-args-count.rs new file mode 100644 index 0000000000000..7cb98ff307fd6 --- /dev/null +++ b/tests/ui/delegation/generics/trait-impl-wrong-args-count.rs @@ -0,0 +1,111 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +// Testing delegation from trait impl to free functions. +mod test_1 { + mod to_reuse { + pub fn bar<'a: 'a, 'b: 'b, A, B>(x: &super::XX) {} + pub fn bar1(x: &super::XX) {} + pub fn bar2(x: &super::XX) {} + } + + trait Trait<'a, 'b, 'c, A, B, const N: usize>: Sized { + fn bar<'x: 'x, 'y: 'y, AA, BB, const NN: usize>(&self) {} + fn bar1<'x: 'x, 'y: 'y, AA, BB, const NN: usize>(&self) {} + fn bar2(&self) {} + fn bar3(&self) {} + fn bar4(&self) {} + } + + struct X<'x1, 'x2, 'x3, 'x4, X1, X2, const X3: usize>( + &'x1 X1, &'x2 X2, &'x3 X1, &'x4 [usize; X3]); + type XX = X::<'static, 'static, 'static, 'static, i32, i32, 3>; + + impl<'a, 'b, 'c, A, B, const N: usize> Trait<'a, 'b, 'c, A, B, N> for XX { + reuse to_reuse::bar; + //~^ ERROR: function takes at most 2 generic arguments but 3 generic arguments were supplied + + reuse to_reuse::bar1; + //~^ ERROR: function takes 0 generic arguments but 3 generic arguments were supplied + + reuse to_reuse::bar2; + //~^ ERROR: type annotations needed + //~| ERROR: type annotations needed + + reuse to_reuse::bar2:: as bar3; + + reuse to_reuse::bar2:: as bar4; + } +} + +// Testing delegations of trait impl to other different trait +// with errors in Trait1 generics count. +mod test_2 { + trait Trait { + fn bar<'x: 'x, 'y: 'y, AA, BB, const NN: usize>() {} + fn bar1<'x: 'x, 'y: 'y, AA, BB, const NN: usize>() {} + fn bar2() {} + fn bar3() {} + fn bar4() {} + } + + trait Trait1 { + fn bar<'x: 'x, AA, BB, const NN: usize>() {} + } + + struct X; + + impl Trait1 for X {} + + impl Trait for X { + reuse ::bar; + //~^ ERROR: missing generics for trait + + reuse >::bar as bar1; + + reuse >::bar::<'static, u32, u32, 1> as bar2; + + reuse ::bar::<'static, u32, u32, 1> as bar3; + //~^ ERROR: missing generics for trait + + reuse ::bar as bar4; + //~^ ERROR: missing generics for trait + } +} + +// Testing delegations of trait impl to other different trait +// with Trait1::bar and Trait1::foo wrong generics count. +mod test_3 { + trait Trait { + fn bar<'x: 'x, 'y: 'y, AA, BB, const NN: usize>() {} + fn bar1<'x: 'x, 'y: 'y, AA, BB, const NN: usize>() {} + fn bar2() {} + fn bar3() {} + } + + trait Trait1 { + fn bar() {} + fn foo() {} + } + + struct X; + + impl Trait1 for X {} + + impl Trait for X { + reuse >::bar; + //~^ ERROR: associated function takes 0 generic arguments but 3 generic arguments were supplied + + reuse >::bar as bar1; + //~^ ERROR: associated function takes 0 generic arguments but 3 generic arguments were supplied + + reuse >::foo as bar2; + //~^ ERROR: type annotations needed + + reuse >::foo as bar3; + //~^ ERROR: associated function takes at most 2 generic arguments but 3 generic arguments were supplied + } +} + +fn main() { +} diff --git a/tests/ui/delegation/generics/trait-impl-wrong-args-count.stderr b/tests/ui/delegation/generics/trait-impl-wrong-args-count.stderr new file mode 100644 index 0000000000000..00dfedef47b5a --- /dev/null +++ b/tests/ui/delegation/generics/trait-impl-wrong-args-count.stderr @@ -0,0 +1,156 @@ +error[E0107]: function takes at most 2 generic arguments but 3 generic arguments were supplied + --> $DIR/trait-impl-wrong-args-count.rs:25:25 + | +LL | fn bar<'x: 'x, 'y: 'y, AA, BB, const NN: usize>(&self) {} + | ----------------- help: remove the unnecessary generic argument +... +LL | reuse to_reuse::bar; + | ^^^ expected at most 2 generic arguments + | +note: function defined here, with at most 2 generic parameters: `A`, `B` + --> $DIR/trait-impl-wrong-args-count.rs:7:16 + | +LL | pub fn bar<'a: 'a, 'b: 'b, A, B>(x: &super::XX) {} + | ^^^ - - + +error[E0107]: function takes 0 generic arguments but 3 generic arguments were supplied + --> $DIR/trait-impl-wrong-args-count.rs:28:25 + | +LL | reuse to_reuse::bar1; + | ^^^^ expected 0 generic arguments + | +note: function defined here, with 0 generic parameters + --> $DIR/trait-impl-wrong-args-count.rs:8:16 + | +LL | pub fn bar1(x: &super::XX) {} + | ^^^^ + +error[E0284]: type annotations needed + --> $DIR/trait-impl-wrong-args-count.rs:31:25 + | +LL | reuse to_reuse::bar2; + | ^^^^ cannot infer the value of the const parameter `X` declared on the function `bar2` + | +note: required by a const generic parameter in `bar2` + --> $DIR/trait-impl-wrong-args-count.rs:9:39 + | +LL | pub fn bar2(x: &super::XX) {} + | ^^^^^^^^^^^^^^ required by this const generic parameter in `bar2` +help: consider specifying the generic arguments + | +LL | reuse to_reuse::bar2::; + | ++++++++++++++++++++++++++ + +error[E0284]: type annotations needed + --> $DIR/trait-impl-wrong-args-count.rs:31:25 + | +LL | reuse to_reuse::bar2; + | ^^^^ cannot infer the value of the const parameter `Y` declared on the function `bar2` + | +note: required by a const generic parameter in `bar2` + --> $DIR/trait-impl-wrong-args-count.rs:9:55 + | +LL | pub fn bar2(x: &super::XX) {} + | ^^^^^^^^^^^^^ required by this const generic parameter in `bar2` +help: consider specifying the generic arguments + | +LL | reuse to_reuse::bar2::; + | ++++++++++++++++++++++++++ + +error[E0107]: missing generics for trait `test_2::Trait1` + --> $DIR/trait-impl-wrong-args-count.rs:61:21 + | +LL | reuse ::bar; + | ^^^^^^ expected 2 generic arguments + | +note: trait defined here, with 2 generic parameters: `A`, `B` + --> $DIR/trait-impl-wrong-args-count.rs:52:11 + | +LL | trait Trait1 { + | ^^^^^^ - - +help: add missing generic arguments + | +LL | reuse >::bar; + | ++++++ + +error[E0107]: missing generics for trait `test_2::Trait1` + --> $DIR/trait-impl-wrong-args-count.rs:68:21 + | +LL | reuse ::bar::<'static, u32, u32, 1> as bar3; + | ^^^^^^ expected 2 generic arguments + | +note: trait defined here, with 2 generic parameters: `A`, `B` + --> $DIR/trait-impl-wrong-args-count.rs:52:11 + | +LL | trait Trait1 { + | ^^^^^^ - - +help: add missing generic arguments + | +LL | reuse >::bar::<'static, u32, u32, 1> as bar3; + | ++++++ + +error[E0107]: missing generics for trait `test_2::Trait1` + --> $DIR/trait-impl-wrong-args-count.rs:71:21 + | +LL | reuse ::bar as bar4; + | ^^^^^^ expected 2 generic arguments + | +note: trait defined here, with 2 generic parameters: `A`, `B` + --> $DIR/trait-impl-wrong-args-count.rs:52:11 + | +LL | trait Trait1 { + | ^^^^^^ - - +help: add missing generic arguments + | +LL | reuse >::bar as bar4; + | ++++++ + +error[E0107]: associated function takes 0 generic arguments but 3 generic arguments were supplied + --> $DIR/trait-impl-wrong-args-count.rs:96:40 + | +LL | reuse >::bar; + | ^^^ expected 0 generic arguments + | +note: associated function defined here, with 0 generic parameters + --> $DIR/trait-impl-wrong-args-count.rs:87:12 + | +LL | fn bar() {} + | ^^^ + +error[E0107]: associated function takes 0 generic arguments but 3 generic arguments were supplied + --> $DIR/trait-impl-wrong-args-count.rs:99:40 + | +LL | reuse >::bar as bar1; + | ^^^ expected 0 generic arguments + | +note: associated function defined here, with 0 generic parameters + --> $DIR/trait-impl-wrong-args-count.rs:87:12 + | +LL | fn bar() {} + | ^^^ + +error[E0282]: type annotations needed + --> $DIR/trait-impl-wrong-args-count.rs:102:40 + | +LL | reuse >::foo as bar2; + | ^^^ cannot infer type of the type parameter `X` declared on the associated function `foo` + +error[E0107]: associated function takes at most 2 generic arguments but 3 generic arguments were supplied + --> $DIR/trait-impl-wrong-args-count.rs:105:40 + | +LL | fn bar3() {} + | --- help: remove the unnecessary generic argument +... +LL | reuse >::foo as bar3; + | ^^^ expected at most 2 generic arguments + | +note: associated function defined here, with at most 2 generic parameters: `X`, `Y` + --> $DIR/trait-impl-wrong-args-count.rs:88:12 + | +LL | fn foo() {} + | ^^^ - - + +error: aborting due to 11 previous errors + +Some errors have detailed explanations: E0107, E0282, E0284. +For more information about an error, try `rustc --explain E0107`.