| use cov_mark::check; |
| use expect_test::expect; |
| |
| use super::{check, check_infer, check_infer_with_mismatches, check_no_mismatches, check_types}; |
| |
| #[test] |
| fn infer_await() { |
| check_types( |
| r#" |
| //- minicore: future |
| struct IntFuture; |
| |
| impl core::future::Future for IntFuture { |
| type Output = u64; |
| } |
| |
| fn test() { |
| let r = IntFuture; |
| let v = r.await; |
| v; |
| } //^ u64 |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn infer_async() { |
| check_types( |
| r#" |
| //- minicore: future |
| async fn foo() -> u64 { 128 } |
| |
| fn test() { |
| let r = foo(); |
| let v = r.await; |
| v; |
| } //^ u64 |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn infer_desugar_async() { |
| check_types( |
| r#" |
| //- minicore: future, sized |
| async fn foo() -> u64 { 128 } |
| |
| fn test() { |
| let r = foo(); |
| r; |
| } //^ impl Future<Output = u64> |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn infer_async_block() { |
| check_types( |
| r#" |
| //- minicore: future, option |
| async fn test() { |
| let a = async { 42 }; |
| a; |
| // ^ impl Future<Output = i32> |
| let x = a.await; |
| x; |
| // ^ i32 |
| let b = async {}.await; |
| b; |
| // ^ () |
| let c = async { |
| let y = None; |
| y |
| // ^ Option<u64> |
| }; |
| let _: Option<u64> = c.await; |
| c; |
| // ^ impl Future<Output = Option<u64>> |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn infer_async_closure() { |
| check_types( |
| r#" |
| //- minicore: future, option |
| async fn test() { |
| let f = async move |x: i32| x + 42; |
| f; |
| // ^ impl Fn(i32) -> impl Future<Output = i32> |
| let a = f(4); |
| a; |
| // ^ impl Future<Output = i32> |
| let x = a.await; |
| x; |
| // ^ i32 |
| let f = async move || 42; |
| f; |
| // ^ impl Fn() -> impl Future<Output = i32> |
| let a = f(); |
| a; |
| // ^ impl Future<Output = i32> |
| let x = a.await; |
| x; |
| // ^ i32 |
| let b = ((async move || {})()).await; |
| b; |
| // ^ () |
| let c = async move || { |
| let y = None; |
| y |
| // ^ Option<u64> |
| }; |
| let _: Option<u64> = c().await; |
| c; |
| // ^ impl Fn() -> impl Future<Output = Option<u64>> |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn auto_sized_async_block() { |
| check_no_mismatches( |
| r#" |
| //- minicore: future, sized |
| |
| use core::future::Future; |
| struct MyFut<Fut>(Fut); |
| |
| impl<Fut> Future for MyFut<Fut> |
| where Fut: Future |
| { |
| type Output = Fut::Output; |
| } |
| async fn reproduction() -> usize { |
| let f = async {999usize}; |
| MyFut(f).await |
| } |
| "#, |
| ); |
| check_no_mismatches( |
| r#" |
| //- minicore: future |
| //#11815 |
| #[lang = "sized"] |
| pub trait Sized {} |
| |
| #[lang = "unsize"] |
| pub trait Unsize<T: ?Sized> {} |
| |
| #[lang = "coerce_unsized"] |
| pub trait CoerceUnsized<T> {} |
| |
| pub unsafe trait Allocator {} |
| |
| pub struct Global; |
| unsafe impl Allocator for Global {} |
| |
| #[lang = "owned_box"] |
| #[fundamental] |
| pub struct Box<T: ?Sized, A: Allocator = Global>(T); |
| |
| impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> for Box<T, A> {} |
| |
| fn send() -> Box<dyn Future<Output = ()> + Send + 'static>{ |
| Box(async move {}) |
| } |
| |
| fn not_send() -> Box<dyn Future<Output = ()> + 'static> { |
| Box(async move {}) |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn into_future_trait() { |
| check_types( |
| r#" |
| //- minicore: future |
| struct Futurable; |
| impl core::future::IntoFuture for Futurable { |
| type Output = u64; |
| type IntoFuture = IntFuture; |
| } |
| |
| struct IntFuture; |
| impl core::future::Future for IntFuture { |
| type Output = u64; |
| } |
| |
| fn test() { |
| let r = Futurable; |
| let v = r.await; |
| v; |
| } //^ u64 |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn infer_try_trait() { |
| check_types( |
| r#" |
| //- minicore: try, result, from |
| fn test() { |
| let r: Result<i32, u64> = Result::Ok(1); |
| let v = r?; |
| v; |
| } //^ i32 |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn infer_try_block() { |
| // FIXME: We should test more cases, but it currently doesn't work, since |
| // our labeled block type inference is broken. |
| check_types( |
| r#" |
| //- minicore: try, option |
| fn test() { |
| let x: Option<_> = try { Some(2)?; }; |
| //^ Option<()> |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn infer_for_loop() { |
| check_types( |
| r#" |
| //- minicore: iterator |
| //- /main.rs crate:main deps:alloc |
| #![no_std] |
| use alloc::collections::Vec; |
| |
| fn test() { |
| let v = Vec::new(); |
| v.push("foo"); |
| for x in v { |
| x; |
| } //^ &str |
| } |
| |
| //- /alloc.rs crate:alloc |
| #![no_std] |
| pub mod collections { |
| pub struct Vec<T> {} |
| impl<T> Vec<T> { |
| pub fn new() -> Self { Vec {} } |
| pub fn push(&mut self, t: T) { } |
| } |
| |
| impl<T> IntoIterator for Vec<T> { |
| type Item = T; |
| type IntoIter = IntoIter<T>; |
| } |
| |
| struct IntoIter<T> {} |
| impl<T> Iterator for IntoIter<T> { |
| type Item = T; |
| } |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn infer_ops_neg() { |
| check_types( |
| r#" |
| //- /main.rs crate:main deps:std |
| struct Bar; |
| struct Foo; |
| |
| impl std::ops::Neg for Bar { |
| type Output = Foo; |
| } |
| |
| fn test() { |
| let a = Bar; |
| let b = -a; |
| b; |
| } //^ Foo |
| |
| //- /std.rs crate:std |
| #[prelude_import] use ops::*; |
| mod ops { |
| #[lang = "neg"] |
| pub trait Neg { |
| type Output; |
| } |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn infer_ops_not() { |
| check_types( |
| r#" |
| //- /main.rs crate:main deps:std |
| struct Bar; |
| struct Foo; |
| |
| impl std::ops::Not for Bar { |
| type Output = Foo; |
| } |
| |
| fn test() { |
| let a = Bar; |
| let b = !a; |
| b; |
| } //^ Foo |
| |
| //- /std.rs crate:std |
| #[prelude_import] use ops::*; |
| mod ops { |
| #[lang = "not"] |
| pub trait Not { |
| type Output; |
| } |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn infer_from_bound_1() { |
| check_types( |
| r#" |
| trait Trait<T> {} |
| struct S<T>(T); |
| impl<U> Trait<U> for S<U> {} |
| fn foo<T: Trait<u32>>(t: T) {} |
| fn test() { |
| let s = S(unknown); |
| // ^^^^^^^ u32 |
| foo(s); |
| }"#, |
| ); |
| } |
| |
| #[test] |
| fn infer_from_bound_2() { |
| check_types( |
| r#" |
| trait Trait<T> {} |
| struct S<T>(T); |
| impl<U> Trait<U> for S<U> {} |
| fn foo<U, T: Trait<U>>(t: T) -> U { loop {} } |
| fn test() { |
| let s = S(unknown); |
| // ^^^^^^^ u32 |
| let x: u32 = foo(s); |
| }"#, |
| ); |
| } |
| |
| #[test] |
| fn trait_default_method_self_bound_implements_trait() { |
| cov_mark::check!(trait_self_implements_self); |
| check( |
| r#" |
| trait Trait { |
| fn foo(&self) -> i64; |
| fn bar(&self) -> () { |
| self.foo(); |
| // ^^^^^^^^^^ type: i64 |
| } |
| }"#, |
| ); |
| } |
| |
| #[test] |
| fn trait_default_method_self_bound_implements_super_trait() { |
| check( |
| r#" |
| trait SuperTrait { |
| fn foo(&self) -> i64; |
| } |
| trait Trait: SuperTrait { |
| fn bar(&self) -> () { |
| self.foo(); |
| // ^^^^^^^^^^ type: i64 |
| } |
| }"#, |
| ); |
| } |
| |
| #[test] |
| fn infer_project_associated_type() { |
| check_types( |
| r#" |
| trait Iterable { |
| type Item; |
| } |
| struct S; |
| impl Iterable for S { type Item = u32; } |
| fn test<T: Iterable>() { |
| let x: <S as Iterable>::Item = 1; |
| // ^ u32 |
| let y: <T as Iterable>::Item = u; |
| // ^ Iterable::Item<T> |
| let z: T::Item = u; |
| // ^ Iterable::Item<T> |
| let a: <T>::Item = u; |
| // ^ Iterable::Item<T> |
| }"#, |
| ); |
| } |
| |
| #[test] |
| fn infer_return_associated_type() { |
| check_types( |
| r#" |
| trait Iterable { |
| type Item; |
| } |
| struct S; |
| impl Iterable for S { type Item = u32; } |
| fn foo1<T: Iterable>(t: T) -> T::Item { loop {} } |
| fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item { loop {} } |
| fn foo3<T: Iterable>(t: T) -> <T>::Item { loop {} } |
| fn test() { |
| foo1(S); |
| // ^^^^^^^ u32 |
| foo2(S); |
| // ^^^^^^^ u32 |
| foo3(S); |
| // ^^^^^^^ u32 |
| }"#, |
| ); |
| } |
| |
| #[test] |
| fn associated_type_shorthand_from_method_bound() { |
| check_types( |
| r#" |
| trait Iterable { |
| type Item; |
| } |
| struct S<T>; |
| impl<T> S<T> { |
| fn foo(self) -> T::Item where T: Iterable { loop {} } |
| } |
| fn test<T: Iterable>() { |
| let s: S<T>; |
| s.foo(); |
| // ^^^^^^^ Iterable::Item<T> |
| }"#, |
| ); |
| } |
| |
| #[test] |
| fn associated_type_shorthand_from_self_issue_12484() { |
| check_types( |
| r#" |
| trait Bar { |
| type A; |
| } |
| trait Foo { |
| type A; |
| fn test(a: Self::A, _: impl Bar) { |
| a; |
| //^ Foo::A<Self> |
| } |
| }"#, |
| ); |
| } |
| |
| #[test] |
| fn infer_associated_type_bound() { |
| check_types( |
| r#" |
| trait Iterable { |
| type Item; |
| } |
| fn test<T: Iterable<Item=u32>>() { |
| let y: T::Item = unknown; |
| // ^^^^^^^ u32 |
| }"#, |
| ); |
| } |
| |
| #[test] |
| fn infer_const_body() { |
| // FIXME make check_types work with other bodies |
| check_infer( |
| r#" |
| const A: u32 = 1 + 1; |
| static B: u64 = { let x = 1; x }; |
| "#, |
| expect![[r#" |
| 15..16 '1': u32 |
| 15..20 '1 + 1': u32 |
| 19..20 '1': u32 |
| 38..54 '{ let ...1; x }': u64 |
| 44..45 'x': u64 |
| 48..49 '1': u64 |
| 51..52 'x': u64 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn tuple_struct_fields() { |
| check_infer( |
| r#" |
| struct S(i32, u64); |
| fn test() -> u64 { |
| let a = S(4, 6); |
| let b = a.0; |
| a.1 |
| }"#, |
| expect![[r#" |
| 37..86 '{ ... a.1 }': u64 |
| 47..48 'a': S |
| 51..52 'S': extern "rust-call" S(i32, u64) -> S |
| 51..58 'S(4, 6)': S |
| 53..54 '4': i32 |
| 56..57 '6': u64 |
| 68..69 'b': i32 |
| 72..73 'a': S |
| 72..75 'a.0': i32 |
| 81..82 'a': S |
| 81..84 'a.1': u64 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn tuple_struct_with_fn() { |
| check_infer( |
| r#" |
| struct S(fn(u32) -> u64); |
| fn test() -> u64 { |
| let a = S(|i| 2*i as u64); |
| let b = a.0(4); |
| a.0(2) |
| }"#, |
| expect![[r#" |
| 43..108 '{ ...0(2) }': u64 |
| 53..54 'a': S |
| 57..58 'S': extern "rust-call" S(fn(u32) -> u64) -> S |
| 57..74 'S(|i| ...s u64)': S |
| 59..73 '|i| 2*i as u64': impl Fn(u32) -> u64 |
| 60..61 'i': u32 |
| 63..64 '2': u64 |
| 63..73 '2*i as u64': u64 |
| 65..66 'i': u32 |
| 65..73 'i as u64': u64 |
| 84..85 'b': u64 |
| 88..89 'a': S |
| 88..91 'a.0': fn(u32) -> u64 |
| 88..94 'a.0(4)': u64 |
| 92..93 '4': u32 |
| 100..101 'a': S |
| 100..103 'a.0': fn(u32) -> u64 |
| 100..106 'a.0(2)': u64 |
| 104..105 '2': u32 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn indexing_arrays() { |
| check_infer( |
| "fn main() { &mut [9][2]; }", |
| expect![[r#" |
| 10..26 '{ &mut...[2]; }': () |
| 12..23 '&mut [9][2]': &mut {unknown} |
| 17..20 '[9]': [i32; 1] |
| 17..23 '[9][2]': {unknown} |
| 18..19 '9': i32 |
| 21..22 '2': i32 |
| "#]], |
| ) |
| } |
| |
| #[test] |
| fn infer_ops_index() { |
| check_types( |
| r#" |
| //- minicore: index |
| struct Bar; |
| struct Foo; |
| |
| impl core::ops::Index<u32> for Bar { |
| type Output = Foo; |
| } |
| |
| fn test() { |
| let a = Bar; |
| let b = a[1u32]; |
| b; |
| } //^ Foo |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn infer_ops_index_field() { |
| check_types( |
| r#" |
| //- minicore: index |
| struct Bar; |
| struct Foo { |
| field: u32; |
| } |
| |
| impl core::ops::Index<u32> for Bar { |
| type Output = Foo; |
| } |
| |
| fn test() { |
| let a = Bar; |
| let b = a[1u32].field; |
| b; |
| } //^ u32 |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn infer_ops_index_field_autoderef() { |
| check_types( |
| r#" |
| //- minicore: index |
| struct Bar; |
| struct Foo { |
| field: u32; |
| } |
| |
| impl core::ops::Index<u32> for Bar { |
| type Output = Foo; |
| } |
| |
| fn test() { |
| let a = Bar; |
| let b = (&a[1u32]).field; |
| b; |
| } //^ u32 |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn infer_ops_index_int() { |
| check_types( |
| r#" |
| //- minicore: index |
| struct Bar; |
| struct Foo; |
| |
| impl core::ops::Index<u32> for Bar { |
| type Output = Foo; |
| } |
| |
| struct Range; |
| impl core::ops::Index<Range> for Bar { |
| type Output = Bar; |
| } |
| |
| fn test() { |
| let a = Bar; |
| let b = a[1]; |
| b; |
| //^ Foo |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn infer_ops_index_autoderef() { |
| check_types( |
| r#" |
| //- minicore: index, slice |
| fn test() { |
| let a = &[1u32, 2, 3]; |
| let b = a[1]; |
| b; |
| } //^ u32 |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn deref_trait() { |
| check_types( |
| r#" |
| //- minicore: deref |
| struct Arc<T: ?Sized>; |
| impl<T: ?Sized> core::ops::Deref for Arc<T> { |
| type Target = T; |
| } |
| |
| struct S; |
| impl S { |
| fn foo(&self) -> u128 { 0 } |
| } |
| |
| fn test(s: Arc<S>) { |
| (*s, s.foo()); |
| } //^^^^^^^^^^^^^ (S, u128) |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn deref_trait_with_inference_var() { |
| check_types( |
| r#" |
| //- minicore: deref |
| struct Arc<T: ?Sized>; |
| fn new_arc<T: ?Sized>() -> Arc<T> { Arc } |
| impl<T: ?Sized> core::ops::Deref for Arc<T> { |
| type Target = T; |
| } |
| |
| struct S; |
| fn foo(a: Arc<S>) {} |
| |
| fn test() { |
| let a = new_arc(); |
| let b = *a; |
| //^^ S |
| foo(a); |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn deref_trait_infinite_recursion() { |
| check_types( |
| r#" |
| //- minicore: deref |
| struct S; |
| |
| impl core::ops::Deref for S { |
| type Target = S; |
| } |
| |
| fn test(s: S) { |
| s.foo(); |
| } //^^^^^^^ {unknown} |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn deref_trait_with_question_mark_size() { |
| check_types( |
| r#" |
| //- minicore: deref |
| struct Arc<T: ?Sized>; |
| impl<T: ?Sized> core::ops::Deref for Arc<T> { |
| type Target = T; |
| } |
| |
| struct S; |
| impl S { |
| fn foo(&self) -> u128 { 0 } |
| } |
| |
| fn test(s: Arc<S>) { |
| (*s, s.foo()); |
| } //^^^^^^^^^^^^^ (S, u128) |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn deref_trait_with_implicit_sized_requirement_on_inference_var() { |
| check_types( |
| r#" |
| //- minicore: deref |
| struct Foo<T>; |
| impl<T> core::ops::Deref for Foo<T> { |
| type Target = (); |
| } |
| fn test() { |
| let foo = Foo; |
| *foo; |
| //^^^^ () |
| let _: Foo<u8> = foo; |
| } |
| "#, |
| ) |
| } |
| |
| #[test] |
| fn obligation_from_function_clause() { |
| check_types( |
| r#" |
| struct S; |
| |
| trait Trait<T> {} |
| impl Trait<u32> for S {} |
| |
| fn foo<T: Trait<U>, U>(t: T) -> U { loop {} } |
| |
| fn test(s: S) { |
| foo(s); |
| } //^^^^^^ u32 |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn obligation_from_method_clause() { |
| check_types( |
| r#" |
| //- /main.rs |
| struct S; |
| |
| trait Trait<T> {} |
| impl Trait<isize> for S {} |
| |
| struct O; |
| impl O { |
| fn foo<T: Trait<U>, U>(&self, t: T) -> U { loop {} } |
| } |
| |
| fn test() { |
| O.foo(S); |
| } //^^^^^^^^ isize |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn obligation_from_self_method_clause() { |
| check_types( |
| r#" |
| struct S; |
| |
| trait Trait<T> {} |
| impl Trait<i64> for S {} |
| |
| impl S { |
| fn foo<U>(&self) -> U where Self: Trait<U> { loop {} } |
| } |
| |
| fn test() { |
| S.foo(); |
| } //^^^^^^^ i64 |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn obligation_from_impl_clause() { |
| check_types( |
| r#" |
| struct S; |
| |
| trait Trait<T> {} |
| impl Trait<&str> for S {} |
| |
| struct O<T>; |
| impl<U, T: Trait<U>> O<T> { |
| fn foo(&self) -> U { loop {} } |
| } |
| |
| fn test(o: O<S>) { |
| o.foo(); |
| } //^^^^^^^ &str |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn generic_param_env_1() { |
| check_types( |
| r#" |
| trait Clone {} |
| trait Trait { fn foo(self) -> u128; } |
| struct S; |
| impl Clone for S {} |
| impl<T> Trait for T where T: Clone {} |
| fn test<T: Clone>(t: T) { t.foo(); } |
| //^^^^^^^ u128 |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn generic_param_env_1_not_met() { |
| check_types( |
| r#" |
| //- /main.rs |
| trait Clone {} |
| trait Trait { fn foo(self) -> u128; } |
| struct S; |
| impl Clone for S {} |
| impl<T> Trait for T where T: Clone {} |
| fn test<T>(t: T) { t.foo(); } |
| //^^^^^^^ {unknown} |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn generic_param_env_2() { |
| check_types( |
| r#" |
| trait Trait { fn foo(self) -> u128; } |
| struct S; |
| impl Trait for S {} |
| fn test<T: Trait>(t: T) { t.foo(); } |
| //^^^^^^^ u128 |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn generic_param_env_2_not_met() { |
| check_types( |
| r#" |
| trait Trait { fn foo(self) -> u128; } |
| struct S; |
| impl Trait for S {} |
| fn test<T>(t: T) { t.foo(); } |
| //^^^^^^^ {unknown} |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn generic_param_env_deref() { |
| check_types( |
| r#" |
| //- minicore: deref |
| trait Trait {} |
| impl<T> core::ops::Deref for T where T: Trait { |
| type Target = i128; |
| } |
| fn test<T: Trait>(t: T) { *t; } |
| //^^ i128 |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn associated_type_placeholder() { |
| // inside the generic function, the associated type gets normalized to a placeholder `ApplL::Out<T>` [https://rust-lang.github.io/rustc-guide/traits/associated-types.html#placeholder-associated-types]. |
| check_types( |
| r#" |
| pub trait ApplyL { |
| type Out; |
| } |
| |
| pub struct RefMutL<T>; |
| |
| impl<T> ApplyL for RefMutL<T> { |
| type Out = <T as ApplyL>::Out; |
| } |
| |
| fn test<T: ApplyL>() { |
| let y: <RefMutL<T> as ApplyL>::Out = no_matter; |
| y; |
| } //^ ApplyL::Out<T> |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn associated_type_placeholder_2() { |
| check_types( |
| r#" |
| pub trait ApplyL { |
| type Out; |
| } |
| fn foo<T: ApplyL>(t: T) -> <T as ApplyL>::Out; |
| |
| fn test<T: ApplyL>(t: T) { |
| let y = foo(t); |
| y; |
| } //^ ApplyL::Out<T> |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn argument_impl_trait() { |
| check_infer_with_mismatches( |
| r#" |
| //- minicore: sized |
| trait Trait<T> { |
| fn foo(&self) -> T; |
| fn foo2(&self) -> i64; |
| } |
| fn bar(x: impl Trait<u16>) {} |
| struct S<T>(T); |
| impl<T> Trait<T> for S<T> {} |
| |
| fn test(x: impl Trait<u64>, y: &impl Trait<u32>) { |
| x; |
| y; |
| let z = S(1); |
| bar(z); |
| x.foo(); |
| y.foo(); |
| z.foo(); |
| x.foo2(); |
| y.foo2(); |
| z.foo2(); |
| }"#, |
| expect![[r#" |
| 29..33 'self': &Self |
| 54..58 'self': &Self |
| 77..78 'x': impl Trait<u16> |
| 97..99 '{}': () |
| 154..155 'x': impl Trait<u64> |
| 174..175 'y': &impl Trait<u32> |
| 195..323 '{ ...2(); }': () |
| 201..202 'x': impl Trait<u64> |
| 208..209 'y': &impl Trait<u32> |
| 219..220 'z': S<u16> |
| 223..224 'S': extern "rust-call" S<u16>(u16) -> S<u16> |
| 223..227 'S(1)': S<u16> |
| 225..226 '1': u16 |
| 233..236 'bar': fn bar(S<u16>) |
| 233..239 'bar(z)': () |
| 237..238 'z': S<u16> |
| 245..246 'x': impl Trait<u64> |
| 245..252 'x.foo()': u64 |
| 258..259 'y': &impl Trait<u32> |
| 258..265 'y.foo()': u32 |
| 271..272 'z': S<u16> |
| 271..278 'z.foo()': u16 |
| 284..285 'x': impl Trait<u64> |
| 284..292 'x.foo2()': i64 |
| 298..299 'y': &impl Trait<u32> |
| 298..306 'y.foo2()': i64 |
| 312..313 'z': S<u16> |
| 312..320 'z.foo2()': i64 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn argument_impl_trait_type_args_1() { |
| check_infer_with_mismatches( |
| r#" |
| //- minicore: sized |
| trait Trait {} |
| trait Foo { |
| // this function has an implicit Self param, an explicit type param, |
| // and an implicit impl Trait param! |
| fn bar<T>(x: impl Trait) -> T { loop {} } |
| } |
| fn foo<T>(x: impl Trait) -> T { loop {} } |
| struct S; |
| impl Trait for S {} |
| struct F; |
| impl Foo for F {} |
| |
| fn test() { |
| Foo::bar(S); |
| <F as Foo>::bar(S); |
| F::bar(S); |
| Foo::bar::<u32>(S); |
| <F as Foo>::bar::<u32>(S); |
| |
| foo(S); |
| foo::<u32>(S); |
| foo::<u32, i32>(S); // we should ignore the extraneous i32 |
| }"#, |
| expect![[r#" |
| 155..156 'x': impl Trait |
| 175..186 '{ loop {} }': T |
| 177..184 'loop {}': ! |
| 182..184 '{}': () |
| 199..200 'x': impl Trait |
| 219..230 '{ loop {} }': T |
| 221..228 'loop {}': ! |
| 226..228 '{}': () |
| 300..509 '{ ... i32 }': () |
| 306..314 'Foo::bar': fn bar<{unknown}, {unknown}>(S) -> {unknown} |
| 306..317 'Foo::bar(S)': {unknown} |
| 315..316 'S': S |
| 323..338 '<F as Foo>::bar': fn bar<F, {unknown}>(S) -> {unknown} |
| 323..341 '<F as ...bar(S)': {unknown} |
| 339..340 'S': S |
| 347..353 'F::bar': fn bar<F, {unknown}>(S) -> {unknown} |
| 347..356 'F::bar(S)': {unknown} |
| 354..355 'S': S |
| 362..377 'Foo::bar::<u32>': fn bar<{unknown}, u32>(S) -> u32 |
| 362..380 'Foo::b...32>(S)': u32 |
| 378..379 'S': S |
| 386..408 '<F as ...:<u32>': fn bar<F, u32>(S) -> u32 |
| 386..411 '<F as ...32>(S)': u32 |
| 409..410 'S': S |
| 418..421 'foo': fn foo<{unknown}>(S) -> {unknown} |
| 418..424 'foo(S)': {unknown} |
| 422..423 'S': S |
| 430..440 'foo::<u32>': fn foo<u32>(S) -> u32 |
| 430..443 'foo::<u32>(S)': u32 |
| 441..442 'S': S |
| 449..464 'foo::<u32, i32>': fn foo<u32>(S) -> u32 |
| 449..467 'foo::<...32>(S)': u32 |
| 465..466 'S': S |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn argument_impl_trait_type_args_2() { |
| check_infer_with_mismatches( |
| r#" |
| //- minicore: sized |
| trait Trait {} |
| struct S; |
| impl Trait for S {} |
| struct F<T>; |
| impl<T> F<T> { |
| fn foo<U>(self, x: impl Trait) -> (T, U) { loop {} } |
| } |
| |
| fn test() { |
| F.foo(S); |
| F::<u32>.foo(S); |
| F::<u32>.foo::<i32>(S); |
| F::<u32>.foo::<i32, u32>(S); // extraneous argument should be ignored |
| }"#, |
| expect![[r#" |
| 87..91 'self': F<T> |
| 93..94 'x': impl Trait |
| 118..129 '{ loop {} }': (T, U) |
| 120..127 'loop {}': ! |
| 125..127 '{}': () |
| 143..283 '{ ...ored }': () |
| 149..150 'F': F<{unknown}> |
| 149..157 'F.foo(S)': ({unknown}, {unknown}) |
| 155..156 'S': S |
| 163..171 'F::<u32>': F<u32> |
| 163..178 'F::<u32>.foo(S)': (u32, {unknown}) |
| 176..177 'S': S |
| 184..192 'F::<u32>': F<u32> |
| 184..206 'F::<u3...32>(S)': (u32, i32) |
| 204..205 'S': S |
| 212..220 'F::<u32>': F<u32> |
| 212..239 'F::<u3...32>(S)': (u32, i32) |
| 237..238 'S': S |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn argument_impl_trait_to_fn_pointer() { |
| check_infer_with_mismatches( |
| r#" |
| //- minicore: sized |
| trait Trait {} |
| fn foo(x: impl Trait) { loop {} } |
| struct S; |
| impl Trait for S {} |
| |
| fn test() { |
| let f: fn(S) -> () = foo; |
| }"#, |
| expect![[r#" |
| 22..23 'x': impl Trait |
| 37..48 '{ loop {} }': () |
| 39..46 'loop {}': ! |
| 44..46 '{}': () |
| 90..123 '{ ...foo; }': () |
| 100..101 'f': fn(S) |
| 117..120 'foo': fn foo(S) |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn impl_trait() { |
| check_infer( |
| r#" |
| //- minicore: sized |
| trait Trait<T> { |
| fn foo(&self) -> T; |
| fn foo2(&self) -> i64; |
| } |
| fn bar() -> impl Trait<u64> {} |
| |
| fn test(x: impl Trait<u64>, y: &impl Trait<u64>) { |
| x; |
| y; |
| let z = bar(); |
| x.foo(); |
| y.foo(); |
| z.foo(); |
| x.foo2(); |
| y.foo2(); |
| z.foo2(); |
| }"#, |
| expect![[r#" |
| 29..33 'self': &Self |
| 54..58 'self': &Self |
| 98..100 '{}': () |
| 110..111 'x': impl Trait<u64> |
| 130..131 'y': &impl Trait<u64> |
| 151..268 '{ ...2(); }': () |
| 157..158 'x': impl Trait<u64> |
| 164..165 'y': &impl Trait<u64> |
| 175..176 'z': impl Trait<u64> |
| 179..182 'bar': fn bar() -> impl Trait<u64> |
| 179..184 'bar()': impl Trait<u64> |
| 190..191 'x': impl Trait<u64> |
| 190..197 'x.foo()': u64 |
| 203..204 'y': &impl Trait<u64> |
| 203..210 'y.foo()': u64 |
| 216..217 'z': impl Trait<u64> |
| 216..223 'z.foo()': u64 |
| 229..230 'x': impl Trait<u64> |
| 229..237 'x.foo2()': i64 |
| 243..244 'y': &impl Trait<u64> |
| 243..251 'y.foo2()': i64 |
| 257..258 'z': impl Trait<u64> |
| 257..265 'z.foo2()': i64 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn simple_return_pos_impl_trait() { |
| cov_mark::check!(lower_rpit); |
| check_infer( |
| r#" |
| //- minicore: sized |
| trait Trait<T> { |
| fn foo(&self) -> T; |
| } |
| fn bar() -> impl Trait<u64> { loop {} } |
| |
| fn test() { |
| let a = bar(); |
| a.foo(); |
| }"#, |
| expect![[r#" |
| 29..33 'self': &Self |
| 71..82 '{ loop {} }': ! |
| 73..80 'loop {}': ! |
| 78..80 '{}': () |
| 94..129 '{ ...o(); }': () |
| 104..105 'a': impl Trait<u64> |
| 108..111 'bar': fn bar() -> impl Trait<u64> |
| 108..113 'bar()': impl Trait<u64> |
| 119..120 'a': impl Trait<u64> |
| 119..126 'a.foo()': u64 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn more_return_pos_impl_trait() { |
| check_infer( |
| r#" |
| //- minicore: sized |
| trait Iterator { |
| type Item; |
| fn next(&mut self) -> Self::Item; |
| } |
| trait Trait<T> { |
| fn foo(&self) -> T; |
| } |
| fn bar() -> (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>) { loop {} } |
| fn baz<T>(t: T) -> (impl Iterator<Item = impl Trait<T>>, impl Trait<T>) { loop {} } |
| |
| fn test() { |
| let (a, b) = bar(); |
| a.next().foo(); |
| b.foo(); |
| let (c, d) = baz(1u128); |
| c.next().foo(); |
| d.foo(); |
| }"#, |
| expect![[r#" |
| 49..53 'self': &mut Self |
| 101..105 'self': &Self |
| 184..195 '{ loop {} }': ({unknown}, {unknown}) |
| 186..193 'loop {}': ! |
| 191..193 '{}': () |
| 206..207 't': T |
| 268..279 '{ loop {} }': ({unknown}, {unknown}) |
| 270..277 'loop {}': ! |
| 275..277 '{}': () |
| 291..413 '{ ...o(); }': () |
| 301..307 '(a, b)': (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>) |
| 302..303 'a': impl Iterator<Item = impl Trait<u32>> |
| 305..306 'b': impl Trait<u64> |
| 310..313 'bar': fn bar() -> (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>) |
| 310..315 'bar()': (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>) |
| 321..322 'a': impl Iterator<Item = impl Trait<u32>> |
| 321..329 'a.next()': impl Trait<u32> |
| 321..335 'a.next().foo()': u32 |
| 341..342 'b': impl Trait<u64> |
| 341..348 'b.foo()': u64 |
| 358..364 '(c, d)': (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>) |
| 359..360 'c': impl Iterator<Item = impl Trait<u128>> |
| 362..363 'd': impl Trait<u128> |
| 367..370 'baz': fn baz<u128>(u128) -> (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>) |
| 367..377 'baz(1u128)': (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>) |
| 371..376 '1u128': u128 |
| 383..384 'c': impl Iterator<Item = impl Trait<u128>> |
| 383..391 'c.next()': impl Trait<u128> |
| 383..397 'c.next().foo()': u128 |
| 403..404 'd': impl Trait<u128> |
| 403..410 'd.foo()': u128 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn infer_from_return_pos_impl_trait() { |
| check_infer_with_mismatches( |
| r#" |
| //- minicore: fn, sized |
| trait Trait<T> {} |
| struct Bar<T>(T); |
| impl<T> Trait<T> for Bar<T> {} |
| fn foo<const C: u8, T>() -> (impl FnOnce(&str, T), impl Trait<u8>) { |
| (|input, t| {}, Bar(C)) |
| } |
| "#, |
| expect![[r#" |
| 134..165 '{ ...(C)) }': (impl Fn(&str, T), Bar<u8>) |
| 140..163 '(|inpu...ar(C))': (impl Fn(&str, T), Bar<u8>) |
| 141..154 '|input, t| {}': impl Fn(&str, T) |
| 142..147 'input': &str |
| 149..150 't': T |
| 152..154 '{}': () |
| 156..159 'Bar': extern "rust-call" Bar<u8>(u8) -> Bar<u8> |
| 156..162 'Bar(C)': Bar<u8> |
| 160..161 'C': u8 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn return_pos_impl_trait_in_projection() { |
| // Note that the unused type param `X` is significant; see #13307. |
| check_no_mismatches( |
| r#" |
| //- minicore: sized |
| trait Future { type Output; } |
| impl Future for () { type Output = i32; } |
| type Foo<F> = (<F as Future>::Output, F); |
| fn foo<X>() -> Foo<impl Future<Output = ()>> { |
| (0, ()) |
| } |
| "#, |
| ) |
| } |
| |
| #[test] |
| fn dyn_trait() { |
| check_infer( |
| r#" |
| //- minicore: sized |
| trait Trait<T> { |
| fn foo(&self) -> T; |
| fn foo2(&self) -> i64; |
| } |
| fn bar() -> dyn Trait<u64> {} |
| |
| fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) { |
| x; |
| y; |
| let z = bar(); |
| x.foo(); |
| y.foo(); |
| z.foo(); |
| x.foo2(); |
| y.foo2(); |
| z.foo2(); |
| }"#, |
| expect![[r#" |
| 29..33 'self': &Self |
| 54..58 'self': &Self |
| 97..99 '{}': dyn Trait<u64> |
| 109..110 'x': dyn Trait<u64> |
| 128..129 'y': &dyn Trait<u64> |
| 148..265 '{ ...2(); }': () |
| 154..155 'x': dyn Trait<u64> |
| 161..162 'y': &dyn Trait<u64> |
| 172..173 'z': dyn Trait<u64> |
| 176..179 'bar': fn bar() -> dyn Trait<u64> |
| 176..181 'bar()': dyn Trait<u64> |
| 187..188 'x': dyn Trait<u64> |
| 187..194 'x.foo()': u64 |
| 200..201 'y': &dyn Trait<u64> |
| 200..207 'y.foo()': u64 |
| 213..214 'z': dyn Trait<u64> |
| 213..220 'z.foo()': u64 |
| 226..227 'x': dyn Trait<u64> |
| 226..234 'x.foo2()': i64 |
| 240..241 'y': &dyn Trait<u64> |
| 240..248 'y.foo2()': i64 |
| 254..255 'z': dyn Trait<u64> |
| 254..262 'z.foo2()': i64 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn dyn_trait_in_impl() { |
| check_infer( |
| r#" |
| //- minicore: sized |
| trait Trait<T, U> { |
| fn foo(&self) -> (T, U); |
| } |
| struct S<T, U> {} |
| impl<T, U> S<T, U> { |
| fn bar(&self) -> &dyn Trait<T, U> { loop {} } |
| } |
| trait Trait2<T, U> { |
| fn baz(&self) -> (T, U); |
| } |
| impl<T, U> Trait2<T, U> for dyn Trait<T, U> { } |
| |
| fn test(s: S<u32, i32>) { |
| s.bar().baz(); |
| }"#, |
| expect![[r#" |
| 32..36 'self': &Self |
| 102..106 'self': &S<T, U> |
| 128..139 '{ loop {} }': &dyn Trait<T, U> |
| 130..137 'loop {}': ! |
| 135..137 '{}': () |
| 175..179 'self': &Self |
| 251..252 's': S<u32, i32> |
| 267..289 '{ ...z(); }': () |
| 273..274 's': S<u32, i32> |
| 273..280 's.bar()': &dyn Trait<u32, i32> |
| 273..286 's.bar().baz()': (u32, i32) |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn dyn_trait_bare() { |
| check_infer( |
| r#" |
| //- minicore: sized |
| trait Trait { |
| fn foo(&self) -> u64; |
| } |
| fn bar() -> Trait {} |
| |
| fn test(x: Trait, y: &Trait) -> u64 { |
| x; |
| y; |
| let z = bar(); |
| x.foo(); |
| y.foo(); |
| z.foo(); |
| }"#, |
| expect![[r#" |
| 26..30 'self': &Self |
| 60..62 '{}': dyn Trait |
| 72..73 'x': dyn Trait |
| 82..83 'y': &dyn Trait |
| 100..175 '{ ...o(); }': u64 |
| 106..107 'x': dyn Trait |
| 113..114 'y': &dyn Trait |
| 124..125 'z': dyn Trait |
| 128..131 'bar': fn bar() -> dyn Trait |
| 128..133 'bar()': dyn Trait |
| 139..140 'x': dyn Trait |
| 139..146 'x.foo()': u64 |
| 152..153 'y': &dyn Trait |
| 152..159 'y.foo()': u64 |
| 165..166 'z': dyn Trait |
| 165..172 'z.foo()': u64 |
| "#]], |
| ); |
| |
| check_infer_with_mismatches( |
| r#" |
| //- minicore: fn, coerce_unsized |
| struct S; |
| impl S { |
| fn foo(&self) {} |
| } |
| fn f(_: &Fn(S)) {} |
| fn main() { |
| f(&|number| number.foo()); |
| } |
| "#, |
| expect![[r#" |
| 31..35 'self': &S |
| 37..39 '{}': () |
| 47..48 '_': &dyn Fn(S) |
| 58..60 '{}': () |
| 71..105 '{ ...()); }': () |
| 77..78 'f': fn f(&dyn Fn(S)) |
| 77..102 'f(&|nu...foo())': () |
| 79..101 '&|numb....foo()': &impl Fn(S) |
| 80..101 '|numbe....foo()': impl Fn(S) |
| 81..87 'number': S |
| 89..95 'number': S |
| 89..101 'number.foo()': () |
| "#]], |
| ) |
| } |
| |
| #[test] |
| fn weird_bounds() { |
| check_infer( |
| r#" |
| //- minicore: sized |
| trait Trait {} |
| fn test( |
| a: impl Trait + 'lifetime, |
| b: impl 'lifetime, |
| c: impl (Trait), |
| d: impl ('lifetime), |
| e: impl ?Sized, |
| f: impl Trait + ?Sized |
| ) {} |
| "#, |
| expect![[r#" |
| 28..29 'a': impl Trait |
| 59..60 'b': impl Sized |
| 82..83 'c': impl Trait |
| 103..104 'd': impl Sized |
| 128..129 'e': impl ?Sized |
| 148..149 'f': impl Trait + ?Sized |
| 173..175 '{}': () |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn error_bound_chalk() { |
| check_types( |
| r#" |
| trait Trait { |
| fn foo(&self) -> u32 { 0 } |
| } |
| |
| fn test(x: (impl Trait + UnknownTrait)) { |
| x.foo(); |
| } //^^^^^^^ u32 |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn assoc_type_bindings() { |
| check_infer( |
| r#" |
| //- minicore: sized |
| trait Trait { |
| type Type; |
| } |
| |
| fn get<T: Trait>(t: T) -> <T as Trait>::Type {} |
| fn get2<U, T: Trait<Type = U>>(t: T) -> U {} |
| fn set<T: Trait<Type = u64>>(t: T) -> T {t} |
| |
| struct S<T>; |
| impl<T> Trait for S<T> { type Type = T; } |
| |
| fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) { |
| get(x); |
| get2(x); |
| get(y); |
| get2(y); |
| get(set(S)); |
| get2(set(S)); |
| get2(S::<str>); |
| }"#, |
| expect![[r#" |
| 49..50 't': T |
| 77..79 '{}': Trait::Type<T> |
| 111..112 't': T |
| 122..124 '{}': U |
| 154..155 't': T |
| 165..168 '{t}': T |
| 166..167 't': T |
| 256..257 'x': T |
| 262..263 'y': impl Trait<Type = i64> |
| 289..397 '{ ...r>); }': () |
| 295..298 'get': fn get<T>(T) -> <T as Trait>::Type |
| 295..301 'get(x)': u32 |
| 299..300 'x': T |
| 307..311 'get2': fn get2<u32, T>(T) -> u32 |
| 307..314 'get2(x)': u32 |
| 312..313 'x': T |
| 320..323 'get': fn get<impl Trait<Type = i64>>(impl Trait<Type = i64>) -> <impl Trait<Type = i64> as Trait>::Type |
| 320..326 'get(y)': i64 |
| 324..325 'y': impl Trait<Type = i64> |
| 332..336 'get2': fn get2<i64, impl Trait<Type = i64>>(impl Trait<Type = i64>) -> i64 |
| 332..339 'get2(y)': i64 |
| 337..338 'y': impl Trait<Type = i64> |
| 345..348 'get': fn get<S<u64>>(S<u64>) -> <S<u64> as Trait>::Type |
| 345..356 'get(set(S))': u64 |
| 349..352 'set': fn set<S<u64>>(S<u64>) -> S<u64> |
| 349..355 'set(S)': S<u64> |
| 353..354 'S': S<u64> |
| 362..366 'get2': fn get2<u64, S<u64>>(S<u64>) -> u64 |
| 362..374 'get2(set(S))': u64 |
| 367..370 'set': fn set<S<u64>>(S<u64>) -> S<u64> |
| 367..373 'set(S)': S<u64> |
| 371..372 'S': S<u64> |
| 380..384 'get2': fn get2<str, S<str>>(S<str>) -> str |
| 380..394 'get2(S::<str>)': str |
| 385..393 'S::<str>': S<str> |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn impl_trait_assoc_binding_projection_bug() { |
| check_types( |
| r#" |
| //- minicore: iterator |
| pub trait Language { |
| type Kind; |
| } |
| pub enum RustLanguage {} |
| impl Language for RustLanguage { |
| type Kind = SyntaxKind; |
| } |
| struct SyntaxNode<L> {} |
| fn foo() -> impl Iterator<Item = SyntaxNode<RustLanguage>> {} |
| |
| trait Clone { |
| fn clone(&self) -> Self; |
| } |
| |
| fn api_walkthrough() { |
| for node in foo() { |
| node.clone(); |
| } //^^^^^^^^^^^^ {unknown} |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn projection_eq_within_chalk() { |
| check_infer( |
| r#" |
| trait Trait1 { |
| type Type; |
| } |
| trait Trait2<T> { |
| fn foo(self) -> T; |
| } |
| impl<T, U> Trait2<T> for U where U: Trait1<Type = T> {} |
| |
| fn test<T: Trait1<Type = u32>>(x: T) { |
| x.foo(); |
| }"#, |
| expect![[r#" |
| 61..65 'self': Self |
| 163..164 'x': T |
| 169..185 '{ ...o(); }': () |
| 175..176 'x': T |
| 175..182 'x.foo()': u32 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn where_clause_trait_in_scope_for_method_resolution() { |
| check_types( |
| r#" |
| mod foo { |
| pub trait Trait { |
| fn foo(&self) -> u32 { 0 } |
| } |
| } |
| |
| fn test<T: foo::Trait>(x: T) { |
| x.foo(); |
| } //^^^^^^^ u32 |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn super_trait_method_resolution() { |
| check_infer( |
| r#" |
| mod foo { |
| pub trait SuperTrait { |
| fn foo(&self) -> u32 {} |
| } |
| } |
| trait Trait1: foo::SuperTrait {} |
| trait Trait2 where Self: foo::SuperTrait {} |
| |
| fn test<T: Trait1, U: Trait2>(x: T, y: U) { |
| x.foo(); |
| y.foo(); |
| }"#, |
| expect![[r#" |
| 53..57 'self': &Self |
| 66..68 '{}': u32 |
| 185..186 'x': T |
| 191..192 'y': U |
| 197..226 '{ ...o(); }': () |
| 203..204 'x': T |
| 203..210 'x.foo()': u32 |
| 216..217 'y': U |
| 216..223 'y.foo()': u32 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn super_trait_impl_trait_method_resolution() { |
| check_infer( |
| r#" |
| //- minicore: sized |
| mod foo { |
| pub trait SuperTrait { |
| fn foo(&self) -> u32 {} |
| } |
| } |
| trait Trait1: foo::SuperTrait {} |
| |
| fn test(x: &impl Trait1) { |
| x.foo(); |
| }"#, |
| expect![[r#" |
| 53..57 'self': &Self |
| 66..68 '{}': u32 |
| 119..120 'x': &impl Trait1 |
| 136..152 '{ ...o(); }': () |
| 142..143 'x': &impl Trait1 |
| 142..149 'x.foo()': u32 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn super_trait_cycle() { |
| // This just needs to not crash |
| check_infer( |
| r#" |
| trait A: B {} |
| trait B: A {} |
| |
| fn test<T: A>(x: T) { |
| x.foo(); |
| } |
| "#, |
| expect![[r#" |
| 43..44 'x': T |
| 49..65 '{ ...o(); }': () |
| 55..56 'x': T |
| 55..62 'x.foo()': {unknown} |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn super_trait_assoc_type_bounds() { |
| check_infer( |
| r#" |
| trait SuperTrait { type Type; } |
| trait Trait where Self: SuperTrait {} |
| |
| fn get2<U, T: Trait<Type = U>>(t: T) -> U {} |
| fn set<T: Trait<Type = u64>>(t: T) -> T {t} |
| |
| struct S<T>; |
| impl<T> SuperTrait for S<T> { type Type = T; } |
| impl<T> Trait for S<T> {} |
| |
| fn test() { |
| get2(set(S)); |
| }"#, |
| expect![[r#" |
| 102..103 't': T |
| 113..115 '{}': U |
| 145..146 't': T |
| 156..159 '{t}': T |
| 157..158 't': T |
| 258..279 '{ ...S)); }': () |
| 264..268 'get2': fn get2<u64, S<u64>>(S<u64>) -> u64 |
| 264..276 'get2(set(S))': u64 |
| 269..272 'set': fn set<S<u64>>(S<u64>) -> S<u64> |
| 269..275 'set(S)': S<u64> |
| 273..274 'S': S<u64> |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn fn_trait() { |
| check_infer_with_mismatches( |
| r#" |
| //- minicore: fn |
| |
| fn test<F: FnOnce(u32, u64) -> u128>(f: F) { |
| f.call_once((1, 2)); |
| }"#, |
| expect![[r#" |
| 38..39 'f': F |
| 44..72 '{ ...2)); }': () |
| 50..51 'f': F |
| 50..69 'f.call...1, 2))': u128 |
| 62..68 '(1, 2)': (u32, u64) |
| 63..64 '1': u32 |
| 66..67 '2': u64 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn fn_ptr_and_item() { |
| check_infer_with_mismatches( |
| r#" |
| //- minicore: fn |
| |
| trait Foo<T> { |
| fn foo(&self) -> T; |
| } |
| |
| struct Bar<T>(T); |
| |
| impl<A1, R, F: FnOnce(A1) -> R> Foo<(A1, R)> for Bar<F> { |
| fn foo(&self) -> (A1, R) { loop {} } |
| } |
| |
| enum Opt<T> { None, Some(T) } |
| impl<T> Opt<T> { |
| fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Opt<U> { loop {} } |
| } |
| |
| fn test() { |
| let bar: Bar<fn(u8) -> u32>; |
| bar.foo(); |
| |
| let opt: Opt<u8>; |
| let f: fn(u8) -> u32; |
| opt.map(f); |
| }"#, |
| expect![[r#" |
| 28..32 'self': &Self |
| 132..136 'self': &Bar<F> |
| 149..160 '{ loop {} }': (A1, R) |
| 151..158 'loop {}': ! |
| 156..158 '{}': () |
| 244..248 'self': Opt<T> |
| 250..251 'f': F |
| 266..277 '{ loop {} }': Opt<U> |
| 268..275 'loop {}': ! |
| 273..275 '{}': () |
| 291..407 '{ ...(f); }': () |
| 301..304 'bar': Bar<fn(u8) -> u32> |
| 330..333 'bar': Bar<fn(u8) -> u32> |
| 330..339 'bar.foo()': (u8, u32) |
| 350..353 'opt': Opt<u8> |
| 372..373 'f': fn(u8) -> u32 |
| 394..397 'opt': Opt<u8> |
| 394..404 'opt.map(f)': Opt<u32> |
| 402..403 'f': fn(u8) -> u32 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn fn_trait_deref_with_ty_default() { |
| check_infer( |
| r#" |
| //- minicore: deref, fn |
| struct Foo; |
| |
| impl Foo { |
| fn foo(&self) -> usize {} |
| } |
| |
| struct Lazy<T, F = fn() -> T>(F); |
| |
| impl<T, F> Lazy<T, F> { |
| pub fn new(f: F) -> Lazy<T, F> {} |
| } |
| |
| impl<T, F: FnOnce() -> T> core::ops::Deref for Lazy<T, F> { |
| type Target = T; |
| } |
| |
| fn test() { |
| let lazy1: Lazy<Foo, _> = Lazy::new(|| Foo); |
| let r1 = lazy1.foo(); |
| |
| fn make_foo_fn() -> Foo {} |
| let make_foo_fn_ptr: fn() -> Foo = make_foo_fn; |
| let lazy2: Lazy<Foo, _> = Lazy::new(make_foo_fn_ptr); |
| let r2 = lazy2.foo(); |
| }"#, |
| expect![[r#" |
| 36..40 'self': &Foo |
| 51..53 '{}': usize |
| 131..132 'f': F |
| 151..153 '{}': Lazy<T, F> |
| 251..497 '{ ...o(); }': () |
| 261..266 'lazy1': Lazy<Foo, impl Fn() -> Foo> |
| 283..292 'Lazy::new': fn new<Foo, impl Fn() -> Foo>(impl Fn() -> Foo) -> Lazy<Foo, impl Fn() -> Foo> |
| 283..300 'Lazy::...| Foo)': Lazy<Foo, impl Fn() -> Foo> |
| 293..299 '|| Foo': impl Fn() -> Foo |
| 296..299 'Foo': Foo |
| 310..312 'r1': usize |
| 315..320 'lazy1': Lazy<Foo, impl Fn() -> Foo> |
| 315..326 'lazy1.foo()': usize |
| 368..383 'make_foo_fn_ptr': fn() -> Foo |
| 399..410 'make_foo_fn': fn make_foo_fn() -> Foo |
| 420..425 'lazy2': Lazy<Foo, fn() -> Foo> |
| 442..451 'Lazy::new': fn new<Foo, fn() -> Foo>(fn() -> Foo) -> Lazy<Foo, fn() -> Foo> |
| 442..468 'Lazy::...n_ptr)': Lazy<Foo, fn() -> Foo> |
| 452..467 'make_foo_fn_ptr': fn() -> Foo |
| 478..480 'r2': usize |
| 483..488 'lazy2': Lazy<Foo, fn() -> Foo> |
| 483..494 'lazy2.foo()': usize |
| 357..359 '{}': Foo |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn closure_1() { |
| check_infer_with_mismatches( |
| r#" |
| //- minicore: fn |
| enum Option<T> { Some(T), None } |
| impl<T> Option<T> { |
| fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> { loop {} } |
| } |
| |
| fn test() { |
| let x = Option::Some(1u32); |
| x.map(|v| v + 1); |
| x.map(|_v| 1u64); |
| let y: Option<i64> = x.map(|_v| 1); |
| }"#, |
| expect![[r#" |
| 86..90 'self': Option<T> |
| 92..93 'f': F |
| 111..122 '{ loop {} }': Option<U> |
| 113..120 'loop {}': ! |
| 118..120 '{}': () |
| 136..255 '{ ... 1); }': () |
| 146..147 'x': Option<u32> |
| 150..162 'Option::Some': extern "rust-call" Some<u32>(u32) -> Option<u32> |
| 150..168 'Option...(1u32)': Option<u32> |
| 163..167 '1u32': u32 |
| 174..175 'x': Option<u32> |
| 174..190 'x.map(...v + 1)': Option<u32> |
| 180..189 '|v| v + 1': impl Fn(u32) -> u32 |
| 181..182 'v': u32 |
| 184..185 'v': u32 |
| 184..189 'v + 1': u32 |
| 188..189 '1': u32 |
| 196..197 'x': Option<u32> |
| 196..212 'x.map(... 1u64)': Option<u64> |
| 202..211 '|_v| 1u64': impl Fn(u32) -> u64 |
| 203..205 '_v': u32 |
| 207..211 '1u64': u64 |
| 222..223 'y': Option<i64> |
| 239..240 'x': Option<u32> |
| 239..252 'x.map(|_v| 1)': Option<i64> |
| 245..251 '|_v| 1': impl Fn(u32) -> i64 |
| 246..248 '_v': u32 |
| 250..251 '1': i64 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn closure_2() { |
| check_types( |
| r#" |
| //- minicore: add, fn |
| |
| impl core::ops::Add for u64 { |
| type Output = Self; |
| fn add(self, rhs: u64) -> Self::Output {0} |
| } |
| |
| impl core::ops::Add for u128 { |
| type Output = Self; |
| fn add(self, rhs: u128) -> Self::Output {0} |
| } |
| |
| fn test<F: FnOnce(u32) -> u64>(f: F) { |
| f(1); |
| // ^ u32 |
| //^^^^ u64 |
| let g = |v| v + 1; |
| //^^^^^ u64 |
| //^^^^^^^^^ impl Fn(u64) -> u64 |
| g(1u64); |
| //^^^^^^^ u64 |
| let h = |v| 1u128 + v; |
| //^^^^^^^^^^^^^ impl Fn(u128) -> u128 |
| }"#, |
| ); |
| } |
| |
| #[test] |
| fn closure_as_argument_inference_order() { |
| check_infer_with_mismatches( |
| r#" |
| //- minicore: fn |
| fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U { loop {} } |
| fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U { loop {} } |
| |
| struct S; |
| impl S { |
| fn method(self) -> u64; |
| |
| fn foo1<T, U, F: FnOnce(T) -> U>(self, x: T, f: F) -> U { loop {} } |
| fn foo2<T, U, F: FnOnce(T) -> U>(self, f: F, x: T) -> U { loop {} } |
| } |
| |
| fn test() { |
| let x1 = foo1(S, |s| s.method()); |
| let x2 = foo2(|s| s.method(), S); |
| let x3 = S.foo1(S, |s| s.method()); |
| let x4 = S.foo2(|s| s.method(), S); |
| }"#, |
| expect![[r#" |
| 33..34 'x': T |
| 39..40 'f': F |
| 50..61 '{ loop {} }': U |
| 52..59 'loop {}': ! |
| 57..59 '{}': () |
| 95..96 'f': F |
| 101..102 'x': T |
| 112..123 '{ loop {} }': U |
| 114..121 'loop {}': ! |
| 119..121 '{}': () |
| 158..162 'self': S |
| 210..214 'self': S |
| 216..217 'x': T |
| 222..223 'f': F |
| 233..244 '{ loop {} }': U |
| 235..242 'loop {}': ! |
| 240..242 '{}': () |
| 282..286 'self': S |
| 288..289 'f': F |
| 294..295 'x': T |
| 305..316 '{ loop {} }': U |
| 307..314 'loop {}': ! |
| 312..314 '{}': () |
| 330..489 '{ ... S); }': () |
| 340..342 'x1': u64 |
| 345..349 'foo1': fn foo1<S, u64, impl Fn(S) -> u64>(S, impl Fn(S) -> u64) -> u64 |
| 345..368 'foo1(S...hod())': u64 |
| 350..351 'S': S |
| 353..367 '|s| s.method()': impl Fn(S) -> u64 |
| 354..355 's': S |
| 357..358 's': S |
| 357..367 's.method()': u64 |
| 378..380 'x2': u64 |
| 383..387 'foo2': fn foo2<S, u64, impl Fn(S) -> u64>(impl Fn(S) -> u64, S) -> u64 |
| 383..406 'foo2(|...(), S)': u64 |
| 388..402 '|s| s.method()': impl Fn(S) -> u64 |
| 389..390 's': S |
| 392..393 's': S |
| 392..402 's.method()': u64 |
| 404..405 'S': S |
| 416..418 'x3': u64 |
| 421..422 'S': S |
| 421..446 'S.foo1...hod())': u64 |
| 428..429 'S': S |
| 431..445 '|s| s.method()': impl Fn(S) -> u64 |
| 432..433 's': S |
| 435..436 's': S |
| 435..445 's.method()': u64 |
| 456..458 'x4': u64 |
| 461..462 'S': S |
| 461..486 'S.foo2...(), S)': u64 |
| 468..482 '|s| s.method()': impl Fn(S) -> u64 |
| 469..470 's': S |
| 472..473 's': S |
| 472..482 's.method()': u64 |
| 484..485 'S': S |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn fn_item_fn_trait() { |
| check_types( |
| r#" |
| //- minicore: fn |
| struct S; |
| |
| fn foo() -> S { S } |
| |
| fn takes_closure<U, F: FnOnce() -> U>(f: F) -> U { f() } |
| |
| fn test() { |
| takes_closure(foo); |
| } //^^^^^^^^^^^^^^^^^^ S |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn unselected_projection_in_trait_env_1() { |
| check_types( |
| r#" |
| //- /main.rs |
| trait Trait { |
| type Item; |
| } |
| |
| trait Trait2 { |
| fn foo(&self) -> u32; |
| } |
| |
| fn test<T: Trait>() where T::Item: Trait2 { |
| let x: T::Item = no_matter; |
| x.foo(); |
| } //^^^^^^^ u32 |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn unselected_projection_in_trait_env_2() { |
| check_types( |
| r#" |
| trait Trait<T> { |
| type Item; |
| } |
| |
| trait Trait2 { |
| fn foo(&self) -> u32; |
| } |
| |
| fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> { |
| let x: T::Item = no_matter; |
| x.foo(); |
| } //^^^^^^^ u32 |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn unselected_projection_on_impl_self() { |
| check_infer( |
| r#" |
| //- /main.rs |
| trait Trait { |
| type Item; |
| |
| fn f(&self, x: Self::Item); |
| } |
| |
| struct S; |
| |
| impl Trait for S { |
| type Item = u32; |
| fn f(&self, x: Self::Item) { let y = x; } |
| } |
| |
| struct S2; |
| |
| impl Trait for S2 { |
| type Item = i32; |
| fn f(&self, x: <Self>::Item) { let y = x; } |
| }"#, |
| expect![[r#" |
| 40..44 'self': &Self |
| 46..47 'x': Trait::Item<Self> |
| 126..130 'self': &S |
| 132..133 'x': u32 |
| 147..161 '{ let y = x; }': () |
| 153..154 'y': u32 |
| 157..158 'x': u32 |
| 228..232 'self': &S2 |
| 234..235 'x': i32 |
| 251..265 '{ let y = x; }': () |
| 257..258 'y': i32 |
| 261..262 'x': i32 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn unselected_projection_on_trait_self() { |
| check_types( |
| r#" |
| trait Trait { |
| type Item; |
| |
| fn f(&self) -> Self::Item { loop {} } |
| } |
| |
| struct S; |
| impl Trait for S { |
| type Item = u32; |
| } |
| |
| fn test() { |
| S.f(); |
| } //^^^^^ u32 |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn unselected_projection_chalk_fold() { |
| check_types( |
| r#" |
| trait Interner {} |
| trait Fold<I: Interner, TI = I> { |
| type Result; |
| } |
| |
| struct Ty<I: Interner> {} |
| impl<I: Interner, TI: Interner> Fold<I, TI> for Ty<I> { |
| type Result = Ty<TI>; |
| } |
| |
| fn fold<I: Interner, T>(interner: &I, t: T) -> T::Result |
| where |
| T: Fold<I, I>, |
| { |
| loop {} |
| } |
| |
| fn foo<I: Interner>(interner: &I, t: Ty<I>) { |
| fold(interner, t); |
| } //^^^^^^^^^^^^^^^^^ Ty<I> |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn trait_impl_self_ty() { |
| check_types( |
| r#" |
| trait Trait<T> { |
| fn foo(&self); |
| } |
| |
| struct S; |
| |
| impl Trait<Self> for S {} |
| |
| fn test() { |
| S.foo(); |
| } //^^^^^^^ () |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn trait_impl_self_ty_cycle() { |
| check_types( |
| r#" |
| trait Trait { |
| fn foo(&self); |
| } |
| |
| struct S<T>; |
| |
| impl Trait for S<Self> {} |
| |
| fn test() { |
| S.foo(); |
| } //^^^^^^^ {unknown} |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn unselected_projection_in_trait_env_cycle_1() { |
| // This is not a cycle, because the `T: Trait2<T::Item>` bound depends only on the `T: Trait` |
| // bound, not on itself (since only `Trait` can define `Item`). |
| check_types( |
| r#" |
| trait Trait { |
| type Item; |
| } |
| |
| trait Trait2<T> {} |
| |
| fn test<T: Trait>() where T: Trait2<T::Item> { |
| let x: T::Item = no_matter; |
| } //^^^^^^^^^ Trait::Item<T> |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn unselected_projection_in_trait_env_cycle_2() { |
| // this is a legitimate cycle |
| check_types( |
| r#" |
| //- /main.rs |
| trait Trait<T> { |
| type Item; |
| } |
| |
| fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> { |
| let x: T::Item = no_matter; |
| } //^^^^^^^^^ {unknown} |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn unselected_projection_in_trait_env_cycle_3() { |
| // this is a cycle for rustc; we currently accept it |
| check_types( |
| r#" |
| //- /main.rs |
| trait Trait { |
| type Item; |
| type OtherItem; |
| } |
| |
| fn test<T>() where T: Trait<OtherItem = T::Item> { |
| let x: T::Item = no_matter; |
| } //^^^^^^^^^ Trait::Item<T> |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn unselected_projection_in_trait_env_no_cycle() { |
| // this is not a cycle |
| check_types( |
| r#" |
| //- minicore: index |
| use core::ops::Index; |
| |
| type Key<S: UnificationStoreBase> = <S as UnificationStoreBase>::Key; |
| |
| pub trait UnificationStoreBase: Index<Output = Key<Self>> { |
| type Key; |
| |
| fn len(&self) -> usize; |
| } |
| |
| pub trait UnificationStoreMut: UnificationStoreBase { |
| fn push(&mut self, value: Self::Key); |
| } |
| |
| fn test<T>(t: T) where T: UnificationStoreMut { |
| let x; |
| t.push(x); |
| let y: Key<T>; |
| (x, y); |
| } //^^^^^^ (UnificationStoreBase::Key<T>, UnificationStoreBase::Key<T>) |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn inline_assoc_type_bounds_1() { |
| check_types( |
| r#" |
| trait Iterator { |
| type Item; |
| } |
| trait OtherTrait<T> { |
| fn foo(&self) -> T; |
| } |
| |
| // workaround for Chalk assoc type normalization problems |
| pub struct S<T>; |
| impl<T: Iterator> Iterator for S<T> { |
| type Item = <T as Iterator>::Item; |
| } |
| |
| fn test<I: Iterator<Item: OtherTrait<u32>>>() { |
| let x: <S<I> as Iterator>::Item; |
| x.foo(); |
| } //^^^^^^^ u32 |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn inline_assoc_type_bounds_2() { |
| check_types( |
| r#" |
| trait Iterator { |
| type Item; |
| } |
| |
| fn test<I: Iterator<Item: Iterator<Item = u32>>>() { |
| let x: <<I as Iterator>::Item as Iterator>::Item; |
| x; |
| } //^ u32 |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn proc_macro_server_types() { |
| check_infer( |
| r#" |
| macro_rules! with_api { |
| ($S:ident, $self:ident, $m:ident) => { |
| $m! { |
| TokenStream { |
| fn new() -> $S::TokenStream; |
| }, |
| Group { |
| }, |
| } |
| }; |
| } |
| macro_rules! associated_item { |
| (type TokenStream) => |
| (type TokenStream: 'static;); |
| (type Group) => |
| (type Group: 'static;); |
| ($($item:tt)*) => ($($item)*;) |
| } |
| macro_rules! declare_server_traits { |
| ($($name:ident { |
| $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* |
| }),* $(,)?) => { |
| pub trait Types { |
| $(associated_item!(type $name);)* |
| } |
| |
| $(pub trait $name: Types { |
| $(associated_item!(fn $method($($arg: $arg_ty),*) $(-> $ret_ty)?);)* |
| })* |
| |
| pub trait Server: Types $(+ $name)* {} |
| impl<S: Types $(+ $name)*> Server for S {} |
| } |
| } |
| |
| with_api!(Self, self_, declare_server_traits); |
| struct G {} |
| struct T {} |
| struct RustAnalyzer; |
| impl Types for RustAnalyzer { |
| type TokenStream = T; |
| type Group = G; |
| } |
| |
| fn make<T>() -> T { loop {} } |
| impl TokenStream for RustAnalyzer { |
| fn new() -> Self::TokenStream { |
| let group: Self::Group = make(); |
| make() |
| } |
| }"#, |
| expect![[r#" |
| 1075..1086 '{ loop {} }': T |
| 1077..1084 'loop {}': ! |
| 1082..1084 '{}': () |
| 1157..1220 '{ ... }': T |
| 1171..1176 'group': G |
| 1192..1196 'make': fn make<G>() -> G |
| 1192..1198 'make()': G |
| 1208..1212 'make': fn make<T>() -> T |
| 1208..1214 'make()': T |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn unify_impl_trait() { |
| check_infer_with_mismatches( |
| r#" |
| //- minicore: sized |
| trait Trait<T> {} |
| |
| fn foo(x: impl Trait<u32>) { loop {} } |
| fn bar<T>(x: impl Trait<T>) -> T { loop {} } |
| |
| struct S<T>(T); |
| impl<T> Trait<T> for S<T> {} |
| |
| fn default<T>() -> T { loop {} } |
| |
| fn test() -> impl Trait<i32> { |
| let s1 = S(default()); |
| foo(s1); |
| let x: i32 = bar(S(default())); |
| S(default()) |
| }"#, |
| expect![[r#" |
| 26..27 'x': impl Trait<u32> |
| 46..57 '{ loop {} }': () |
| 48..55 'loop {}': ! |
| 53..55 '{}': () |
| 68..69 'x': impl Trait<T> |
| 91..102 '{ loop {} }': T |
| 93..100 'loop {}': ! |
| 98..100 '{}': () |
| 171..182 '{ loop {} }': T |
| 173..180 'loop {}': ! |
| 178..180 '{}': () |
| 213..309 '{ ...t()) }': S<i32> |
| 223..225 's1': S<u32> |
| 228..229 'S': extern "rust-call" S<u32>(u32) -> S<u32> |
| 228..240 'S(default())': S<u32> |
| 230..237 'default': fn default<u32>() -> u32 |
| 230..239 'default()': u32 |
| 246..249 'foo': fn foo(S<u32>) |
| 246..253 'foo(s1)': () |
| 250..252 's1': S<u32> |
| 263..264 'x': i32 |
| 272..275 'bar': fn bar<i32>(S<i32>) -> i32 |
| 272..289 'bar(S(...lt()))': i32 |
| 276..277 'S': extern "rust-call" S<i32>(i32) -> S<i32> |
| 276..288 'S(default())': S<i32> |
| 278..285 'default': fn default<i32>() -> i32 |
| 278..287 'default()': i32 |
| 295..296 'S': extern "rust-call" S<i32>(i32) -> S<i32> |
| 295..307 'S(default())': S<i32> |
| 297..304 'default': fn default<i32>() -> i32 |
| 297..306 'default()': i32 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn assoc_types_from_bounds() { |
| check_infer( |
| r#" |
| //- minicore: fn |
| trait T { |
| type O; |
| } |
| |
| impl T for () { |
| type O = (); |
| } |
| |
| fn f<X, F>(_v: F) |
| where |
| X: T, |
| F: FnOnce(&X::O), |
| { } |
| |
| fn main() { |
| f::<(), _>(|z| { z; }); |
| }"#, |
| expect![[r#" |
| 72..74 '_v': F |
| 117..120 '{ }': () |
| 132..163 '{ ... }); }': () |
| 138..148 'f::<(), _>': fn f<(), impl Fn(&())>(impl Fn(&())) |
| 138..160 'f::<()... z; })': () |
| 149..159 '|z| { z; }': impl Fn(&()) |
| 150..151 'z': &() |
| 153..159 '{ z; }': () |
| 155..156 'z': &() |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn associated_type_bound() { |
| check_types( |
| r#" |
| pub trait Trait { |
| type Item: OtherTrait<u32>; |
| } |
| pub trait OtherTrait<T> { |
| fn foo(&self) -> T; |
| } |
| |
| // this is just a workaround for chalk#234 |
| pub struct S<T>; |
| impl<T: Trait> Trait for S<T> { |
| type Item = <T as Trait>::Item; |
| } |
| |
| fn test<T: Trait>() { |
| let y: <S<T> as Trait>::Item = no_matter; |
| y.foo(); |
| } //^^^^^^^ u32 |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn associated_type_in_type_bound() { |
| check_types( |
| r#" |
| //- minicore: deref |
| fn fb(f: Foo<&u8>) { |
| f.foobar(); |
| //^^^^^^^^^^ u8 |
| } |
| trait Bar { |
| fn bar(&self) -> u8; |
| } |
| impl Bar for u8 { |
| fn bar(&self) -> u8 { *self } |
| } |
| |
| struct Foo<F> { |
| foo: F, |
| } |
| impl<F: core::ops::Deref<Target = impl Bar>> Foo<F> { |
| fn foobar(&self) -> u8 { |
| self.foo.deref().bar() |
| } |
| } |
| "#, |
| ) |
| } |
| |
| #[test] |
| fn dyn_trait_through_chalk() { |
| check_types( |
| r#" |
| //- minicore: deref |
| struct Box<T: ?Sized> {} |
| impl<T: ?Sized> core::ops::Deref for Box<T> { |
| type Target = T; |
| } |
| trait Trait { |
| fn foo(&self); |
| } |
| |
| fn test(x: Box<dyn Trait>) { |
| x.foo(); |
| } //^^^^^^^ () |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn string_to_owned() { |
| check_types( |
| r#" |
| struct String {} |
| pub trait ToOwned { |
| type Owned; |
| fn to_owned(&self) -> Self::Owned; |
| } |
| impl ToOwned for str { |
| type Owned = String; |
| } |
| fn test() { |
| "foo".to_owned(); |
| } //^^^^^^^^^^^^^^^^ String |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn iterator_chain() { |
| check_infer_with_mismatches( |
| r#" |
| //- minicore: fn, option |
| pub trait Iterator { |
| type Item; |
| |
| fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F> |
| where |
| F: FnMut(Self::Item) -> Option<B>, |
| { loop {} } |
| |
| fn for_each<F>(self, f: F) |
| where |
| F: FnMut(Self::Item), |
| { loop {} } |
| } |
| |
| pub trait IntoIterator { |
| type Item; |
| type IntoIter: Iterator<Item = Self::Item>; |
| fn into_iter(self) -> Self::IntoIter; |
| } |
| |
| pub struct FilterMap<I, F> { } |
| impl<B, I: Iterator, F> Iterator for FilterMap<I, F> |
| where |
| F: FnMut(I::Item) -> Option<B>, |
| { |
| type Item = B; |
| } |
| |
| #[stable(feature = "rust1", since = "1.0.0")] |
| impl<I: Iterator> IntoIterator for I { |
| type Item = I::Item; |
| type IntoIter = I; |
| |
| fn into_iter(self) -> I { |
| self |
| } |
| } |
| |
| struct Vec<T> {} |
| impl<T> Vec<T> { |
| fn new() -> Self { loop {} } |
| } |
| |
| impl<T> IntoIterator for Vec<T> { |
| type Item = T; |
| type IntoIter = IntoIter<T>; |
| } |
| |
| pub struct IntoIter<T> { } |
| impl<T> Iterator for IntoIter<T> { |
| type Item = T; |
| } |
| |
| fn main() { |
| Vec::<i32>::new().into_iter() |
| .filter_map(|x| if x > 0 { Some(x as u32) } else { None }) |
| .for_each(|y| { y; }); |
| }"#, |
| expect![[r#" |
| 61..65 'self': Self |
| 67..68 'f': F |
| 152..163 '{ loop {} }': FilterMap<Self, F> |
| 154..161 'loop {}': ! |
| 159..161 '{}': () |
| 184..188 'self': Self |
| 190..191 'f': F |
| 240..251 '{ loop {} }': () |
| 242..249 'loop {}': ! |
| 247..249 '{}': () |
| 360..364 'self': Self |
| 689..693 'self': I |
| 700..720 '{ ... }': I |
| 710..714 'self': I |
| 779..790 '{ loop {} }': Vec<T> |
| 781..788 'loop {}': ! |
| 786..788 '{}': () |
| 977..1104 '{ ... }); }': () |
| 983..998 'Vec::<i32>::new': fn new<i32>() -> Vec<i32> |
| 983..1000 'Vec::<...:new()': Vec<i32> |
| 983..1012 'Vec::<...iter()': IntoIter<i32> |
| 983..1075 'Vec::<...one })': FilterMap<IntoIter<i32>, impl Fn(i32) -> Option<u32>> |
| 983..1101 'Vec::<... y; })': () |
| 1029..1074 '|x| if...None }': impl Fn(i32) -> Option<u32> |
| 1030..1031 'x': i32 |
| 1033..1074 'if x >...None }': Option<u32> |
| 1036..1037 'x': i32 |
| 1036..1041 'x > 0': bool |
| 1040..1041 '0': i32 |
| 1042..1060 '{ Some...u32) }': Option<u32> |
| 1044..1048 'Some': extern "rust-call" Some<u32>(u32) -> Option<u32> |
| 1044..1058 'Some(x as u32)': Option<u32> |
| 1049..1050 'x': i32 |
| 1049..1057 'x as u32': u32 |
| 1066..1074 '{ None }': Option<u32> |
| 1068..1072 'None': Option<u32> |
| 1090..1100 '|y| { y; }': impl Fn(u32) |
| 1091..1092 'y': u32 |
| 1094..1100 '{ y; }': () |
| 1096..1097 'y': u32 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn nested_assoc() { |
| check_types( |
| r#" |
| struct Bar; |
| struct Foo; |
| |
| trait A { |
| type OutputA; |
| } |
| |
| impl A for Bar { |
| type OutputA = Foo; |
| } |
| |
| trait B { |
| type Output; |
| fn foo() -> Self::Output; |
| } |
| |
| impl<T:A> B for T { |
| type Output = T::OutputA; |
| fn foo() -> Self::Output { loop {} } |
| } |
| |
| fn main() { |
| Bar::foo(); |
| } //^^^^^^^^^^ Foo |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn trait_object_no_coercion() { |
| check_infer_with_mismatches( |
| r#" |
| trait Foo {} |
| |
| fn foo(x: &dyn Foo) {} |
| |
| fn test(x: &dyn Foo) { |
| foo(x); |
| }"#, |
| expect![[r#" |
| 21..22 'x': &dyn Foo |
| 34..36 '{}': () |
| 46..47 'x': &dyn Foo |
| 59..74 '{ foo(x); }': () |
| 65..68 'foo': fn foo(&dyn Foo) |
| 65..71 'foo(x)': () |
| 69..70 'x': &dyn Foo |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn builtin_copy() { |
| check_infer_with_mismatches( |
| r#" |
| //- minicore: copy |
| struct IsCopy; |
| impl Copy for IsCopy {} |
| struct NotCopy; |
| |
| trait Test { fn test(&self) -> bool; } |
| impl<T: Copy> Test for T {} |
| |
| fn test() { |
| IsCopy.test(); |
| NotCopy.test(); |
| (IsCopy, IsCopy).test(); |
| (IsCopy, NotCopy).test(); |
| }"#, |
| expect![[r#" |
| 78..82 'self': &Self |
| 134..235 '{ ...t(); }': () |
| 140..146 'IsCopy': IsCopy |
| 140..153 'IsCopy.test()': bool |
| 159..166 'NotCopy': NotCopy |
| 159..173 'NotCopy.test()': {unknown} |
| 179..195 '(IsCop...sCopy)': (IsCopy, IsCopy) |
| 179..202 '(IsCop...test()': bool |
| 180..186 'IsCopy': IsCopy |
| 188..194 'IsCopy': IsCopy |
| 208..225 '(IsCop...tCopy)': (IsCopy, NotCopy) |
| 208..232 '(IsCop...test()': {unknown} |
| 209..215 'IsCopy': IsCopy |
| 217..224 'NotCopy': NotCopy |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn builtin_fn_def_copy() { |
| check_infer_with_mismatches( |
| r#" |
| //- minicore: copy |
| fn foo() {} |
| fn bar<T: Copy>(T) -> T {} |
| struct Struct(usize); |
| enum Enum { Variant(usize) } |
| |
| trait Test { fn test(&self) -> bool; } |
| impl<T: Copy> Test for T {} |
| |
| fn test() { |
| foo.test(); |
| bar.test(); |
| Struct.test(); |
| Enum::Variant.test(); |
| }"#, |
| expect![[r#" |
| 9..11 '{}': () |
| 28..29 'T': {unknown} |
| 36..38 '{}': T |
| 36..38: expected T, got () |
| 113..117 'self': &Self |
| 169..249 '{ ...t(); }': () |
| 175..178 'foo': fn foo() |
| 175..185 'foo.test()': bool |
| 191..194 'bar': fn bar<{unknown}>({unknown}) -> {unknown} |
| 191..201 'bar.test()': bool |
| 207..213 'Struct': extern "rust-call" Struct(usize) -> Struct |
| 207..220 'Struct.test()': bool |
| 226..239 'Enum::Variant': extern "rust-call" Variant(usize) -> Enum |
| 226..246 'Enum::...test()': bool |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn builtin_fn_ptr_copy() { |
| check_infer_with_mismatches( |
| r#" |
| //- minicore: copy |
| trait Test { fn test(&self) -> bool; } |
| impl<T: Copy> Test for T {} |
| |
| fn test(f1: fn(), f2: fn(usize) -> u8, f3: fn(u8, u8) -> &u8) { |
| f1.test(); |
| f2.test(); |
| f3.test(); |
| }"#, |
| expect![[r#" |
| 22..26 'self': &Self |
| 76..78 'f1': fn() |
| 86..88 'f2': fn(usize) -> u8 |
| 107..109 'f3': fn(u8, u8) -> &u8 |
| 130..178 '{ ...t(); }': () |
| 136..138 'f1': fn() |
| 136..145 'f1.test()': bool |
| 151..153 'f2': fn(usize) -> u8 |
| 151..160 'f2.test()': bool |
| 166..168 'f3': fn(u8, u8) -> &u8 |
| 166..175 'f3.test()': bool |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn builtin_sized() { |
| check_infer_with_mismatches( |
| r#" |
| //- minicore: sized |
| trait Test { fn test(&self) -> bool; } |
| impl<T: Sized> Test for T {} |
| |
| fn test() { |
| 1u8.test(); |
| (*"foo").test(); // not Sized |
| (1u8, 1u8).test(); |
| (1u8, *"foo").test(); // not Sized |
| }"#, |
| expect![[r#" |
| 22..26 'self': &Self |
| 79..194 '{ ...ized }': () |
| 85..88 '1u8': u8 |
| 85..95 '1u8.test()': bool |
| 101..116 '(*"foo").test()': {unknown} |
| 102..108 '*"foo"': str |
| 103..108 '"foo"': &str |
| 135..145 '(1u8, 1u8)': (u8, u8) |
| 135..152 '(1u8, ...test()': bool |
| 136..139 '1u8': u8 |
| 141..144 '1u8': u8 |
| 158..171 '(1u8, *"foo")': (u8, str) |
| 158..178 '(1u8, ...test()': {unknown} |
| 159..162 '1u8': u8 |
| 164..170 '*"foo"': str |
| 165..170 '"foo"': &str |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn integer_range_iterate() { |
| check_types( |
| r#" |
| //- minicore: range, iterator |
| //- /main.rs crate:main |
| fn test() { |
| for x in 0..100 { x; } |
| } //^ i32 |
| |
| trait Step {} |
| impl Step for i32 {} |
| impl Step for i64 {} |
| |
| impl<A: Step> core::iter::Iterator for core::ops::Range<A> { |
| type Item = A; |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn infer_closure_arg() { |
| check_infer( |
| r#" |
| //- /lib.rs |
| |
| enum Option<T> { |
| None, |
| Some(T) |
| } |
| |
| fn foo() { |
| let s = Option::None; |
| let f = |x: Option<i32>| {}; |
| (&f)(s) |
| }"#, |
| expect![[r#" |
| 52..126 '{ ...)(s) }': () |
| 62..63 's': Option<i32> |
| 66..78 'Option::None': Option<i32> |
| 88..89 'f': impl Fn(Option<i32>) |
| 92..111 '|x: Op...2>| {}': impl Fn(Option<i32>) |
| 93..94 'x': Option<i32> |
| 109..111 '{}': () |
| 117..124 '(&f)(s)': () |
| 118..120 '&f': &impl Fn(Option<i32>) |
| 119..120 'f': impl Fn(Option<i32>) |
| 122..123 's': Option<i32> |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn dyn_fn_param_informs_call_site_closure_signature() { |
| cov_mark::check!(dyn_fn_param_informs_call_site_closure_signature); |
| check_types( |
| r#" |
| //- minicore: fn, coerce_unsized |
| struct S; |
| impl S { |
| fn inherent(&self) -> u8 { 0 } |
| } |
| fn take_dyn_fn(f: &dyn Fn(S)) {} |
| |
| fn f() { |
| take_dyn_fn(&|x| { x.inherent(); }); |
| //^^^^^^^^^^^^ u8 |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn infer_fn_trait_arg() { |
| check_infer_with_mismatches( |
| r#" |
| //- minicore: fn, option |
| fn foo<F, T>(f: F) -> T |
| where |
| F: Fn(Option<i32>) -> T, |
| { |
| let s = None; |
| f(s) |
| } |
| "#, |
| expect![[r#" |
| 13..14 'f': F |
| 59..89 '{ ...f(s) }': T |
| 69..70 's': Option<i32> |
| 73..77 'None': Option<i32> |
| 83..84 'f': F |
| 83..87 'f(s)': T |
| 85..86 's': Option<i32> |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn infer_box_fn_arg() { |
| // The type mismatch is because we don't define Unsize and CoerceUnsized |
| check_infer_with_mismatches( |
| r#" |
| //- minicore: fn, deref, option |
| #[lang = "owned_box"] |
| pub struct Box<T: ?Sized> { |
| inner: *mut T, |
| } |
| |
| impl<T: ?Sized> core::ops::Deref for Box<T> { |
| type Target = T; |
| |
| fn deref(&self) -> &T { |
| unsafe { &*self.inner } |
| } |
| } |
| |
| fn foo() { |
| let s = None; |
| let f: Box<dyn FnOnce(&Option<i32>)> = Box { inner: &mut (|ps| {}) }; |
| f(&s); |
| }"#, |
| expect![[r#" |
| 154..158 'self': &Box<T> |
| 166..205 '{ ... }': &T |
| 176..199 'unsafe...nner }': &T |
| 185..197 '&*self.inner': &T |
| 186..197 '*self.inner': T |
| 187..191 'self': &Box<T> |
| 187..197 'self.inner': *mut T |
| 218..324 '{ ...&s); }': () |
| 228..229 's': Option<i32> |
| 232..236 'None': Option<i32> |
| 246..247 'f': Box<dyn FnOnce(&Option<i32>)> |
| 281..310 'Box { ... {}) }': Box<dyn FnOnce(&Option<i32>)> |
| 294..308 '&mut (|ps| {})': &mut impl Fn(&Option<i32>) |
| 300..307 '|ps| {}': impl Fn(&Option<i32>) |
| 301..303 'ps': &Option<i32> |
| 305..307 '{}': () |
| 316..317 'f': Box<dyn FnOnce(&Option<i32>)> |
| 316..321 'f(&s)': () |
| 318..320 '&s': &Option<i32> |
| 319..320 's': Option<i32> |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn infer_dyn_fn_output() { |
| check_types( |
| r#" |
| //- minicore: fn |
| fn foo() { |
| let f: &dyn Fn() -> i32; |
| f(); |
| //^^^ i32 |
| }"#, |
| ); |
| } |
| |
| #[test] |
| fn infer_dyn_fn_once_output() { |
| check_types( |
| r#" |
| //- minicore: fn |
| fn foo() { |
| let f: dyn FnOnce() -> i32; |
| f(); |
| //^^^ i32 |
| }"#, |
| ); |
| } |
| |
| #[test] |
| fn variable_kinds_1() { |
| check_types( |
| r#" |
| trait Trait<T> { fn get(self, t: T) -> T; } |
| struct S; |
| impl Trait<u128> for S {} |
| impl Trait<f32> for S {} |
| fn test() { |
| S.get(1); |
| //^^^^^^^^ u128 |
| S.get(1.); |
| //^^^^^^^^^ f32 |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn variable_kinds_2() { |
| check_types( |
| r#" |
| trait Trait { fn get(self) -> Self; } |
| impl Trait for u128 {} |
| impl Trait for f32 {} |
| fn test() { |
| 1.get(); |
| //^^^^^^^ u128 |
| (1.).get(); |
| //^^^^^^^^^^ f32 |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn underscore_import() { |
| check_types( |
| r#" |
| mod tr { |
| pub trait Tr { |
| fn method(&self) -> u8 { 0 } |
| } |
| } |
| |
| struct Tr; |
| impl crate::tr::Tr for Tr {} |
| |
| use crate::tr::Tr as _; |
| fn test() { |
| Tr.method(); |
| //^^^^^^^^^^^ u8 |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn inner_use() { |
| check_types( |
| r#" |
| mod m { |
| pub trait Tr { |
| fn method(&self) -> u8 { 0 } |
| } |
| |
| impl Tr for () {} |
| } |
| |
| fn f() { |
| use m::Tr; |
| |
| ().method(); |
| //^^^^^^^^^^^ u8 |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn trait_in_scope_with_inner_item() { |
| check_infer( |
| r#" |
| mod m { |
| pub trait Tr { |
| fn method(&self) -> u8 { 0 } |
| } |
| |
| impl Tr for () {} |
| } |
| |
| use m::Tr; |
| |
| fn f() { |
| fn inner() { |
| ().method(); |
| //^^^^^^^^^^^ u8 |
| } |
| }"#, |
| expect![[r#" |
| 46..50 'self': &Self |
| 58..63 '{ 0 }': u8 |
| 60..61 '0': u8 |
| 115..185 '{ ... } }': () |
| 132..183 '{ ... }': () |
| 142..144 '()': () |
| 142..153 '().method()': u8 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn inner_use_in_block() { |
| check_types( |
| r#" |
| mod m { |
| pub trait Tr { |
| fn method(&self) -> u8 { 0 } |
| } |
| |
| impl Tr for () {} |
| } |
| |
| fn f() { |
| { |
| use m::Tr; |
| |
| ().method(); |
| //^^^^^^^^^^^ u8 |
| } |
| |
| { |
| ().method(); |
| //^^^^^^^^^^^ {unknown} |
| } |
| |
| ().method(); |
| //^^^^^^^^^^^ {unknown} |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn nested_inner_function_calling_self() { |
| check_infer( |
| r#" |
| struct S; |
| fn f() { |
| fn inner() -> S { |
| let s = inner(); |
| } |
| }"#, |
| expect![[r#" |
| 17..73 '{ ... } }': () |
| 39..71 '{ ... }': S |
| 53..54 's': S |
| 57..62 'inner': fn inner() -> S |
| 57..64 'inner()': S |
| "#]], |
| ) |
| } |
| |
| #[test] |
| fn infer_default_trait_type_parameter() { |
| check_infer( |
| r#" |
| struct A; |
| |
| trait Op<RHS=Self> { |
| type Output; |
| |
| fn do_op(self, rhs: RHS) -> Self::Output; |
| } |
| |
| impl Op for A { |
| type Output = bool; |
| |
| fn do_op(self, rhs: Self) -> Self::Output { |
| true |
| } |
| } |
| |
| fn test() { |
| let x = A; |
| let y = A; |
| let r = x.do_op(y); |
| }"#, |
| expect![[r#" |
| 63..67 'self': Self |
| 69..72 'rhs': RHS |
| 153..157 'self': A |
| 159..162 'rhs': A |
| 186..206 '{ ... }': bool |
| 196..200 'true': bool |
| 220..277 '{ ...(y); }': () |
| 230..231 'x': A |
| 234..235 'A': A |
| 245..246 'y': A |
| 249..250 'A': A |
| 260..261 'r': bool |
| 264..265 'x': A |
| 264..274 'x.do_op(y)': bool |
| 272..273 'y': A |
| "#]], |
| ) |
| } |
| |
| #[test] |
| fn qualified_path_as_qualified_trait() { |
| check_infer( |
| r#" |
| mod foo { |
| |
| pub trait Foo { |
| type Target; |
| } |
| pub trait Bar { |
| type Output; |
| fn boo() -> Self::Output { |
| loop {} |
| } |
| } |
| } |
| |
| struct F; |
| impl foo::Foo for F { |
| type Target = (); |
| } |
| impl foo::Bar for F { |
| type Output = <F as foo::Foo>::Target; |
| } |
| |
| fn foo() { |
| use foo::Bar; |
| let x = <F as Bar>::boo(); |
| }"#, |
| expect![[r#" |
| 132..163 '{ ... }': Bar::Output<Self> |
| 146..153 'loop {}': ! |
| 151..153 '{}': () |
| 306..358 '{ ...o(); }': () |
| 334..335 'x': () |
| 338..353 '<F as Bar>::boo': fn boo<F>() -> <F as Bar>::Output |
| 338..355 '<F as ...:boo()': () |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn renamed_extern_crate_in_block() { |
| check_types( |
| r#" |
| //- /lib.rs crate:lib deps:serde |
| use serde::Deserialize; |
| |
| struct Foo {} |
| |
| const _ : () = { |
| extern crate serde as _serde; |
| impl _serde::Deserialize for Foo { |
| fn deserialize() -> u8 { 0 } |
| } |
| }; |
| |
| fn foo() { |
| Foo::deserialize(); |
| //^^^^^^^^^^^^^^^^^^ u8 |
| } |
| |
| //- /serde.rs crate:serde |
| |
| pub trait Deserialize { |
| fn deserialize() -> u8; |
| }"#, |
| ); |
| } |
| |
| #[test] |
| fn bin_op_with_rhs_is_self_for_assoc_bound() { |
| check_no_mismatches( |
| r#"//- minicore: eq |
| fn repro<T>(t: T) -> bool |
| where |
| T: Request, |
| T::Output: Convertable, |
| { |
| let a = execute(&t).convert(); |
| let b = execute(&t).convert(); |
| a.eq(&b); |
| let a = execute(&t).convert2(); |
| let b = execute(&t).convert2(); |
| a.eq(&b) |
| } |
| fn execute<T>(t: &T) -> T::Output |
| where |
| T: Request, |
| { |
| <T as Request>::output() |
| } |
| trait Convertable { |
| type TraitSelf: PartialEq<Self::TraitSelf>; |
| type AssocAsDefaultSelf: PartialEq; |
| fn convert(self) -> Self::AssocAsDefaultSelf; |
| fn convert2(self) -> Self::TraitSelf; |
| } |
| trait Request { |
| type Output; |
| fn output() -> Self::Output; |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn bin_op_adt_with_rhs_primitive() { |
| check_infer_with_mismatches( |
| r#" |
| //- minicore: add |
| struct Wrapper(u32); |
| impl core::ops::Add<u32> for Wrapper { |
| type Output = Self; |
| fn add(self, rhs: u32) -> Wrapper { |
| Wrapper(rhs) |
| } |
| } |
| fn main(){ |
| let wrapped = Wrapper(10); |
| let num: u32 = 2; |
| let res = wrapped + num; |
| |
| }"#, |
| expect![[r#" |
| 95..99 'self': Wrapper |
| 101..104 'rhs': u32 |
| 122..150 '{ ... }': Wrapper |
| 132..139 'Wrapper': extern "rust-call" Wrapper(u32) -> Wrapper |
| 132..144 'Wrapper(rhs)': Wrapper |
| 140..143 'rhs': u32 |
| 162..248 '{ ...um; }': () |
| 172..179 'wrapped': Wrapper |
| 182..189 'Wrapper': extern "rust-call" Wrapper(u32) -> Wrapper |
| 182..193 'Wrapper(10)': Wrapper |
| 190..192 '10': u32 |
| 203..206 'num': u32 |
| 214..215 '2': u32 |
| 225..228 'res': Wrapper |
| 231..238 'wrapped': Wrapper |
| 231..244 'wrapped + num': Wrapper |
| 241..244 'num': u32 |
| "#]], |
| ) |
| } |
| |
| #[test] |
| fn builtin_binop_expectation_works_on_single_reference() { |
| check_types( |
| r#" |
| //- minicore: add |
| use core::ops::Add; |
| impl Add<i32> for i32 { type Output = i32 } |
| impl Add<&i32> for i32 { type Output = i32 } |
| impl Add<u32> for u32 { type Output = u32 } |
| impl Add<&u32> for u32 { type Output = u32 } |
| |
| struct V<T>; |
| impl<T> V<T> { |
| fn default() -> Self { loop {} } |
| fn get(&self, _: &T) -> &T { loop {} } |
| } |
| |
| fn take_u32(_: u32) {} |
| fn minimized() { |
| let v = V::default(); |
| let p = v.get(&0); |
| //^ &u32 |
| take_u32(42 + p); |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn no_builtin_binop_expectation_for_general_ty_var() { |
| // FIXME: Ideally type mismatch should be reported on `take_u32(42 - p)`. |
| check_types( |
| r#" |
| //- minicore: add |
| use core::ops::Add; |
| impl Add<i32> for i32 { type Output = i32; } |
| impl Add<&i32> for i32 { type Output = i32; } |
| // This is needed to prevent chalk from giving unique solution to `i32: Add<&?0>` after applying |
| // fallback to integer type variable for `42`. |
| impl Add<&()> for i32 { type Output = (); } |
| |
| struct V<T>; |
| impl<T> V<T> { |
| fn default() -> Self { loop {} } |
| fn get(&self) -> &T { loop {} } |
| } |
| |
| fn take_u32(_: u32) {} |
| fn minimized() { |
| let v = V::default(); |
| let p = v.get(); |
| //^ &{unknown} |
| take_u32(42 + p); |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn no_builtin_binop_expectation_for_non_builtin_types() { |
| check_no_mismatches( |
| r#" |
| //- minicore: default, eq |
| struct S; |
| impl Default for S { fn default() -> Self { S } } |
| impl Default for i32 { fn default() -> Self { 0 } } |
| impl PartialEq<S> for i32 { fn eq(&self, _: &S) -> bool { true } } |
| impl PartialEq<i32> for i32 { fn eq(&self, _: &S) -> bool { true } } |
| |
| fn take_s(_: S) {} |
| fn test() { |
| let s = Default::default(); |
| let _eq = 0 == s; |
| take_s(s); |
| } |
| "#, |
| ) |
| } |
| |
| #[test] |
| fn array_length() { |
| check_infer( |
| r#" |
| trait T { |
| type Output; |
| fn do_thing(&self) -> Self::Output; |
| } |
| |
| impl T for [u8; 4] { |
| type Output = usize; |
| fn do_thing(&self) -> Self::Output { |
| 2 |
| } |
| } |
| |
| impl T for [u8; 2] { |
| type Output = u8; |
| fn do_thing(&self) -> Self::Output { |
| 2 |
| } |
| } |
| |
| fn main() { |
| let v = [0u8; 2]; |
| let v2 = v.do_thing(); |
| let v3 = [0u8; 4]; |
| let v4 = v3.do_thing(); |
| } |
| "#, |
| expect![[r#" |
| 44..48 'self': &Self |
| 133..137 'self': &[u8; 4] |
| 155..172 '{ ... }': usize |
| 165..166 '2': usize |
| 236..240 'self': &[u8; 2] |
| 258..275 '{ ... }': u8 |
| 268..269 '2': u8 |
| 289..392 '{ ...g(); }': () |
| 299..300 'v': [u8; 2] |
| 303..311 '[0u8; 2]': [u8; 2] |
| 304..307 '0u8': u8 |
| 309..310 '2': usize |
| 321..323 'v2': u8 |
| 326..327 'v': [u8; 2] |
| 326..338 'v.do_thing()': u8 |
| 348..350 'v3': [u8; 4] |
| 353..361 '[0u8; 4]': [u8; 4] |
| 354..357 '0u8': u8 |
| 359..360 '4': usize |
| 371..373 'v4': usize |
| 376..378 'v3': [u8; 4] |
| 376..389 'v3.do_thing()': usize |
| "#]], |
| ) |
| } |
| |
| #[test] |
| fn const_generics() { |
| check_infer( |
| r#" |
| trait T { |
| type Output; |
| fn do_thing(&self) -> Self::Output; |
| } |
| |
| impl<const L: usize> T for [u8; L] { |
| type Output = [u8; L]; |
| fn do_thing(&self) -> Self::Output { |
| *self |
| } |
| } |
| |
| fn main() { |
| let v = [0u8; 2]; |
| let v2 = v.do_thing(); |
| } |
| "#, |
| expect![[r#" |
| 44..48 'self': &Self |
| 151..155 'self': &[u8; L] |
| 173..194 '{ ... }': [u8; L] |
| 183..188 '*self': [u8; L] |
| 184..188 'self': &[u8; L] |
| 208..260 '{ ...g(); }': () |
| 218..219 'v': [u8; 2] |
| 222..230 '[0u8; 2]': [u8; 2] |
| 223..226 '0u8': u8 |
| 228..229 '2': usize |
| 240..242 'v2': [u8; 2] |
| 245..246 'v': [u8; 2] |
| 245..257 'v.do_thing()': [u8; 2] |
| "#]], |
| ) |
| } |
| |
| #[test] |
| fn fn_returning_unit() { |
| check_infer_with_mismatches( |
| r#" |
| //- minicore: fn |
| fn test<F: FnOnce()>(f: F) { |
| let _: () = f(); |
| }"#, |
| expect![[r#" |
| 21..22 'f': F |
| 27..51 '{ ...f(); }': () |
| 37..38 '_': () |
| 45..46 'f': F |
| 45..48 'f()': () |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn trait_in_scope_of_trait_impl() { |
| check_infer( |
| r#" |
| mod foo { |
| pub trait Foo { |
| fn foo(self); |
| fn bar(self) -> usize { 0 } |
| } |
| } |
| impl foo::Foo for u32 { |
| fn foo(self) { |
| let _x = self.bar(); |
| } |
| } |
| "#, |
| expect![[r#" |
| 45..49 'self': Self |
| 67..71 'self': Self |
| 82..87 '{ 0 }': usize |
| 84..85 '0': usize |
| 131..135 'self': u32 |
| 137..173 '{ ... }': () |
| 151..153 '_x': usize |
| 156..160 'self': u32 |
| 156..166 'self.bar()': usize |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn infer_async_ret_type() { |
| check_types( |
| r#" |
| //- minicore: future, result |
| struct Fooey; |
| |
| impl Fooey { |
| fn collect<B: Convert>(self) -> B { |
| B::new() |
| } |
| } |
| |
| trait Convert { |
| fn new() -> Self; |
| } |
| impl Convert for u32 { |
| fn new() -> Self { 0 } |
| } |
| |
| async fn get_accounts() -> Result<u32, ()> { |
| let ret = Fooey.collect(); |
| // ^^^^^^^^^^^^^^^ u32 |
| Ok(ret) |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn local_impl_1() { |
| check_types( |
| r#" |
| trait Trait<T> { |
| fn foo(&self) -> T; |
| } |
| |
| fn test() { |
| struct S; |
| impl Trait<u32> for S { |
| fn foo(&self) -> u32 { 0 } |
| } |
| |
| S.foo(); |
| // ^^^^^^^ u32 |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn local_impl_2() { |
| check_types( |
| r#" |
| struct S; |
| |
| fn test() { |
| trait Trait<T> { |
| fn foo(&self) -> T; |
| } |
| impl Trait<u32> for S { |
| fn foo(&self) -> u32 { 0 } |
| } |
| |
| S.foo(); |
| // ^^^^^^^ u32 |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn local_impl_3() { |
| check_types( |
| r#" |
| trait Trait<T> { |
| fn foo(&self) -> T; |
| } |
| |
| fn test() { |
| struct S1; |
| { |
| struct S2; |
| |
| impl Trait<S1> for S2 { |
| fn foo(&self) -> S1 { S1 } |
| } |
| |
| S2.foo(); |
| // ^^^^^^^^ S1 |
| } |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn foreign_trait_with_local_trait_impl() { |
| check!(block_local_impls); |
| check( |
| r#" |
| mod module { |
| pub trait T { |
| const C: usize; |
| fn f(&self); |
| } |
| } |
| |
| fn f() { |
| use module::T; |
| impl T for usize { |
| const C: usize = 0; |
| fn f(&self) {} |
| } |
| 0usize.f(); |
| //^^^^^^^^^^ type: () |
| usize::C; |
| //^^^^^^^^type: usize |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn regression_14443_trait_solve() { |
| check_no_mismatches( |
| r#" |
| trait T { |
| fn f(&self) {} |
| } |
| |
| |
| fn main() { |
| struct A; |
| impl T for A {} |
| |
| let a = A; |
| |
| let b = { |
| struct B; |
| impl T for B {} |
| |
| B |
| }; |
| |
| a.f(); |
| b.f(); |
| } |
| "#, |
| ) |
| } |
| |
| #[test] |
| fn associated_type_sized_bounds() { |
| check_infer( |
| r#" |
| //- minicore: sized |
| struct Yes; |
| trait IsSized { const IS_SIZED: Yes; } |
| impl<T: Sized> IsSized for T { const IS_SIZED: Yes = Yes; } |
| |
| trait Foo { |
| type Explicit: Sized; |
| type Implicit; |
| type Relaxed: ?Sized; |
| } |
| fn f<F: Foo>() { |
| F::Explicit::IS_SIZED; |
| F::Implicit::IS_SIZED; |
| F::Relaxed::IS_SIZED; |
| } |
| "#, |
| expect![[r#" |
| 104..107 'Yes': Yes |
| 212..295 '{ ...ZED; }': () |
| 218..239 'F::Exp..._SIZED': Yes |
| 245..266 'F::Imp..._SIZED': Yes |
| 272..292 'F::Rel..._SIZED': {unknown} |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn dyn_map() { |
| check_types( |
| r#" |
| pub struct Key<K, V, P = (K, V)> {} |
| |
| pub trait Policy { |
| type K; |
| type V; |
| } |
| |
| impl<K, V> Policy for (K, V) { |
| type K = K; |
| type V = V; |
| } |
| |
| pub struct KeyMap<KEY> {} |
| |
| impl<P: Policy> KeyMap<Key<P::K, P::V, P>> { |
| pub fn get(&self, key: &P::K) -> P::V { |
| loop {} |
| } |
| } |
| |
| struct Fn {} |
| struct FunctionId {} |
| |
| fn test() { |
| let key_map: &KeyMap<Key<Fn, FunctionId>> = loop {}; |
| let key; |
| let result = key_map.get(key); |
| //^^^^^^ FunctionId |
| } |
| "#, |
| ) |
| } |
| |
| #[test] |
| fn dyn_multiple_auto_traits_in_different_order() { |
| check_no_mismatches( |
| r#" |
| auto trait Send {} |
| auto trait Sync {} |
| |
| fn f(t: &(dyn Sync + Send)) {} |
| fn g(t: &(dyn Send + Sync)) { |
| f(t); |
| } |
| "#, |
| ); |
| |
| check_no_mismatches( |
| r#" |
| auto trait Send {} |
| auto trait Sync {} |
| trait T {} |
| |
| fn f(t: &(dyn T + Send + Sync)) {} |
| fn g(t: &(dyn Sync + T + Send)) { |
| f(t); |
| } |
| "#, |
| ); |
| |
| check_infer_with_mismatches( |
| r#" |
| auto trait Send {} |
| auto trait Sync {} |
| trait T1 {} |
| trait T2 {} |
| |
| fn f(t: &(dyn T1 + T2 + Send + Sync)) {} |
| fn g(t: &(dyn Sync + T2 + T1 + Send)) { |
| f(t); |
| } |
| "#, |
| expect![[r#" |
| 68..69 't': &{unknown} |
| 101..103 '{}': () |
| 109..110 't': &{unknown} |
| 142..155 '{ f(t); }': () |
| 148..149 'f': fn f(&{unknown}) |
| 148..152 'f(t)': () |
| 150..151 't': &{unknown} |
| "#]], |
| ); |
| |
| check_no_mismatches( |
| r#" |
| auto trait Send {} |
| auto trait Sync {} |
| trait T { |
| type Proj: Send + Sync; |
| } |
| |
| fn f(t: &(dyn T<Proj = ()> + Send + Sync)) {} |
| fn g(t: &(dyn Sync + T<Proj = ()> + Send)) { |
| f(t); |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn dyn_multiple_projection_bounds() { |
| check_no_mismatches( |
| r#" |
| trait Trait { |
| type T; |
| type U; |
| } |
| |
| fn f(t: &dyn Trait<T = (), U = ()>) {} |
| fn g(t: &dyn Trait<U = (), T = ()>) { |
| f(t); |
| } |
| "#, |
| ); |
| |
| check_types( |
| r#" |
| trait Trait { |
| type T; |
| } |
| |
| fn f(t: &dyn Trait<T = (), T = ()>) {} |
| //^&{unknown} |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn dyn_duplicate_auto_trait() { |
| check_no_mismatches( |
| r#" |
| auto trait Send {} |
| |
| fn f(t: &(dyn Send + Send)) {} |
| fn g(t: &(dyn Send)) { |
| f(t); |
| } |
| "#, |
| ); |
| |
| check_no_mismatches( |
| r#" |
| auto trait Send {} |
| trait T {} |
| |
| fn f(t: &(dyn T + Send + Send)) {} |
| fn g(t: &(dyn T + Send)) { |
| f(t); |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn gats_in_path() { |
| check_types( |
| r#" |
| //- minicore: deref |
| use core::ops::Deref; |
| trait PointerFamily { |
| type Pointer<T>: Deref<Target = T>; |
| } |
| |
| fn f<P: PointerFamily>(p: P::Pointer<i32>) { |
| let a = *p; |
| //^ i32 |
| } |
| fn g<P: PointerFamily>(p: <P as PointerFamily>::Pointer<i32>) { |
| let a = *p; |
| //^ i32 |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn gats_with_impl_trait() { |
| // FIXME: the last function (`fn i()`) is not valid Rust as of this writing because you cannot |
| // specify the same associated type multiple times even if their arguments are different (c.f. |
| // `fn h()`, which is valid). Reconsider how to treat these invalid types. |
| check_types( |
| r#" |
| //- minicore: deref |
| use core::ops::Deref; |
| |
| trait Trait { |
| type Assoc<T>: Deref<Target = T>; |
| fn get<U>(&self) -> Self::Assoc<U>; |
| } |
| |
| fn f<T>(v: impl Trait) { |
| let a = v.get::<i32>().deref(); |
| //^ &i32 |
| let a = v.get::<T>().deref(); |
| //^ &T |
| } |
| fn g<'a, T: 'a>(v: impl Trait<Assoc<T> = &'a T>) { |
| let a = v.get::<T>(); |
| //^ &T |
| let a = v.get::<()>(); |
| //^ Trait::Assoc<(), impl Trait<Assoc<T> = &T>> |
| } |
| fn h<'a>(v: impl Trait<Assoc<i32> = &'a i32> + Trait<Assoc<i64> = &'a i64>) { |
| let a = v.get::<i32>(); |
| //^ &i32 |
| let a = v.get::<i64>(); |
| //^ &i64 |
| } |
| fn i<'a>(v: impl Trait<Assoc<i32> = &'a i32, Assoc<i64> = &'a i64>) { |
| let a = v.get::<i32>(); |
| //^ &i32 |
| let a = v.get::<i64>(); |
| //^ &i64 |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn gats_with_dyn() { |
| // This test is here to keep track of how we infer things despite traits with GATs being not |
| // object-safe currently. |
| // FIXME: reconsider how to treat these invalid types. |
| check_infer_with_mismatches( |
| r#" |
| //- minicore: deref |
| use core::ops::Deref; |
| |
| trait Trait { |
| type Assoc<T>: Deref<Target = T>; |
| fn get<U>(&self) -> Self::Assoc<U>; |
| } |
| |
| fn f<'a>(v: &dyn Trait<Assoc<i32> = &'a i32>) { |
| v.get::<i32>().deref(); |
| } |
| "#, |
| expect![[r#" |
| 90..94 'self': &Self |
| 127..128 'v': &(dyn Trait<Assoc<i32> = &i32>) |
| 164..195 '{ ...f(); }': () |
| 170..171 'v': &(dyn Trait<Assoc<i32> = &i32>) |
| 170..184 'v.get::<i32>()': &i32 |
| 170..192 'v.get:...eref()': &i32 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn gats_in_associated_type_binding() { |
| check_types( |
| r#" |
| trait Trait { |
| type Assoc<T>; |
| fn get<U>(&self) -> Self::Assoc<U>; |
| } |
| |
| fn f<T>(t: T) |
| where |
| T: Trait<Assoc<i32> = u32>, |
| T: Trait<Assoc<isize> = usize>, |
| { |
| let a = t.get::<i32>(); |
| //^ u32 |
| let a = t.get::<isize>(); |
| //^ usize |
| let a = t.get::<()>(); |
| //^ Trait::Assoc<(), T> |
| } |
| |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn gats_in_bounds_for_assoc() { |
| check_types( |
| r#" |
| trait Trait { |
| type Assoc: Another<Gat<i32> = usize>; |
| type Assoc2<T>: Another<Gat<T> = T>; |
| } |
| trait Another { |
| type Gat<T>; |
| fn foo(&self) -> Self::Gat<i32>; |
| fn bar<T>(&self) -> Self::Gat<T>; |
| } |
| |
| fn test<T: Trait>(a: T::Assoc, b: T::Assoc2<isize>) { |
| let v = a.foo(); |
| //^ usize |
| let v = b.bar::<isize>(); |
| //^ isize |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn bin_op_with_scalar_fallback() { |
| // Extra impls are significant so that chalk doesn't give us definite guidances. |
| check_types( |
| r#" |
| //- minicore: add |
| use core::ops::Add; |
| |
| struct Vec2<T>(T, T); |
| |
| impl Add for Vec2<i32> { |
| type Output = Self; |
| fn add(self, rhs: Self) -> Self::Output { loop {} } |
| } |
| impl Add for Vec2<u32> { |
| type Output = Self; |
| fn add(self, rhs: Self) -> Self::Output { loop {} } |
| } |
| impl Add for Vec2<f32> { |
| type Output = Self; |
| fn add(self, rhs: Self) -> Self::Output { loop {} } |
| } |
| impl Add for Vec2<f64> { |
| type Output = Self; |
| fn add(self, rhs: Self) -> Self::Output { loop {} } |
| } |
| |
| fn test() { |
| let a = Vec2(1, 2); |
| let b = Vec2(3, 4); |
| let c = a + b; |
| //^ Vec2<i32> |
| let a = Vec2(1., 2.); |
| let b = Vec2(3., 4.); |
| let c = a + b; |
| //^ Vec2<f64> |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn trait_method_with_scalar_fallback() { |
| check_types( |
| r#" |
| trait Trait { |
| type Output; |
| fn foo(&self) -> Self::Output; |
| } |
| impl<T> Trait for T { |
| type Output = T; |
| fn foo(&self) -> Self::Output { loop {} } |
| } |
| fn test() { |
| let a = 42; |
| let b = a.foo(); |
| //^ i32 |
| let a = 3.14; |
| let b = a.foo(); |
| //^ f64 |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn associated_type_in_struct_expr_path() { |
| // FIXME: All annotation should be resolvable. |
| // For lines marked as unstable, see rust-lang/rust#86935. |
| // FIXME: Remove the comments once stablized. |
| check_types( |
| r#" |
| trait Trait { |
| type Assoc; |
| fn f(); |
| } |
| |
| struct S { x: u32 } |
| |
| impl Trait for () { |
| type Assoc = S; |
| |
| fn f() { |
| let x = 42; |
| let a = Self::Assoc { x }; |
| // ^ S |
| let a = <Self>::Assoc { x }; // unstable |
| // ^ {unknown} |
| |
| // should be `Copy` but we don't track ownership anyway. |
| let value = S { x }; |
| if let Self::Assoc { x } = value {} |
| // ^ u32 |
| if let <Self>::Assoc { x } = value {} // unstable |
| // ^ {unknown} |
| } |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn associated_type_in_struct_expr_path_enum() { |
| // FIXME: All annotation should be resolvable. |
| // For lines marked as unstable, see rust-lang/rust#86935. |
| // FIXME: Remove the comments once stablized. |
| check_types( |
| r#" |
| trait Trait { |
| type Assoc; |
| fn f(); |
| } |
| |
| enum E { |
| Unit, |
| Struct { x: u32 }, |
| } |
| |
| impl Trait for () { |
| type Assoc = E; |
| |
| fn f() { |
| let a = Self::Assoc::Unit; |
| // ^ E |
| let a = <Self>::Assoc::Unit; |
| // ^ E |
| let a = <Self::Assoc>::Unit; |
| // ^ E |
| let a = <<Self>::Assoc>::Unit; |
| // ^ E |
| |
| // should be `Copy` but we don't track ownership anyway. |
| let value = E::Unit; |
| if let Self::Assoc::Unit = value {} |
| // ^^^^^^^^^^^^^^^^^ E |
| if let <Self>::Assoc::Unit = value {} |
| // ^^^^^^^^^^^^^^^^^^^ E |
| if let <Self::Assoc>::Unit = value {} |
| // ^^^^^^^^^^^^^^^^^^^ E |
| if let <<Self>::Assoc>::Unit = value {} |
| // ^^^^^^^^^^^^^^^^^^^^^ E |
| |
| let x = 42; |
| let a = Self::Assoc::Struct { x }; |
| // ^ E |
| let a = <Self>::Assoc::Struct { x }; // unstable |
| // ^ {unknown} |
| let a = <Self::Assoc>::Struct { x }; // unstable |
| // ^ {unknown} |
| let a = <<Self>::Assoc>::Struct { x }; // unstable |
| // ^ {unknown} |
| |
| // should be `Copy` but we don't track ownership anyway. |
| let value = E::Struct { x: 42 }; |
| if let Self::Assoc::Struct { x } = value {} |
| // ^ u32 |
| if let <Self>::Assoc::Struct { x } = value {} // unstable |
| // ^ {unknown} |
| if let <Self::Assoc>::Struct { x } = value {} // unstable |
| // ^ {unknown} |
| if let <<Self>::Assoc>::Struct { x } = value {} // unstable |
| // ^ {unknown} |
| } |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn derive_macro_bounds() { |
| check_types( |
| r#" |
| //- minicore: clone, derive |
| #[derive(Clone)] |
| struct Copy; |
| struct NotCopy; |
| #[derive(Clone)] |
| struct Generic<T>(T); |
| trait Tr { |
| type Assoc; |
| } |
| impl Tr for Copy { |
| type Assoc = NotCopy; |
| } |
| #[derive(Clone)] |
| struct AssocGeneric<T: Tr>(T::Assoc); |
| |
| // Currently rustc does not accept this. |
| // #[derive(Clone)] |
| // struct AssocGeneric2<T: Tr>(<T as Tr>::Assoc); |
| |
| #[derive(Clone)] |
| struct AssocGeneric3<T: Tr>(Generic<T::Assoc>); |
| |
| #[derive(Clone)] |
| struct Vec<T>(); |
| |
| #[derive(Clone)] |
| struct R1(Vec<R2>); |
| #[derive(Clone)] |
| struct R2(R1); |
| |
| fn f() { |
| let x = (&Copy).clone(); |
| //^ Copy |
| let x = (&NotCopy).clone(); |
| //^ &NotCopy |
| let x = (&Generic(Copy)).clone(); |
| //^ Generic<Copy> |
| let x = (&Generic(NotCopy)).clone(); |
| //^ &Generic<NotCopy> |
| let x: &AssocGeneric<Copy> = &AssocGeneric(NotCopy); |
| let x = x.clone(); |
| //^ &AssocGeneric<Copy> |
| // let x: &AssocGeneric2<Copy> = &AssocGeneric2(NotCopy); |
| // let x = x.clone(); |
| let x: &AssocGeneric3<Copy> = &AssocGeneric3(Generic(NotCopy)); |
| let x = x.clone(); |
| //^ &AssocGeneric3<Copy> |
| let x = (&R1(Vec())).clone(); |
| //^ R1 |
| let x = (&R2(R1(Vec()))).clone(); |
| //^ R2 |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn trait_obligations_should_be_registered_during_path_inference() { |
| check_types( |
| r#" |
| //- minicore: fn, from |
| struct S<T>(T); |
| fn map<T, U, F: FnOnce(T) -> S<U>>(_: T, _: F) -> U { loop {} } |
| |
| fn test(v: S<i32>) { |
| let res = map(v, Into::into); |
| //^^^ i32 |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn fn_obligation_should_be_registered_during_path_inference() { |
| check_types( |
| r#" |
| //- minicore: fn, from |
| struct S<T>(T); |
| impl<T> S<T> { |
| fn foo<U: Into<S<T>>>(_: U) -> Self { loop {} } |
| } |
| fn map<T, U, F: FnOnce(T) -> U>(_: T, _: F) -> U { loop {} } |
| |
| fn test(v: S<i32>) { |
| let res = map(v, S::foo); |
| //^^^ S<i32> |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn associated_type_in_argument() { |
| check( |
| r#" |
| trait A { |
| fn m(&self) -> i32; |
| } |
| |
| fn x<T: B>(k: &<T as B>::Ty) { |
| k.m(); |
| } |
| |
| struct X; |
| struct Y; |
| |
| impl A for X { |
| fn m(&self) -> i32 { |
| 8 |
| } |
| } |
| |
| impl A for Y { |
| fn m(&self) -> i32 { |
| 32 |
| } |
| } |
| |
| trait B { |
| type Ty: A; |
| } |
| |
| impl B for u16 { |
| type Ty = X; |
| } |
| |
| fn ttt() { |
| let inp = Y; |
| x::<u16>(&inp); |
| //^^^^ expected &X, got &Y |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn infer_borrow() { |
| check_types( |
| r#" |
| //- minicore: index |
| pub struct SomeMap<K>; |
| |
| pub trait Borrow<Borrowed: ?Sized> { |
| fn borrow(&self) -> &Borrowed; |
| } |
| |
| impl<T: ?Sized> Borrow<T> for T { |
| fn borrow(&self) -> &T { |
| self |
| } |
| } |
| |
| impl<T: ?Sized> Borrow<T> for &T { |
| fn borrow(&self) -> &T { |
| &**self |
| } |
| } |
| |
| impl<K, KB: Borrow<K>> core::ops::Index<KB> for SomeMap<K> { |
| type Output = (); |
| |
| fn index(&self, _: KB) -> &() { |
| &() |
| } |
| } |
| |
| impl<K> core::ops::IndexMut<K> for SomeMap<K> { |
| fn index_mut(&mut self, _: K) -> &mut () { |
| &mut () |
| } |
| } |
| |
| fn foo() { |
| let mut map = SomeMap; |
| map["a"] = (); |
| map; |
| //^^^ SomeMap<&str> |
| } |
| "#, |
| ); |
| } |