mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-05 01:38:47 +00:00
1982 lines
38 KiB
Rust
1982 lines
38 KiB
Rust
use insta::assert_snapshot;
|
|
|
|
use ra_db::fixture::WithFixture;
|
|
|
|
use super::{infer, infer_with_mismatches, type_at, type_at_pos};
|
|
use crate::test_db::TestDB;
|
|
|
|
#[test]
|
|
fn infer_await() {
|
|
let (db, pos) = TestDB::with_position(
|
|
r#"
|
|
//- /main.rs crate:main deps:std
|
|
|
|
struct IntFuture;
|
|
|
|
impl Future for IntFuture {
|
|
type Output = u64;
|
|
}
|
|
|
|
fn test() {
|
|
let r = IntFuture;
|
|
let v = r.await;
|
|
v<|>;
|
|
}
|
|
|
|
//- /std.rs crate:std
|
|
#[prelude_import] use future::*;
|
|
mod future {
|
|
#[lang = "future_trait"]
|
|
trait Future {
|
|
type Output;
|
|
}
|
|
}
|
|
|
|
"#,
|
|
);
|
|
assert_eq!("u64", type_at_pos(&db, pos));
|
|
}
|
|
|
|
#[test]
|
|
fn infer_async() {
|
|
let (db, pos) = TestDB::with_position(
|
|
r#"
|
|
//- /main.rs crate:main deps:std
|
|
|
|
async fn foo() -> u64 {
|
|
128
|
|
}
|
|
|
|
fn test() {
|
|
let r = foo();
|
|
let v = r.await;
|
|
v<|>;
|
|
}
|
|
|
|
//- /std.rs crate:std
|
|
#[prelude_import] use future::*;
|
|
mod future {
|
|
#[lang = "future_trait"]
|
|
trait Future {
|
|
type Output;
|
|
}
|
|
}
|
|
|
|
"#,
|
|
);
|
|
assert_eq!("u64", type_at_pos(&db, pos));
|
|
}
|
|
|
|
#[test]
|
|
fn infer_desugar_async() {
|
|
let (db, pos) = TestDB::with_position(
|
|
r#"
|
|
//- /main.rs crate:main deps:std
|
|
|
|
async fn foo() -> u64 {
|
|
128
|
|
}
|
|
|
|
fn test() {
|
|
let r = foo();
|
|
r<|>;
|
|
}
|
|
|
|
//- /std.rs crate:std
|
|
#[prelude_import] use future::*;
|
|
mod future {
|
|
trait Future {
|
|
type Output;
|
|
}
|
|
}
|
|
|
|
"#,
|
|
);
|
|
assert_eq!("impl Future<Output = u64>", type_at_pos(&db, pos));
|
|
}
|
|
|
|
#[test]
|
|
fn infer_try() {
|
|
let (db, pos) = TestDB::with_position(
|
|
r#"
|
|
//- /main.rs crate:main deps:std
|
|
|
|
fn test() {
|
|
let r: Result<i32, u64> = Result::Ok(1);
|
|
let v = r?;
|
|
v<|>;
|
|
}
|
|
|
|
//- /std.rs crate:std
|
|
|
|
#[prelude_import] use ops::*;
|
|
mod ops {
|
|
trait Try {
|
|
type Ok;
|
|
type Error;
|
|
}
|
|
}
|
|
|
|
#[prelude_import] use result::*;
|
|
mod result {
|
|
enum Result<O, E> {
|
|
Ok(O),
|
|
Err(E)
|
|
}
|
|
|
|
impl<O, E> crate::ops::Try for Result<O, E> {
|
|
type Ok = O;
|
|
type Error = E;
|
|
}
|
|
}
|
|
|
|
"#,
|
|
);
|
|
assert_eq!("i32", type_at_pos(&db, pos));
|
|
}
|
|
|
|
#[test]
|
|
fn infer_for_loop() {
|
|
let (db, pos) = TestDB::with_position(
|
|
r#"
|
|
//- /main.rs crate:main deps:std
|
|
|
|
use std::collections::Vec;
|
|
|
|
fn test() {
|
|
let v = Vec::new();
|
|
v.push("foo");
|
|
for x in v {
|
|
x<|>;
|
|
}
|
|
}
|
|
|
|
//- /std.rs crate:std
|
|
|
|
#[prelude_import] use iter::*;
|
|
mod iter {
|
|
trait IntoIterator {
|
|
type Item;
|
|
}
|
|
}
|
|
|
|
mod collections {
|
|
struct Vec<T> {}
|
|
impl<T> Vec<T> {
|
|
fn new() -> Self { Vec {} }
|
|
fn push(&mut self, t: T) { }
|
|
}
|
|
|
|
impl<T> crate::iter::IntoIterator for Vec<T> {
|
|
type Item=T;
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
assert_eq!("&str", type_at_pos(&db, pos));
|
|
}
|
|
|
|
#[test]
|
|
fn infer_ops_neg() {
|
|
let (db, pos) = TestDB::with_position(
|
|
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<|>;
|
|
}
|
|
|
|
//- /std.rs crate:std
|
|
|
|
#[prelude_import] use ops::*;
|
|
mod ops {
|
|
#[lang = "neg"]
|
|
pub trait Neg {
|
|
type Output;
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
assert_eq!("Foo", type_at_pos(&db, pos));
|
|
}
|
|
|
|
#[test]
|
|
fn infer_ops_not() {
|
|
let (db, pos) = TestDB::with_position(
|
|
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<|>;
|
|
}
|
|
|
|
//- /std.rs crate:std
|
|
|
|
#[prelude_import] use ops::*;
|
|
mod ops {
|
|
#[lang = "not"]
|
|
pub trait Not {
|
|
type Output;
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
assert_eq!("Foo", type_at_pos(&db, pos));
|
|
}
|
|
|
|
#[test]
|
|
fn infer_from_bound_1() {
|
|
assert_snapshot!(
|
|
infer(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);
|
|
foo(s);
|
|
}
|
|
"#),
|
|
@r###"
|
|
[86; 87) 't': T
|
|
[92; 94) '{}': ()
|
|
[105; 144) '{ ...(s); }': ()
|
|
[115; 116) 's': S<u32>
|
|
[119; 120) 'S': S<u32>(u32) -> S<u32>
|
|
[119; 129) 'S(unknown)': S<u32>
|
|
[121; 128) 'unknown': u32
|
|
[135; 138) 'foo': fn foo<S<u32>>(S<u32>) -> ()
|
|
[135; 141) 'foo(s)': ()
|
|
[139; 140) 's': S<u32>
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn infer_from_bound_2() {
|
|
assert_snapshot!(
|
|
infer(r#"
|
|
trait Trait<T> {}
|
|
struct S<T>(T);
|
|
impl<U> Trait<U> for S<U> {}
|
|
fn foo<U, T: Trait<U>>(t: T) -> U {}
|
|
fn test() {
|
|
let s = S(unknown);
|
|
let x: u32 = foo(s);
|
|
}
|
|
"#),
|
|
@r###"
|
|
[87; 88) 't': T
|
|
[98; 100) '{}': ()
|
|
[111; 163) '{ ...(s); }': ()
|
|
[121; 122) 's': S<u32>
|
|
[125; 126) 'S': S<u32>(u32) -> S<u32>
|
|
[125; 135) 'S(unknown)': S<u32>
|
|
[127; 134) 'unknown': u32
|
|
[145; 146) 'x': u32
|
|
[154; 157) 'foo': fn foo<u32, S<u32>>(S<u32>) -> u32
|
|
[154; 160) 'foo(s)': u32
|
|
[158; 159) 's': S<u32>
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn trait_default_method_self_bound_implements_trait() {
|
|
test_utils::covers!(trait_self_implements_self);
|
|
assert_snapshot!(
|
|
infer(r#"
|
|
trait Trait {
|
|
fn foo(&self) -> i64;
|
|
fn bar(&self) -> {
|
|
let x = self.foo();
|
|
}
|
|
}
|
|
"#),
|
|
@r###"
|
|
[27; 31) 'self': &Self
|
|
[53; 57) 'self': &Self
|
|
[62; 97) '{ ... }': ()
|
|
[76; 77) 'x': i64
|
|
[80; 84) 'self': &Self
|
|
[80; 90) 'self.foo()': i64
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn trait_default_method_self_bound_implements_super_trait() {
|
|
test_utils::covers!(trait_self_implements_self);
|
|
assert_snapshot!(
|
|
infer(r#"
|
|
trait SuperTrait {
|
|
fn foo(&self) -> i64;
|
|
}
|
|
trait Trait: SuperTrait {
|
|
fn bar(&self) -> {
|
|
let x = self.foo();
|
|
}
|
|
}
|
|
"#),
|
|
@r###"
|
|
[32; 36) 'self': &Self
|
|
[86; 90) 'self': &Self
|
|
[95; 130) '{ ... }': ()
|
|
[109; 110) 'x': i64
|
|
[113; 117) 'self': &Self
|
|
[113; 123) 'self.foo()': i64
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn infer_project_associated_type() {
|
|
// y, z, a don't yet work because of https://github.com/rust-lang/chalk/issues/234
|
|
assert_snapshot!(
|
|
infer(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;
|
|
let y: <T as Iterable>::Item = no_matter;
|
|
let z: T::Item = no_matter;
|
|
let a: <T>::Item = no_matter;
|
|
}
|
|
"#),
|
|
@r###"
|
|
[108; 261) '{ ...ter; }': ()
|
|
[118; 119) 'x': u32
|
|
[145; 146) '1': u32
|
|
[156; 157) 'y': {unknown}
|
|
[183; 192) 'no_matter': {unknown}
|
|
[202; 203) 'z': {unknown}
|
|
[215; 224) 'no_matter': {unknown}
|
|
[234; 235) 'a': {unknown}
|
|
[249; 258) 'no_matter': {unknown}
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn infer_return_associated_type() {
|
|
assert_snapshot!(
|
|
infer(r#"
|
|
trait Iterable {
|
|
type Item;
|
|
}
|
|
struct S;
|
|
impl Iterable for S { type Item = u32; }
|
|
fn foo1<T: Iterable>(t: T) -> T::Item {}
|
|
fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item {}
|
|
fn foo3<T: Iterable>(t: T) -> <T>::Item {}
|
|
fn test() {
|
|
let x = foo1(S);
|
|
let y = foo2(S);
|
|
let z = foo3(S);
|
|
}
|
|
"#),
|
|
@r###"
|
|
[106; 107) 't': T
|
|
[123; 125) '{}': ()
|
|
[147; 148) 't': T
|
|
[178; 180) '{}': ()
|
|
[202; 203) 't': T
|
|
[221; 223) '{}': ()
|
|
[234; 300) '{ ...(S); }': ()
|
|
[244; 245) 'x': u32
|
|
[248; 252) 'foo1': fn foo1<S>(S) -> <S as Iterable>::Item
|
|
[248; 255) 'foo1(S)': u32
|
|
[253; 254) 'S': S
|
|
[265; 266) 'y': u32
|
|
[269; 273) 'foo2': fn foo2<S>(S) -> <S as Iterable>::Item
|
|
[269; 276) 'foo2(S)': u32
|
|
[274; 275) 'S': S
|
|
[286; 287) 'z': u32
|
|
[290; 294) 'foo3': fn foo3<S>(S) -> <S as Iterable>::Item
|
|
[290; 297) 'foo3(S)': u32
|
|
[295; 296) 'S': S
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn infer_associated_type_bound() {
|
|
assert_snapshot!(
|
|
infer(r#"
|
|
trait Iterable {
|
|
type Item;
|
|
}
|
|
fn test<T: Iterable<Item=u32>>() {
|
|
let y: T::Item = unknown;
|
|
}
|
|
"#),
|
|
@r###"
|
|
[67; 100) '{ ...own; }': ()
|
|
[77; 78) 'y': {unknown}
|
|
[90; 97) 'unknown': {unknown}
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn infer_const_body() {
|
|
assert_snapshot!(
|
|
infer(r#"
|
|
const A: u32 = 1 + 1;
|
|
static B: u64 = { let x = 1; x };
|
|
"#),
|
|
@r###"
|
|
[16; 17) '1': u32
|
|
[16; 21) '1 + 1': u32
|
|
[20; 21) '1': u32
|
|
[39; 55) '{ let ...1; x }': u64
|
|
[45; 46) 'x': u64
|
|
[49; 50) '1': u64
|
|
[52; 53) 'x': u64
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn tuple_struct_fields() {
|
|
assert_snapshot!(
|
|
infer(r#"
|
|
struct S(i32, u64);
|
|
fn test() -> u64 {
|
|
let a = S(4, 6);
|
|
let b = a.0;
|
|
a.1
|
|
}
|
|
"#),
|
|
@r###"
|
|
[38; 87) '{ ... a.1 }': u64
|
|
[48; 49) 'a': S
|
|
[52; 53) 'S': S(i32, u64) -> S
|
|
[52; 59) 'S(4, 6)': S
|
|
[54; 55) '4': i32
|
|
[57; 58) '6': u64
|
|
[69; 70) 'b': i32
|
|
[73; 74) 'a': S
|
|
[73; 76) 'a.0': i32
|
|
[82; 83) 'a': S
|
|
[82; 85) 'a.1': u64
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn tuple_struct_with_fn() {
|
|
assert_snapshot!(
|
|
infer(r#"
|
|
struct S(fn(u32) -> u64);
|
|
fn test() -> u64 {
|
|
let a = S(|i| 2*i);
|
|
let b = a.0(4);
|
|
a.0(2)
|
|
}
|
|
"#),
|
|
@r###"
|
|
[44; 102) '{ ...0(2) }': u64
|
|
[54; 55) 'a': S
|
|
[58; 59) 'S': S(fn(u32) -> u64) -> S
|
|
[58; 68) 'S(|i| 2*i)': S
|
|
[60; 67) '|i| 2*i': |u32| -> u64
|
|
[61; 62) 'i': u32
|
|
[64; 65) '2': u32
|
|
[64; 67) '2*i': u32
|
|
[66; 67) 'i': u32
|
|
[78; 79) 'b': u64
|
|
[82; 83) 'a': S
|
|
[82; 85) 'a.0': fn(u32) -> u64
|
|
[82; 88) 'a.0(4)': u64
|
|
[86; 87) '4': u32
|
|
[94; 95) 'a': S
|
|
[94; 97) 'a.0': fn(u32) -> u64
|
|
[94; 100) 'a.0(2)': u64
|
|
[98; 99) '2': u32
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn indexing_arrays() {
|
|
assert_snapshot!(
|
|
infer("fn main() { &mut [9][2]; }"),
|
|
@r###"
|
|
[10; 26) '{ &mut...[2]; }': ()
|
|
[12; 23) '&mut [9][2]': &mut {unknown}
|
|
[17; 20) '[9]': [i32; _]
|
|
[17; 23) '[9][2]': {unknown}
|
|
[18; 19) '9': i32
|
|
[21; 22) '2': i32
|
|
"###
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
fn infer_ops_index() {
|
|
let (db, pos) = TestDB::with_position(
|
|
r#"
|
|
//- /main.rs crate:main deps:std
|
|
|
|
struct Bar;
|
|
struct Foo;
|
|
|
|
impl std::ops::Index<u32> for Bar {
|
|
type Output = Foo;
|
|
}
|
|
|
|
fn test() {
|
|
let a = Bar;
|
|
let b = a[1];
|
|
b<|>;
|
|
}
|
|
|
|
//- /std.rs crate:std
|
|
|
|
#[prelude_import] use ops::*;
|
|
mod ops {
|
|
#[lang = "index"]
|
|
pub trait Index<Idx> {
|
|
type Output;
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
assert_eq!("Foo", type_at_pos(&db, pos));
|
|
}
|
|
|
|
#[test]
|
|
fn infer_ops_index_autoderef() {
|
|
let (db, pos) = TestDB::with_position(
|
|
r#"
|
|
//- /main.rs crate:main deps:std
|
|
fn test() {
|
|
let a = &[1u32, 2, 3];
|
|
let b = a[1];
|
|
b<|>;
|
|
}
|
|
|
|
//- /std.rs crate:std
|
|
impl<T> ops::Index<u32> for [T] {
|
|
type Output = T;
|
|
}
|
|
|
|
#[prelude_import] use ops::*;
|
|
mod ops {
|
|
#[lang = "index"]
|
|
pub trait Index<Idx> {
|
|
type Output;
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
assert_eq!("u32", type_at_pos(&db, pos));
|
|
}
|
|
|
|
#[test]
|
|
fn deref_trait() {
|
|
let t = type_at(
|
|
r#"
|
|
//- /main.rs
|
|
#[lang = "deref"]
|
|
trait Deref {
|
|
type Target;
|
|
fn deref(&self) -> &Self::Target;
|
|
}
|
|
|
|
struct Arc<T>;
|
|
impl<T> Deref for Arc<T> {
|
|
type Target = T;
|
|
}
|
|
|
|
struct S;
|
|
impl S {
|
|
fn foo(&self) -> u128 {}
|
|
}
|
|
|
|
fn test(s: Arc<S>) {
|
|
(*s, s.foo())<|>;
|
|
}
|
|
"#,
|
|
);
|
|
assert_eq!(t, "(S, u128)");
|
|
}
|
|
|
|
#[test]
|
|
fn deref_trait_with_inference_var() {
|
|
let t = type_at(
|
|
r#"
|
|
//- /main.rs
|
|
#[lang = "deref"]
|
|
trait Deref {
|
|
type Target;
|
|
fn deref(&self) -> &Self::Target;
|
|
}
|
|
|
|
struct Arc<T>;
|
|
fn new_arc<T>() -> Arc<T> {}
|
|
impl<T> Deref for Arc<T> {
|
|
type Target = T;
|
|
}
|
|
|
|
struct S;
|
|
fn foo(a: Arc<S>) {}
|
|
|
|
fn test() {
|
|
let a = new_arc();
|
|
let b = (*a)<|>;
|
|
foo(a);
|
|
}
|
|
"#,
|
|
);
|
|
assert_eq!(t, "S");
|
|
}
|
|
|
|
#[test]
|
|
fn deref_trait_infinite_recursion() {
|
|
let t = type_at(
|
|
r#"
|
|
//- /main.rs
|
|
#[lang = "deref"]
|
|
trait Deref {
|
|
type Target;
|
|
fn deref(&self) -> &Self::Target;
|
|
}
|
|
|
|
struct S;
|
|
|
|
impl Deref for S {
|
|
type Target = S;
|
|
}
|
|
|
|
fn test(s: S) {
|
|
s.foo()<|>;
|
|
}
|
|
"#,
|
|
);
|
|
assert_eq!(t, "{unknown}");
|
|
}
|
|
|
|
#[test]
|
|
fn deref_trait_with_question_mark_size() {
|
|
let t = type_at(
|
|
r#"
|
|
//- /main.rs
|
|
#[lang = "deref"]
|
|
trait Deref {
|
|
type Target;
|
|
fn deref(&self) -> &Self::Target;
|
|
}
|
|
|
|
struct Arc<T>;
|
|
impl<T> Deref for Arc<T> {
|
|
type Target = T;
|
|
}
|
|
|
|
struct S;
|
|
impl S {
|
|
fn foo(&self) -> u128 {}
|
|
}
|
|
|
|
fn test(s: Arc<S>) {
|
|
(*s, s.foo())<|>;
|
|
}
|
|
"#,
|
|
);
|
|
assert_eq!(t, "(S, u128)");
|
|
}
|
|
|
|
#[test]
|
|
fn obligation_from_function_clause() {
|
|
let t = type_at(
|
|
r#"
|
|
//- /main.rs
|
|
struct S;
|
|
|
|
trait Trait<T> {}
|
|
impl Trait<u32> for S {}
|
|
|
|
fn foo<T: Trait<U>, U>(t: T) -> U {}
|
|
|
|
fn test(s: S) {
|
|
foo(s)<|>;
|
|
}
|
|
"#,
|
|
);
|
|
assert_eq!(t, "u32");
|
|
}
|
|
|
|
#[test]
|
|
fn obligation_from_method_clause() {
|
|
let t = type_at(
|
|
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 {}
|
|
}
|
|
|
|
fn test() {
|
|
O.foo(S)<|>;
|
|
}
|
|
"#,
|
|
);
|
|
assert_eq!(t, "isize");
|
|
}
|
|
|
|
#[test]
|
|
fn obligation_from_self_method_clause() {
|
|
let t = type_at(
|
|
r#"
|
|
//- /main.rs
|
|
struct S;
|
|
|
|
trait Trait<T> {}
|
|
impl Trait<i64> for S {}
|
|
|
|
impl S {
|
|
fn foo<U>(&self) -> U where Self: Trait<U> {}
|
|
}
|
|
|
|
fn test() {
|
|
S.foo()<|>;
|
|
}
|
|
"#,
|
|
);
|
|
assert_eq!(t, "i64");
|
|
}
|
|
|
|
#[test]
|
|
fn obligation_from_impl_clause() {
|
|
let t = type_at(
|
|
r#"
|
|
//- /main.rs
|
|
struct S;
|
|
|
|
trait Trait<T> {}
|
|
impl Trait<&str> for S {}
|
|
|
|
struct O<T>;
|
|
impl<U, T: Trait<U>> O<T> {
|
|
fn foo(&self) -> U {}
|
|
}
|
|
|
|
fn test(o: O<S>) {
|
|
o.foo()<|>;
|
|
}
|
|
"#,
|
|
);
|
|
assert_eq!(t, "&str");
|
|
}
|
|
|
|
#[test]
|
|
fn generic_param_env_1() {
|
|
let t = type_at(
|
|
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: Clone>(t: T) { t.foo()<|>; }
|
|
"#,
|
|
);
|
|
assert_eq!(t, "u128");
|
|
}
|
|
|
|
#[test]
|
|
fn generic_param_env_1_not_met() {
|
|
let t = type_at(
|
|
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()<|>; }
|
|
"#,
|
|
);
|
|
assert_eq!(t, "{unknown}");
|
|
}
|
|
|
|
#[test]
|
|
fn generic_param_env_2() {
|
|
let t = type_at(
|
|
r#"
|
|
//- /main.rs
|
|
trait Trait { fn foo(self) -> u128; }
|
|
struct S;
|
|
impl Trait for S {}
|
|
fn test<T: Trait>(t: T) { t.foo()<|>; }
|
|
"#,
|
|
);
|
|
assert_eq!(t, "u128");
|
|
}
|
|
|
|
#[test]
|
|
fn generic_param_env_2_not_met() {
|
|
let t = type_at(
|
|
r#"
|
|
//- /main.rs
|
|
trait Trait { fn foo(self) -> u128; }
|
|
struct S;
|
|
impl Trait for S {}
|
|
fn test<T>(t: T) { t.foo()<|>; }
|
|
"#,
|
|
);
|
|
assert_eq!(t, "{unknown}");
|
|
}
|
|
|
|
#[test]
|
|
fn generic_param_env_deref() {
|
|
let t = type_at(
|
|
r#"
|
|
//- /main.rs
|
|
#[lang = "deref"]
|
|
trait Deref {
|
|
type Target;
|
|
}
|
|
trait Trait {}
|
|
impl<T> Deref for T where T: Trait {
|
|
type Target = i128;
|
|
}
|
|
fn test<T: Trait>(t: T) { (*t)<|>; }
|
|
"#,
|
|
);
|
|
assert_eq!(t, "i128");
|
|
}
|
|
|
|
#[test]
|
|
fn associated_type_placeholder() {
|
|
let t = type_at(
|
|
r#"
|
|
//- /main.rs
|
|
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<|>;
|
|
}
|
|
"#,
|
|
);
|
|
// 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].
|
|
assert_eq!(t, "ApplyL::Out<T>");
|
|
}
|
|
|
|
#[test]
|
|
fn associated_type_placeholder_2() {
|
|
let t = type_at(
|
|
r#"
|
|
//- /main.rs
|
|
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<|>;
|
|
}
|
|
"#,
|
|
);
|
|
// FIXME here Chalk doesn't normalize the type to a placeholder. I think we
|
|
// need to add a rule like Normalize(<T as ApplyL>::Out -> ApplyL::Out<T>)
|
|
// to the trait env ourselves here; probably Chalk can't do this by itself.
|
|
// assert_eq!(t, "ApplyL::Out<[missing name]>");
|
|
assert_eq!(t, "{unknown}");
|
|
}
|
|
|
|
#[test]
|
|
fn argument_impl_trait() {
|
|
assert_snapshot!(
|
|
infer_with_mismatches(r#"
|
|
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();
|
|
}
|
|
"#, true),
|
|
@r###"
|
|
[30; 34) 'self': &Self
|
|
[55; 59) 'self': &Self
|
|
[78; 79) 'x': impl Trait<u16>
|
|
[98; 100) '{}': ()
|
|
[155; 156) 'x': impl Trait<u64>
|
|
[175; 176) 'y': &impl Trait<u32>
|
|
[196; 324) '{ ...2(); }': ()
|
|
[202; 203) 'x': impl Trait<u64>
|
|
[209; 210) 'y': &impl Trait<u32>
|
|
[220; 221) 'z': S<u16>
|
|
[224; 225) 'S': S<u16>(u16) -> S<u16>
|
|
[224; 228) 'S(1)': S<u16>
|
|
[226; 227) '1': u16
|
|
[234; 237) 'bar': fn bar(S<u16>) -> ()
|
|
[234; 240) 'bar(z)': ()
|
|
[238; 239) 'z': S<u16>
|
|
[246; 247) 'x': impl Trait<u64>
|
|
[246; 253) 'x.foo()': u64
|
|
[259; 260) 'y': &impl Trait<u32>
|
|
[259; 266) 'y.foo()': u32
|
|
[272; 273) 'z': S<u16>
|
|
[272; 279) 'z.foo()': u16
|
|
[285; 286) 'x': impl Trait<u64>
|
|
[285; 293) 'x.foo2()': i64
|
|
[299; 300) 'y': &impl Trait<u32>
|
|
[299; 307) 'y.foo2()': i64
|
|
[313; 314) 'z': S<u16>
|
|
[313; 321) 'z.foo2()': i64
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn argument_impl_trait_type_args_1() {
|
|
assert_snapshot!(
|
|
infer_with_mismatches(r#"
|
|
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
|
|
}
|
|
"#, true),
|
|
@r###"
|
|
[156; 157) 'x': impl Trait
|
|
[176; 187) '{ loop {} }': T
|
|
[178; 185) 'loop {}': !
|
|
[183; 185) '{}': ()
|
|
[200; 201) 'x': impl Trait
|
|
[220; 231) '{ loop {} }': T
|
|
[222; 229) 'loop {}': !
|
|
[227; 229) '{}': ()
|
|
[301; 510) '{ ... i32 }': ()
|
|
[307; 315) 'Foo::bar': fn bar<{unknown}, {unknown}>(S) -> {unknown}
|
|
[307; 318) 'Foo::bar(S)': {unknown}
|
|
[316; 317) 'S': S
|
|
[324; 339) '<F as Foo>::bar': fn bar<F, {unknown}>(S) -> {unknown}
|
|
[324; 342) '<F as ...bar(S)': {unknown}
|
|
[340; 341) 'S': S
|
|
[348; 354) 'F::bar': fn bar<F, {unknown}>(S) -> {unknown}
|
|
[348; 357) 'F::bar(S)': {unknown}
|
|
[355; 356) 'S': S
|
|
[363; 378) 'Foo::bar::<u32>': fn bar<{unknown}, u32>(S) -> u32
|
|
[363; 381) 'Foo::b...32>(S)': u32
|
|
[379; 380) 'S': S
|
|
[387; 409) '<F as ...:<u32>': fn bar<F, u32>(S) -> u32
|
|
[387; 412) '<F as ...32>(S)': u32
|
|
[410; 411) 'S': S
|
|
[419; 422) 'foo': fn foo<{unknown}>(S) -> {unknown}
|
|
[419; 425) 'foo(S)': {unknown}
|
|
[423; 424) 'S': S
|
|
[431; 441) 'foo::<u32>': fn foo<u32>(S) -> u32
|
|
[431; 444) 'foo::<u32>(S)': u32
|
|
[442; 443) 'S': S
|
|
[450; 465) 'foo::<u32, i32>': fn foo<u32>(S) -> u32
|
|
[450; 468) 'foo::<...32>(S)': u32
|
|
[466; 467) 'S': S
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn argument_impl_trait_type_args_2() {
|
|
assert_snapshot!(
|
|
infer_with_mismatches(r#"
|
|
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
|
|
}
|
|
"#, true),
|
|
@r###"
|
|
[88; 92) 'self': F<T>
|
|
[94; 95) 'x': impl Trait
|
|
[119; 130) '{ loop {} }': (T, U)
|
|
[121; 128) 'loop {}': !
|
|
[126; 128) '{}': ()
|
|
[144; 284) '{ ...ored }': ()
|
|
[150; 151) 'F': F<{unknown}>
|
|
[150; 158) 'F.foo(S)': ({unknown}, {unknown})
|
|
[156; 157) 'S': S
|
|
[164; 172) 'F::<u32>': F<u32>
|
|
[164; 179) 'F::<u32>.foo(S)': (u32, {unknown})
|
|
[177; 178) 'S': S
|
|
[185; 193) 'F::<u32>': F<u32>
|
|
[185; 207) 'F::<u3...32>(S)': (u32, i32)
|
|
[205; 206) 'S': S
|
|
[213; 221) 'F::<u32>': F<u32>
|
|
[213; 240) 'F::<u3...32>(S)': (u32, i32)
|
|
[238; 239) 'S': S
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn argument_impl_trait_to_fn_pointer() {
|
|
assert_snapshot!(
|
|
infer_with_mismatches(r#"
|
|
trait Trait {}
|
|
fn foo(x: impl Trait) { loop {} }
|
|
struct S;
|
|
impl Trait for S {}
|
|
|
|
fn test() {
|
|
let f: fn(S) -> () = foo;
|
|
}
|
|
"#, true),
|
|
@r###"
|
|
[23; 24) 'x': impl Trait
|
|
[38; 49) '{ loop {} }': ()
|
|
[40; 47) 'loop {}': !
|
|
[45; 47) '{}': ()
|
|
[91; 124) '{ ...foo; }': ()
|
|
[101; 102) 'f': fn(S) -> ()
|
|
[118; 121) 'foo': fn foo(S) -> ()
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn impl_trait() {
|
|
assert_snapshot!(
|
|
infer(r#"
|
|
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();
|
|
}
|
|
"#),
|
|
@r###"
|
|
[30; 34) 'self': &Self
|
|
[55; 59) 'self': &Self
|
|
[99; 101) '{}': ()
|
|
[111; 112) 'x': impl Trait<u64>
|
|
[131; 132) 'y': &impl Trait<u64>
|
|
[152; 269) '{ ...2(); }': ()
|
|
[158; 159) 'x': impl Trait<u64>
|
|
[165; 166) 'y': &impl Trait<u64>
|
|
[176; 177) 'z': impl Trait<u64>
|
|
[180; 183) 'bar': fn bar() -> impl Trait<u64>
|
|
[180; 185) 'bar()': impl Trait<u64>
|
|
[191; 192) 'x': impl Trait<u64>
|
|
[191; 198) 'x.foo()': u64
|
|
[204; 205) 'y': &impl Trait<u64>
|
|
[204; 211) 'y.foo()': u64
|
|
[217; 218) 'z': impl Trait<u64>
|
|
[217; 224) 'z.foo()': u64
|
|
[230; 231) 'x': impl Trait<u64>
|
|
[230; 238) 'x.foo2()': i64
|
|
[244; 245) 'y': &impl Trait<u64>
|
|
[244; 252) 'y.foo2()': i64
|
|
[258; 259) 'z': impl Trait<u64>
|
|
[258; 266) 'z.foo2()': i64
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn dyn_trait() {
|
|
assert_snapshot!(
|
|
infer(r#"
|
|
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();
|
|
}
|
|
"#),
|
|
@r###"
|
|
[30; 34) 'self': &Self
|
|
[55; 59) 'self': &Self
|
|
[98; 100) '{}': ()
|
|
[110; 111) 'x': dyn Trait<u64>
|
|
[129; 130) 'y': &dyn Trait<u64>
|
|
[149; 266) '{ ...2(); }': ()
|
|
[155; 156) 'x': dyn Trait<u64>
|
|
[162; 163) 'y': &dyn Trait<u64>
|
|
[173; 174) 'z': dyn Trait<u64>
|
|
[177; 180) 'bar': fn bar() -> dyn Trait<u64>
|
|
[177; 182) 'bar()': dyn Trait<u64>
|
|
[188; 189) 'x': dyn Trait<u64>
|
|
[188; 195) 'x.foo()': u64
|
|
[201; 202) 'y': &dyn Trait<u64>
|
|
[201; 208) 'y.foo()': u64
|
|
[214; 215) 'z': dyn Trait<u64>
|
|
[214; 221) 'z.foo()': u64
|
|
[227; 228) 'x': dyn Trait<u64>
|
|
[227; 235) 'x.foo2()': i64
|
|
[241; 242) 'y': &dyn Trait<u64>
|
|
[241; 249) 'y.foo2()': i64
|
|
[255; 256) 'z': dyn Trait<u64>
|
|
[255; 263) 'z.foo2()': i64
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn dyn_trait_bare() {
|
|
assert_snapshot!(
|
|
infer(r#"
|
|
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();
|
|
}
|
|
"#),
|
|
@r###"
|
|
[27; 31) 'self': &Self
|
|
[61; 63) '{}': ()
|
|
[73; 74) 'x': dyn Trait
|
|
[83; 84) 'y': &dyn Trait
|
|
[101; 176) '{ ...o(); }': ()
|
|
[107; 108) 'x': dyn Trait
|
|
[114; 115) 'y': &dyn Trait
|
|
[125; 126) 'z': dyn Trait
|
|
[129; 132) 'bar': fn bar() -> dyn Trait
|
|
[129; 134) 'bar()': dyn Trait
|
|
[140; 141) 'x': dyn Trait
|
|
[140; 147) 'x.foo()': u64
|
|
[153; 154) 'y': &dyn Trait
|
|
[153; 160) 'y.foo()': u64
|
|
[166; 167) 'z': dyn Trait
|
|
[166; 173) 'z.foo()': u64
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn weird_bounds() {
|
|
assert_snapshot!(
|
|
infer(r#"
|
|
trait Trait {}
|
|
fn test(a: impl Trait + 'lifetime, b: impl 'lifetime, c: impl (Trait), d: impl ('lifetime), e: impl ?Sized, f: impl Trait + ?Sized) {
|
|
}
|
|
"#),
|
|
@r###"
|
|
[24; 25) 'a': impl Trait + {error}
|
|
[51; 52) 'b': impl {error}
|
|
[70; 71) 'c': impl Trait
|
|
[87; 88) 'd': impl {error}
|
|
[108; 109) 'e': impl {error}
|
|
[124; 125) 'f': impl Trait + {error}
|
|
[148; 151) '{ }': ()
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn error_bound_chalk() {
|
|
let t = type_at(
|
|
r#"
|
|
//- /main.rs
|
|
trait Trait {
|
|
fn foo(&self) -> u32 {}
|
|
}
|
|
|
|
fn test(x: (impl Trait + UnknownTrait)) {
|
|
x.foo()<|>;
|
|
}
|
|
"#,
|
|
);
|
|
assert_eq!(t, "u32");
|
|
}
|
|
|
|
#[test]
|
|
fn assoc_type_bindings() {
|
|
assert_snapshot!(
|
|
infer(r#"
|
|
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>);
|
|
}
|
|
"#),
|
|
@r###"
|
|
[50; 51) 't': T
|
|
[78; 80) '{}': ()
|
|
[112; 113) 't': T
|
|
[123; 125) '{}': ()
|
|
[155; 156) 't': T
|
|
[166; 169) '{t}': T
|
|
[167; 168) 't': T
|
|
[257; 258) 'x': T
|
|
[263; 264) 'y': impl Trait<Type = i64>
|
|
[290; 398) '{ ...r>); }': ()
|
|
[296; 299) 'get': fn get<T>(T) -> <T as Trait>::Type
|
|
[296; 302) 'get(x)': {unknown}
|
|
[300; 301) 'x': T
|
|
[308; 312) 'get2': fn get2<{unknown}, T>(T) -> {unknown}
|
|
[308; 315) 'get2(x)': {unknown}
|
|
[313; 314) 'x': T
|
|
[321; 324) 'get': fn get<impl Trait<Type = i64>>(impl Trait<Type = i64>) -> <impl Trait<Type = i64> as Trait>::Type
|
|
[321; 327) 'get(y)': {unknown}
|
|
[325; 326) 'y': impl Trait<Type = i64>
|
|
[333; 337) 'get2': fn get2<{unknown}, impl Trait<Type = i64>>(impl Trait<Type = i64>) -> {unknown}
|
|
[333; 340) 'get2(y)': {unknown}
|
|
[338; 339) 'y': impl Trait<Type = i64>
|
|
[346; 349) 'get': fn get<S<u64>>(S<u64>) -> <S<u64> as Trait>::Type
|
|
[346; 357) 'get(set(S))': u64
|
|
[350; 353) 'set': fn set<S<u64>>(S<u64>) -> S<u64>
|
|
[350; 356) 'set(S)': S<u64>
|
|
[354; 355) 'S': S<u64>
|
|
[363; 367) 'get2': fn get2<u64, S<u64>>(S<u64>) -> u64
|
|
[363; 375) 'get2(set(S))': u64
|
|
[368; 371) 'set': fn set<S<u64>>(S<u64>) -> S<u64>
|
|
[368; 374) 'set(S)': S<u64>
|
|
[372; 373) 'S': S<u64>
|
|
[381; 385) 'get2': fn get2<str, S<str>>(S<str>) -> str
|
|
[381; 395) 'get2(S::<str>)': str
|
|
[386; 394) 'S::<str>': S<str>
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn impl_trait_assoc_binding_projection_bug() {
|
|
let (db, pos) = TestDB::with_position(
|
|
r#"
|
|
//- /main.rs crate:main deps:std
|
|
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()<|>;
|
|
}
|
|
}
|
|
|
|
//- /std.rs crate:std
|
|
#[prelude_import] use iter::*;
|
|
mod iter {
|
|
trait IntoIterator {
|
|
type Item;
|
|
}
|
|
trait Iterator {
|
|
type Item;
|
|
}
|
|
impl<T: Iterator> IntoIterator for T {
|
|
type Item = <T as Iterator>::Item;
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
assert_eq!("{unknown}", type_at_pos(&db, pos));
|
|
}
|
|
|
|
#[test]
|
|
fn projection_eq_within_chalk() {
|
|
// std::env::set_var("CHALK_DEBUG", "1");
|
|
assert_snapshot!(
|
|
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();
|
|
}
|
|
"#),
|
|
@r###"
|
|
[62; 66) 'self': Self
|
|
[164; 165) 'x': T
|
|
[170; 186) '{ ...o(); }': ()
|
|
[176; 177) 'x': T
|
|
[176; 183) 'x.foo()': {unknown}
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn where_clause_trait_in_scope_for_method_resolution() {
|
|
let t = type_at(
|
|
r#"
|
|
//- /main.rs
|
|
mod foo {
|
|
trait Trait {
|
|
fn foo(&self) -> u32 {}
|
|
}
|
|
}
|
|
|
|
fn test<T: foo::Trait>(x: T) {
|
|
x.foo()<|>;
|
|
}
|
|
"#,
|
|
);
|
|
assert_eq!(t, "u32");
|
|
}
|
|
|
|
#[test]
|
|
fn super_trait_method_resolution() {
|
|
assert_snapshot!(
|
|
infer(r#"
|
|
mod foo {
|
|
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();
|
|
}
|
|
"#),
|
|
@r###"
|
|
[50; 54) 'self': &Self
|
|
[63; 65) '{}': ()
|
|
[182; 183) 'x': T
|
|
[188; 189) 'y': U
|
|
[194; 223) '{ ...o(); }': ()
|
|
[200; 201) 'x': T
|
|
[200; 207) 'x.foo()': u32
|
|
[213; 214) 'y': U
|
|
[213; 220) 'y.foo()': u32
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn super_trait_impl_trait_method_resolution() {
|
|
assert_snapshot!(
|
|
infer(r#"
|
|
mod foo {
|
|
trait SuperTrait {
|
|
fn foo(&self) -> u32 {}
|
|
}
|
|
}
|
|
trait Trait1: foo::SuperTrait {}
|
|
|
|
fn test(x: &impl Trait1) {
|
|
x.foo();
|
|
}
|
|
"#),
|
|
@r###"
|
|
[50; 54) 'self': &Self
|
|
[63; 65) '{}': ()
|
|
[116; 117) 'x': &impl Trait1
|
|
[133; 149) '{ ...o(); }': ()
|
|
[139; 140) 'x': &impl Trait1
|
|
[139; 146) 'x.foo()': u32
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn super_trait_cycle() {
|
|
// This just needs to not crash
|
|
assert_snapshot!(
|
|
infer(r#"
|
|
trait A: B {}
|
|
trait B: A {}
|
|
|
|
fn test<T: A>(x: T) {
|
|
x.foo();
|
|
}
|
|
"#),
|
|
@r###"
|
|
[44; 45) 'x': T
|
|
[50; 66) '{ ...o(); }': ()
|
|
[56; 57) 'x': T
|
|
[56; 63) 'x.foo()': {unknown}
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn super_trait_assoc_type_bounds() {
|
|
assert_snapshot!(
|
|
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));
|
|
}
|
|
"#),
|
|
@r###"
|
|
[103; 104) 't': T
|
|
[114; 116) '{}': ()
|
|
[146; 147) 't': T
|
|
[157; 160) '{t}': T
|
|
[158; 159) 't': T
|
|
[259; 280) '{ ...S)); }': ()
|
|
[265; 269) 'get2': fn get2<u64, S<u64>>(S<u64>) -> u64
|
|
[265; 277) 'get2(set(S))': u64
|
|
[270; 273) 'set': fn set<S<u64>>(S<u64>) -> S<u64>
|
|
[270; 276) 'set(S)': S<u64>
|
|
[274; 275) 'S': S<u64>
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn fn_trait() {
|
|
assert_snapshot!(
|
|
infer(r#"
|
|
trait FnOnce<Args> {
|
|
type Output;
|
|
|
|
fn call_once(self, args: Args) -> <Self as FnOnce<Args>>::Output;
|
|
}
|
|
|
|
fn test<F: FnOnce(u32, u64) -> u128>(f: F) {
|
|
f.call_once((1, 2));
|
|
}
|
|
"#),
|
|
@r###"
|
|
[57; 61) 'self': Self
|
|
[63; 67) 'args': Args
|
|
[150; 151) 'f': F
|
|
[156; 184) '{ ...2)); }': ()
|
|
[162; 163) 'f': F
|
|
[162; 181) 'f.call...1, 2))': {unknown}
|
|
[174; 180) '(1, 2)': (u32, u64)
|
|
[175; 176) '1': u32
|
|
[178; 179) '2': u64
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn closure_1() {
|
|
assert_snapshot!(
|
|
infer(r#"
|
|
#[lang = "fn_once"]
|
|
trait FnOnce<Args> {
|
|
type Output;
|
|
}
|
|
|
|
enum Option<T> { Some(T), None }
|
|
impl<T> Option<T> {
|
|
fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {}
|
|
}
|
|
|
|
fn test() {
|
|
let x = Option::Some(1u32);
|
|
x.map(|v| v + 1);
|
|
x.map(|_v| 1u64);
|
|
let y: Option<i64> = x.map(|_v| 1);
|
|
}
|
|
"#),
|
|
@r###"
|
|
[148; 152) 'self': Option<T>
|
|
[154; 155) 'f': F
|
|
[173; 175) '{}': ()
|
|
[189; 308) '{ ... 1); }': ()
|
|
[199; 200) 'x': Option<u32>
|
|
[203; 215) 'Option::Some': Some<u32>(u32) -> Option<u32>
|
|
[203; 221) 'Option...(1u32)': Option<u32>
|
|
[216; 220) '1u32': u32
|
|
[227; 228) 'x': Option<u32>
|
|
[227; 243) 'x.map(...v + 1)': Option<u32>
|
|
[233; 242) '|v| v + 1': |u32| -> u32
|
|
[234; 235) 'v': u32
|
|
[237; 238) 'v': u32
|
|
[237; 242) 'v + 1': u32
|
|
[241; 242) '1': u32
|
|
[249; 250) 'x': Option<u32>
|
|
[249; 265) 'x.map(... 1u64)': Option<u64>
|
|
[255; 264) '|_v| 1u64': |u32| -> u64
|
|
[256; 258) '_v': u32
|
|
[260; 264) '1u64': u64
|
|
[275; 276) 'y': Option<i64>
|
|
[292; 293) 'x': Option<u32>
|
|
[292; 305) 'x.map(|_v| 1)': Option<i64>
|
|
[298; 304) '|_v| 1': |u32| -> i64
|
|
[299; 301) '_v': u32
|
|
[303; 304) '1': i64
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn closure_2() {
|
|
assert_snapshot!(
|
|
infer(r#"
|
|
trait FnOnce<Args> {
|
|
type Output;
|
|
}
|
|
|
|
fn test<F: FnOnce(u32) -> u64>(f: F) {
|
|
f(1);
|
|
let g = |v| v + 1;
|
|
g(1u64);
|
|
let h = |v| 1u128 + v;
|
|
}
|
|
"#),
|
|
@r###"
|
|
[73; 74) 'f': F
|
|
[79; 155) '{ ...+ v; }': ()
|
|
[85; 86) 'f': F
|
|
[85; 89) 'f(1)': {unknown}
|
|
[87; 88) '1': i32
|
|
[99; 100) 'g': |u64| -> i32
|
|
[103; 112) '|v| v + 1': |u64| -> i32
|
|
[104; 105) 'v': u64
|
|
[107; 108) 'v': u64
|
|
[107; 112) 'v + 1': i32
|
|
[111; 112) '1': i32
|
|
[118; 119) 'g': |u64| -> i32
|
|
[118; 125) 'g(1u64)': i32
|
|
[120; 124) '1u64': u64
|
|
[135; 136) 'h': |u128| -> u128
|
|
[139; 152) '|v| 1u128 + v': |u128| -> u128
|
|
[140; 141) 'v': u128
|
|
[143; 148) '1u128': u128
|
|
[143; 152) '1u128 + v': u128
|
|
[151; 152) 'v': u128
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn closure_as_argument_inference_order() {
|
|
assert_snapshot!(
|
|
infer(r#"
|
|
#[lang = "fn_once"]
|
|
trait FnOnce<Args> {
|
|
type Output;
|
|
}
|
|
|
|
fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U {}
|
|
fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U {}
|
|
|
|
struct S;
|
|
impl S {
|
|
fn method(self) -> u64;
|
|
|
|
fn foo1<T, U, F: FnOnce(T) -> U>(self, x: T, f: F) -> U {}
|
|
fn foo2<T, U, F: FnOnce(T) -> U>(self, f: F, x: T) -> U {}
|
|
}
|
|
|
|
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);
|
|
}
|
|
"#),
|
|
@r###"
|
|
[95; 96) 'x': T
|
|
[101; 102) 'f': F
|
|
[112; 114) '{}': ()
|
|
[148; 149) 'f': F
|
|
[154; 155) 'x': T
|
|
[165; 167) '{}': ()
|
|
[202; 206) 'self': S
|
|
[254; 258) 'self': S
|
|
[260; 261) 'x': T
|
|
[266; 267) 'f': F
|
|
[277; 279) '{}': ()
|
|
[317; 321) 'self': S
|
|
[323; 324) 'f': F
|
|
[329; 330) 'x': T
|
|
[340; 342) '{}': ()
|
|
[356; 515) '{ ... S); }': ()
|
|
[366; 368) 'x1': u64
|
|
[371; 375) 'foo1': fn foo1<S, u64, |S| -> u64>(S, |S| -> u64) -> u64
|
|
[371; 394) 'foo1(S...hod())': u64
|
|
[376; 377) 'S': S
|
|
[379; 393) '|s| s.method()': |S| -> u64
|
|
[380; 381) 's': S
|
|
[383; 384) 's': S
|
|
[383; 393) 's.method()': u64
|
|
[404; 406) 'x2': u64
|
|
[409; 413) 'foo2': fn foo2<S, u64, |S| -> u64>(|S| -> u64, S) -> u64
|
|
[409; 432) 'foo2(|...(), S)': u64
|
|
[414; 428) '|s| s.method()': |S| -> u64
|
|
[415; 416) 's': S
|
|
[418; 419) 's': S
|
|
[418; 428) 's.method()': u64
|
|
[430; 431) 'S': S
|
|
[442; 444) 'x3': u64
|
|
[447; 448) 'S': S
|
|
[447; 472) 'S.foo1...hod())': u64
|
|
[454; 455) 'S': S
|
|
[457; 471) '|s| s.method()': |S| -> u64
|
|
[458; 459) 's': S
|
|
[461; 462) 's': S
|
|
[461; 471) 's.method()': u64
|
|
[482; 484) 'x4': u64
|
|
[487; 488) 'S': S
|
|
[487; 512) 'S.foo2...(), S)': u64
|
|
[494; 508) '|s| s.method()': |S| -> u64
|
|
[495; 496) 's': S
|
|
[498; 499) 's': S
|
|
[498; 508) 's.method()': u64
|
|
[510; 511) 'S': S
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn unselected_projection_in_trait_env_1() {
|
|
let t = type_at(
|
|
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()<|>;
|
|
}
|
|
"#,
|
|
);
|
|
assert_eq!(t, "u32");
|
|
}
|
|
|
|
#[test]
|
|
fn unselected_projection_in_trait_env_2() {
|
|
let t = type_at(
|
|
r#"
|
|
//- /main.rs
|
|
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()<|>;
|
|
}
|
|
"#,
|
|
);
|
|
assert_eq!(t, "u32");
|
|
}
|
|
|
|
#[test]
|
|
fn trait_impl_self_ty() {
|
|
let t = type_at(
|
|
r#"
|
|
//- /main.rs
|
|
trait Trait<T> {
|
|
fn foo(&self);
|
|
}
|
|
|
|
struct S;
|
|
|
|
impl Trait<Self> for S {}
|
|
|
|
fn test() {
|
|
S.foo()<|>;
|
|
}
|
|
"#,
|
|
);
|
|
assert_eq!(t, "()");
|
|
}
|
|
|
|
#[test]
|
|
fn trait_impl_self_ty_cycle() {
|
|
let t = type_at(
|
|
r#"
|
|
//- /main.rs
|
|
trait Trait {
|
|
fn foo(&self);
|
|
}
|
|
|
|
struct S<T>;
|
|
|
|
impl Trait for S<Self> {}
|
|
|
|
fn test() {
|
|
S.foo()<|>;
|
|
}
|
|
"#,
|
|
);
|
|
assert_eq!(t, "{unknown}");
|
|
}
|
|
|
|
#[test]
|
|
fn unselected_projection_in_trait_env_cycle_1() {
|
|
let t = type_at(
|
|
r#"
|
|
//- /main.rs
|
|
trait Trait {
|
|
type Item;
|
|
}
|
|
|
|
trait Trait2<T> {}
|
|
|
|
fn test<T: Trait>() where T: Trait2<T::Item> {
|
|
let x: T::Item = no_matter<|>;
|
|
}
|
|
"#,
|
|
);
|
|
// this is a legitimate cycle
|
|
assert_eq!(t, "{unknown}");
|
|
}
|
|
|
|
#[test]
|
|
fn unselected_projection_in_trait_env_cycle_2() {
|
|
let t = type_at(
|
|
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<|>;
|
|
}
|
|
"#,
|
|
);
|
|
// this is a legitimate cycle
|
|
assert_eq!(t, "{unknown}");
|
|
}
|
|
|
|
#[test]
|
|
fn unify_impl_trait() {
|
|
assert_snapshot!(
|
|
infer_with_mismatches(r#"
|
|
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())
|
|
}
|
|
"#, true),
|
|
@r###"
|
|
[27; 28) 'x': impl Trait<u32>
|
|
[47; 58) '{ loop {} }': ()
|
|
[49; 56) 'loop {}': !
|
|
[54; 56) '{}': ()
|
|
[69; 70) 'x': impl Trait<T>
|
|
[92; 103) '{ loop {} }': T
|
|
[94; 101) 'loop {}': !
|
|
[99; 101) '{}': ()
|
|
[172; 183) '{ loop {} }': T
|
|
[174; 181) 'loop {}': !
|
|
[179; 181) '{}': ()
|
|
[214; 310) '{ ...t()) }': S<{unknown}>
|
|
[224; 226) 's1': S<u32>
|
|
[229; 230) 'S': S<u32>(u32) -> S<u32>
|
|
[229; 241) 'S(default())': S<u32>
|
|
[231; 238) 'default': fn default<u32>() -> u32
|
|
[231; 240) 'default()': u32
|
|
[247; 250) 'foo': fn foo(S<u32>) -> ()
|
|
[247; 254) 'foo(s1)': ()
|
|
[251; 253) 's1': S<u32>
|
|
[264; 265) 'x': i32
|
|
[273; 276) 'bar': fn bar<i32>(S<i32>) -> i32
|
|
[273; 290) 'bar(S(...lt()))': i32
|
|
[277; 278) 'S': S<i32>(i32) -> S<i32>
|
|
[277; 289) 'S(default())': S<i32>
|
|
[279; 286) 'default': fn default<i32>() -> i32
|
|
[279; 288) 'default()': i32
|
|
[296; 297) 'S': S<{unknown}>({unknown}) -> S<{unknown}>
|
|
[296; 308) 'S(default())': S<{unknown}>
|
|
[298; 305) 'default': fn default<{unknown}>() -> {unknown}
|
|
[298; 307) 'default()': {unknown}
|
|
"###
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn assoc_types_from_bounds() {
|
|
assert_snapshot!(
|
|
infer(r#"
|
|
//- /main.rs
|
|
#[lang = "fn_once"]
|
|
trait FnOnce<Args> {
|
|
type Output;
|
|
}
|
|
|
|
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; });
|
|
}
|
|
"#),
|
|
@r###"
|
|
[147; 149) '_v': F
|
|
[192; 195) '{ }': ()
|
|
[207; 238) '{ ... }); }': ()
|
|
[213; 223) 'f::<(), _>': fn f<(), |&()| -> ()>(|&()| -> ()) -> ()
|
|
[213; 235) 'f::<()... z; })': ()
|
|
[224; 234) '|z| { z; }': |&()| -> ()
|
|
[225; 226) 'z': &()
|
|
[228; 234) '{ z; }': ()
|
|
[230; 231) 'z': &()
|
|
"###
|
|
);
|
|
}
|