1
1
use crate :: consts:: { constant_context, constant_simple} ;
2
2
use crate :: differing_macro_contexts;
3
3
use crate :: source:: snippet_opt;
4
+ use if_chain:: if_chain;
4
5
use rustc_ast:: ast:: InlineAsmTemplatePiece ;
5
6
use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher } ;
6
7
use rustc_hir:: def:: Res ;
@@ -29,6 +30,30 @@ pub struct SpanlessEq<'a, 'tcx> {
29
30
maybe_typeck_results : Option < & ' tcx TypeckResults < ' tcx > > ,
30
31
allow_side_effects : bool ,
31
32
expr_fallback : Option < Box < dyn FnMut ( & Expr < ' _ > , & Expr < ' _ > ) -> bool + ' a > > ,
33
+ /// This adds an additional type comparison to locals that insures that even the
34
+ /// inferred of the value is the same.
35
+ ///
36
+ /// **Example**
37
+ /// * Context 1
38
+ /// ```ignore
39
+ /// let vec = Vec::new();
40
+ /// vec.push("A string");
41
+ /// ```
42
+ ///
43
+ /// * Context 2
44
+ /// ```ignore
45
+ /// let vec = Vec::new();
46
+ /// vec.push(0); // An integer
47
+ /// ```
48
+ ///
49
+ /// Only comparing the first local definition would usually return that they are
50
+ /// equal, since they are identical. However, they are different due to the context
51
+ /// as they have different inferred types.
52
+ ///
53
+ /// This option enables or disables the specific check of the inferred type.
54
+ ///
55
+ /// Note: This check will only be done if `self.maybe_typeck_results` is `Some()`.
56
+ check_inferred_local_types : bool ,
32
57
}
33
58
34
59
impl < ' a , ' tcx > SpanlessEq < ' a , ' tcx > {
@@ -38,6 +63,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
38
63
maybe_typeck_results : cx. maybe_typeck_results ( ) ,
39
64
allow_side_effects : true ,
40
65
expr_fallback : None ,
66
+ check_inferred_local_types : false ,
41
67
}
42
68
}
43
69
@@ -56,6 +82,13 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
56
82
}
57
83
}
58
84
85
+ pub fn enable_check_inferred_local_types ( self ) -> Self {
86
+ Self {
87
+ check_inferred_local_types : true ,
88
+ ..self
89
+ }
90
+ }
91
+
59
92
/// Use this method to wrap comparisons that may involve inter-expression context.
60
93
/// See `self.locals`.
61
94
pub fn inter_expr ( & mut self ) -> HirEqInterExpr < ' _ , ' a , ' tcx > {
@@ -96,6 +129,21 @@ impl HirEqInterExpr<'_, '_, '_> {
96
129
pub fn eq_stmt ( & mut self , left : & Stmt < ' _ > , right : & Stmt < ' _ > ) -> bool {
97
130
match ( & left. kind , & right. kind ) {
98
131
( & StmtKind :: Local ( ref l) , & StmtKind :: Local ( ref r) ) => {
132
+ // See `SpanlessEq::check_inferred_local_types` for an explication of this check
133
+ if_chain ! {
134
+ if l. ty. is_none( ) && r. ty. is_none( ) ;
135
+ if self . inner. check_inferred_local_types;
136
+ if let Some ( tcx) = self . inner. maybe_typeck_results;
137
+
138
+ // Check the inferred types
139
+ let l_ty = tcx. pat_ty( & l. pat) ;
140
+ let r_ty = tcx. pat_ty( & r. pat) ;
141
+ if l_ty != r_ty;
142
+ then {
143
+ return false ;
144
+ }
145
+ }
146
+
99
147
// eq_pat adds the HirIds to the locals map. We therefor call it last to make sure that
100
148
// these only get added if the init and type is equal.
101
149
both ( & l. init , & r. init , |l, r| self . eq_expr ( l, r) )
0 commit comments