From db32a2e4211f9444ef4f10b633e400d27ed2662e Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 10 Apr 2020 22:05:46 +0200 Subject: Implement inline associated type bounds Like `Iterator`. This is an unstable feature, but it's used in the standard library e.g. in the definition of Flatten, so we can't get away with not implementing it :) --- crates/ra_hir_ty/src/tests/traits.rs | 47 ++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'crates/ra_hir_ty/src/tests') diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 22ae6ca90..53461bdbb 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -1923,6 +1923,53 @@ fn test() where T: Trait, U: Trait { assert_eq!(t, "{unknown}"); } +#[test] +fn inline_assoc_type_bounds_1() { + let t = type_at( + r#" +//- /main.rs +trait Iterator { + type Item; +} +trait OtherTrait { + fn foo(&self) -> T; +} + +// workaround for Chalk assoc type normalization problems +pub struct S; +impl Iterator for S { + type Item = ::Item; +} + +fn test>>() { + let x: as Iterator>::Item; + x.foo()<|>; +} +"#, + ); + assert_eq!(t, "u32"); +} + +#[test] +fn inline_assoc_type_bounds_2() { + let t = type_at( + r#" +//- /main.rs +trait Iterator { + type Item; +} + +fn test>>() { + let x: <::Item as Iterator>::Item; + x<|>; +} +"#, + ); + // assert_eq!(t, "u32"); + // doesn't currently work, Chalk #234 + assert_eq!(t, "{unknown}"); +} + #[test] fn unify_impl_trait() { assert_snapshot!( -- cgit v1.2.3 From c8b2ec8c20be44ae19d15e90ff812745f029899e Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 12 Apr 2020 12:28:24 +0200 Subject: Add support for bounds on associated types in trait definitions E.g. ``` trait Trait { type Item: SomeOtherTrait; } ``` Note that these don't simply desugar to where clauses; as I understand it, where clauses have to be proved by the *user* of the trait, but these bounds are proved by the *implementor*. (Also, where clauses on associated types are unstable.) --- crates/ra_hir_ty/src/tests/traits.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'crates/ra_hir_ty/src/tests') diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 22ae6ca90..af8c63d64 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -2022,6 +2022,33 @@ fn main() { ); } +#[test] +fn associated_type_bound() { + let t = type_at( + r#" +//- /main.rs +pub trait Trait { + type Item: OtherTrait; +} +pub trait OtherTrait { + fn foo(&self) -> T; +} + +// this is just a workaround for chalk#234 +pub struct S; +impl Trait for S { + type Item = ::Item; +} + +fn test() { + let y: as Trait>::Item = no_matter; + y.foo()<|>; +} +"#, + ); + assert_eq!(t, "u32"); +} + #[test] fn dyn_trait_through_chalk() { let t = type_at( -- cgit v1.2.3 From d88d67819b3f052422ad3f024e44ad73dde1630b Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 12 Apr 2020 12:29:03 +0200 Subject: Handle `Self::Type` in trait definitions when referring to own associated type It was implemented for other generic parameters for the trait, but not for `Self`. --- crates/ra_hir_ty/src/tests/regression.rs | 3 +-- crates/ra_hir_ty/src/tests/traits.rs | 26 +++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 3 deletions(-) (limited to 'crates/ra_hir_ty/src/tests') diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs index 3402e0cb5..d69115a2f 100644 --- a/crates/ra_hir_ty/src/tests/regression.rs +++ b/crates/ra_hir_ty/src/tests/regression.rs @@ -451,8 +451,7 @@ pub mod str { "#, ); - // should be Option, but currently not because of Chalk ambiguity problem - assert_eq!("(Option<{unknown}>, Option<{unknown}>)", super::type_at_pos(&db, pos)); + assert_eq!("(Option, Option)", super::type_at_pos(&db, pos)); } #[test] diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 22ae6ca90..d088bf309 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -1803,7 +1803,7 @@ fn test() where T::Item: Trait2, T: Trait, U: Trait<()> { } #[test] -fn unselected_projection_on_trait_self() { +fn unselected_projection_on_impl_self() { assert_snapshot!(infer( r#" //- /main.rs @@ -1843,6 +1843,30 @@ impl Trait for S2 { "###); } +#[test] +fn unselected_projection_on_trait_self() { + let t = type_at( + r#" +//- /main.rs +trait Trait { + type Item; + + fn f(&self) -> Self::Item { loop {} } +} + +struct S; +impl Trait for S { + type Item = u32; +} + +fn test() { + S.f()<|>; +} +"#, + ); + assert_eq!(t, "u32"); +} + #[test] fn trait_impl_self_ty() { let t = type_at( -- cgit v1.2.3 From 14570df015d1641d1e382c9898e7c6d981b99e97 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 10 Apr 2020 17:44:43 +0200 Subject: Switch Chalk to recursive solver + various fixes related to that. --- crates/ra_hir_ty/src/tests/traits.rs | 50 +++++++++++++++--------------------- 1 file changed, 21 insertions(+), 29 deletions(-) (limited to 'crates/ra_hir_ty/src/tests') diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index b3a2fc439..0e4fd7bfd 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -349,7 +349,6 @@ trait Trait: SuperTrait { #[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 { @@ -368,12 +367,12 @@ fn test() { [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} + [156; 157) 'y': Iterable::Item + [183; 192) 'no_matter': Iterable::Item + [202; 203) 'z': Iterable::Item + [215; 224) 'no_matter': Iterable::Item + [234; 235) 'a': Iterable::Item + [249; 258) 'no_matter': Iterable::Item "### ); } @@ -433,8 +432,8 @@ fn test>() { "#), @r###" [67; 100) '{ ...own; }': () - [77; 78) 'y': {unknown} - [90; 97) 'unknown': {unknown} + [77; 78) 'y': u32 + [90; 97) 'unknown': u32 "### ); } @@ -549,7 +548,7 @@ impl std::ops::Index for Bar { fn test() { let a = Bar; - let b = a[1]; + let b = a[1u32]; b<|>; } @@ -574,7 +573,7 @@ fn infer_ops_index_autoderef() { //- /main.rs crate:main deps:std fn test() { let a = &[1u32, 2, 3]; - let b = a[1]; + let b = a[1u32]; b<|>; } @@ -916,11 +915,7 @@ fn test(t: T) { } "#, ); - // FIXME here Chalk doesn't normalize the type to a placeholder. I think we - // need to add a rule like Normalize(::Out -> ApplyL::Out) - // 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}"); + assert_eq!(t, "ApplyL::Out"); } #[test] @@ -1329,16 +1324,16 @@ fn test>(x: T, y: impl Trait) { [263; 264) 'y': impl Trait [290; 398) '{ ...r>); }': () [296; 299) 'get': fn get(T) -> ::Type - [296; 302) 'get(x)': {unknown} + [296; 302) 'get(x)': u32 [300; 301) 'x': T - [308; 312) 'get2': fn get2<{unknown}, T>(T) -> {unknown} - [308; 315) 'get2(x)': {unknown} + [308; 312) 'get2': fn get2(T) -> u32 + [308; 315) 'get2(x)': u32 [313; 314) 'x': T [321; 324) 'get': fn get>(impl Trait) -> as Trait>::Type - [321; 327) 'get(y)': {unknown} + [321; 327) 'get(y)': i64 [325; 326) 'y': impl Trait - [333; 337) 'get2': fn get2<{unknown}, impl Trait>(impl Trait) -> {unknown} - [333; 340) 'get2(y)': {unknown} + [333; 337) 'get2': fn get2>(impl Trait) -> i64 + [333; 340) 'get2(y)': i64 [338; 339) 'y': impl Trait [346; 349) 'get': fn get>(S) -> as Trait>::Type [346; 357) 'get(set(S))': u64 @@ -1402,7 +1397,6 @@ mod iter { #[test] fn projection_eq_within_chalk() { - // std::env::set_var("CHALK_DEBUG", "1"); assert_snapshot!( infer(r#" trait Trait1 { @@ -1422,7 +1416,7 @@ fn test>(x: T) { [164; 165) 'x': T [170; 186) '{ ...o(); }': () [176; 177) 'x': T - [176; 183) 'x.foo()': {unknown} + [176; 183) 'x.foo()': u32 "### ); } @@ -1578,7 +1572,7 @@ fn test u128>(f: F) { [150; 151) 'f': F [156; 184) '{ ...2)); }': () [162; 163) 'f': F - [162; 181) 'f.call...1, 2))': {unknown} + [162; 181) 'f.call...1, 2))': u128 [174; 180) '(1, 2)': (u32, u64) [175; 176) '1': u32 [178; 179) '2': u64 @@ -1829,7 +1823,7 @@ impl Trait for S2 { "#, ), @r###" [54; 58) 'self': &Self - [60; 61) 'x': {unknown} + [60; 61) 'x': Trait::Item [140; 144) 'self': &S [146; 147) 'x': u32 [161; 175) '{ let y = x; }': () @@ -1989,9 +1983,7 @@ fn test>>() { } "#, ); - // assert_eq!(t, "u32"); - // doesn't currently work, Chalk #234 - assert_eq!(t, "{unknown}"); + assert_eq!(t, "u32"); } #[test] -- cgit v1.2.3 From 39fe3a6486a2cbdf00bce8bd4861a900e0ff5811 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Mon, 13 Apr 2020 11:55:34 +0200 Subject: Test for non-working proc macro server assoc types --- crates/ra_hir_ty/src/tests/traits.rs | 68 ++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) (limited to 'crates/ra_hir_ty/src/tests') diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 0e4fd7bfd..0a889f805 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -1986,6 +1986,74 @@ fn test>>() { assert_eq!(t, "u32"); } +#[test] +fn proc_macro_server_types() { + assert_snapshot!( + infer_with_mismatches(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 + Clone;); + (type Group) => + (type Group: 'static + Clone;); + ($($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(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?);)* + })* + + pub trait Server: Types $(+ $name)* {} + impl Server for S {} + } +} +with_api!(Self, self_, declare_server_traits); +struct Group {} +struct TokenStream {} +struct Rustc; +impl Types for Rustc { + type TokenStream = TokenStream; + type Group = Group; +} +fn make() -> T { loop {} } +impl TokenStream for Rustc { + fn new() -> Self::TokenStream { + let group: Self::Group = make(); + make() + } +} +"#, true), + @r###" + [1115; 1126) '{ loop {} }': T + [1117; 1124) 'loop {}': ! + [1122; 1124) '{}': () + [1190; 1253) '{ ... }': {unknown} + [1204; 1209) 'group': {unknown} + [1225; 1229) 'make': fn make<{unknown}>() -> {unknown} + [1225; 1231) 'make()': {unknown} + [1241; 1245) 'make': fn make<{unknown}>() -> {unknown} + [1241; 1247) 'make()': {unknown} + "### + ); +} + #[test] fn unify_impl_trait() { assert_snapshot!( -- cgit v1.2.3