From c417b98f02004a10819111903882482b39e50d17 Mon Sep 17 00:00:00 2001 From: Evgenii P Date: Sat, 3 Aug 2019 01:15:43 +0700 Subject: Implement completion for the .await syntax --- crates/ra_hir/src/source_binder.rs | 37 +++++++++++ crates/ra_hir/src/ty/method_resolution.rs | 16 ++++- crates/ra_ide_api/src/completion/complete_dot.rs | 80 +++++++++++++++++++++--- 3 files changed, 122 insertions(+), 11 deletions(-) diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index c2c6921cb..8496b143a 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -23,6 +23,7 @@ use crate::{ scope::{ExprScopes, ScopeId}, BodySourceMap, }, + ty::method_resolution::implements_trait, ids::LocationCtx, AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HirDatabase, HirFileId, MacroDef, Module, Name, Path, PerNs, Resolver, Static, Struct, Trait, Ty, @@ -409,6 +410,42 @@ impl SourceAnalyzer { crate::ty::autoderef(db, &self.resolver, canonical).map(|canonical| canonical.value) } + /// Checks that particular type `ty` implements `std::future::Future` trait. + /// This function is used in `.await` syntax completion. + pub fn impls_future(&self, db: &impl HirDatabase, ty: Ty) -> bool { + // Search for std::future::Future trait in scope + let future_trait = self.resolver.traits_in_scope(db) + .into_iter() + .filter(|t| { + let std = t.module(db).parent(db) + .and_then(|m| m + .name(db) + .and_then(|n| Some(n.to_string() == "std"))) + .unwrap_or(false); + + let future = t.module(db).name(db) + .and_then(|n| Some(n.to_string() == "future")) + .unwrap_or(false); + + let future_trait = t.name(db) + .and_then(|n| Some(n.to_string() == "Future")) + .unwrap_or(false); + + std && future && future_trait + }) + .nth(0); + + if let Some(trait_) = future_trait { + let krate = self.resolver.krate(); + if let Some(krate) = krate { + let canonical_ty = crate::ty::Canonical { value: ty, num_vars: 0 }; + return implements_trait(&canonical_ty, db, &self.resolver, krate, trait_); + } + } + + false + } + #[cfg(test)] pub(crate) fn body_source_map(&self) -> Arc { self.body_source_map.clone().unwrap() diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index d421bf9ef..2e2f88138 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs @@ -15,7 +15,7 @@ use crate::{ resolve::Resolver, traits::TraitItem, ty::primitive::{FloatBitness, UncertainFloatTy, UncertainIntTy}, - ty::{Ty, TypeCtor}, + ty::{Ty, TypeCtor, traits::Solution}, Crate, Function, HirDatabase, Module, Name, Trait, }; @@ -255,6 +255,20 @@ fn iterate_inherent_methods( None } +pub(crate) fn implements_trait(ty: &Canonical, db: &impl HirDatabase, resolver: &Resolver, krate: Crate, trait_: Trait) -> bool { + let env = lower::trait_env(db, resolver); + let goal = generic_implements_goal(db, env.clone(), trait_, ty.clone()); + let solution = db.trait_solve(krate, goal); + + if let Some(solution) = solution { + if let Solution::Unique(_) = solution { + return true + } + } + + false +} + impl Ty { // This would be nicer if it just returned an iterator, but that runs into // lifetime problems, because we need to borrow temp `CrateImplBlocks`. diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs index 536ba36df..b6579be63 100644 --- a/crates/ra_ide_api/src/completion/complete_dot.rs +++ b/crates/ra_ide_api/src/completion/complete_dot.rs @@ -1,19 +1,49 @@ use hir::{AdtDef, Ty, TypeCtor}; -use crate::completion::{CompletionContext, Completions}; +use crate::{completion::{ + completion_context::CompletionContext, + completion_item::Completions, +}, CompletionItem}; +use ra_syntax::ast::AstNode; +use ra_text_edit::TextEditBuilder; use rustc_hash::FxHashSet; +use crate::completion::completion_item::{Builder, CompletionKind}; +use ra_syntax::TextRange; -/// Complete dot accesses, i.e. fields or methods (currently only fields). +/// Applies postfix edition but with CompletionKind::Reference +fn postfix_reference(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder { + let edit = { + let receiver_range = + ctx.dot_receiver.as_ref().expect("no receiver available").syntax().text_range(); + let delete_range = TextRange::from_to(receiver_range.start(), ctx.source_range().end()); + let mut builder = TextEditBuilder::default(); + builder.replace(delete_range, snippet.to_string()); + builder.finish() + }; + CompletionItem::new(CompletionKind::Reference, ctx.source_range(), label) + .detail(detail) + .snippet_edit(edit) +} + +/// Complete dot accesses, i.e. fields or methods (and .await syntax). pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { - let receiver_ty = - match ctx.dot_receiver.as_ref().and_then(|it| ctx.analyzer.type_of(ctx.db, it)) { - Some(it) => it, - None => return, - }; - if !ctx.is_call { - complete_fields(acc, ctx, receiver_ty.clone()); + if let Some(dot_receiver) = &ctx.dot_receiver { + let receiver_text = dot_receiver.syntax().text().to_string(); + let receiver_ty = ctx.analyzer.type_of(ctx.db, &dot_receiver); + + if let Some(receiver_ty) = receiver_ty { + if !ctx.is_call { + complete_fields(acc, ctx, receiver_ty.clone()); + } + complete_methods(acc, ctx, receiver_ty.clone()); + + // Suggest .await syntax for types that implement std::future::Future + if ctx.analyzer.impls_future(ctx.db, receiver_ty) { + postfix_reference(ctx, ".await", "expr.await", &format!("{}.await", receiver_text)) + .add_to(acc); + } + } } - complete_methods(acc, ctx, receiver_ty); } fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) { @@ -406,4 +436,34 @@ mod tests { "### ); } + + #[test] + fn test_completion_await_impls_future() { + assert_debug_snapshot_matches!( + do_ref_completion( + r" + // Mock Future trait from stdlib + pub mod std { pub mod future { pub trait Future {} } } + + use std::future::*; + struct A {} + impl Future for A {} + + fn foo(a: A) { + a.<|> + } + "), + @r###" + ⋮[ + ⋮ CompletionItem { + ⋮ label: ".await", + ⋮ source_range: [249; 249), + ⋮ delete: [247; 249), + ⋮ insert: "a.await", + ⋮ detail: "expr.await", + ⋮ }, + ⋮] + "### + ) + } } -- cgit v1.2.3 From 30bc3b93bec06256350b66869f2885ee71c3bedd Mon Sep 17 00:00:00 2001 From: Evgenii P Date: Sat, 3 Aug 2019 01:16:20 +0700 Subject: rustfmt --- crates/ra_hir/src/source_binder.rs | 23 +++++++++++++---------- crates/ra_hir/src/ty/method_resolution.rs | 12 +++++++++--- crates/ra_ide_api/src/completion/complete_dot.rs | 12 ++++++------ 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 8496b143a..67cb19615 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -23,8 +23,8 @@ use crate::{ scope::{ExprScopes, ScopeId}, BodySourceMap, }, - ty::method_resolution::implements_trait, ids::LocationCtx, + ty::method_resolution::implements_trait, AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HirDatabase, HirFileId, MacroDef, Module, Name, Path, PerNs, Resolver, Static, Struct, Trait, Ty, }; @@ -414,22 +414,25 @@ impl SourceAnalyzer { /// This function is used in `.await` syntax completion. pub fn impls_future(&self, db: &impl HirDatabase, ty: Ty) -> bool { // Search for std::future::Future trait in scope - let future_trait = self.resolver.traits_in_scope(db) + let future_trait = self + .resolver + .traits_in_scope(db) .into_iter() .filter(|t| { - let std = t.module(db).parent(db) - .and_then(|m| m - .name(db) - .and_then(|n| Some(n.to_string() == "std"))) + let std = t + .module(db) + .parent(db) + .and_then(|m| m.name(db).and_then(|n| Some(n.to_string() == "std"))) .unwrap_or(false); - let future = t.module(db).name(db) + let future = t + .module(db) + .name(db) .and_then(|n| Some(n.to_string() == "future")) .unwrap_or(false); - let future_trait = t.name(db) - .and_then(|n| Some(n.to_string() == "Future")) - .unwrap_or(false); + let future_trait = + t.name(db).and_then(|n| Some(n.to_string() == "Future")).unwrap_or(false); std && future && future_trait }) diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 2e2f88138..8731d6ba4 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs @@ -15,7 +15,7 @@ use crate::{ resolve::Resolver, traits::TraitItem, ty::primitive::{FloatBitness, UncertainFloatTy, UncertainIntTy}, - ty::{Ty, TypeCtor, traits::Solution}, + ty::{traits::Solution, Ty, TypeCtor}, Crate, Function, HirDatabase, Module, Name, Trait, }; @@ -255,14 +255,20 @@ fn iterate_inherent_methods( None } -pub(crate) fn implements_trait(ty: &Canonical, db: &impl HirDatabase, resolver: &Resolver, krate: Crate, trait_: Trait) -> bool { +pub(crate) fn implements_trait( + ty: &Canonical, + db: &impl HirDatabase, + resolver: &Resolver, + krate: Crate, + trait_: Trait, +) -> bool { let env = lower::trait_env(db, resolver); let goal = generic_implements_goal(db, env.clone(), trait_, ty.clone()); let solution = db.trait_solve(krate, goal); if let Some(solution) = solution { if let Solution::Unique(_) = solution { - return true + return true; } } diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs index b6579be63..1dbbdb1bc 100644 --- a/crates/ra_ide_api/src/completion/complete_dot.rs +++ b/crates/ra_ide_api/src/completion/complete_dot.rs @@ -1,14 +1,14 @@ use hir::{AdtDef, Ty, TypeCtor}; -use crate::{completion::{ - completion_context::CompletionContext, - completion_item::Completions, -}, CompletionItem}; +use crate::completion::completion_item::{Builder, CompletionKind}; +use crate::{ + completion::{completion_context::CompletionContext, completion_item::Completions}, + CompletionItem, +}; use ra_syntax::ast::AstNode; +use ra_syntax::TextRange; use ra_text_edit::TextEditBuilder; use rustc_hash::FxHashSet; -use crate::completion::completion_item::{Builder, CompletionKind}; -use ra_syntax::TextRange; /// Applies postfix edition but with CompletionKind::Reference fn postfix_reference(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder { -- cgit v1.2.3 From ab7774545cb5e45064c907429417bdee8d89f4d4 Mon Sep 17 00:00:00 2001 From: Evgenii P Date: Sat, 3 Aug 2019 01:53:51 +0700 Subject: Use future lang item instead of hardcoded std::future::Future --- crates/ra_hir/src/source_binder.rs | 41 ++++++------------------ crates/ra_ide_api/src/completion/complete_dot.rs | 17 ++++++---- 2 files changed, 21 insertions(+), 37 deletions(-) diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 67cb19615..7720329e3 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -24,6 +24,7 @@ use crate::{ BodySourceMap, }, ids::LocationCtx, + lang_item::LangItemTarget, ty::method_resolution::implements_trait, AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HirDatabase, HirFileId, MacroDef, Module, Name, Path, PerNs, Resolver, Static, Struct, Trait, Ty, @@ -410,40 +411,18 @@ impl SourceAnalyzer { crate::ty::autoderef(db, &self.resolver, canonical).map(|canonical| canonical.value) } - /// Checks that particular type `ty` implements `std::future::Future` trait. + /// Checks that particular type `ty` implements `Future` trait (`future_trait` lang item). /// This function is used in `.await` syntax completion. pub fn impls_future(&self, db: &impl HirDatabase, ty: Ty) -> bool { - // Search for std::future::Future trait in scope - let future_trait = self - .resolver - .traits_in_scope(db) - .into_iter() - .filter(|t| { - let std = t - .module(db) - .parent(db) - .and_then(|m| m.name(db).and_then(|n| Some(n.to_string() == "std"))) - .unwrap_or(false); - - let future = t - .module(db) - .name(db) - .and_then(|n| Some(n.to_string() == "future")) - .unwrap_or(false); - - let future_trait = - t.name(db).and_then(|n| Some(n.to_string() == "Future")).unwrap_or(false); - - std && future && future_trait - }) - .nth(0); + let krate = self.resolver.krate(); + if let Some(krate) = krate { + let future_trait = match db.lang_item(krate, "future_trait".into()) { + Some(LangItemTarget::Trait(t)) => t, + _ => return false, + }; - if let Some(trait_) = future_trait { - let krate = self.resolver.krate(); - if let Some(krate) = krate { - let canonical_ty = crate::ty::Canonical { value: ty, num_vars: 0 }; - return implements_trait(&canonical_ty, db, &self.resolver, krate, trait_); - } + let canonical_ty = crate::ty::Canonical { value: ty, num_vars: 0 }; + return implements_trait(&canonical_ty, db, &self.resolver, krate, future_trait); } false diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs index 1dbbdb1bc..93e5d816d 100644 --- a/crates/ra_ide_api/src/completion/complete_dot.rs +++ b/crates/ra_ide_api/src/completion/complete_dot.rs @@ -37,7 +37,7 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { } complete_methods(acc, ctx, receiver_ty.clone()); - // Suggest .await syntax for types that implement std::future::Future + // Suggest .await syntax for types that implement Future trait if ctx.analyzer.impls_future(ctx.db, receiver_ty) { postfix_reference(ctx, ".await", "expr.await", &format!("{}.await", receiver_text)) .add_to(acc); @@ -441,9 +441,14 @@ mod tests { fn test_completion_await_impls_future() { assert_debug_snapshot_matches!( do_ref_completion( - r" + r###" // Mock Future trait from stdlib - pub mod std { pub mod future { pub trait Future {} } } + pub mod std { + pub mod future { + #[lang = "future_trait"] + pub trait Future {} + } + } use std::future::*; struct A {} @@ -452,13 +457,13 @@ mod tests { fn foo(a: A) { a.<|> } - "), + "###), @r###" ⋮[ ⋮ CompletionItem { ⋮ label: ".await", - ⋮ source_range: [249; 249), - ⋮ delete: [247; 249), + ⋮ source_range: [358; 358), + ⋮ delete: [356; 358), ⋮ insert: "a.await", ⋮ detail: "expr.await", ⋮ }, -- cgit v1.2.3 From 291bd81e74742472572c88ccf3d2cf9cf70af6b2 Mon Sep 17 00:00:00 2001 From: Evgenii P Date: Sat, 3 Aug 2019 01:56:27 +0700 Subject: Relax trait solving more for completion --- crates/ra_hir/src/ty/method_resolution.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 8731d6ba4..aa625a013 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs @@ -266,13 +266,7 @@ pub(crate) fn implements_trait( let goal = generic_implements_goal(db, env.clone(), trait_, ty.clone()); let solution = db.trait_solve(krate, goal); - if let Some(solution) = solution { - if let Solution::Unique(_) = solution { - return true; - } - } - - false + solution.is_some() } impl Ty { -- cgit v1.2.3 From 40facb559a1f12ae608439041c9b3629ea633b77 Mon Sep 17 00:00:00 2001 From: Evgenii P Date: Sat, 3 Aug 2019 02:40:59 +0700 Subject: Change postfix completion to keyword completion --- crates/ra_ide_api/src/completion/complete_dot.rs | 30 +++++++----------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs index 93e5d816d..272a38f11 100644 --- a/crates/ra_ide_api/src/completion/complete_dot.rs +++ b/crates/ra_ide_api/src/completion/complete_dot.rs @@ -10,25 +10,9 @@ use ra_syntax::TextRange; use ra_text_edit::TextEditBuilder; use rustc_hash::FxHashSet; -/// Applies postfix edition but with CompletionKind::Reference -fn postfix_reference(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder { - let edit = { - let receiver_range = - ctx.dot_receiver.as_ref().expect("no receiver available").syntax().text_range(); - let delete_range = TextRange::from_to(receiver_range.start(), ctx.source_range().end()); - let mut builder = TextEditBuilder::default(); - builder.replace(delete_range, snippet.to_string()); - builder.finish() - }; - CompletionItem::new(CompletionKind::Reference, ctx.source_range(), label) - .detail(detail) - .snippet_edit(edit) -} - /// Complete dot accesses, i.e. fields or methods (and .await syntax). pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { if let Some(dot_receiver) = &ctx.dot_receiver { - let receiver_text = dot_receiver.syntax().text().to_string(); let receiver_ty = ctx.analyzer.type_of(ctx.db, &dot_receiver); if let Some(receiver_ty) = receiver_ty { @@ -39,7 +23,9 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { // Suggest .await syntax for types that implement Future trait if ctx.analyzer.impls_future(ctx.db, receiver_ty) { - postfix_reference(ctx, ".await", "expr.await", &format!("{}.await", receiver_text)) + CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await") + .detail("expr.await") + .insert_text("await") .add_to(acc); } } @@ -440,7 +426,7 @@ mod tests { #[test] fn test_completion_await_impls_future() { assert_debug_snapshot_matches!( - do_ref_completion( + do_completion( r###" // Mock Future trait from stdlib pub mod std { @@ -457,14 +443,14 @@ mod tests { fn foo(a: A) { a.<|> } - "###), + "###, CompletionKind::Keyword), @r###" ⋮[ ⋮ CompletionItem { - ⋮ label: ".await", + ⋮ label: "await", ⋮ source_range: [358; 358), - ⋮ delete: [356; 358), - ⋮ insert: "a.await", + ⋮ delete: [358; 358), + ⋮ insert: "await", ⋮ detail: "expr.await", ⋮ }, ⋮] -- cgit v1.2.3 From 858736c47758250c9a4b897300fce24e35e9a579 Mon Sep 17 00:00:00 2001 From: Evgenii P Date: Sat, 3 Aug 2019 02:46:00 +0700 Subject: do fixup: remove unused import --- crates/ra_hir/src/ty/method_resolution.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index aa625a013..88d012a74 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs @@ -15,7 +15,7 @@ use crate::{ resolve::Resolver, traits::TraitItem, ty::primitive::{FloatBitness, UncertainFloatTy, UncertainIntTy}, - ty::{traits::Solution, Ty, TypeCtor}, + ty::{Ty, TypeCtor}, Crate, Function, HirDatabase, Module, Name, Trait, }; -- cgit v1.2.3 From 957de26a1dba7134a6b3b340681880060aa90b3c Mon Sep 17 00:00:00 2001 From: Evgenii P Date: Sat, 3 Aug 2019 02:48:36 +0700 Subject: do fixup: remove unused imports in complete_dot.rs --- crates/ra_ide_api/src/completion/complete_dot.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs index 272a38f11..e8fd37bca 100644 --- a/crates/ra_ide_api/src/completion/complete_dot.rs +++ b/crates/ra_ide_api/src/completion/complete_dot.rs @@ -1,13 +1,10 @@ use hir::{AdtDef, Ty, TypeCtor}; -use crate::completion::completion_item::{Builder, CompletionKind}; +use crate::completion::completion_item::CompletionKind; use crate::{ completion::{completion_context::CompletionContext, completion_item::Completions}, CompletionItem, }; -use ra_syntax::ast::AstNode; -use ra_syntax::TextRange; -use ra_text_edit::TextEditBuilder; use rustc_hash::FxHashSet; /// Complete dot accesses, i.e. fields or methods (and .await syntax). -- cgit v1.2.3 From 6a94f203fc5e2dc6f48a592c26b48f3a98638d77 Mon Sep 17 00:00:00 2001 From: Evgenii P Date: Sat, 3 Aug 2019 17:07:20 +0700 Subject: Use std::future::Future trait from stdlib --- crates/ra_hir/src/source_binder.rs | 57 +++++++++++++++--------- crates/ra_ide_api/src/completion/complete_dot.rs | 19 ++++---- 2 files changed, 44 insertions(+), 32 deletions(-) diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 7720329e3..6a9f228b8 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -7,28 +7,29 @@ /// purely for "IDE needs". use std::sync::Arc; -use ra_db::{FileId, FilePosition}; -use ra_syntax::{ - algo::find_node_at_offset, - ast::{self, AstNode, NameOwner}, - AstPtr, - SyntaxKind::*, - SyntaxNode, SyntaxNodePtr, TextRange, TextUnit, -}; -use rustc_hash::{FxHashMap, FxHashSet}; - use crate::{ - expr, expr::{ + self, scope::{ExprScopes, ScopeId}, BodySourceMap, }, ids::LocationCtx, - lang_item::LangItemTarget, + name, + path::{PathKind, PathSegment}, ty::method_resolution::implements_trait, AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HirDatabase, HirFileId, - MacroDef, Module, Name, Path, PerNs, Resolver, Static, Struct, Trait, Ty, + MacroDef, Module, ModuleDef, Name, Path, PerNs, Resolution, Resolver, Static, Struct, Trait, + Ty, +}; +use ra_db::{FileId, FilePosition}; +use ra_syntax::{ + algo::find_node_at_offset, + ast::{self, AstNode, NameOwner}, + AstPtr, + SyntaxKind::*, + SyntaxNode, SyntaxNodePtr, TextRange, TextUnit, }; +use rustc_hash::{FxHashMap, FxHashSet}; /// Locates the module by `FileId`. Picks topmost module in the file. pub fn module_from_file_id(db: &impl HirDatabase, file_id: FileId) -> Option { @@ -411,18 +412,32 @@ impl SourceAnalyzer { crate::ty::autoderef(db, &self.resolver, canonical).map(|canonical| canonical.value) } - /// Checks that particular type `ty` implements `Future` trait (`future_trait` lang item). + /// Checks that particular type `ty` implements `std::future::Future`. /// This function is used in `.await` syntax completion. pub fn impls_future(&self, db: &impl HirDatabase, ty: Ty) -> bool { - let krate = self.resolver.krate(); - if let Some(krate) = krate { - let future_trait = match db.lang_item(krate, "future_trait".into()) { - Some(LangItemTarget::Trait(t)) => t, - _ => return false, + let std_future_path = Path { + kind: PathKind::Abs, + segments: vec![ + PathSegment { name: name::STD, args_and_bindings: None }, + PathSegment { name: name::FUTURE_MOD, args_and_bindings: None }, + PathSegment { name: name::FUTURE_TYPE, args_and_bindings: None }, + ], + }; + + let std_future_trait = + match self.resolver.resolve_path_segments(db, &std_future_path).into_fully_resolved() { + PerNs { types: Some(Resolution::Def(ModuleDef::Trait(trait_))), .. } => { + Some(trait_) + } + _ => None, }; - let canonical_ty = crate::ty::Canonical { value: ty, num_vars: 0 }; - return implements_trait(&canonical_ty, db, &self.resolver, krate, future_trait); + let krate = self.resolver.krate(); + if let Some(krate) = krate { + if let Some(trait_) = std_future_trait { + let canonical_ty = crate::ty::Canonical { value: ty, num_vars: 0 }; + return implements_trait(&canonical_ty, db, &self.resolver, krate, trait_); + } } false diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs index e8fd37bca..9a3b353a9 100644 --- a/crates/ra_ide_api/src/completion/complete_dot.rs +++ b/crates/ra_ide_api/src/completion/complete_dot.rs @@ -425,28 +425,25 @@ mod tests { assert_debug_snapshot_matches!( do_completion( r###" - // Mock Future trait from stdlib - pub mod std { - pub mod future { - #[lang = "future_trait"] - pub trait Future {} - } - } - + //- /main.rs use std::future::*; struct A {} impl Future for A {} - fn foo(a: A) { a.<|> } + + //- /std/lib.rs + pub mod future { + pub trait Future {} + } "###, CompletionKind::Keyword), @r###" ⋮[ ⋮ CompletionItem { ⋮ label: "await", - ⋮ source_range: [358; 358), - ⋮ delete: [358; 358), + ⋮ source_range: [74; 74), + ⋮ delete: [74; 74), ⋮ insert: "await", ⋮ detail: "expr.await", ⋮ }, -- cgit v1.2.3 From 4034ea9e4ebe2959327ddbf6c1d1e3103dd01f80 Mon Sep 17 00:00:00 2001 From: Evgenii P Date: Sun, 4 Aug 2019 07:56:29 +0700 Subject: source_binder.rs: fix order of imports --- crates/ra_hir/src/source_binder.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 6a9f228b8..cf9a9e108 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -7,6 +7,16 @@ /// purely for "IDE needs". use std::sync::Arc; +use ra_db::{FileId, FilePosition}; +use ra_syntax::{ + algo::find_node_at_offset, + ast::{self, AstNode, NameOwner}, + AstPtr, + SyntaxKind::*, + SyntaxNode, SyntaxNodePtr, TextRange, TextUnit, +}; +use rustc_hash::{FxHashMap, FxHashSet}; + use crate::{ expr::{ self, @@ -21,15 +31,6 @@ use crate::{ MacroDef, Module, ModuleDef, Name, Path, PerNs, Resolution, Resolver, Static, Struct, Trait, Ty, }; -use ra_db::{FileId, FilePosition}; -use ra_syntax::{ - algo::find_node_at_offset, - ast::{self, AstNode, NameOwner}, - AstPtr, - SyntaxKind::*, - SyntaxNode, SyntaxNodePtr, TextRange, TextUnit, -}; -use rustc_hash::{FxHashMap, FxHashSet}; /// Locates the module by `FileId`. Picks topmost module in the file. pub fn module_from_file_id(db: &impl HirDatabase, file_id: FileId) -> Option { -- cgit v1.2.3 From d610adfc2bfe3d4e9fec61b7a5bc02cfea503384 Mon Sep 17 00:00:00 2001 From: Evgenii P Date: Sun, 4 Aug 2019 08:03:17 +0700 Subject: Employ early return pattern more --- crates/ra_hir/src/source_binder.rs | 18 ++++++------- crates/ra_ide_api/src/completion/complete_dot.rs | 34 +++++++++++++----------- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index cf9a9e108..2c4cedd8b 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -428,20 +428,18 @@ impl SourceAnalyzer { let std_future_trait = match self.resolver.resolve_path_segments(db, &std_future_path).into_fully_resolved() { PerNs { types: Some(Resolution::Def(ModuleDef::Trait(trait_))), .. } => { - Some(trait_) + trait_ } - _ => None, + _ => return false, }; - let krate = self.resolver.krate(); - if let Some(krate) = krate { - if let Some(trait_) = std_future_trait { - let canonical_ty = crate::ty::Canonical { value: ty, num_vars: 0 }; - return implements_trait(&canonical_ty, db, &self.resolver, krate, trait_); - } - } + let krate = match self.resolver.krate() { + Some(krate) => krate, + _ => return false, + }; - false + let canonical_ty = crate::ty::Canonical { value: ty, num_vars: 0 }; + return implements_trait(&canonical_ty, db, &self.resolver, krate, std_future_trait); } #[cfg(test)] diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs index 9a3b353a9..d43ff2eec 100644 --- a/crates/ra_ide_api/src/completion/complete_dot.rs +++ b/crates/ra_ide_api/src/completion/complete_dot.rs @@ -9,23 +9,27 @@ use rustc_hash::FxHashSet; /// Complete dot accesses, i.e. fields or methods (and .await syntax). pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { - if let Some(dot_receiver) = &ctx.dot_receiver { - let receiver_ty = ctx.analyzer.type_of(ctx.db, &dot_receiver); + let dot_receiver = match &ctx.dot_receiver { + Some(expr) => expr, + _ => return, + }; - if let Some(receiver_ty) = receiver_ty { - if !ctx.is_call { - complete_fields(acc, ctx, receiver_ty.clone()); - } - complete_methods(acc, ctx, receiver_ty.clone()); + let receiver_ty = match ctx.analyzer.type_of(ctx.db, &dot_receiver) { + Some(ty) => ty, + _ => return, + }; - // Suggest .await syntax for types that implement Future trait - if ctx.analyzer.impls_future(ctx.db, receiver_ty) { - CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await") - .detail("expr.await") - .insert_text("await") - .add_to(acc); - } - } + if !ctx.is_call { + complete_fields(acc, ctx, receiver_ty.clone()); + } + complete_methods(acc, ctx, receiver_ty.clone()); + + // Suggest .await syntax for types that implement Future trait + if ctx.analyzer.impls_future(ctx.db, receiver_ty) { + CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await") + .detail("expr.await") + .insert_text("await") + .add_to(acc); } } -- cgit v1.2.3 From 8597af8ed4ebed2e86e379a5a440b37373ace76d Mon Sep 17 00:00:00 2001 From: Evgenii P Date: Sun, 4 Aug 2019 08:08:46 +0700 Subject: Idiomatic return --- crates/ra_hir/src/source_binder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 2c4cedd8b..656061086 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -439,7 +439,7 @@ impl SourceAnalyzer { }; let canonical_ty = crate::ty::Canonical { value: ty, num_vars: 0 }; - return implements_trait(&canonical_ty, db, &self.resolver, krate, std_future_trait); + implements_trait(&canonical_ty, db, &self.resolver, krate, std_future_trait) } #[cfg(test)] -- cgit v1.2.3 From 9f9c5aa65914763f5a9ff80230544fea48cbcdf1 Mon Sep 17 00:00:00 2001 From: Evgenii P Date: Sun, 4 Aug 2019 08:45:14 +0700 Subject: rustfmt --- crates/ra_hir/src/source_binder.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 656061086..e86716d74 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -427,9 +427,7 @@ impl SourceAnalyzer { let std_future_trait = match self.resolver.resolve_path_segments(db, &std_future_path).into_fully_resolved() { - PerNs { types: Some(Resolution::Def(ModuleDef::Trait(trait_))), .. } => { - trait_ - } + PerNs { types: Some(Resolution::Def(ModuleDef::Trait(trait_))), .. } => trait_, _ => return false, }; -- cgit v1.2.3