@@ -9,7 +9,7 @@ mod macros;
9
9
mod display_source_code;
10
10
mod incremental;
11
11
12
- use std:: { env, sync:: Arc } ;
12
+ use std:: { collections :: HashMap , env, sync:: Arc } ;
13
13
14
14
use base_db:: { fixture:: WithFixture , FileRange , SourceDatabase , SourceDatabaseExt } ;
15
15
use expect_test:: Expect ;
@@ -83,9 +83,107 @@ fn check_types_impl(ra_fixture: &str, display_source: bool) {
83
83
checked_one = true ;
84
84
}
85
85
}
86
+
86
87
assert ! ( checked_one, "no `//^` annotations found" ) ;
87
88
}
88
89
90
+ fn check_no_mismatches ( ra_fixture : & str ) {
91
+ check_mismatches_impl ( ra_fixture, true )
92
+ }
93
+
94
+ #[ allow( unused) ]
95
+ fn check_mismatches ( ra_fixture : & str ) {
96
+ check_mismatches_impl ( ra_fixture, false )
97
+ }
98
+
99
+ fn check_mismatches_impl ( ra_fixture : & str , allow_none : bool ) {
100
+ let _tracing = setup_tracing ( ) ;
101
+ let ( db, file_id) = TestDB :: with_single_file ( ra_fixture) ;
102
+ let module = db. module_for_file ( file_id) ;
103
+ let def_map = module. def_map ( & db) ;
104
+
105
+ let mut defs: Vec < DefWithBodyId > = Vec :: new ( ) ;
106
+ visit_module ( & db, & def_map, module. local_id , & mut |it| defs. push ( it) ) ;
107
+ defs. sort_by_key ( |def| match def {
108
+ DefWithBodyId :: FunctionId ( it) => {
109
+ let loc = it. lookup ( & db) ;
110
+ loc. source ( & db) . value . syntax ( ) . text_range ( ) . start ( )
111
+ }
112
+ DefWithBodyId :: ConstId ( it) => {
113
+ let loc = it. lookup ( & db) ;
114
+ loc. source ( & db) . value . syntax ( ) . text_range ( ) . start ( )
115
+ }
116
+ DefWithBodyId :: StaticId ( it) => {
117
+ let loc = it. lookup ( & db) ;
118
+ loc. source ( & db) . value . syntax ( ) . text_range ( ) . start ( )
119
+ }
120
+ } ) ;
121
+ let mut mismatches = HashMap :: new ( ) ;
122
+ let mut push_mismatch = |src_ptr : InFile < SyntaxNode > , mismatch : TypeMismatch | {
123
+ let range = src_ptr. value . text_range ( ) ;
124
+ if src_ptr. file_id . call_node ( & db) . is_some ( ) {
125
+ panic ! ( "type mismatch in macro expansion" ) ;
126
+ }
127
+ let file_range = FileRange { file_id : src_ptr. file_id . original_file ( & db) , range } ;
128
+ let actual = format ! ( "expected {}, got {}" , mismatch. expected. display_test( & db) ,
129
+ mismatch. actual. display_test( & db) ) ;
130
+ mismatches. insert ( file_range, actual) ;
131
+ } ;
132
+ for def in defs {
133
+ let ( _body, body_source_map) = db. body_with_source_map ( def) ;
134
+ let inference_result = db. infer ( def) ;
135
+ for ( pat, mismatch) in inference_result. pat_type_mismatches ( ) {
136
+ let syntax_ptr = match body_source_map. pat_syntax ( pat) {
137
+ Ok ( sp) => {
138
+ let root = db. parse_or_expand ( sp. file_id ) . unwrap ( ) ;
139
+ sp. map ( |ptr| {
140
+ ptr. either (
141
+ |it| it. to_node ( & root) . syntax ( ) . clone ( ) ,
142
+ |it| it. to_node ( & root) . syntax ( ) . clone ( ) ,
143
+ )
144
+ } )
145
+ }
146
+ Err ( SyntheticSyntax ) => continue ,
147
+ } ;
148
+ push_mismatch ( syntax_ptr, mismatch. clone ( ) ) ;
149
+ }
150
+ for ( expr, mismatch) in inference_result. expr_type_mismatches ( ) {
151
+ let node = match body_source_map. expr_syntax ( expr) {
152
+ Ok ( sp) => {
153
+ let root = db. parse_or_expand ( sp. file_id ) . unwrap ( ) ;
154
+ sp. map ( |ptr| ptr. to_node ( & root) . syntax ( ) . clone ( ) )
155
+ }
156
+ Err ( SyntheticSyntax ) => continue ,
157
+ } ;
158
+ push_mismatch ( node, mismatch. clone ( ) ) ;
159
+ }
160
+ }
161
+ let mut checked_one = false ;
162
+ for ( file_id, annotations) in db. extract_annotations ( ) {
163
+ for ( range, expected) in annotations {
164
+ let file_range = FileRange { file_id, range } ;
165
+ if let Some ( mismatch) = mismatches. remove ( & file_range) {
166
+ assert_eq ! ( mismatch, expected) ;
167
+ } else {
168
+ assert ! ( false , "Expected mismatch not encountered: {}\n " , expected) ;
169
+ }
170
+ checked_one = true ;
171
+ }
172
+ }
173
+ let mut buf = String :: new ( ) ;
174
+ for ( range, mismatch) in mismatches {
175
+ format_to ! (
176
+ buf,
177
+ "{:?}: {}\n " ,
178
+ range. range,
179
+ mismatch,
180
+ ) ;
181
+ }
182
+ assert ! ( buf. is_empty( ) , "Unexpected type mismatches:\n {}" , buf) ;
183
+
184
+ assert ! ( checked_one || allow_none, "no `//^` annotations found" ) ;
185
+ }
186
+
89
187
fn type_at_range ( db : & TestDB , pos : FileRange ) -> Ty {
90
188
let file = db. parse ( pos. file_id ) . ok ( ) . unwrap ( ) ;
91
189
let expr = algo:: find_node_at_range :: < ast:: Expr > ( file. syntax ( ) , pos. range ) . unwrap ( ) ;
0 commit comments