From 16a7d8cc850002b427fdc8d21ccde81caaed7902 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 13 Aug 2019 23:09:08 +0200 Subject: Add `impl Trait` and `dyn Trait` types - refactor bounds handling in the AST a bit - add HIR for bounds - add `Ty::Dyn` and `Ty::Opaque` variants and lower `dyn Trait` / `impl Trait` syntax to them --- crates/ra_hir/src/ty/tests.rs | 120 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) (limited to 'crates/ra_hir/src/ty/tests.rs') diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 57fd5492d..93c62b0d4 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -3273,6 +3273,126 @@ fn test(t: T) { assert_eq!(t, "{unknown}"); } +#[test] +fn impl_trait() { + assert_snapshot_matches!( + infer(r#" +trait Trait { + fn foo(&self) -> T; +} +fn bar() -> impl Trait {} + +fn test(x: impl Trait, y: &impl Trait) { + x; + y; + let z = bar(); + x.foo(); + y.foo(); + z.foo(); +} +"#), + @r###" + ⋮ + ⋮[30; 34) 'self': &Self + ⋮[72; 74) '{}': () + ⋮[84; 85) 'x': impl Trait + ⋮[104; 105) 'y': &impl Trait + ⋮[125; 200) '{ ...o(); }': () + ⋮[131; 132) 'x': impl Trait + ⋮[138; 139) 'y': &impl Trait + ⋮[149; 150) 'z': impl Trait + ⋮[153; 156) 'bar': fn bar() -> impl Trait + ⋮[153; 158) 'bar()': impl Trait + ⋮[164; 165) 'x': impl Trait + ⋮[164; 171) 'x.foo()': {unknown} + ⋮[177; 178) 'y': &impl Trait + ⋮[177; 184) 'y.foo()': {unknown} + ⋮[190; 191) 'z': impl Trait + ⋮[190; 197) 'z.foo()': {unknown} + "### + ); +} + +#[test] +fn dyn_trait() { + assert_snapshot_matches!( + infer(r#" +trait Trait { + fn foo(&self) -> T; +} +fn bar() -> dyn Trait {} + +fn test(x: dyn Trait, y: &dyn Trait) { + x; + y; + let z = bar(); + x.foo(); + y.foo(); + z.foo(); +} +"#), + @r###" + ⋮ + ⋮[30; 34) 'self': &Self + ⋮[71; 73) '{}': () + ⋮[83; 84) 'x': dyn Trait + ⋮[102; 103) 'y': &dyn Trait + ⋮[122; 197) '{ ...o(); }': () + ⋮[128; 129) 'x': dyn Trait + ⋮[135; 136) 'y': &dyn Trait + ⋮[146; 147) 'z': dyn Trait + ⋮[150; 153) 'bar': fn bar() -> dyn Trait + ⋮[150; 155) 'bar()': dyn Trait + ⋮[161; 162) 'x': dyn Trait + ⋮[161; 168) 'x.foo()': {unknown} + ⋮[174; 175) 'y': &dyn Trait + ⋮[174; 181) 'y.foo()': {unknown} + ⋮[187; 188) 'z': dyn Trait + ⋮[187; 194) 'z.foo()': {unknown} + "### + ); +} + +#[test] +fn dyn_trait_bare() { + assert_snapshot_matches!( + 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': {unknown} + ⋮[83; 84) 'y': &{unknown} + ⋮[101; 176) '{ ...o(); }': () + ⋮[107; 108) 'x': {unknown} + ⋮[114; 115) 'y': &{unknown} + ⋮[125; 126) 'z': {unknown} + ⋮[129; 132) 'bar': fn bar() -> {unknown} + ⋮[129; 134) 'bar()': {unknown} + ⋮[140; 141) 'x': {unknown} + ⋮[140; 147) 'x.foo()': {unknown} + ⋮[153; 154) 'y': &{unknown} + ⋮[153; 160) 'y.foo()': {unknown} + ⋮[166; 167) 'z': {unknown} + ⋮[166; 173) 'z.foo()': {unknown} + "### + ); +} + fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { let file = db.parse(pos.file_id).ok().unwrap(); let expr = algo::find_node_at_offset::(file.syntax(), pos.offset).unwrap(); -- cgit v1.2.3 From b1a40042e8f595af0486cf1cc70b63be1ff302b3 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Thu, 22 Aug 2019 13:23:50 +0200 Subject: Handle impl/dyn Trait in method resolution When we have one of these, the `Trait` doesn't need to be in scope to call its methods. So we need to consider this when looking for method candidates. (Actually I think the same is true when we have a bound `T: some::Trait`, but we don't handle that yet). At the same time, since Chalk doesn't handle these types yet, add a small hack to skip Chalk in method resolution and just consider `impl Trait: Trait` always true. This is enough to e.g. get completions for `impl Trait`, but since we don't do any unification we won't infer the return type of e.g. `impl Into::into()`. --- crates/ra_hir/src/ty/tests.rs | 82 +++++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 30 deletions(-) (limited to 'crates/ra_hir/src/ty/tests.rs') diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 93c62b0d4..41cea9564 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -3279,6 +3279,7 @@ fn impl_trait() { infer(r#" trait Trait { fn foo(&self) -> T; + fn foo2(&self) -> i64; } fn bar() -> impl Trait {} @@ -3289,26 +3290,36 @@ fn test(x: impl Trait, y: &impl Trait) { x.foo(); y.foo(); z.foo(); + x.foo2(); + y.foo2(); + z.foo2(); } "#), @r###" ⋮ ⋮[30; 34) 'self': &Self - ⋮[72; 74) '{}': () - ⋮[84; 85) 'x': impl Trait - ⋮[104; 105) 'y': &impl Trait - ⋮[125; 200) '{ ...o(); }': () - ⋮[131; 132) 'x': impl Trait - ⋮[138; 139) 'y': &impl Trait - ⋮[149; 150) 'z': impl Trait - ⋮[153; 156) 'bar': fn bar() -> impl Trait - ⋮[153; 158) 'bar()': impl Trait - ⋮[164; 165) 'x': impl Trait - ⋮[164; 171) 'x.foo()': {unknown} - ⋮[177; 178) 'y': &impl Trait - ⋮[177; 184) 'y.foo()': {unknown} - ⋮[190; 191) 'z': impl Trait - ⋮[190; 197) 'z.foo()': {unknown} + ⋮[55; 59) 'self': &Self + ⋮[99; 101) '{}': () + ⋮[111; 112) 'x': impl Trait + ⋮[131; 132) 'y': &impl Trait + ⋮[152; 269) '{ ...2(); }': () + ⋮[158; 159) 'x': impl Trait + ⋮[165; 166) 'y': &impl Trait + ⋮[176; 177) 'z': impl Trait + ⋮[180; 183) 'bar': fn bar() -> impl Trait + ⋮[180; 185) 'bar()': impl Trait + ⋮[191; 192) 'x': impl Trait + ⋮[191; 198) 'x.foo()': {unknown} + ⋮[204; 205) 'y': &impl Trait + ⋮[204; 211) 'y.foo()': {unknown} + ⋮[217; 218) 'z': impl Trait + ⋮[217; 224) 'z.foo()': {unknown} + ⋮[230; 231) 'x': impl Trait + ⋮[230; 238) 'x.foo2()': i64 + ⋮[244; 245) 'y': &impl Trait + ⋮[244; 252) 'y.foo2()': i64 + ⋮[258; 259) 'z': impl Trait + ⋮[258; 266) 'z.foo2()': i64 "### ); } @@ -3319,6 +3330,7 @@ fn dyn_trait() { infer(r#" trait Trait { fn foo(&self) -> T; + fn foo2(&self) -> i64; } fn bar() -> dyn Trait {} @@ -3329,26 +3341,36 @@ fn test(x: dyn Trait, y: &dyn Trait) { x.foo(); y.foo(); z.foo(); + x.foo2(); + y.foo2(); + z.foo2(); } "#), @r###" ⋮ ⋮[30; 34) 'self': &Self - ⋮[71; 73) '{}': () - ⋮[83; 84) 'x': dyn Trait - ⋮[102; 103) 'y': &dyn Trait - ⋮[122; 197) '{ ...o(); }': () - ⋮[128; 129) 'x': dyn Trait - ⋮[135; 136) 'y': &dyn Trait - ⋮[146; 147) 'z': dyn Trait - ⋮[150; 153) 'bar': fn bar() -> dyn Trait - ⋮[150; 155) 'bar()': dyn Trait - ⋮[161; 162) 'x': dyn Trait - ⋮[161; 168) 'x.foo()': {unknown} - ⋮[174; 175) 'y': &dyn Trait - ⋮[174; 181) 'y.foo()': {unknown} - ⋮[187; 188) 'z': dyn Trait - ⋮[187; 194) 'z.foo()': {unknown} + ⋮[55; 59) 'self': &Self + ⋮[98; 100) '{}': () + ⋮[110; 111) 'x': dyn Trait + ⋮[129; 130) 'y': &dyn Trait + ⋮[149; 266) '{ ...2(); }': () + ⋮[155; 156) 'x': dyn Trait + ⋮[162; 163) 'y': &dyn Trait + ⋮[173; 174) 'z': dyn Trait + ⋮[177; 180) 'bar': fn bar() -> dyn Trait + ⋮[177; 182) 'bar()': dyn Trait + ⋮[188; 189) 'x': dyn Trait + ⋮[188; 195) 'x.foo()': {unknown} + ⋮[201; 202) 'y': &dyn Trait + ⋮[201; 208) 'y.foo()': {unknown} + ⋮[214; 215) 'z': dyn Trait + ⋮[214; 221) 'z.foo()': {unknown} + ⋮[227; 228) 'x': dyn Trait + ⋮[227; 235) 'x.foo2()': i64 + ⋮[241; 242) 'y': &dyn Trait + ⋮[241; 249) 'y.foo2()': i64 + ⋮[255; 256) 'z': dyn Trait + ⋮[255; 263) 'z.foo2()': i64 "### ); } -- cgit v1.2.3 From 4768f5e7177159b894d65a50b1e4492cb4048ac3 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Thu, 22 Aug 2019 17:43:09 +0200 Subject: Improve/fix type bound lowering --- crates/ra_hir/src/ty/tests.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'crates/ra_hir/src/ty/tests.rs') diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 41cea9564..c5818b738 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -3415,6 +3415,39 @@ fn test(x: Trait, y: &Trait) -> u64 { ); } +#[test] +fn weird_bounds() { + assert_snapshot_matches!( + infer(r#" +trait Trait {} +fn test() { + let a: impl Trait + 'lifetime = foo; + let b: impl 'lifetime = foo; + let b: impl (Trait) = foo; + let b: impl ('lifetime) = foo; + let d: impl ?Sized = foo; + let e: impl Trait + ?Sized = foo; +} +"#), + @r###" + ⋮ + ⋮[26; 237) '{ ...foo; }': () + ⋮[36; 37) 'a': impl Trait + {error} + ⋮[64; 67) 'foo': impl Trait + {error} + ⋮[77; 78) 'b': impl {error} + ⋮[97; 100) 'foo': impl {error} + ⋮[110; 111) 'b': impl Trait + ⋮[128; 131) 'foo': impl Trait + ⋮[141; 142) 'b': impl {error} + ⋮[163; 166) 'foo': impl {error} + ⋮[176; 177) 'd': impl {error} + ⋮[193; 196) 'foo': impl {error} + ⋮[206; 207) 'e': impl Trait + {error} + ⋮[231; 234) 'foo': impl Trait + {error} + "### + ); +} + fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { let file = db.parse(pos.file_id).ok().unwrap(); let expr = algo::find_node_at_offset::(file.syntax(), pos.offset).unwrap(); -- cgit v1.2.3