aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/source_binder.rs35
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs14
-rw-r--r--crates/ra_ide_api/src/completion/complete_dot.rs65
3 files changed, 104 insertions, 10 deletions
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index c2c6921cb..e86716d74 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -18,14 +18,18 @@ use ra_syntax::{
18use rustc_hash::{FxHashMap, FxHashSet}; 18use rustc_hash::{FxHashMap, FxHashSet};
19 19
20use crate::{ 20use crate::{
21 expr,
22 expr::{ 21 expr::{
22 self,
23 scope::{ExprScopes, ScopeId}, 23 scope::{ExprScopes, ScopeId},
24 BodySourceMap, 24 BodySourceMap,
25 }, 25 },
26 ids::LocationCtx, 26 ids::LocationCtx,
27 name,
28 path::{PathKind, PathSegment},
29 ty::method_resolution::implements_trait,
27 AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HirDatabase, HirFileId, 30 AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HirDatabase, HirFileId,
28 MacroDef, Module, Name, Path, PerNs, Resolver, Static, Struct, Trait, Ty, 31 MacroDef, Module, ModuleDef, Name, Path, PerNs, Resolution, Resolver, Static, Struct, Trait,
32 Ty,
29}; 33};
30 34
31/// Locates the module by `FileId`. Picks topmost module in the file. 35/// Locates the module by `FileId`. Picks topmost module in the file.
@@ -409,6 +413,33 @@ impl SourceAnalyzer {
409 crate::ty::autoderef(db, &self.resolver, canonical).map(|canonical| canonical.value) 413 crate::ty::autoderef(db, &self.resolver, canonical).map(|canonical| canonical.value)
410 } 414 }
411 415
416 /// Checks that particular type `ty` implements `std::future::Future`.
417 /// This function is used in `.await` syntax completion.
418 pub fn impls_future(&self, db: &impl HirDatabase, ty: Ty) -> bool {
419 let std_future_path = Path {
420 kind: PathKind::Abs,
421 segments: vec![
422 PathSegment { name: name::STD, args_and_bindings: None },
423 PathSegment { name: name::FUTURE_MOD, args_and_bindings: None },
424 PathSegment { name: name::FUTURE_TYPE, args_and_bindings: None },
425 ],
426 };
427
428 let std_future_trait =
429 match self.resolver.resolve_path_segments(db, &std_future_path).into_fully_resolved() {
430 PerNs { types: Some(Resolution::Def(ModuleDef::Trait(trait_))), .. } => trait_,
431 _ => return false,
432 };
433
434 let krate = match self.resolver.krate() {
435 Some(krate) => krate,
436 _ => return false,
437 };
438
439 let canonical_ty = crate::ty::Canonical { value: ty, num_vars: 0 };
440 implements_trait(&canonical_ty, db, &self.resolver, krate, std_future_trait)
441 }
442
412 #[cfg(test)] 443 #[cfg(test)]
413 pub(crate) fn body_source_map(&self) -> Arc<BodySourceMap> { 444 pub(crate) fn body_source_map(&self) -> Arc<BodySourceMap> {
414 self.body_source_map.clone().unwrap() 445 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..88d012a74 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -255,6 +255,20 @@ fn iterate_inherent_methods<T>(
255 None 255 None
256} 256}
257 257
258pub(crate) fn implements_trait(
259 ty: &Canonical<Ty>,
260 db: &impl HirDatabase,
261 resolver: &Resolver,
262 krate: Crate,
263 trait_: Trait,
264) -> bool {
265 let env = lower::trait_env(db, resolver);
266 let goal = generic_implements_goal(db, env.clone(), trait_, ty.clone());
267 let solution = db.trait_solve(krate, goal);
268
269 solution.is_some()
270}
271
258impl Ty { 272impl Ty {
259 // This would be nicer if it just returned an iterator, but that runs into 273 // This would be nicer if it just returned an iterator, but that runs into
260 // lifetime problems, because we need to borrow temp `CrateImplBlocks`. 274 // 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..d43ff2eec 100644
--- a/crates/ra_ide_api/src/completion/complete_dot.rs
+++ b/crates/ra_ide_api/src/completion/complete_dot.rs
@@ -1,19 +1,36 @@
1use hir::{AdtDef, Ty, TypeCtor}; 1use hir::{AdtDef, Ty, TypeCtor};
2 2
3use crate::completion::{CompletionContext, Completions}; 3use crate::completion::completion_item::CompletionKind;
4use crate::{
5 completion::{completion_context::CompletionContext, completion_item::Completions},
6 CompletionItem,
7};
4use rustc_hash::FxHashSet; 8use rustc_hash::FxHashSet;
5 9
6/// Complete dot accesses, i.e. fields or methods (currently only fields). 10/// Complete dot accesses, i.e. fields or methods (and .await syntax).
7pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { 11pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
8 let receiver_ty = 12 let dot_receiver = match &ctx.dot_receiver {
9 match ctx.dot_receiver.as_ref().and_then(|it| ctx.analyzer.type_of(ctx.db, it)) { 13 Some(expr) => expr,
10 Some(it) => it, 14 _ => return,
11 None => return, 15 };
12 }; 16
17 let receiver_ty = match ctx.analyzer.type_of(ctx.db, &dot_receiver) {
18 Some(ty) => ty,
19 _ => return,
20 };
21
13 if !ctx.is_call { 22 if !ctx.is_call {
14 complete_fields(acc, ctx, receiver_ty.clone()); 23 complete_fields(acc, ctx, receiver_ty.clone());
15 } 24 }
16 complete_methods(acc, ctx, receiver_ty); 25 complete_methods(acc, ctx, receiver_ty.clone());
26
27 // Suggest .await syntax for types that implement Future trait
28 if ctx.analyzer.impls_future(ctx.db, receiver_ty) {
29 CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await")
30 .detail("expr.await")
31 .insert_text("await")
32 .add_to(acc);
33 }
17} 34}
18 35
19fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) { 36fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) {
@@ -406,4 +423,36 @@ mod tests {
406 "### 423 "###
407 ); 424 );
408 } 425 }
426
427 #[test]
428 fn test_completion_await_impls_future() {
429 assert_debug_snapshot_matches!(
430 do_completion(
431 r###"
432 //- /main.rs
433 use std::future::*;
434 struct A {}
435 impl Future for A {}
436 fn foo(a: A) {
437 a.<|>
438 }
439
440 //- /std/lib.rs
441 pub mod future {
442 pub trait Future {}
443 }
444 "###, CompletionKind::Keyword),
445 @r###"
446 ⋮[
447 ⋮ CompletionItem {
448 ⋮ label: "await",
449 ⋮ source_range: [74; 74),
450 ⋮ delete: [74; 74),
451 ⋮ insert: "await",
452 ⋮ detail: "expr.await",
453 ⋮ },
454 ⋮]
455 "###
456 )
457 }
409} 458}