diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-08-12 20:43:57 +0100 |
---|---|---|
committer | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-08-12 20:43:57 +0100 |
commit | 2c65a059840dd2092a00e90337a8221cd832c456 (patch) | |
tree | fa1f8c46158271eb859928ed9da3eb389f861c09 /crates/ra_hir/src/ty/tests.rs | |
parent | 0cf48e48d75d267bfa38ff1319e7f7c0468fb53f (diff) | |
parent | 5af9691dc9132db61b50c4e90cdeda6fea0c5dd9 (diff) |
Merge #1677
1677: Associated types r=flodiebold a=flodiebold
This implements basic support for (fully qualified) associated type projections:
- handle fully qualified paths like `<T as Trait>::AssocType` (basically desugaring to something like `Trait<Self=T>::AssocType`)
- lower these to a new `Ty::Projection` enum variant
- also introduce `Ty::UnselectedProjection` for cases like `T::AssocType` where the trait from which the type comes isn't specified, but these aren't handled further so far
- in inference, normalize these projections using Chalk: basically, when encountering a type e.g. from a type annotation or signature, we replace these `Ty::Projection`s by type variables and add obligations to normalize the associated type
Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/ty/tests.rs')
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 101 |
1 files changed, 95 insertions, 6 deletions
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index d5f7a4d25..28727bb18 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -2508,15 +2508,55 @@ struct S; | |||
2508 | impl Iterable for S { type Item = u32; } | 2508 | impl Iterable for S { type Item = u32; } |
2509 | fn test<T: Iterable>() { | 2509 | fn test<T: Iterable>() { |
2510 | let x: <S as Iterable>::Item = 1; | 2510 | let x: <S as Iterable>::Item = 1; |
2511 | let y: T::Item = no_matter; | 2511 | let y: <T as Iterable>::Item = no_matter; |
2512 | let z: T::Item = no_matter; | ||
2512 | } | 2513 | } |
2513 | "#), | 2514 | "#), |
2514 | @r###" | 2515 | @r###" |
2515 | [108; 181) '{ ...ter; }': () | 2516 | ⋮ |
2516 | [118; 119) 'x': i32 | 2517 | ⋮[108; 227) '{ ...ter; }': () |
2517 | [145; 146) '1': i32 | 2518 | ⋮[118; 119) 'x': u32 |
2518 | [156; 157) 'y': {unknown} | 2519 | ⋮[145; 146) '1': u32 |
2519 | [169; 178) 'no_matter': {unknown}"### | 2520 | ⋮[156; 157) 'y': {unknown} |
2521 | ⋮[183; 192) 'no_matter': {unknown} | ||
2522 | ⋮[202; 203) 'z': {unknown} | ||
2523 | ⋮[215; 224) 'no_matter': {unknown} | ||
2524 | "### | ||
2525 | ); | ||
2526 | } | ||
2527 | |||
2528 | #[test] | ||
2529 | fn infer_return_associated_type() { | ||
2530 | assert_snapshot_matches!( | ||
2531 | infer(r#" | ||
2532 | trait Iterable { | ||
2533 | type Item; | ||
2534 | } | ||
2535 | struct S; | ||
2536 | impl Iterable for S { type Item = u32; } | ||
2537 | fn foo1<T: Iterable>(t: T) -> T::Item {} | ||
2538 | fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item {} | ||
2539 | fn test() { | ||
2540 | let x = foo1(S); | ||
2541 | let y = foo2(S); | ||
2542 | } | ||
2543 | "#), | ||
2544 | @r###" | ||
2545 | ⋮ | ||
2546 | ⋮[106; 107) 't': T | ||
2547 | ⋮[123; 125) '{}': () | ||
2548 | ⋮[147; 148) 't': T | ||
2549 | ⋮[178; 180) '{}': () | ||
2550 | ⋮[191; 236) '{ ...(S); }': () | ||
2551 | ⋮[201; 202) 'x': {unknown} | ||
2552 | ⋮[205; 209) 'foo1': fn foo1<S>(T) -> {unknown} | ||
2553 | ⋮[205; 212) 'foo1(S)': {unknown} | ||
2554 | ⋮[210; 211) 'S': S | ||
2555 | ⋮[222; 223) 'y': u32 | ||
2556 | ⋮[226; 230) 'foo2': fn foo2<S>(T) -> <T as Iterable>::Item | ||
2557 | ⋮[226; 233) 'foo2(S)': u32 | ||
2558 | ⋮[231; 232) 'S': S | ||
2559 | "### | ||
2520 | ); | 2560 | ); |
2521 | } | 2561 | } |
2522 | 2562 | ||
@@ -3141,6 +3181,55 @@ fn test<T: Trait>(t: T) { (*t)<|>; } | |||
3141 | assert_eq!(t, "i128"); | 3181 | assert_eq!(t, "i128"); |
3142 | } | 3182 | } |
3143 | 3183 | ||
3184 | #[test] | ||
3185 | fn associated_type_placeholder() { | ||
3186 | let t = type_at( | ||
3187 | r#" | ||
3188 | //- /main.rs | ||
3189 | pub trait ApplyL { | ||
3190 | type Out; | ||
3191 | } | ||
3192 | |||
3193 | pub struct RefMutL<T>; | ||
3194 | |||
3195 | impl<T> ApplyL for RefMutL<T> { | ||
3196 | type Out = <T as ApplyL>::Out; | ||
3197 | } | ||
3198 | |||
3199 | fn test<T: ApplyL>() { | ||
3200 | let y: <RefMutL<T> as ApplyL>::Out = no_matter; | ||
3201 | y<|>; | ||
3202 | } | ||
3203 | "#, | ||
3204 | ); | ||
3205 | // 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]. | ||
3206 | // FIXME: fix type parameter names going missing when going through Chalk | ||
3207 | assert_eq!(t, "ApplyL::Out<[missing name]>"); | ||
3208 | } | ||
3209 | |||
3210 | #[test] | ||
3211 | fn associated_type_placeholder_2() { | ||
3212 | let t = type_at( | ||
3213 | r#" | ||
3214 | //- /main.rs | ||
3215 | pub trait ApplyL { | ||
3216 | type Out; | ||
3217 | } | ||
3218 | fn foo<T: ApplyL>(t: T) -> <T as ApplyL>::Out; | ||
3219 | |||
3220 | fn test<T: ApplyL>(t: T) { | ||
3221 | let y = foo(t); | ||
3222 | y<|>; | ||
3223 | } | ||
3224 | "#, | ||
3225 | ); | ||
3226 | // FIXME here Chalk doesn't normalize the type to a placeholder. I think we | ||
3227 | // need to add a rule like Normalize(<T as ApplyL>::Out -> ApplyL::Out<T>) | ||
3228 | // to the trait env ourselves here; probably Chalk can't do this by itself. | ||
3229 | // assert_eq!(t, "ApplyL::Out<[missing name]>"); | ||
3230 | assert_eq!(t, "{unknown}"); | ||
3231 | } | ||
3232 | |||
3144 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { | 3233 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { |
3145 | let file = db.parse(pos.file_id).ok().unwrap(); | 3234 | let file = db.parse(pos.file_id).ok().unwrap(); |
3146 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); | 3235 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); |