File tree Expand file tree Collapse file tree 4 files changed +93
-38
lines changed Expand file tree Collapse file tree 4 files changed +93
-38
lines changed Original file line number Diff line number Diff line change @@ -133,9 +133,9 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
133
133
// }
134
134
//
135
135
// We suggest #[derive(Default)] if
136
- // - `val` is `Default::default()`
137
- // - `val` is `0`
138
- // - `val` is `false`
136
+ // - `val` is `Default::default()`
137
+ // - `val` is `0`
138
+ // - `val` is `false`
139
139
fn check_expr ( tcx : TyCtxt < ' _ > , kind : hir:: ExprKind < ' _ > ) -> bool {
140
140
match kind {
141
141
hir:: ExprKind :: Lit ( spanned_lit) => match spanned_lit. node {
@@ -152,9 +152,20 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
152
152
// field: Default::default(),
153
153
true
154
154
}
155
- _ => {
156
- false
155
+ hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( _, path) )
156
+ if let Res :: Def (
157
+ DefKind :: Ctor ( CtorOf :: Variant , CtorKind :: Const ) ,
158
+ def_id,
159
+ ) = path. res
160
+ && let def_id = tcx. parent ( def_id) // From Ctor to variant
161
+ && tcx. is_lang_item ( def_id, hir:: LangItem :: OptionNone ) =>
162
+ {
163
+ // FIXME: We should use a better check where we explore existing
164
+ // `impl Default for def_id` of the found type and see compare them
165
+ // against what we have here. For now, special case `Option::None`.
166
+ true
157
167
}
168
+ _ => false ,
158
169
}
159
170
}
160
171
if fields. iter ( ) . all ( |f| check_expr ( cx. tcx , f. expr . kind ) ) {
Original file line number Diff line number Diff line change 25
25
// }
26
26
//
27
27
28
+ // Explicit check against numeric literals and `Default::default()` calls.
28
29
#[derive(Default)] struct D {
29
30
x: Option<i32>,
30
31
y: i32,
31
32
}
32
33
33
- //
34
- // #[derive(Debug)]
35
- // struct E {
36
- // x: Option<i32>,
37
- // }
38
- //
39
- // impl Default for E {
40
- // fn default() -> Self {
41
- // E {
42
- // x: None,
43
- // }
44
- // }
45
- // }
46
34
35
+ // Explicit check against `None` literal, in the same way that we check against numeric literals.
36
+ #[derive(Debug)]
37
+ #[derive(Default)] struct E {
38
+ x: Option<i32>,
39
+ }
40
+
41
+
42
+ // Detection of unit variant ctors that could have been marked `#[default]`.
47
43
#[derive(Default)] enum F {
48
44
#[default] Unit,
49
45
Tuple(i32),
50
46
}
51
47
52
48
49
+ // Comparison of `impl` *fields* with their `Default::default()` bodies.
50
+ // struct G {
51
+ // f: F,
52
+ // }
53
+
54
+ // impl Default for G {
55
+ // fn default() -> Self {
56
+ // G {
57
+ // f: F::Unit,
58
+ // }
59
+ // }
60
+ // }
61
+
53
62
fn main() {
54
63
// let _ = A::default();
55
64
// let _ = B::default();
56
65
// let _ = C::default();
57
- // let _ = D::default();
58
- // let _ = E::default();
66
+ let _ = D::default();
67
+ let _ = E::default();
59
68
let _ = F::default();
69
+ // let _ = G::default();
60
70
}
Original file line number Diff line number Diff line change 25
25
// }
26
26
//
27
27
28
+ // Explicit check against numeric literals and `Default::default()` calls.
28
29
struct D {
29
30
x : Option < i32 > ,
30
31
y : i32 ,
@@ -38,20 +39,22 @@ impl Default for D { //~ ERROR
38
39
}
39
40
}
40
41
}
41
- //
42
- // #[derive(Debug)]
43
- // struct E {
44
- // x: Option<i32>,
45
- // }
46
- //
47
- // impl Default for E {
48
- // fn default() -> Self {
49
- // E {
50
- // x: None,
51
- // }
52
- // }
53
- // }
54
42
43
+ // Explicit check against `None` literal, in the same way that we check against numeric literals.
44
+ #[ derive( Debug ) ]
45
+ struct E {
46
+ x : Option < i32 > ,
47
+ }
48
+
49
+ impl Default for E { //~ ERROR
50
+ fn default ( ) -> Self {
51
+ E {
52
+ x : None ,
53
+ }
54
+ }
55
+ }
56
+
57
+ // Detection of unit variant ctors that could have been marked `#[default]`.
55
58
enum F {
56
59
Unit ,
57
60
Tuple ( i32 ) ,
@@ -63,11 +66,25 @@ impl Default for F { //~ ERROR
63
66
}
64
67
}
65
68
69
+ // Comparison of `impl` *fields* with their `Default::default()` bodies.
70
+ // struct G {
71
+ // f: F,
72
+ // }
73
+
74
+ // impl Default for G {
75
+ // fn default() -> Self {
76
+ // G {
77
+ // f: F::Unit,
78
+ // }
79
+ // }
80
+ // }
81
+
66
82
fn main ( ) {
67
83
// let _ = A::default();
68
84
// let _ = B::default();
69
85
// let _ = C::default();
70
- // let _ = D::default();
71
- // let _ = E::default();
86
+ let _ = D :: default ( ) ;
87
+ let _ = E :: default ( ) ;
72
88
let _ = F :: default ( ) ;
89
+ // let _ = G::default();
73
90
}
Original file line number Diff line number Diff line change 1
1
error: `impl Default` that could be derived
2
- --> $DIR/manual-default-impl-could-be-derived.rs:33 :1
2
+ --> $DIR/manual-default-impl-could-be-derived.rs:34 :1
3
3
|
4
4
LL | / impl Default for D {
5
5
LL | | fn default() -> Self {
@@ -21,7 +21,24 @@ LL ~ #[derive(Default)] struct D {
21
21
|
22
22
23
23
error: `impl Default` that could be derived
24
- --> $DIR/manual-default-impl-could-be-derived.rs:60:1
24
+ --> $DIR/manual-default-impl-could-be-derived.rs:49:1
25
+ |
26
+ LL | / impl Default for E {
27
+ LL | | fn default() -> Self {
28
+ LL | | E {
29
+ LL | | x: None,
30
+ LL | | }
31
+ LL | | }
32
+ LL | | }
33
+ | |_^
34
+ |
35
+ help: you don't need to manually `impl Default`, you can derive it
36
+ |
37
+ LL ~ #[derive(Default)] struct E {
38
+ |
39
+
40
+ error: `impl Default` that could be derived
41
+ --> $DIR/manual-default-impl-could-be-derived.rs:63:1
25
42
|
26
43
LL | / impl Default for F {
27
44
LL | | fn default() -> Self {
@@ -36,5 +53,5 @@ LL ~ #[derive(Default)] enum F {
36
53
LL ~ #[default] Unit,
37
54
|
38
55
39
- error: aborting due to 2 previous errors
56
+ error: aborting due to 3 previous errors
40
57
You can’t perform that action at this time.
0 commit comments