11use crate :: consts:: { constant_context, constant_simple} ;
22use crate :: differing_macro_contexts;
33use crate :: source:: snippet_opt;
4+ use if_chain:: if_chain;
45use rustc_ast:: ast:: InlineAsmTemplatePiece ;
56use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher } ;
67use rustc_hir:: def:: Res ;
@@ -29,6 +30,30 @@ pub struct SpanlessEq<'a, 'tcx> {
2930 maybe_typeck_results : Option < & ' tcx TypeckResults < ' tcx > > ,
3031 allow_side_effects : bool ,
3132 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 ,
3257}
3358
3459impl < ' a , ' tcx > SpanlessEq < ' a , ' tcx > {
@@ -38,6 +63,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
3863 maybe_typeck_results : cx. maybe_typeck_results ( ) ,
3964 allow_side_effects : true ,
4065 expr_fallback : None ,
66+ check_inferred_local_types : false ,
4167 }
4268 }
4369
@@ -56,6 +82,13 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
5682 }
5783 }
5884
85+ pub fn enable_check_inferred_local_types ( self ) -> Self {
86+ Self {
87+ check_inferred_local_types : true ,
88+ ..self
89+ }
90+ }
91+
5992 /// Use this method to wrap comparisons that may involve inter-expression context.
6093 /// See `self.locals`.
6194 pub fn inter_expr ( & mut self ) -> HirEqInterExpr < ' _ , ' a , ' tcx > {
@@ -96,6 +129,21 @@ impl HirEqInterExpr<'_, '_, '_> {
96129 pub fn eq_stmt ( & mut self , left : & Stmt < ' _ > , right : & Stmt < ' _ > ) -> bool {
97130 match ( & left. kind , & right. kind ) {
98131 ( & 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+
99147 // eq_pat adds the HirIds to the locals map. We therefor call it last to make sure that
100148 // these only get added if the init and type is equal.
101149 both ( & l. init , & r. init , |l, r| self . eq_expr ( l, r) )
0 commit comments