Skip to content

Commit 23a51f5

Browse files
committed
Always generate generics that match trait in impl trait scenario
1 parent f824853 commit 23a51f5

8 files changed

Lines changed: 616 additions & 65 deletions

File tree

compiler/rustc_ast_lowering/src/delegation.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -724,9 +724,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
724724
result: &mut GenericsGenerationResult<'hir>,
725725
add_lifetimes: bool,
726726
) -> hir::PathSegment<'hir> {
727-
// The first condition is needed when there is SelfAndUserSpecified case,
727+
// The second condition is needed when there is SelfAndUserSpecified case,
728728
// we don't want to propagate generics params in this situation.
729-
let segment = if !result.generics.is_user_specified()
729+
let segment = if result.can_propagate()
730+
&& !result.generics.is_user_specified()
730731
&& let Some(args) = result
731732
.generics
732733
.into_hir_generics(self, item_id, span)

compiler/rustc_ast_lowering/src/delegation/generics.rs

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,15 @@ pub(super) enum HirOrAstGenerics<'hir> {
3838
Hir(DelegationGenerics<&'hir hir::Generics<'hir>>),
3939
}
4040

41+
pub(super) enum PropagationKind {
42+
Allowed,
43+
Forbidden,
44+
}
45+
4146
pub(super) struct GenericsGenerationResult<'hir> {
4247
pub(super) generics: HirOrAstGenerics<'hir>,
4348
pub(super) args_segment_id: Option<HirId>,
49+
pub(super) propagation_kind: PropagationKind,
4450
}
4551

4652
pub(super) struct GenericsGenerationResults<'hir> {
@@ -127,12 +133,20 @@ impl<'hir> HirOrAstGenerics<'hir> {
127133
}
128134

129135
impl<'a> GenericsGenerationResult<'a> {
130-
fn new(generics: DelegationGenerics<Generics>) -> GenericsGenerationResult<'a> {
136+
fn new(
137+
generics: DelegationGenerics<Generics>,
138+
propagation_kind: PropagationKind,
139+
) -> GenericsGenerationResult<'a> {
131140
GenericsGenerationResult {
132141
generics: HirOrAstGenerics::Ast(generics),
133142
args_segment_id: None,
143+
propagation_kind,
134144
}
135145
}
146+
147+
pub(super) fn can_propagate(&self) -> bool {
148+
matches!(self.propagation_kind, PropagationKind::Allowed)
149+
}
136150
}
137151

138152
impl<'hir> GenericsGenerationResults<'hir> {
@@ -147,6 +161,8 @@ impl<'hir> GenericsGenerationResults<'hir> {
147161
// method call will be supported (if HIR generics were not obtained
148162
// then it means that we did not propagated them, thus we do not need
149163
// to generate params).
164+
// FIXME(fn_delegation): in impl trait case we still need to generate
165+
// generic params, so this should be reworked.
150166
let parent = self
151167
.parent
152168
.generics
@@ -189,6 +205,8 @@ impl<'hir> GenericsGenerationResults<'hir> {
189205
// method call will be supported (if HIR generics were not obtained
190206
// then it means that we did not propagated them, thus we do not need
191207
// to generate predicates).
208+
// FIXME(fn_delegation): in impl trait case we still need to generate
209+
// generic params, so this should be reworked.
192210
self.parent
193211
.generics
194212
.into_hir_generics(ctx, item_id, span)
@@ -215,10 +233,38 @@ impl<'hir> LoweringContext<'_, 'hir> {
215233
item_id: NodeId,
216234
span: Span,
217235
) -> GenericsGenerationResults<'hir> {
218-
let delegation_in_free_ctx = !matches!(
219-
self.tcx.def_kind(self.tcx.local_parent(self.local_def_id(item_id))),
220-
DefKind::Trait | DefKind::Impl { .. }
221-
);
236+
let delegation_parent_kind =
237+
self.tcx.def_kind(self.tcx.local_parent(self.local_def_id(item_id)));
238+
239+
// If we are in impl trait always generate function whose generics matches
240+
// those that are defined in trait.
241+
if matches!(delegation_parent_kind, DefKind::Impl { of_trait: true }) {
242+
// Considering parent generics, during signature inheritance
243+
// we will take those args that are in impl trait header trait ref.
244+
let parent = GenericsGenerationResult::new(
245+
DelegationGenerics::Default(None),
246+
PropagationKind::Forbidden,
247+
);
248+
249+
// Check if we can propagate generics: now we do it only if delegation
250+
// path resolution matches the signature.
251+
// FIXME(fn_delegation): more advanced checks for propagation,
252+
// i.e., comparing generics of signature and `res` fn.
253+
let res = self.get_resolution_id(delegation.id);
254+
let prop_kind = if res.is_some_and(|def_id| def_id == root_fn_id) {
255+
PropagationKind::Allowed
256+
} else {
257+
PropagationKind::Forbidden
258+
};
259+
260+
let child = DelegationGenerics::Default(self.get_fn_like_generics(root_fn_id, span));
261+
let child = GenericsGenerationResult::new(child, prop_kind);
262+
263+
return GenericsGenerationResults { parent, child };
264+
}
265+
266+
let delegation_in_free_ctx =
267+
!matches!(delegation_parent_kind, DefKind::Trait | DefKind::Impl { .. });
222268

223269
let root_function_in_trait =
224270
matches!(self.tcx.def_kind(self.tcx.parent(root_fn_id)), DefKind::Trait);
@@ -263,8 +309,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
263309
};
264310

265311
GenericsGenerationResults {
266-
parent: GenericsGenerationResult::new(parent_generics),
267-
child: GenericsGenerationResult::new(child_generics),
312+
parent: GenericsGenerationResult::new(parent_generics, PropagationKind::Allowed),
313+
child: GenericsGenerationResult::new(child_generics, PropagationKind::Allowed),
268314
}
269315
}
270316

compiler/rustc_hir_analysis/src/delegation.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,8 @@ fn create_generic_args<'tcx>(
339339

340340
(FnKind::AssocTraitImpl, FnKind::AssocTrait) => {
341341
// Special case, as user specifies Trait args in impl trait header, we want to treat
342-
// them as parent args.
342+
// them as parent args. We always generate a function whose generics match
343+
// child generics in trait.
343344
let parent = tcx.local_parent(delegation_id);
344345
parent_args = tcx.impl_trait_header(parent).trait_ref.instantiate_identity().args;
345346
tcx.mk_args(&delegation_args[delegation_parent_args_count..])
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
#![feature(fn_delegation)]
2+
#![allow(incomplete_features)]
3+
#![allow(late_bound_lifetime_arguments)]
4+
5+
mod test_1 {
6+
mod to_reuse {
7+
pub fn foo<'a: 'a, 'b: 'b, A, B, const N: usize>() {}
8+
pub fn bar<'a: 'a, 'b: 'b, A, B, const N: usize>(_x: &super::XX) {}
9+
}
10+
11+
trait Trait<'a, 'b, 'c, A, B, const N: usize>: Sized {
12+
fn foo<'x: 'x, 'y: 'y, AA, BB, const NN: usize>() {}
13+
fn bar<'x: 'x, 'y: 'y, AA, BB, const NN: usize>(&self) {}
14+
15+
fn foo1<'x: 'x, 'y: 'y, AA, BB, const NN: usize>() {}
16+
fn bar1<'x: 'x, 'y: 'y, AA, BB, const NN: usize>(&self) {}
17+
}
18+
19+
trait Trait1<'a, 'b, 'c, A, B, const N: usize>: Sized {
20+
fn foo1<'x: 'x, 'y: 'y, AA, BB, const NN: usize>() {}
21+
fn bar1<'x: 'x, 'y: 'y, AA, BB, const NN: usize>(&self) {}
22+
}
23+
24+
#[allow(dead_code)] // Fields are used instead of phantom data for generics use
25+
struct X<'x1, 'x2, 'x3, 'x4, X1, X2, const X3: usize>(
26+
&'x1 X1, &'x2 X2, &'x3 X1, &'x4 [usize; X3]);
27+
type XX = X::<'static, 'static, 'static, 'static, i32, i32, 3>;
28+
29+
impl<'a, 'b, 'c, A, B, const N: usize> Trait<'a, 'b, 'c, A, B, N> for XX {
30+
reuse to_reuse::foo;
31+
//~^ ERROR: type annotations needed
32+
reuse to_reuse::bar;
33+
//~^ ERROR: type annotations needed
34+
35+
reuse Trait1::foo1;
36+
//~^ ERROR: type annotations needed
37+
//~| ERROR: type annotations needed
38+
reuse Trait1::bar1;
39+
//~^ ERROR: no method named `bar1` found for reference
40+
}
41+
}
42+
43+
mod test_2 {
44+
mod to_reuse {
45+
pub fn foo<A, B, const N: usize>() {}
46+
pub fn bar<A, B, const N: usize>(_x: &super::X) {}
47+
}
48+
49+
trait Trait<'a, 'b, 'c, A, B, const N: usize>: Sized {
50+
fn foo<AA, BB, const NN: usize>() {}
51+
fn bar<AA, BB, const NN: usize>(&self) {}
52+
53+
fn foo1<AA, BB, const NN: usize>() {}
54+
fn bar1<AA, BB, const NN: usize>(&self) {}
55+
}
56+
57+
trait Trait1<'a, 'b, 'c, A, B, const N: usize>: Sized {
58+
fn foo1<AA, BB, const NN: usize>() {}
59+
fn bar1<AA, BB, const NN: usize>(&self) {}
60+
}
61+
62+
struct X;
63+
impl<'a, A, B, const N: usize> Trait<'a, 'static, 'static, A, B, N> for X {
64+
reuse to_reuse::foo;
65+
//~^ ERROR: type annotations needed
66+
reuse to_reuse::bar;
67+
//~^ ERROR: type annotations needed
68+
69+
reuse Trait1::foo1;
70+
//~^ ERROR: type annotations needed
71+
//~| ERROR: type annotations needed
72+
reuse Trait1::bar1;
73+
//~^ ERROR: no method named `bar1` found for reference
74+
}
75+
}
76+
77+
mod test_4 {
78+
mod to_reuse {
79+
pub fn foo<'a: 'a, 'b: 'b, A, B, const N: usize>() {}
80+
pub fn bar<'a: 'a, 'b: 'b, A, B, const N: usize>(_x: &super::X) {}
81+
}
82+
83+
trait Trait<A, B, const N: usize>: Sized {
84+
fn foo<'x: 'x, 'y: 'y, AA, BB, const NN: usize>() {}
85+
fn bar<'x: 'x, 'y: 'y, AA, BB, const NN: usize>(&self) {}
86+
87+
fn foo1<'x: 'x, 'y: 'y, AA, BB, const NN: usize>() {}
88+
fn bar1<'x: 'x, 'y: 'y, AA, BB, const NN: usize>(&self) {}
89+
}
90+
91+
trait Trait1<A, B, const N: usize>: Sized {
92+
fn foo1<'x: 'x, 'y: 'y, AA, BB, const NN: usize>() {}
93+
fn bar1<'x: 'x, 'y: 'y, AA, BB, const NN: usize>(&self) {}
94+
}
95+
96+
struct X;
97+
impl<'a, 'c, A, B, const N: usize> Trait<A, B, N> for X {
98+
reuse to_reuse::foo;
99+
//~^ ERROR: type annotations needed
100+
reuse to_reuse::bar;
101+
//~^ ERROR: type annotations needed
102+
103+
reuse Trait1::foo1;
104+
//~^ ERROR: type annotations needed
105+
//~| ERROR: type annotations needed
106+
reuse Trait1::bar1;
107+
//~^ ERROR: no method named `bar1` found for reference
108+
}
109+
}
110+
111+
mod test_5 {
112+
mod to_reuse {
113+
pub fn foo<'a: 'a, 'b: 'b, A, B, const N: usize>() {}
114+
}
115+
116+
trait Trait: Sized {
117+
fn foo<'x: 'x, 'y: 'y, AA, BB, const NN: usize>() {}
118+
fn foo1<'x: 'x, 'y: 'y, AA, BB, const NN: usize>() {}
119+
}
120+
121+
trait Trait1: Sized {
122+
fn foo1<'x: 'x, 'y: 'y, AA, BB, const NN: usize>() {}
123+
}
124+
125+
struct X<A, B>(A, B);
126+
impl<'a, 'c, A, B> Trait for X<A, B> {
127+
reuse to_reuse::foo;
128+
//~^ ERROR: type annotations needed
129+
130+
reuse Trait1::foo1;
131+
//~^ ERROR: type annotations needed
132+
//~| ERROR: type annotations needed
133+
}
134+
}
135+
136+
mod test_6 {
137+
mod to_reuse {
138+
pub fn foo<A, B, const N: usize>() {}
139+
pub fn bar<A, B, const N: usize>(_x: &super::X) {}
140+
}
141+
142+
trait Trait<A, B, const N: usize>: Sized {
143+
fn foo<AA, BB, const NN: usize>() {}
144+
fn bar<AA, BB, const NN: usize>(&self) {}
145+
146+
fn foo1<AA, BB, const NN: usize>() {}
147+
fn bar1<AA, BB, const NN: usize>(&self) {}
148+
}
149+
150+
trait Trait1<A, B, const N: usize>: Sized {
151+
fn foo1<AA, BB, const NN: usize>() {}
152+
fn bar1<AA, BB, const NN: usize>(&self) {}
153+
}
154+
155+
struct X;
156+
impl<'a, 'c, A, B, const N: usize> Trait<A, B, N> for X {
157+
reuse to_reuse::foo;
158+
//~^ ERROR: type annotations needed
159+
reuse to_reuse::bar;
160+
//~^ ERROR: type annotations needed
161+
162+
reuse Trait1::foo1;
163+
//~^ ERROR: type annotations needed
164+
//~| ERROR: type annotations needed
165+
reuse Trait1::bar1;
166+
//~^ ERROR: no method named `bar1` found for reference
167+
}
168+
}
169+
170+
fn main() {
171+
}

0 commit comments

Comments
 (0)