From 4ae4d9c311084e3092eb4c2d35e98f6c2c70315b Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Wed, 4 Sep 2019 22:32:02 +0200 Subject: Add some more tests --- crates/ra_hir/src/ty/tests.rs | 205 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) (limited to 'crates/ra_hir/src/ty') diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index d92d4659b..cb5540cb6 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -3643,6 +3643,211 @@ fn test>(x: T) { "### ); } + +#[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(x: T) { + x.foo()<|>; +} +"#, + ); + // FIXME should be u32 + assert_eq!(t, "{unknown}"); +} + +#[test] +fn super_trait_method_resolution() { + assert_snapshot!( + infer(r#" +mod foo { + trait SuperTrait { + fn foo(&self) -> u32 {} + } +} +trait Trait1: SuperTrait {} +trait Trait2 where Self: SuperTrait {} + +fn test(x: T, y: U) { + x.foo(); + y.foo(); +} +"#), + @r###" + [50; 54) 'self': &Self + [63; 65) '{}': () + [172; 173) 'x': T + [178; 179) 'y': U + [184; 213) '{ ...o(); }': () + [190; 191) 'x': T + [190; 197) 'x.foo()': {unknown} + [203; 204) 'y': U + [203; 210) 'y.foo()': {unknown} + "### + ); +} + +#[test] +fn super_trait_assoc_type_bounds() { + assert_snapshot!( + infer(r#" +trait SuperTrait { type Type; } +trait Trait where Self: SuperTrait {} + +fn get2>(t: T) -> U {} +fn set>(t: T) -> T {t} + +struct S; +impl SuperTrait for S { type Type = T; } +impl Trait for S {} + +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<{unknown}, S<{unknown}>>(T) -> U + [265; 277) 'get2(set(S))': {unknown} + [270; 273) 'set': fn set>(T) -> T + [270; 276) 'set(S)': S<{unknown}> + [274; 275) 'S': S<{unknown}> + "### + ); +} + +#[test] +fn fn_trait() { + assert_snapshot!( + infer(r#" +trait FnOnce { + type Output; + + fn call_once(self, args: Args) -> Self::Output; +} + +fn test u128>(f: F) { + f.call_once((1, 2)); +} +"#), + @r###" + [57; 61) 'self': Self + [63; 67) 'args': Args + [132; 133) 'f': F + [138; 166) '{ ...2)); }': () + [144; 145) 'f': F + [144; 163) 'f.call...1, 2))': {unknown} + [156; 162) '(1, 2)': (i32, i32) + [157; 158) '1': i32 + [160; 161) '2': i32 + "### + ); +} + +#[test] +fn closure_1() { + assert_snapshot!( + infer(r#" +trait FnOnce { + type Output; +} + +enum Option { Some(T), None } +impl Option { + fn map U>(self, f: F) -> U {} +} + +fn test() { + let x = Option::Some(1i32); + x.map(|v| v + 1); + x.map(|_v| 1u64); + let y: Option = x.map(|_v| 1); +} +"#), + @r###" + [128; 132) 'self': Option + [134; 135) 'f': F + [145; 147) '{}': () + [161; 280) '{ ... 1); }': () + [171; 172) 'x': Option + [175; 187) 'Option::Some': Some(T) -> Option + [175; 193) 'Option...(1i32)': Option + [188; 192) '1i32': i32 + [199; 200) 'x': Option + [199; 215) 'x.map(...v + 1)': {unknown} + [205; 214) '|v| v + 1': {unknown} + [206; 207) 'v': {unknown} + [209; 210) 'v': {unknown} + [209; 214) 'v + 1': i32 + [213; 214) '1': i32 + [221; 222) 'x': Option + [221; 237) 'x.map(... 1u64)': {unknown} + [227; 236) '|_v| 1u64': {unknown} + [228; 230) '_v': {unknown} + [232; 236) '1u64': u64 + [247; 248) 'y': Option + [264; 265) 'x': Option + [264; 277) 'x.map(|_v| 1)': Option + [270; 276) '|_v| 1': {unknown} + [271; 273) '_v': {unknown} + [275; 276) '1': i32 + "### + ); +} + +#[test] +fn closure_2() { + assert_snapshot!( + infer(r#" +trait FnOnce { + type Output; +} + +fn test 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': {unknown} + [103; 112) '|v| v + 1': {unknown} + [104; 105) 'v': {unknown} + [107; 108) 'v': {unknown} + [107; 112) 'v + 1': i32 + [111; 112) '1': i32 + [118; 119) 'g': {unknown} + [118; 125) 'g(1u64)': {unknown} + [120; 124) '1u64': u64 + [135; 136) 'h': {unknown} + [139; 152) '|v| 1u128 + v': {unknown} + [140; 141) 'v': u128 + [143; 148) '1u128': u128 + [143; 152) '1u128 + v': u128 + [151; 152) 'v': u128 + "### + ); +} + 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 60bdb66ef23f78d8c73afa1897a4542e7e722ed2 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 7 Sep 2019 14:31:43 +0200 Subject: Lower bounds on trait definition, and resolve assoc types from super traits --- crates/ra_hir/src/ty/autoderef.rs | 4 ++-- crates/ra_hir/src/ty/infer.rs | 6 +++--- crates/ra_hir/src/ty/lower.rs | 27 +++++++++++++++------------ crates/ra_hir/src/ty/tests.rs | 10 +++++----- crates/ra_hir/src/ty/traits/chalk.rs | 2 +- 5 files changed, 26 insertions(+), 23 deletions(-) (limited to 'crates/ra_hir/src/ty') diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs index 08f52a53b..caa17f64e 100644 --- a/crates/ra_hir/src/ty/autoderef.rs +++ b/crates/ra_hir/src/ty/autoderef.rs @@ -8,7 +8,7 @@ use std::iter::successors; use log::{info, warn}; use super::{traits::Solution, Canonical, Ty, TypeWalk}; -use crate::{HasGenericParams, HirDatabase, Name, Resolver}; +use crate::{name, HasGenericParams, HirDatabase, Resolver}; const AUTODEREF_RECURSION_LIMIT: usize = 10; @@ -42,7 +42,7 @@ fn deref_by_trait( crate::lang_item::LangItemTarget::Trait(t) => t, _ => return None, }; - let target = deref_trait.associated_type_by_name(db, Name::target())?; + let target = deref_trait.associated_type_by_name(db, &name::TARGET)?; if target.generic_params(db).count_params_including_parent() != 1 { // the Target type + Deref trait should only have one generic parameter, diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index ec3b7ffef..0e6ebd365 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -1453,7 +1453,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { match self.resolver.resolve_path_segments(self.db, &into_iter_path).into_fully_resolved() { PerNs { types: Some(Def(Trait(trait_))), .. } => { - Some(trait_.associated_type_by_name(self.db, name::ITEM)?) + Some(trait_.associated_type_by_name(self.db, &name::ITEM)?) } _ => None, } @@ -1471,7 +1471,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { match self.resolver.resolve_path_segments(self.db, &ops_try_path).into_fully_resolved() { PerNs { types: Some(Def(Trait(trait_))), .. } => { - Some(trait_.associated_type_by_name(self.db, name::OK)?) + Some(trait_.associated_type_by_name(self.db, &name::OK)?) } _ => None, } @@ -1493,7 +1493,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { .into_fully_resolved() { PerNs { types: Some(Def(Trait(trait_))), .. } => { - Some(trait_.associated_type_by_name(self.db, name::OUTPUT)?) + Some(trait_.associated_type_by_name(self.db, &name::OUTPUT)?) } _ => None, } diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index f6f0137cf..480bae740 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs @@ -132,14 +132,16 @@ impl Ty { if let Some(remaining_index) = remaining_index { if remaining_index == path.segments.len() - 1 { let segment = &path.segments[remaining_index]; - let associated_ty = - match trait_ref.trait_.associated_type_by_name(db, segment.name.clone()) { - Some(t) => t, - None => { - // associated type not found - return Ty::Unknown; - } - }; + let associated_ty = match trait_ref + .trait_ + .associated_type_by_name_including_super_traits(db, &segment.name) + { + Some(t) => t, + None => { + // associated type not found + return Ty::Unknown; + } + }; // FIXME handle type parameters on the segment Ty::Projection(ProjectionTy { associated_ty, parameters: trait_ref.substs }) } else { @@ -387,10 +389,11 @@ fn assoc_type_bindings_from_type_bound<'a>( .flat_map(|segment| segment.args_and_bindings.iter()) .flat_map(|args_and_bindings| args_and_bindings.bindings.iter()) .map(move |(name, type_ref)| { - let associated_ty = match trait_ref.trait_.associated_type_by_name(db, name.clone()) { - None => return GenericPredicate::Error, - Some(t) => t, - }; + let associated_ty = + match trait_ref.trait_.associated_type_by_name_including_super_traits(db, &name) { + None => return GenericPredicate::Error, + Some(t) => t, + }; let projection_ty = ProjectionTy { associated_ty, parameters: trait_ref.substs.clone() }; let ty = Ty::from_hir(db, resolver, type_ref); diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index cb5540cb6..17c4e3556 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -3720,11 +3720,11 @@ fn test() { [157; 160) '{t}': T [158; 159) 't': T [259; 280) '{ ...S)); }': () - [265; 269) 'get2': fn get2<{unknown}, S<{unknown}>>(T) -> U - [265; 277) 'get2(set(S))': {unknown} - [270; 273) 'set': fn set>(T) -> T - [270; 276) 'set(S)': S<{unknown}> - [274; 275) 'S': S<{unknown}> + [265; 269) 'get2': fn get2>(T) -> U + [265; 277) 'get2(set(S))': u64 + [270; 273) 'set': fn set>(T) -> T + [270; 276) 'set(S)': S + [274; 275) 'S': S "### ); } diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index c201c5e50..cfe0cab16 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs @@ -636,7 +636,7 @@ pub(crate) fn impl_datum_query( _ => None, }) .filter_map(|t| { - let assoc_ty = trait_.associated_type_by_name(db, t.name(db))?; + let assoc_ty = trait_.associated_type_by_name(db, &t.name(db))?; let ty = db.type_for_def(t.into(), crate::Namespace::Types).subst(&bound_vars); Some(chalk_rust_ir::AssociatedTyValue { impl_id, -- cgit v1.2.3 From d21cdf3c998bb24e48e81a7e6909df2146ce097c Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 7 Sep 2019 15:13:05 +0200 Subject: Lower `Fn(X, Y) -> Z` paths --- crates/ra_hir/src/ty/tests.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'crates/ra_hir/src/ty') diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 17c4e3556..c414e6a95 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -3736,7 +3736,7 @@ fn fn_trait() { trait FnOnce { type Output; - fn call_once(self, args: Args) -> Self::Output; + fn call_once(self, args: Args) -> >::Output; } fn test u128>(f: F) { @@ -3746,13 +3746,13 @@ fn test u128>(f: F) { @r###" [57; 61) 'self': Self [63; 67) 'args': Args - [132; 133) 'f': F - [138; 166) '{ ...2)); }': () - [144; 145) 'f': F - [144; 163) 'f.call...1, 2))': {unknown} - [156; 162) '(1, 2)': (i32, i32) - [157; 158) '1': i32 - [160; 161) '2': i32 + [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 "### ); } -- cgit v1.2.3 From a1776b27c7d7c266d751360b80cc573b1520ef65 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 7 Sep 2019 16:24:26 +0200 Subject: Use traits from where clauses for method resolution E.g. if we have `T: some::Trait`, we can call methods from that trait without it needing to be in scope. --- crates/ra_hir/src/ty/method_resolution.rs | 8 +++++++- crates/ra_hir/src/ty/tests.rs | 21 ++++++++++----------- crates/ra_hir/src/ty/traits.rs | 15 +++++++++++++++ 3 files changed, 32 insertions(+), 12 deletions(-) (limited to 'crates/ra_hir/src/ty') diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 9873a0440..cf787bdaa 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs @@ -212,7 +212,13 @@ fn iterate_trait_method_candidates( // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that) let env = lower::trait_env(db, resolver); // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope - let traits = ty.value.inherent_trait().into_iter().chain(resolver.traits_in_scope(db)); + let inherent_trait = ty.value.inherent_trait().into_iter(); + // if we have `T: Trait` in the param env, the trait doesn't need to be in scope + let traits_from_env = env + .trait_predicates_for_self_ty(&ty.value) + .map(|tr| tr.trait_) + .flat_map(|t| t.all_super_traits(db)); + let traits = inherent_trait.chain(traits_from_env).chain(resolver.traits_in_scope(db)); 'traits: for t in traits { let data = t.trait_data(db); diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index c414e6a95..127c69f8a 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -3660,8 +3660,7 @@ fn test(x: T) { } "#, ); - // FIXME should be u32 - assert_eq!(t, "{unknown}"); + assert_eq!(t, "u32"); } #[test] @@ -3673,8 +3672,8 @@ mod foo { fn foo(&self) -> u32 {} } } -trait Trait1: SuperTrait {} -trait Trait2 where Self: SuperTrait {} +trait Trait1: foo::SuperTrait {} +trait Trait2 where Self: foo::SuperTrait {} fn test(x: T, y: U) { x.foo(); @@ -3684,13 +3683,13 @@ fn test(x: T, y: U) { @r###" [50; 54) 'self': &Self [63; 65) '{}': () - [172; 173) 'x': T - [178; 179) 'y': U - [184; 213) '{ ...o(); }': () - [190; 191) 'x': T - [190; 197) 'x.foo()': {unknown} - [203; 204) 'y': U - [203; 210) 'y.foo()': {unknown} + [182; 183) 'x': T + [188; 189) 'y': U + [194; 223) '{ ...o(); }': () + [200; 201) 'x': T + [200; 207) 'x.foo()': {unknown} + [213; 214) 'y': U + [213; 220) 'y.foo()': {unknown} "### ); } diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs index 6e0271a96..c0c132809 100644 --- a/crates/ra_hir/src/ty/traits.rs +++ b/crates/ra_hir/src/ty/traits.rs @@ -96,6 +96,21 @@ pub struct TraitEnvironment { pub predicates: Vec, } +impl TraitEnvironment { + /// Returns trait refs with the given self type which are supposed to hold + /// in this trait env. E.g. if we are in `foo()`, this will + /// find that `T: SomeTrait` if we call it for `T`. + pub(crate) fn trait_predicates_for_self_ty<'a>( + &'a self, + ty: &'a Ty, + ) -> impl Iterator + 'a { + self.predicates.iter().filter_map(move |pred| match pred { + GenericPredicate::Implemented(tr) if tr.self_ty() == ty => Some(tr), + _ => None, + }) + } +} + /// Something (usually a goal), along with an environment. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct InEnvironment { -- cgit v1.2.3 From 9db34eec209c740ed919afb288f75daa755cd268 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 7 Sep 2019 16:30:37 +0200 Subject: Fix Chalk environments The clauses need to be wrapped in `FromEnv` clauses for elaboration (i.e. things like inferring `T: Clone` from `T: Copy`) to work correctly. --- crates/ra_hir/src/ty/tests.rs | 4 ++-- crates/ra_hir/src/ty/traits/chalk.rs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'crates/ra_hir/src/ty') diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 127c69f8a..3f86a5c80 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -3687,9 +3687,9 @@ fn test(x: T, y: U) { [188; 189) 'y': U [194; 223) '{ ...o(); }': () [200; 201) 'x': T - [200; 207) 'x.foo()': {unknown} + [200; 207) 'x.foo()': u32 [213; 214) 'y': U - [213; 220) 'y.foo()': {unknown} + [213; 220) 'y.foo()': u32 "### ); } diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index cfe0cab16..8a127efa1 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs @@ -314,7 +314,8 @@ impl ToChalk for Arc { // for env, we just ignore errors continue; } - clauses.push(pred.clone().to_chalk(db).cast()); + let program_clause: chalk_ir::ProgramClause = pred.clone().to_chalk(db).cast(); + clauses.push(program_clause.into_from_env_clause()); } chalk_ir::Environment::new().add_clauses(clauses) } -- cgit v1.2.3 From 8fb3cab76c60fbff5ae6f5984ac07b09b42b742c Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 7 Sep 2019 16:39:05 +0200 Subject: Fix crash for super trait cycles --- crates/ra_hir/src/ty/tests.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'crates/ra_hir/src/ty') diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 3f86a5c80..c4bddde85 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -3694,6 +3694,27 @@ fn test(x: T, y: U) { ); } +#[test] +fn super_trait_cycle() { + // This just needs to not crash + assert_snapshot!( + infer(r#" +trait A: B {} +trait B: A {} + +fn test(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!( -- cgit v1.2.3