Skip to content

Commit 82b7a35

Browse files
committed
support enum variants too
1 parent 755e108 commit 82b7a35

File tree

3 files changed

+169
-16
lines changed

3 files changed

+169
-16
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

Lines changed: 93 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2095,15 +2095,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
20952095
.map(|(index, _ty_arg)| index)
20962096
.collect();
20972097

2098-
eprintln!("@@@@@@@@@@@@ checing expr...");
2099-
21002098
// Different expression require different treatment. In general, we hope that we have a literal
21012099
// expression which produces the current `Self` type. Moreoever, we hope that it has a single
21022100
// field which can be "blamed" for the missing trait, so that it can be highlighted.
21032101
match expr.kind {
21042102
hir::ExprKind::Struct(
21052103
hir::QPath::Resolved(
2106-
None,
2104+
_,
21072105
hir::Path { res: hir::def::Res::Def(struct_def_kind, struct_def_id), .. },
21082106
),
21092107
struct_fields,
@@ -2200,10 +2198,98 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
22002198
// We failed to find a matching field in the original struct expression.
22012199
Err(expr)
22022200
}
2203-
_ => {
2204-
eprintln!("!!!!!!!!!!!!! cannot handle expr {:#?}", expr);
2205-
Err(expr)
2206-
} // Stop propagating.
2201+
hir::ExprKind::Call(call_ctor_func, call_ctor_args) => match &call_ctor_func.kind {
2202+
hir::ExprKind::Path(hir::QPath::Resolved(
2203+
_,
2204+
hir::Path {
2205+
res:
2206+
hir::def::Res::Def(
2207+
hir::def::DefKind::Ctor(_ctor_of, hir::def::CtorKind::Fn),
2208+
ctor_def_id,
2209+
),
2210+
..
2211+
},
2212+
)) => {
2213+
let (struct_variant_def, struct_def_generics) = {
2214+
let mut struct_def_id = self.tcx.parent(*ctor_def_id);
2215+
if impl_self_ty_path.did() != struct_def_id {
2216+
// Why do we try this twice?
2217+
//
2218+
// If we're looking at a struct tuple constructor, we'll get the ctor.
2219+
// And the ctor's parent is the struct itself.
2220+
//
2221+
// However, if we're looking at an enum ctor, its parent is the enum variant,
2222+
// whose parent is the enum itself.
2223+
//
2224+
// So the simplest fix is to try both `.parent()` and `.parent().parent()`.
2225+
struct_def_id = self.tcx.parent(struct_def_id);
2226+
}
2227+
if impl_self_ty_path.did() != struct_def_id {
2228+
// If the struct is not the same as `Self`, we cannot refine.
2229+
return Err(expr);
2230+
}
2231+
2232+
let struct_def_generics: &ty::Generics =
2233+
self.tcx.generics_of(struct_def_id);
2234+
2235+
let struct_variant_def: Option<&ty::VariantDef> = impl_self_ty_path
2236+
.variants()
2237+
.iter()
2238+
.find(|variant: &&ty::VariantDef| -> bool {
2239+
variant.ctor.map(|ctor| ctor.1 == *ctor_def_id).unwrap_or(false)
2240+
});
2241+
2242+
let Some(struct_variant_def) = struct_variant_def else {
2243+
return Err(expr);
2244+
};
2245+
2246+
// Use the sole variant definition as our variant from now on:
2247+
(struct_variant_def, struct_def_generics)
2248+
};
2249+
2250+
// Only retain the generics which are relevant (according to the `impl`).
2251+
let struct_def_generics: Vec<&ty::GenericParamDef> = relevant_ty_args_indices
2252+
.into_iter()
2253+
.filter_map(|index| struct_def_generics.params.get(index))
2254+
.collect();
2255+
2256+
// The struct being constructed is the same as the struct in the impl.
2257+
2258+
let blameable_field_defs: Vec<&ty::FieldDef> = struct_variant_def
2259+
.fields
2260+
.iter()
2261+
.filter(|field_def| {
2262+
let field_type: Ty<'tcx> = self.tcx.type_of(field_def.did);
2263+
2264+
// Only retain fields which mention the blameable generics.
2265+
struct_def_generics
2266+
.iter()
2267+
.any(|param| find_param_def_in_ty_walker(field_type.walk(), param))
2268+
})
2269+
.collect();
2270+
2271+
if blameable_field_defs.len() != 1 {
2272+
// We must have a single blameable field, in order to be able to blame it.
2273+
return Err(expr);
2274+
}
2275+
2276+
let blameable_field_def: &ty::FieldDef = blameable_field_defs[0];
2277+
let blameable_field_index = struct_variant_def
2278+
.fields
2279+
.iter()
2280+
.position(|field_def| field_def == blameable_field_def)
2281+
.expect("exists in list");
2282+
2283+
if blameable_field_index < call_ctor_args.len() {
2284+
return Ok(&call_ctor_args[blameable_field_index]);
2285+
}
2286+
2287+
// We failed to find a matching field in the original struct expression.
2288+
Err(expr)
2289+
}
2290+
call_ctor_func_kind => Err(expr),
2291+
},
2292+
_ => Err(expr),
22072293
}
22082294
}
22092295

src/test/ui/tuple/blame-trait-error.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@ enum BurritoKinds<G> {
2727
}
2828
impl<D: T3> T2 for BurritoKinds<D> {}
2929

30+
struct Taco<H>(bool, H);
31+
impl<E: T3> T2 for Taco<E> {}
32+
33+
enum TacoKinds<H> {
34+
OneTaco(bool, H),
35+
TwoTacos(bool, H, H),
36+
}
37+
impl<F: T3> T2 for TacoKinds<F> {}
38+
3039
fn want<V: T1>(_x: V) {}
3140

3241
fn example<Q>(q: Q) {
@@ -35,6 +44,12 @@ fn example<Q>(q: Q) {
3544

3645
want(Wrapper { value: BurritoKinds::SmallBurrito { spicy: true, small_filling: q } });
3746
//~^ ERROR the trait bound `Q: T3` is not satisfied [E0277]
47+
48+
want(Wrapper { value: Taco(false, q) });
49+
//~^ ERROR the trait bound `Q: T3` is not satisfied [E0277]
50+
51+
want(Wrapper { value: TacoKinds::OneTaco(false, q) });
52+
//~^ ERROR the trait bound `Q: T3` is not satisfied [E0277]
3853
}
3954

4055
fn main() {}

src/test/ui/tuple/blame-trait-error.stderr

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
@@@@@@@@@@@@ checing expr...
2-
@@@@@@@@@@@@ checing expr...
31
error[E0277]: the trait bound `Q: T3` is not satisfied
4-
--> $DIR/blame-trait-error.rs:33:60
2+
--> $DIR/blame-trait-error.rs:42:60
53
|
64
LL | want(Wrapper { value: Burrito { spicy: false, filling: q } });
75
| ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q`
@@ -17,7 +15,7 @@ note: required for `Wrapper<Burrito<Q>>` to implement `T1`
1715
LL | impl<B: T2> T1 for Wrapper<B> {}
1816
| ^^ ^^^^^^^^^^
1917
note: required by a bound in `want`
20-
--> $DIR/blame-trait-error.rs:30:12
18+
--> $DIR/blame-trait-error.rs:39:12
2119
|
2220
LL | fn want<V: T1>(_x: V) {}
2321
| ^^ required by this bound in `want`
@@ -26,10 +24,8 @@ help: consider restricting type parameter `Q`
2624
LL | fn example<Q: T3>(q: Q) {
2725
| ++++
2826

29-
@@@@@@@@@@@@ checing expr...
30-
@@@@@@@@@@@@ checing expr...
3127
error[E0277]: the trait bound `Q: T3` is not satisfied
32-
--> $DIR/blame-trait-error.rs:36:84
28+
--> $DIR/blame-trait-error.rs:45:84
3329
|
3430
LL | want(Wrapper { value: BurritoKinds::SmallBurrito { spicy: true, small_filling: q } });
3531
| ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q`
@@ -45,7 +41,7 @@ note: required for `Wrapper<BurritoKinds<Q>>` to implement `T1`
4541
LL | impl<B: T2> T1 for Wrapper<B> {}
4642
| ^^ ^^^^^^^^^^
4743
note: required by a bound in `want`
48-
--> $DIR/blame-trait-error.rs:30:12
44+
--> $DIR/blame-trait-error.rs:39:12
4945
|
5046
LL | fn want<V: T1>(_x: V) {}
5147
| ^^ required by this bound in `want`
@@ -54,6 +50,62 @@ help: consider restricting type parameter `Q`
5450
LL | fn example<Q: T3>(q: Q) {
5551
| ++++
5652

57-
error: aborting due to 2 previous errors
53+
error[E0277]: the trait bound `Q: T3` is not satisfied
54+
--> $DIR/blame-trait-error.rs:48:39
55+
|
56+
LL | want(Wrapper { value: Taco(false, q) });
57+
| ---- ^ the trait `T3` is not implemented for `Q`
58+
| |
59+
| required by a bound introduced by this call
60+
|
61+
note: required for `Taco<Q>` to implement `T2`
62+
--> $DIR/blame-trait-error.rs:31:13
63+
|
64+
LL | impl<E: T3> T2 for Taco<E> {}
65+
| ^^ ^^^^^^^
66+
note: required for `Wrapper<Taco<Q>>` to implement `T1`
67+
--> $DIR/blame-trait-error.rs:12:13
68+
|
69+
LL | impl<B: T2> T1 for Wrapper<B> {}
70+
| ^^ ^^^^^^^^^^
71+
note: required by a bound in `want`
72+
--> $DIR/blame-trait-error.rs:39:12
73+
|
74+
LL | fn want<V: T1>(_x: V) {}
75+
| ^^ required by this bound in `want`
76+
help: consider restricting type parameter `Q`
77+
|
78+
LL | fn example<Q: T3>(q: Q) {
79+
| ++++
80+
81+
error[E0277]: the trait bound `Q: T3` is not satisfied
82+
--> $DIR/blame-trait-error.rs:51:53
83+
|
84+
LL | want(Wrapper { value: TacoKinds::OneTaco(false, q) });
85+
| ---- ^ the trait `T3` is not implemented for `Q`
86+
| |
87+
| required by a bound introduced by this call
88+
|
89+
note: required for `TacoKinds<Q>` to implement `T2`
90+
--> $DIR/blame-trait-error.rs:37:13
91+
|
92+
LL | impl<F: T3> T2 for TacoKinds<F> {}
93+
| ^^ ^^^^^^^^^^^^
94+
note: required for `Wrapper<TacoKinds<Q>>` to implement `T1`
95+
--> $DIR/blame-trait-error.rs:12:13
96+
|
97+
LL | impl<B: T2> T1 for Wrapper<B> {}
98+
| ^^ ^^^^^^^^^^
99+
note: required by a bound in `want`
100+
--> $DIR/blame-trait-error.rs:39:12
101+
|
102+
LL | fn want<V: T1>(_x: V) {}
103+
| ^^ required by this bound in `want`
104+
help: consider restricting type parameter `Q`
105+
|
106+
LL | fn example<Q: T3>(q: Q) {
107+
| ++++
108+
109+
error: aborting due to 4 previous errors
58110

59111
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)