diff options
Diffstat (limited to 'crates/hir_ty/src/tests/coercion.rs')
-rw-r--r-- | crates/hir_ty/src/tests/coercion.rs | 861 |
1 files changed, 861 insertions, 0 deletions
diff --git a/crates/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs new file mode 100644 index 000000000..17efd75cb --- /dev/null +++ b/crates/hir_ty/src/tests/coercion.rs | |||
@@ -0,0 +1,861 @@ | |||
1 | use expect::expect; | ||
2 | use test_utils::mark; | ||
3 | |||
4 | use super::{check_infer, check_infer_with_mismatches}; | ||
5 | |||
6 | #[test] | ||
7 | fn infer_block_expr_type_mismatch() { | ||
8 | check_infer( | ||
9 | r" | ||
10 | fn test() { | ||
11 | let a: i32 = { 1i64 }; | ||
12 | } | ||
13 | ", | ||
14 | expect![[r" | ||
15 | 10..40 '{ ...4 }; }': () | ||
16 | 20..21 'a': i32 | ||
17 | 29..37 '{ 1i64 }': i64 | ||
18 | 31..35 '1i64': i64 | ||
19 | "]], | ||
20 | ); | ||
21 | } | ||
22 | |||
23 | #[test] | ||
24 | fn coerce_places() { | ||
25 | check_infer( | ||
26 | r#" | ||
27 | struct S<T> { a: T } | ||
28 | |||
29 | fn f<T>(_: &[T]) -> T { loop {} } | ||
30 | fn g<T>(_: S<&[T]>) -> T { loop {} } | ||
31 | |||
32 | fn gen<T>() -> *mut [T; 2] { loop {} } | ||
33 | fn test1<U>() -> *mut [U] { | ||
34 | gen() | ||
35 | } | ||
36 | |||
37 | fn test2() { | ||
38 | let arr: &[u8; 1] = &[1]; | ||
39 | |||
40 | let a: &[_] = arr; | ||
41 | let b = f(arr); | ||
42 | let c: &[_] = { arr }; | ||
43 | let d = g(S { a: arr }); | ||
44 | let e: [&[_]; 1] = [arr]; | ||
45 | let f: [&[_]; 2] = [arr; 2]; | ||
46 | let g: (&[_], &[_]) = (arr, arr); | ||
47 | } | ||
48 | |||
49 | #[lang = "sized"] | ||
50 | pub trait Sized {} | ||
51 | #[lang = "unsize"] | ||
52 | pub trait Unsize<T: ?Sized> {} | ||
53 | #[lang = "coerce_unsized"] | ||
54 | pub trait CoerceUnsized<T> {} | ||
55 | |||
56 | impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} | ||
57 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} | ||
58 | "#, | ||
59 | expect![[r" | ||
60 | 30..31 '_': &[T] | ||
61 | 44..55 '{ loop {} }': T | ||
62 | 46..53 'loop {}': ! | ||
63 | 51..53 '{}': () | ||
64 | 64..65 '_': S<&[T]> | ||
65 | 81..92 '{ loop {} }': T | ||
66 | 83..90 'loop {}': ! | ||
67 | 88..90 '{}': () | ||
68 | 121..132 '{ loop {} }': *mut [T; _] | ||
69 | 123..130 'loop {}': ! | ||
70 | 128..130 '{}': () | ||
71 | 159..172 '{ gen() }': *mut [U] | ||
72 | 165..168 'gen': fn gen<U>() -> *mut [U; _] | ||
73 | 165..170 'gen()': *mut [U; _] | ||
74 | 185..419 '{ ...rr); }': () | ||
75 | 195..198 'arr': &[u8; _] | ||
76 | 211..215 '&[1]': &[u8; _] | ||
77 | 212..215 '[1]': [u8; _] | ||
78 | 213..214 '1': u8 | ||
79 | 226..227 'a': &[u8] | ||
80 | 236..239 'arr': &[u8; _] | ||
81 | 249..250 'b': u8 | ||
82 | 253..254 'f': fn f<u8>(&[u8]) -> u8 | ||
83 | 253..259 'f(arr)': u8 | ||
84 | 255..258 'arr': &[u8; _] | ||
85 | 269..270 'c': &[u8] | ||
86 | 279..286 '{ arr }': &[u8] | ||
87 | 281..284 'arr': &[u8; _] | ||
88 | 296..297 'd': u8 | ||
89 | 300..301 'g': fn g<u8>(S<&[u8]>) -> u8 | ||
90 | 300..315 'g(S { a: arr })': u8 | ||
91 | 302..314 'S { a: arr }': S<&[u8]> | ||
92 | 309..312 'arr': &[u8; _] | ||
93 | 325..326 'e': [&[u8]; _] | ||
94 | 340..345 '[arr]': [&[u8]; _] | ||
95 | 341..344 'arr': &[u8; _] | ||
96 | 355..356 'f': [&[u8]; _] | ||
97 | 370..378 '[arr; 2]': [&[u8]; _] | ||
98 | 371..374 'arr': &[u8; _] | ||
99 | 376..377 '2': usize | ||
100 | 388..389 'g': (&[u8], &[u8]) | ||
101 | 406..416 '(arr, arr)': (&[u8], &[u8]) | ||
102 | 407..410 'arr': &[u8; _] | ||
103 | 412..415 'arr': &[u8; _] | ||
104 | "]], | ||
105 | ); | ||
106 | } | ||
107 | |||
108 | #[test] | ||
109 | fn infer_let_stmt_coerce() { | ||
110 | check_infer( | ||
111 | r" | ||
112 | fn test() { | ||
113 | let x: &[isize] = &[1]; | ||
114 | let x: *const [isize] = &[1]; | ||
115 | } | ||
116 | ", | ||
117 | expect![[r" | ||
118 | 10..75 '{ ...[1]; }': () | ||
119 | 20..21 'x': &[isize] | ||
120 | 34..38 '&[1]': &[isize; _] | ||
121 | 35..38 '[1]': [isize; _] | ||
122 | 36..37 '1': isize | ||
123 | 48..49 'x': *const [isize] | ||
124 | 68..72 '&[1]': &[isize; _] | ||
125 | 69..72 '[1]': [isize; _] | ||
126 | 70..71 '1': isize | ||
127 | "]], | ||
128 | ); | ||
129 | } | ||
130 | |||
131 | #[test] | ||
132 | fn infer_custom_coerce_unsized() { | ||
133 | check_infer( | ||
134 | r#" | ||
135 | struct A<T: ?Sized>(*const T); | ||
136 | struct B<T: ?Sized>(*const T); | ||
137 | struct C<T: ?Sized> { inner: *const T } | ||
138 | |||
139 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<B<U>> for B<T> {} | ||
140 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<C<U>> for C<T> {} | ||
141 | |||
142 | fn foo1<T>(x: A<[T]>) -> A<[T]> { x } | ||
143 | fn foo2<T>(x: B<[T]>) -> B<[T]> { x } | ||
144 | fn foo3<T>(x: C<[T]>) -> C<[T]> { x } | ||
145 | |||
146 | fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) { | ||
147 | let d = foo1(a); | ||
148 | let e = foo2(b); | ||
149 | let f = foo3(c); | ||
150 | } | ||
151 | |||
152 | |||
153 | #[lang = "sized"] | ||
154 | pub trait Sized {} | ||
155 | #[lang = "unsize"] | ||
156 | pub trait Unsize<T: ?Sized> {} | ||
157 | #[lang = "coerce_unsized"] | ||
158 | pub trait CoerceUnsized<T> {} | ||
159 | |||
160 | impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} | ||
161 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} | ||
162 | "#, | ||
163 | expect![[r" | ||
164 | 257..258 'x': A<[T]> | ||
165 | 278..283 '{ x }': A<[T]> | ||
166 | 280..281 'x': A<[T]> | ||
167 | 295..296 'x': B<[T]> | ||
168 | 316..321 '{ x }': B<[T]> | ||
169 | 318..319 'x': B<[T]> | ||
170 | 333..334 'x': C<[T]> | ||
171 | 354..359 '{ x }': C<[T]> | ||
172 | 356..357 'x': C<[T]> | ||
173 | 369..370 'a': A<[u8; _]> | ||
174 | 384..385 'b': B<[u8; _]> | ||
175 | 399..400 'c': C<[u8; _]> | ||
176 | 414..480 '{ ...(c); }': () | ||
177 | 424..425 'd': A<[{unknown}]> | ||
178 | 428..432 'foo1': fn foo1<{unknown}>(A<[{unknown}]>) -> A<[{unknown}]> | ||
179 | 428..435 'foo1(a)': A<[{unknown}]> | ||
180 | 433..434 'a': A<[u8; _]> | ||
181 | 445..446 'e': B<[u8]> | ||
182 | 449..453 'foo2': fn foo2<u8>(B<[u8]>) -> B<[u8]> | ||
183 | 449..456 'foo2(b)': B<[u8]> | ||
184 | 454..455 'b': B<[u8; _]> | ||
185 | 466..467 'f': C<[u8]> | ||
186 | 470..474 'foo3': fn foo3<u8>(C<[u8]>) -> C<[u8]> | ||
187 | 470..477 'foo3(c)': C<[u8]> | ||
188 | 475..476 'c': C<[u8; _]> | ||
189 | "]], | ||
190 | ); | ||
191 | } | ||
192 | |||
193 | #[test] | ||
194 | fn infer_if_coerce() { | ||
195 | check_infer( | ||
196 | r#" | ||
197 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | ||
198 | fn test() { | ||
199 | let x = if true { | ||
200 | foo(&[1]) | ||
201 | } else { | ||
202 | &[1] | ||
203 | }; | ||
204 | } | ||
205 | |||
206 | |||
207 | #[lang = "sized"] | ||
208 | pub trait Sized {} | ||
209 | #[lang = "unsize"] | ||
210 | pub trait Unsize<T: ?Sized> {} | ||
211 | "#, | ||
212 | expect![[r" | ||
213 | 10..11 'x': &[T] | ||
214 | 27..38 '{ loop {} }': &[T] | ||
215 | 29..36 'loop {}': ! | ||
216 | 34..36 '{}': () | ||
217 | 49..125 '{ ... }; }': () | ||
218 | 59..60 'x': &[i32] | ||
219 | 63..122 'if tru... }': &[i32] | ||
220 | 66..70 'true': bool | ||
221 | 71..96 '{ ... }': &[i32] | ||
222 | 81..84 'foo': fn foo<i32>(&[i32]) -> &[i32] | ||
223 | 81..90 'foo(&[1])': &[i32] | ||
224 | 85..89 '&[1]': &[i32; _] | ||
225 | 86..89 '[1]': [i32; _] | ||
226 | 87..88 '1': i32 | ||
227 | 102..122 '{ ... }': &[i32; _] | ||
228 | 112..116 '&[1]': &[i32; _] | ||
229 | 113..116 '[1]': [i32; _] | ||
230 | 114..115 '1': i32 | ||
231 | "]], | ||
232 | ); | ||
233 | } | ||
234 | |||
235 | #[test] | ||
236 | fn infer_if_else_coerce() { | ||
237 | check_infer( | ||
238 | r#" | ||
239 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | ||
240 | fn test() { | ||
241 | let x = if true { | ||
242 | &[1] | ||
243 | } else { | ||
244 | foo(&[1]) | ||
245 | }; | ||
246 | } | ||
247 | |||
248 | #[lang = "sized"] | ||
249 | pub trait Sized {} | ||
250 | #[lang = "unsize"] | ||
251 | pub trait Unsize<T: ?Sized> {} | ||
252 | #[lang = "coerce_unsized"] | ||
253 | pub trait CoerceUnsized<T> {} | ||
254 | |||
255 | impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} | ||
256 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} | ||
257 | "#, | ||
258 | expect![[r" | ||
259 | 10..11 'x': &[T] | ||
260 | 27..38 '{ loop {} }': &[T] | ||
261 | 29..36 'loop {}': ! | ||
262 | 34..36 '{}': () | ||
263 | 49..125 '{ ... }; }': () | ||
264 | 59..60 'x': &[i32] | ||
265 | 63..122 'if tru... }': &[i32] | ||
266 | 66..70 'true': bool | ||
267 | 71..91 '{ ... }': &[i32; _] | ||
268 | 81..85 '&[1]': &[i32; _] | ||
269 | 82..85 '[1]': [i32; _] | ||
270 | 83..84 '1': i32 | ||
271 | 97..122 '{ ... }': &[i32] | ||
272 | 107..110 'foo': fn foo<i32>(&[i32]) -> &[i32] | ||
273 | 107..116 'foo(&[1])': &[i32] | ||
274 | 111..115 '&[1]': &[i32; _] | ||
275 | 112..115 '[1]': [i32; _] | ||
276 | 113..114 '1': i32 | ||
277 | "]], | ||
278 | ) | ||
279 | } | ||
280 | |||
281 | #[test] | ||
282 | fn infer_match_first_coerce() { | ||
283 | check_infer( | ||
284 | r#" | ||
285 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | ||
286 | fn test(i: i32) { | ||
287 | let x = match i { | ||
288 | 2 => foo(&[2]), | ||
289 | 1 => &[1], | ||
290 | _ => &[3], | ||
291 | }; | ||
292 | } | ||
293 | |||
294 | #[lang = "sized"] | ||
295 | pub trait Sized {} | ||
296 | #[lang = "unsize"] | ||
297 | pub trait Unsize<T: ?Sized> {} | ||
298 | "#, | ||
299 | expect![[r" | ||
300 | 10..11 'x': &[T] | ||
301 | 27..38 '{ loop {} }': &[T] | ||
302 | 29..36 'loop {}': ! | ||
303 | 34..36 '{}': () | ||
304 | 47..48 'i': i32 | ||
305 | 55..149 '{ ... }; }': () | ||
306 | 65..66 'x': &[i32] | ||
307 | 69..146 'match ... }': &[i32] | ||
308 | 75..76 'i': i32 | ||
309 | 87..88 '2': i32 | ||
310 | 87..88 '2': i32 | ||
311 | 92..95 'foo': fn foo<i32>(&[i32]) -> &[i32] | ||
312 | 92..101 'foo(&[2])': &[i32] | ||
313 | 96..100 '&[2]': &[i32; _] | ||
314 | 97..100 '[2]': [i32; _] | ||
315 | 98..99 '2': i32 | ||
316 | 111..112 '1': i32 | ||
317 | 111..112 '1': i32 | ||
318 | 116..120 '&[1]': &[i32; _] | ||
319 | 117..120 '[1]': [i32; _] | ||
320 | 118..119 '1': i32 | ||
321 | 130..131 '_': i32 | ||
322 | 135..139 '&[3]': &[i32; _] | ||
323 | 136..139 '[3]': [i32; _] | ||
324 | 137..138 '3': i32 | ||
325 | "]], | ||
326 | ); | ||
327 | } | ||
328 | |||
329 | #[test] | ||
330 | fn infer_match_second_coerce() { | ||
331 | check_infer( | ||
332 | r#" | ||
333 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | ||
334 | fn test(i: i32) { | ||
335 | let x = match i { | ||
336 | 1 => &[1], | ||
337 | 2 => foo(&[2]), | ||
338 | _ => &[3], | ||
339 | }; | ||
340 | } | ||
341 | |||
342 | #[lang = "sized"] | ||
343 | pub trait Sized {} | ||
344 | #[lang = "unsize"] | ||
345 | pub trait Unsize<T: ?Sized> {} | ||
346 | #[lang = "coerce_unsized"] | ||
347 | pub trait CoerceUnsized<T> {} | ||
348 | |||
349 | impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} | ||
350 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} | ||
351 | "#, | ||
352 | expect![[r" | ||
353 | 10..11 'x': &[T] | ||
354 | 27..38 '{ loop {} }': &[T] | ||
355 | 29..36 'loop {}': ! | ||
356 | 34..36 '{}': () | ||
357 | 47..48 'i': i32 | ||
358 | 55..149 '{ ... }; }': () | ||
359 | 65..66 'x': &[i32] | ||
360 | 69..146 'match ... }': &[i32] | ||
361 | 75..76 'i': i32 | ||
362 | 87..88 '1': i32 | ||
363 | 87..88 '1': i32 | ||
364 | 92..96 '&[1]': &[i32; _] | ||
365 | 93..96 '[1]': [i32; _] | ||
366 | 94..95 '1': i32 | ||
367 | 106..107 '2': i32 | ||
368 | 106..107 '2': i32 | ||
369 | 111..114 'foo': fn foo<i32>(&[i32]) -> &[i32] | ||
370 | 111..120 'foo(&[2])': &[i32] | ||
371 | 115..119 '&[2]': &[i32; _] | ||
372 | 116..119 '[2]': [i32; _] | ||
373 | 117..118 '2': i32 | ||
374 | 130..131 '_': i32 | ||
375 | 135..139 '&[3]': &[i32; _] | ||
376 | 136..139 '[3]': [i32; _] | ||
377 | 137..138 '3': i32 | ||
378 | "]], | ||
379 | ); | ||
380 | } | ||
381 | |||
382 | #[test] | ||
383 | fn coerce_merge_one_by_one1() { | ||
384 | mark::check!(coerce_merge_fail_fallback); | ||
385 | |||
386 | check_infer( | ||
387 | r" | ||
388 | fn test() { | ||
389 | let t = &mut 1; | ||
390 | let x = match 1 { | ||
391 | 1 => t as *mut i32, | ||
392 | 2 => t as &i32, | ||
393 | _ => t as *const i32, | ||
394 | }; | ||
395 | } | ||
396 | ", | ||
397 | expect![[r" | ||
398 | 10..144 '{ ... }; }': () | ||
399 | 20..21 't': &mut i32 | ||
400 | 24..30 '&mut 1': &mut i32 | ||
401 | 29..30 '1': i32 | ||
402 | 40..41 'x': *const i32 | ||
403 | 44..141 'match ... }': *const i32 | ||
404 | 50..51 '1': i32 | ||
405 | 62..63 '1': i32 | ||
406 | 62..63 '1': i32 | ||
407 | 67..68 't': &mut i32 | ||
408 | 67..80 't as *mut i32': *mut i32 | ||
409 | 90..91 '2': i32 | ||
410 | 90..91 '2': i32 | ||
411 | 95..96 't': &mut i32 | ||
412 | 95..104 't as &i32': &i32 | ||
413 | 114..115 '_': i32 | ||
414 | 119..120 't': &mut i32 | ||
415 | 119..134 't as *const i32': *const i32 | ||
416 | "]], | ||
417 | ); | ||
418 | } | ||
419 | |||
420 | #[test] | ||
421 | fn return_coerce_unknown() { | ||
422 | check_infer_with_mismatches( | ||
423 | r" | ||
424 | fn foo() -> u32 { | ||
425 | return unknown; | ||
426 | } | ||
427 | ", | ||
428 | expect![[r" | ||
429 | 16..39 '{ ...own; }': u32 | ||
430 | 22..36 'return unknown': ! | ||
431 | 29..36 'unknown': u32 | ||
432 | "]], | ||
433 | ); | ||
434 | } | ||
435 | |||
436 | #[test] | ||
437 | fn coerce_autoderef() { | ||
438 | check_infer_with_mismatches( | ||
439 | r" | ||
440 | struct Foo; | ||
441 | fn takes_ref_foo(x: &Foo) {} | ||
442 | fn test() { | ||
443 | takes_ref_foo(&Foo); | ||
444 | takes_ref_foo(&&Foo); | ||
445 | takes_ref_foo(&&&Foo); | ||
446 | } | ||
447 | ", | ||
448 | expect![[r" | ||
449 | 29..30 'x': &Foo | ||
450 | 38..40 '{}': () | ||
451 | 51..132 '{ ...oo); }': () | ||
452 | 57..70 'takes_ref_foo': fn takes_ref_foo(&Foo) | ||
453 | 57..76 'takes_...(&Foo)': () | ||
454 | 71..75 '&Foo': &Foo | ||
455 | 72..75 'Foo': Foo | ||
456 | 82..95 'takes_ref_foo': fn takes_ref_foo(&Foo) | ||
457 | 82..102 'takes_...&&Foo)': () | ||
458 | 96..101 '&&Foo': &&Foo | ||
459 | 97..101 '&Foo': &Foo | ||
460 | 98..101 'Foo': Foo | ||
461 | 108..121 'takes_ref_foo': fn takes_ref_foo(&Foo) | ||
462 | 108..129 'takes_...&&Foo)': () | ||
463 | 122..128 '&&&Foo': &&&Foo | ||
464 | 123..128 '&&Foo': &&Foo | ||
465 | 124..128 '&Foo': &Foo | ||
466 | 125..128 'Foo': Foo | ||
467 | "]], | ||
468 | ); | ||
469 | } | ||
470 | |||
471 | #[test] | ||
472 | fn coerce_autoderef_generic() { | ||
473 | check_infer_with_mismatches( | ||
474 | r" | ||
475 | struct Foo; | ||
476 | fn takes_ref<T>(x: &T) -> T { *x } | ||
477 | fn test() { | ||
478 | takes_ref(&Foo); | ||
479 | takes_ref(&&Foo); | ||
480 | takes_ref(&&&Foo); | ||
481 | } | ||
482 | ", | ||
483 | expect![[r" | ||
484 | 28..29 'x': &T | ||
485 | 40..46 '{ *x }': T | ||
486 | 42..44 '*x': T | ||
487 | 43..44 'x': &T | ||
488 | 57..126 '{ ...oo); }': () | ||
489 | 63..72 'takes_ref': fn takes_ref<Foo>(&Foo) -> Foo | ||
490 | 63..78 'takes_ref(&Foo)': Foo | ||
491 | 73..77 '&Foo': &Foo | ||
492 | 74..77 'Foo': Foo | ||
493 | 84..93 'takes_ref': fn takes_ref<&Foo>(&&Foo) -> &Foo | ||
494 | 84..100 'takes_...&&Foo)': &Foo | ||
495 | 94..99 '&&Foo': &&Foo | ||
496 | 95..99 '&Foo': &Foo | ||
497 | 96..99 'Foo': Foo | ||
498 | 106..115 'takes_ref': fn takes_ref<&&Foo>(&&&Foo) -> &&Foo | ||
499 | 106..123 'takes_...&&Foo)': &&Foo | ||
500 | 116..122 '&&&Foo': &&&Foo | ||
501 | 117..122 '&&Foo': &&Foo | ||
502 | 118..122 '&Foo': &Foo | ||
503 | 119..122 'Foo': Foo | ||
504 | "]], | ||
505 | ); | ||
506 | } | ||
507 | |||
508 | #[test] | ||
509 | fn coerce_autoderef_block() { | ||
510 | check_infer_with_mismatches( | ||
511 | r#" | ||
512 | struct String {} | ||
513 | #[lang = "deref"] | ||
514 | trait Deref { type Target; } | ||
515 | impl Deref for String { type Target = str; } | ||
516 | fn takes_ref_str(x: &str) {} | ||
517 | fn returns_string() -> String { loop {} } | ||
518 | fn test() { | ||
519 | takes_ref_str(&{ returns_string() }); | ||
520 | } | ||
521 | "#, | ||
522 | expect![[r" | ||
523 | 126..127 'x': &str | ||
524 | 135..137 '{}': () | ||
525 | 168..179 '{ loop {} }': String | ||
526 | 170..177 'loop {}': ! | ||
527 | 175..177 '{}': () | ||
528 | 190..235 '{ ... }); }': () | ||
529 | 196..209 'takes_ref_str': fn takes_ref_str(&str) | ||
530 | 196..232 'takes_...g() })': () | ||
531 | 210..231 '&{ ret...ng() }': &String | ||
532 | 211..231 '{ retu...ng() }': String | ||
533 | 213..227 'returns_string': fn returns_string() -> String | ||
534 | 213..229 'return...ring()': String | ||
535 | "]], | ||
536 | ); | ||
537 | } | ||
538 | |||
539 | #[test] | ||
540 | fn closure_return_coerce() { | ||
541 | check_infer_with_mismatches( | ||
542 | r" | ||
543 | fn foo() { | ||
544 | let x = || { | ||
545 | if true { | ||
546 | return &1u32; | ||
547 | } | ||
548 | &&1u32 | ||
549 | }; | ||
550 | } | ||
551 | ", | ||
552 | expect![[r" | ||
553 | 9..105 '{ ... }; }': () | ||
554 | 19..20 'x': || -> &u32 | ||
555 | 23..102 '|| { ... }': || -> &u32 | ||
556 | 26..102 '{ ... }': &u32 | ||
557 | 36..81 'if tru... }': () | ||
558 | 39..43 'true': bool | ||
559 | 44..81 '{ ... }': () | ||
560 | 58..70 'return &1u32': ! | ||
561 | 65..70 '&1u32': &u32 | ||
562 | 66..70 '1u32': u32 | ||
563 | 90..96 '&&1u32': &&u32 | ||
564 | 91..96 '&1u32': &u32 | ||
565 | 92..96 '1u32': u32 | ||
566 | "]], | ||
567 | ); | ||
568 | } | ||
569 | |||
570 | #[test] | ||
571 | fn coerce_fn_item_to_fn_ptr() { | ||
572 | check_infer_with_mismatches( | ||
573 | r" | ||
574 | fn foo(x: u32) -> isize { 1 } | ||
575 | fn test() { | ||
576 | let f: fn(u32) -> isize = foo; | ||
577 | } | ||
578 | ", | ||
579 | expect![[r" | ||
580 | 7..8 'x': u32 | ||
581 | 24..29 '{ 1 }': isize | ||
582 | 26..27 '1': isize | ||
583 | 40..78 '{ ...foo; }': () | ||
584 | 50..51 'f': fn(u32) -> isize | ||
585 | 72..75 'foo': fn foo(u32) -> isize | ||
586 | "]], | ||
587 | ); | ||
588 | } | ||
589 | |||
590 | #[test] | ||
591 | fn coerce_fn_items_in_match_arms() { | ||
592 | mark::check!(coerce_fn_reification); | ||
593 | |||
594 | check_infer_with_mismatches( | ||
595 | r" | ||
596 | fn foo1(x: u32) -> isize { 1 } | ||
597 | fn foo2(x: u32) -> isize { 2 } | ||
598 | fn foo3(x: u32) -> isize { 3 } | ||
599 | fn test() { | ||
600 | let x = match 1 { | ||
601 | 1 => foo1, | ||
602 | 2 => foo2, | ||
603 | _ => foo3, | ||
604 | }; | ||
605 | } | ||
606 | ", | ||
607 | expect![[r" | ||
608 | 8..9 'x': u32 | ||
609 | 25..30 '{ 1 }': isize | ||
610 | 27..28 '1': isize | ||
611 | 39..40 'x': u32 | ||
612 | 56..61 '{ 2 }': isize | ||
613 | 58..59 '2': isize | ||
614 | 70..71 'x': u32 | ||
615 | 87..92 '{ 3 }': isize | ||
616 | 89..90 '3': isize | ||
617 | 103..192 '{ ... }; }': () | ||
618 | 113..114 'x': fn(u32) -> isize | ||
619 | 117..189 'match ... }': fn(u32) -> isize | ||
620 | 123..124 '1': i32 | ||
621 | 135..136 '1': i32 | ||
622 | 135..136 '1': i32 | ||
623 | 140..144 'foo1': fn foo1(u32) -> isize | ||
624 | 154..155 '2': i32 | ||
625 | 154..155 '2': i32 | ||
626 | 159..163 'foo2': fn foo2(u32) -> isize | ||
627 | 173..174 '_': i32 | ||
628 | 178..182 'foo3': fn foo3(u32) -> isize | ||
629 | "]], | ||
630 | ); | ||
631 | } | ||
632 | |||
633 | #[test] | ||
634 | fn coerce_closure_to_fn_ptr() { | ||
635 | check_infer_with_mismatches( | ||
636 | r" | ||
637 | fn test() { | ||
638 | let f: fn(u32) -> isize = |x| { 1 }; | ||
639 | } | ||
640 | ", | ||
641 | expect![[r" | ||
642 | 10..54 '{ ...1 }; }': () | ||
643 | 20..21 'f': fn(u32) -> isize | ||
644 | 42..51 '|x| { 1 }': |u32| -> isize | ||
645 | 43..44 'x': u32 | ||
646 | 46..51 '{ 1 }': isize | ||
647 | 48..49 '1': isize | ||
648 | "]], | ||
649 | ); | ||
650 | } | ||
651 | |||
652 | #[test] | ||
653 | fn coerce_placeholder_ref() { | ||
654 | // placeholders should unify, even behind references | ||
655 | check_infer_with_mismatches( | ||
656 | r" | ||
657 | struct S<T> { t: T } | ||
658 | impl<TT> S<TT> { | ||
659 | fn get(&self) -> &TT { | ||
660 | &self.t | ||
661 | } | ||
662 | } | ||
663 | ", | ||
664 | expect![[r" | ||
665 | 50..54 'self': &S<TT> | ||
666 | 63..86 '{ ... }': &TT | ||
667 | 73..80 '&self.t': &TT | ||
668 | 74..78 'self': &S<TT> | ||
669 | 74..80 'self.t': TT | ||
670 | "]], | ||
671 | ); | ||
672 | } | ||
673 | |||
674 | #[test] | ||
675 | fn coerce_unsize_array() { | ||
676 | check_infer_with_mismatches( | ||
677 | r#" | ||
678 | #[lang = "unsize"] | ||
679 | pub trait Unsize<T> {} | ||
680 | #[lang = "coerce_unsized"] | ||
681 | pub trait CoerceUnsized<T> {} | ||
682 | |||
683 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
684 | |||
685 | fn test() { | ||
686 | let f: &[usize] = &[1, 2, 3]; | ||
687 | } | ||
688 | "#, | ||
689 | expect![[r" | ||
690 | 161..198 '{ ... 3]; }': () | ||
691 | 171..172 'f': &[usize] | ||
692 | 185..195 '&[1, 2, 3]': &[usize; _] | ||
693 | 186..195 '[1, 2, 3]': [usize; _] | ||
694 | 187..188 '1': usize | ||
695 | 190..191 '2': usize | ||
696 | 193..194 '3': usize | ||
697 | "]], | ||
698 | ); | ||
699 | } | ||
700 | |||
701 | #[test] | ||
702 | fn coerce_unsize_trait_object_simple() { | ||
703 | check_infer_with_mismatches( | ||
704 | r#" | ||
705 | #[lang = "sized"] | ||
706 | pub trait Sized {} | ||
707 | #[lang = "unsize"] | ||
708 | pub trait Unsize<T> {} | ||
709 | #[lang = "coerce_unsized"] | ||
710 | pub trait CoerceUnsized<T> {} | ||
711 | |||
712 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
713 | |||
714 | trait Foo<T, U> {} | ||
715 | trait Bar<U, T, X>: Foo<T, U> {} | ||
716 | trait Baz<T, X>: Bar<usize, T, X> {} | ||
717 | |||
718 | struct S<T, X>; | ||
719 | impl<T, X> Foo<T, usize> for S<T, X> {} | ||
720 | impl<T, X> Bar<usize, T, X> for S<T, X> {} | ||
721 | impl<T, X> Baz<T, X> for S<T, X> {} | ||
722 | |||
723 | fn test() { | ||
724 | let obj: &dyn Baz<i8, i16> = &S; | ||
725 | let obj: &dyn Bar<_, i8, i16> = &S; | ||
726 | let obj: &dyn Foo<i8, _> = &S; | ||
727 | } | ||
728 | "#, | ||
729 | expect![[r" | ||
730 | 424..539 '{ ... &S; }': () | ||
731 | 434..437 'obj': &dyn Baz<i8, i16> | ||
732 | 459..461 '&S': &S<i8, i16> | ||
733 | 460..461 'S': S<i8, i16> | ||
734 | 471..474 'obj': &dyn Bar<usize, i8, i16> | ||
735 | 499..501 '&S': &S<i8, i16> | ||
736 | 500..501 'S': S<i8, i16> | ||
737 | 511..514 'obj': &dyn Foo<i8, usize> | ||
738 | 534..536 '&S': &S<i8, {unknown}> | ||
739 | 535..536 'S': S<i8, {unknown}> | ||
740 | "]], | ||
741 | ); | ||
742 | } | ||
743 | |||
744 | #[test] | ||
745 | // The rust reference says this should be possible, but rustc doesn't implement | ||
746 | // it. We used to support it, but Chalk doesn't. | ||
747 | #[ignore] | ||
748 | fn coerce_unsize_trait_object_to_trait_object() { | ||
749 | check_infer_with_mismatches( | ||
750 | r#" | ||
751 | #[lang = "sized"] | ||
752 | pub trait Sized {} | ||
753 | #[lang = "unsize"] | ||
754 | pub trait Unsize<T> {} | ||
755 | #[lang = "coerce_unsized"] | ||
756 | pub trait CoerceUnsized<T> {} | ||
757 | |||
758 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
759 | |||
760 | trait Foo<T, U> {} | ||
761 | trait Bar<U, T, X>: Foo<T, U> {} | ||
762 | trait Baz<T, X>: Bar<usize, T, X> {} | ||
763 | |||
764 | struct S<T, X>; | ||
765 | impl<T, X> Foo<T, usize> for S<T, X> {} | ||
766 | impl<T, X> Bar<usize, T, X> for S<T, X> {} | ||
767 | impl<T, X> Baz<T, X> for S<T, X> {} | ||
768 | |||
769 | fn test() { | ||
770 | let obj: &dyn Baz<i8, i16> = &S; | ||
771 | let obj: &dyn Bar<_, _, _> = obj; | ||
772 | let obj: &dyn Foo<_, _> = obj; | ||
773 | let obj2: &dyn Baz<i8, i16> = &S; | ||
774 | let _: &dyn Foo<_, _> = obj2; | ||
775 | } | ||
776 | "#, | ||
777 | expect![[r" | ||
778 | 424..609 '{ ...bj2; }': () | ||
779 | 434..437 'obj': &dyn Baz<i8, i16> | ||
780 | 459..461 '&S': &S<i8, i16> | ||
781 | 460..461 'S': S<i8, i16> | ||
782 | 471..474 'obj': &dyn Bar<usize, i8, i16> | ||
783 | 496..499 'obj': &dyn Baz<i8, i16> | ||
784 | 509..512 'obj': &dyn Foo<i8, usize> | ||
785 | 531..534 'obj': &dyn Bar<usize, i8, i16> | ||
786 | 544..548 'obj2': &dyn Baz<i8, i16> | ||
787 | 570..572 '&S': &S<i8, i16> | ||
788 | 571..572 'S': S<i8, i16> | ||
789 | 582..583 '_': &dyn Foo<i8, usize> | ||
790 | 602..606 'obj2': &dyn Baz<i8, i16> | ||
791 | "]], | ||
792 | ); | ||
793 | } | ||
794 | |||
795 | #[test] | ||
796 | fn coerce_unsize_super_trait_cycle() { | ||
797 | check_infer_with_mismatches( | ||
798 | r#" | ||
799 | #[lang = "sized"] | ||
800 | pub trait Sized {} | ||
801 | #[lang = "unsize"] | ||
802 | pub trait Unsize<T> {} | ||
803 | #[lang = "coerce_unsized"] | ||
804 | pub trait CoerceUnsized<T> {} | ||
805 | |||
806 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
807 | |||
808 | trait A {} | ||
809 | trait B: C + A {} | ||
810 | trait C: B {} | ||
811 | trait D: C | ||
812 | |||
813 | struct S; | ||
814 | impl A for S {} | ||
815 | impl B for S {} | ||
816 | impl C for S {} | ||
817 | impl D for S {} | ||
818 | |||
819 | fn test() { | ||
820 | let obj: &dyn D = &S; | ||
821 | let obj: &dyn A = &S; | ||
822 | } | ||
823 | "#, | ||
824 | expect![[r" | ||
825 | 328..383 '{ ... &S; }': () | ||
826 | 338..341 'obj': &dyn D | ||
827 | 352..354 '&S': &S | ||
828 | 353..354 'S': S | ||
829 | 364..367 'obj': &dyn A | ||
830 | 378..380 '&S': &S | ||
831 | 379..380 'S': S | ||
832 | "]], | ||
833 | ); | ||
834 | } | ||
835 | |||
836 | #[ignore] | ||
837 | #[test] | ||
838 | fn coerce_unsize_generic() { | ||
839 | // FIXME: Implement this | ||
840 | // https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions | ||
841 | check_infer_with_mismatches( | ||
842 | r#" | ||
843 | #[lang = "unsize"] | ||
844 | pub trait Unsize<T> {} | ||
845 | #[lang = "coerce_unsized"] | ||
846 | pub trait CoerceUnsized<T> {} | ||
847 | |||
848 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
849 | |||
850 | struct Foo<T> { t: T }; | ||
851 | struct Bar<T>(Foo<T>); | ||
852 | |||
853 | fn test() { | ||
854 | let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] }; | ||
855 | let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); | ||
856 | } | ||
857 | "#, | ||
858 | expect![[r" | ||
859 | "]], | ||
860 | ); | ||
861 | } | ||