diff options
Diffstat (limited to 'crates')
37 files changed, 927 insertions, 184 deletions
diff --git a/crates/assists/src/assist_config.rs b/crates/assists/src/assist_config.rs index cda2abfb9..adf02edab 100644 --- a/crates/assists/src/assist_config.rs +++ b/crates/assists/src/assist_config.rs | |||
@@ -4,12 +4,13 @@ | |||
4 | //! module, and we use to statically check that we only produce snippet | 4 | //! module, and we use to statically check that we only produce snippet |
5 | //! assists if we are allowed to. | 5 | //! assists if we are allowed to. |
6 | 6 | ||
7 | use crate::AssistKind; | 7 | use crate::{utils::MergeBehaviour, AssistKind}; |
8 | 8 | ||
9 | #[derive(Clone, Debug, PartialEq, Eq)] | 9 | #[derive(Clone, Debug, PartialEq, Eq)] |
10 | pub struct AssistConfig { | 10 | pub struct AssistConfig { |
11 | pub snippet_cap: Option<SnippetCap>, | 11 | pub snippet_cap: Option<SnippetCap>, |
12 | pub allowed: Option<Vec<AssistKind>>, | 12 | pub allowed: Option<Vec<AssistKind>>, |
13 | pub insert_use: InsertUseConfig, | ||
13 | } | 14 | } |
14 | 15 | ||
15 | impl AssistConfig { | 16 | impl AssistConfig { |
@@ -25,6 +26,21 @@ pub struct SnippetCap { | |||
25 | 26 | ||
26 | impl Default for AssistConfig { | 27 | impl Default for AssistConfig { |
27 | fn default() -> Self { | 28 | fn default() -> Self { |
28 | AssistConfig { snippet_cap: Some(SnippetCap { _private: () }), allowed: None } | 29 | AssistConfig { |
30 | snippet_cap: Some(SnippetCap { _private: () }), | ||
31 | allowed: None, | ||
32 | insert_use: InsertUseConfig::default(), | ||
33 | } | ||
34 | } | ||
35 | } | ||
36 | |||
37 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
38 | pub struct InsertUseConfig { | ||
39 | pub merge: Option<MergeBehaviour>, | ||
40 | } | ||
41 | |||
42 | impl Default for InsertUseConfig { | ||
43 | fn default() -> Self { | ||
44 | InsertUseConfig { merge: Some(MergeBehaviour::Full) } | ||
29 | } | 45 | } |
30 | } | 46 | } |
diff --git a/crates/assists/src/handlers/auto_import.rs b/crates/assists/src/handlers/auto_import.rs index 66e819154..b5eb2c722 100644 --- a/crates/assists/src/handlers/auto_import.rs +++ b/crates/assists/src/handlers/auto_import.rs | |||
@@ -14,10 +14,7 @@ use syntax::{ | |||
14 | SyntaxNode, | 14 | SyntaxNode, |
15 | }; | 15 | }; |
16 | 16 | ||
17 | use crate::{ | 17 | use crate::{utils::insert_use, AssistContext, AssistId, AssistKind, Assists, GroupLabel}; |
18 | utils::{insert_use, MergeBehaviour}, | ||
19 | AssistContext, AssistId, AssistKind, Assists, GroupLabel, | ||
20 | }; | ||
21 | 18 | ||
22 | // Assist: auto_import | 19 | // Assist: auto_import |
23 | // | 20 | // |
@@ -60,7 +57,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
60 | let new_syntax = insert_use( | 57 | let new_syntax = insert_use( |
61 | &scope, | 58 | &scope, |
62 | make::path_from_text(&import.to_string()), | 59 | make::path_from_text(&import.to_string()), |
63 | Some(MergeBehaviour::Full), | 60 | ctx.config.insert_use.merge, |
64 | ); | 61 | ); |
65 | builder.replace(syntax.text_range(), new_syntax.to_string()) | 62 | builder.replace(syntax.text_range(), new_syntax.to_string()) |
66 | }, | 63 | }, |
diff --git a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs index 80c62d8bb..3ea50f375 100644 --- a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs | |||
@@ -10,9 +10,7 @@ use syntax::{ | |||
10 | }; | 10 | }; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | assist_context::AssistBuilder, | 13 | assist_context::AssistBuilder, utils::insert_use, AssistContext, AssistId, AssistKind, Assists, |
14 | utils::{insert_use, MergeBehaviour}, | ||
15 | AssistContext, AssistId, AssistKind, Assists, | ||
16 | }; | 14 | }; |
17 | use ast::make; | 15 | use ast::make; |
18 | use insert_use::ImportScope; | 16 | use insert_use::ImportScope; |
@@ -117,7 +115,7 @@ fn insert_import( | |||
117 | let new_syntax = insert_use( | 115 | let new_syntax = insert_use( |
118 | &scope, | 116 | &scope, |
119 | make::path_from_text(&mod_path.to_string()), | 117 | make::path_from_text(&mod_path.to_string()), |
120 | Some(MergeBehaviour::Full), | 118 | ctx.config.insert_use.merge, |
121 | ); | 119 | ); |
122 | // FIXME: this will currently panic as multiple imports will have overlapping text ranges | 120 | // FIXME: this will currently panic as multiple imports will have overlapping text ranges |
123 | builder.replace(syntax.text_range(), new_syntax.to_string()) | 121 | builder.replace(syntax.text_range(), new_syntax.to_string()) |
diff --git a/crates/assists/src/handlers/replace_qualified_name_with_use.rs b/crates/assists/src/handlers/replace_qualified_name_with_use.rs index 093c3b101..8ac907707 100644 --- a/crates/assists/src/handlers/replace_qualified_name_with_use.rs +++ b/crates/assists/src/handlers/replace_qualified_name_with_use.rs | |||
@@ -2,7 +2,7 @@ use syntax::{algo::SyntaxRewriter, ast, match_ast, AstNode, SyntaxNode, TextRang | |||
2 | use test_utils::mark; | 2 | use test_utils::mark; |
3 | 3 | ||
4 | use crate::{ | 4 | use crate::{ |
5 | utils::{insert_use, ImportScope, MergeBehaviour}, | 5 | utils::{insert_use, ImportScope}, |
6 | AssistContext, AssistId, AssistKind, Assists, | 6 | AssistContext, AssistId, AssistKind, Assists, |
7 | }; | 7 | }; |
8 | use ast::make; | 8 | use ast::make; |
@@ -60,7 +60,7 @@ pub(crate) fn replace_qualified_name_with_use( | |||
60 | let new_syntax = insert_use( | 60 | let new_syntax = insert_use( |
61 | import_scope, | 61 | import_scope, |
62 | make::path_from_text(path_to_import), | 62 | make::path_from_text(path_to_import), |
63 | Some(MergeBehaviour::Full), | 63 | ctx.config.insert_use.merge, |
64 | ); | 64 | ); |
65 | builder.replace(syntax.text_range(), new_syntax.to_string()) | 65 | builder.replace(syntax.text_range(), new_syntax.to_string()) |
66 | } | 66 | } |
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index 7559ddd63..b0511ceb6 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs | |||
@@ -16,7 +16,8 @@ use syntax::{ | |||
16 | 16 | ||
17 | use crate::assist_config::SnippetCap; | 17 | use crate::assist_config::SnippetCap; |
18 | 18 | ||
19 | pub(crate) use insert_use::{insert_use, ImportScope, MergeBehaviour}; | 19 | pub use insert_use::MergeBehaviour; |
20 | pub(crate) use insert_use::{insert_use, ImportScope}; | ||
20 | 21 | ||
21 | pub(crate) fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr { | 22 | pub(crate) fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr { |
22 | extract_trivial_expression(&block) | 23 | extract_trivial_expression(&block) |
diff --git a/crates/assists/src/utils/insert_use.rs b/crates/assists/src/utils/insert_use.rs index 97ac6b832..09f4a2224 100644 --- a/crates/assists/src/utils/insert_use.rs +++ b/crates/assists/src/utils/insert_use.rs | |||
@@ -344,7 +344,7 @@ fn path_cmp_opt(a: Option<ast::Path>, b: Option<ast::Path>) -> Ordering { | |||
344 | } | 344 | } |
345 | 345 | ||
346 | /// What type of merges are allowed. | 346 | /// What type of merges are allowed. |
347 | #[derive(Copy, Clone, PartialEq, Eq)] | 347 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
348 | pub enum MergeBehaviour { | 348 | pub enum MergeBehaviour { |
349 | /// Merge everything together creating deeply nested imports. | 349 | /// Merge everything together creating deeply nested imports. |
350 | Full, | 350 | Full, |
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index c2fc819e7..7a9747fc7 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs | |||
@@ -1283,6 +1283,8 @@ impl Type { | |||
1283 | /// Checks that particular type `ty` implements `std::future::Future`. | 1283 | /// Checks that particular type `ty` implements `std::future::Future`. |
1284 | /// This function is used in `.await` syntax completion. | 1284 | /// This function is used in `.await` syntax completion. |
1285 | pub fn impls_future(&self, db: &dyn HirDatabase) -> bool { | 1285 | pub fn impls_future(&self, db: &dyn HirDatabase) -> bool { |
1286 | // No special case for the type of async block, since Chalk can figure it out. | ||
1287 | |||
1286 | let krate = self.krate; | 1288 | let krate = self.krate; |
1287 | 1289 | ||
1288 | let std_future_trait = | 1290 | let std_future_trait = |
@@ -1600,6 +1602,11 @@ impl Type { | |||
1600 | cb(type_.derived(ty.clone())); | 1602 | cb(type_.derived(ty.clone())); |
1601 | } | 1603 | } |
1602 | } | 1604 | } |
1605 | TypeCtor::OpaqueType(..) => { | ||
1606 | if let Some(bounds) = ty.impl_trait_bounds(db) { | ||
1607 | walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); | ||
1608 | } | ||
1609 | } | ||
1603 | _ => (), | 1610 | _ => (), |
1604 | } | 1611 | } |
1605 | 1612 | ||
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index 30ac12a12..2d91bb21f 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs | |||
@@ -239,7 +239,10 @@ impl ExprCollector<'_> { | |||
239 | None => self.missing_expr(), | 239 | None => self.missing_expr(), |
240 | }, | 240 | }, |
241 | // FIXME: we need to record these effects somewhere... | 241 | // FIXME: we need to record these effects somewhere... |
242 | ast::Effect::Async(_) => self.collect_block_opt(e.block_expr()), | 242 | ast::Effect::Async(_) => { |
243 | let body = self.collect_block_opt(e.block_expr()); | ||
244 | self.alloc_expr(Expr::Async { body }, syntax_ptr) | ||
245 | } | ||
243 | }, | 246 | }, |
244 | ast::Expr::BlockExpr(e) => self.collect_block(e), | 247 | ast::Expr::BlockExpr(e) => self.collect_block(e), |
245 | ast::Expr::LoopExpr(e) => { | 248 | ast::Expr::LoopExpr(e) => { |
@@ -835,8 +838,12 @@ impl ExprCollector<'_> { | |||
835 | 838 | ||
836 | Pat::Missing | 839 | Pat::Missing |
837 | } | 840 | } |
841 | ast::Pat::BoxPat(boxpat) => { | ||
842 | let inner = self.collect_pat_opt(boxpat.pat()); | ||
843 | Pat::Box { inner } | ||
844 | } | ||
838 | // FIXME: implement | 845 | // FIXME: implement |
839 | ast::Pat::BoxPat(_) | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing, | 846 | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing, |
840 | }; | 847 | }; |
841 | let ptr = AstPtr::new(&pat); | 848 | let ptr = AstPtr::new(&pat); |
842 | self.alloc_pat(pattern, Either::Left(ptr)) | 849 | self.alloc_pat(pattern, Either::Left(ptr)) |
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs index 9a8eb4ede..6190906da 100644 --- a/crates/hir_def/src/data.rs +++ b/crates/hir_def/src/data.rs | |||
@@ -54,6 +54,7 @@ pub struct TypeAliasData { | |||
54 | pub name: Name, | 54 | pub name: Name, |
55 | pub type_ref: Option<TypeRef>, | 55 | pub type_ref: Option<TypeRef>, |
56 | pub visibility: RawVisibility, | 56 | pub visibility: RawVisibility, |
57 | pub is_extern: bool, | ||
57 | /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl). | 58 | /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl). |
58 | pub bounds: Vec<TypeBound>, | 59 | pub bounds: Vec<TypeBound>, |
59 | } | 60 | } |
@@ -71,6 +72,7 @@ impl TypeAliasData { | |||
71 | name: typ.name.clone(), | 72 | name: typ.name.clone(), |
72 | type_ref: typ.type_ref.clone(), | 73 | type_ref: typ.type_ref.clone(), |
73 | visibility: item_tree[typ.visibility].clone(), | 74 | visibility: item_tree[typ.visibility].clone(), |
75 | is_extern: typ.is_extern, | ||
74 | bounds: typ.bounds.to_vec(), | 76 | bounds: typ.bounds.to_vec(), |
75 | }) | 77 | }) |
76 | } | 78 | } |
diff --git a/crates/hir_def/src/expr.rs b/crates/hir_def/src/expr.rs index c94b3a36f..e5d740a36 100644 --- a/crates/hir_def/src/expr.rs +++ b/crates/hir_def/src/expr.rs | |||
@@ -111,6 +111,9 @@ pub enum Expr { | |||
111 | TryBlock { | 111 | TryBlock { |
112 | body: ExprId, | 112 | body: ExprId, |
113 | }, | 113 | }, |
114 | Async { | ||
115 | body: ExprId, | ||
116 | }, | ||
114 | Cast { | 117 | Cast { |
115 | expr: ExprId, | 118 | expr: ExprId, |
116 | type_ref: TypeRef, | 119 | type_ref: TypeRef, |
@@ -250,7 +253,7 @@ impl Expr { | |||
250 | f(*expr); | 253 | f(*expr); |
251 | } | 254 | } |
252 | } | 255 | } |
253 | Expr::TryBlock { body } | Expr::Unsafe { body } => f(*body), | 256 | Expr::TryBlock { body } | Expr::Unsafe { body } | Expr::Async { body } => f(*body), |
254 | Expr::Loop { body, .. } => f(*body), | 257 | Expr::Loop { body, .. } => f(*body), |
255 | Expr::While { condition, body, .. } => { | 258 | Expr::While { condition, body, .. } => { |
256 | f(*condition); | 259 | f(*condition); |
@@ -395,6 +398,7 @@ pub enum Pat { | |||
395 | Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> }, | 398 | Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> }, |
396 | TupleStruct { path: Option<Path>, args: Vec<PatId>, ellipsis: Option<usize> }, | 399 | TupleStruct { path: Option<Path>, args: Vec<PatId>, ellipsis: Option<usize> }, |
397 | Ref { pat: PatId, mutability: Mutability }, | 400 | Ref { pat: PatId, mutability: Mutability }, |
401 | Box { inner: PatId }, | ||
398 | } | 402 | } |
399 | 403 | ||
400 | impl Pat { | 404 | impl Pat { |
@@ -415,6 +419,7 @@ impl Pat { | |||
415 | Pat::Record { args, .. } => { | 419 | Pat::Record { args, .. } => { |
416 | args.iter().map(|f| f.pat).for_each(f); | 420 | args.iter().map(|f| f.pat).for_each(f); |
417 | } | 421 | } |
422 | Pat::Box { inner } => f(*inner), | ||
418 | } | 423 | } |
419 | } | 424 | } |
420 | } | 425 | } |
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index e14722cae..52abb8e7f 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs | |||
@@ -592,6 +592,7 @@ pub struct TypeAlias { | |||
592 | pub bounds: Box<[TypeBound]>, | 592 | pub bounds: Box<[TypeBound]>, |
593 | pub generic_params: GenericParamsId, | 593 | pub generic_params: GenericParamsId, |
594 | pub type_ref: Option<TypeRef>, | 594 | pub type_ref: Option<TypeRef>, |
595 | pub is_extern: bool, | ||
595 | pub ast_id: FileAstId<ast::TypeAlias>, | 596 | pub ast_id: FileAstId<ast::TypeAlias>, |
596 | } | 597 | } |
597 | 598 | ||
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index 6a503d785..d93377c3b 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs | |||
@@ -364,6 +364,7 @@ impl Ctx { | |||
364 | generic_params, | 364 | generic_params, |
365 | type_ref, | 365 | type_ref, |
366 | ast_id, | 366 | ast_id, |
367 | is_extern: false, | ||
367 | }; | 368 | }; |
368 | Some(id(self.data().type_aliases.alloc(res))) | 369 | Some(id(self.data().type_aliases.alloc(res))) |
369 | } | 370 | } |
@@ -558,8 +559,9 @@ impl Ctx { | |||
558 | statik.into() | 559 | statik.into() |
559 | } | 560 | } |
560 | ast::ExternItem::TypeAlias(ty) => { | 561 | ast::ExternItem::TypeAlias(ty) => { |
561 | let id = self.lower_type_alias(&ty)?; | 562 | let foreign_ty = self.lower_type_alias(&ty)?; |
562 | id.into() | 563 | self.data().type_aliases[foreign_ty.index].is_extern = true; |
564 | foreign_ty.into() | ||
563 | } | 565 | } |
564 | ast::ExternItem::MacroCall(_) => return None, | 566 | ast::ExternItem::MacroCall(_) => return None, |
565 | }; | 567 | }; |
diff --git a/crates/hir_def/src/item_tree/tests.rs b/crates/hir_def/src/item_tree/tests.rs index 620e697d4..eed3d0d6f 100644 --- a/crates/hir_def/src/item_tree/tests.rs +++ b/crates/hir_def/src/item_tree/tests.rs | |||
@@ -236,7 +236,7 @@ fn smoke() { | |||
236 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_trait"))] }, input: None }]) }] | 236 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_trait"))] }, input: None }]) }] |
237 | Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(0), auto: false, items: [TypeAlias(Idx::<TypeAlias>(0)), Const(Idx::<Const>(0)), Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<syntax::ast::generated::nodes::Trait>(2) } | 237 | Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(0), auto: false, items: [TypeAlias(Idx::<TypeAlias>(0)), Const(Idx::<Const>(0)), Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<syntax::ast::generated::nodes::Trait>(2) } |
238 | > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_ty"))] }, input: None }]) }] | 238 | > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_ty"))] }, input: None }]) }] |
239 | > TypeAlias { name: Name(Text("AssocTy")), visibility: RawVisibilityId("pub(self)"), bounds: [Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Tr"))] }, generic_args: [Some(GenericArgs { args: [Type(Tuple([]))], has_self_type: false, bindings: [] })] })], generic_params: GenericParamsId(4294967295), type_ref: None, ast_id: FileAstId::<syntax::ast::generated::nodes::TypeAlias>(8) } | 239 | > TypeAlias { name: Name(Text("AssocTy")), visibility: RawVisibilityId("pub(self)"), bounds: [Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Tr"))] }, generic_args: [Some(GenericArgs { args: [Type(Tuple([]))], has_self_type: false, bindings: [] })] })], generic_params: GenericParamsId(4294967295), type_ref: None, is_extern: false, ast_id: FileAstId::<syntax::ast::generated::nodes::TypeAlias>(8) } |
240 | > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_const"))] }, input: None }]) }] | 240 | > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_const"))] }, input: None }]) }] |
241 | > Const { name: Some(Name(Text("CONST"))), visibility: RawVisibilityId("pub(self)"), type_ref: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("u8"))] }, generic_args: [None] }), ast_id: FileAstId::<syntax::ast::generated::nodes::Const>(9) } | 241 | > Const { name: Some(Name(Text("CONST"))), visibility: RawVisibilityId("pub(self)"), type_ref: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("u8"))] }, generic_args: [None] }), ast_id: FileAstId::<syntax::ast::generated::nodes::Const>(9) } |
242 | > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_method"))] }, input: None }]) }] | 242 | > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_method"))] }, input: None }]) }] |
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml index 7d02aaf95..bc86df2b1 100644 --- a/crates/hir_ty/Cargo.toml +++ b/crates/hir_ty/Cargo.toml | |||
@@ -17,9 +17,9 @@ ena = "0.14.0" | |||
17 | log = "0.4.8" | 17 | log = "0.4.8" |
18 | rustc-hash = "1.1.0" | 18 | rustc-hash = "1.1.0" |
19 | scoped-tls = "1" | 19 | scoped-tls = "1" |
20 | chalk-solve = { version = "0.25.0" } | 20 | chalk-solve = { version = "0.27.0" } |
21 | chalk-ir = { version = "0.25.0" } | 21 | chalk-ir = { version = "0.27.0" } |
22 | chalk-recursive = { version = "0.25.0" } | 22 | chalk-recursive = { version = "0.27.0" } |
23 | 23 | ||
24 | stdx = { path = "../stdx", version = "0.0.0" } | 24 | stdx = { path = "../stdx", version = "0.0.0" } |
25 | hir_def = { path = "../hir_def", version = "0.0.0" } | 25 | hir_def = { path = "../hir_def", version = "0.0.0" } |
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs index 64b68014d..f389c5a4b 100644 --- a/crates/hir_ty/src/display.rs +++ b/crates/hir_ty/src/display.rs | |||
@@ -380,20 +380,34 @@ impl HirDisplay for ApplicationTy { | |||
380 | write!(f, ">")?; | 380 | write!(f, ">")?; |
381 | } | 381 | } |
382 | } | 382 | } |
383 | TypeCtor::ForeignType(type_alias) => { | ||
384 | let type_alias = f.db.type_alias_data(type_alias); | ||
385 | write!(f, "{}", type_alias.name)?; | ||
386 | if self.parameters.len() > 0 { | ||
387 | write!(f, "<")?; | ||
388 | f.write_joined(&*self.parameters.0, ", ")?; | ||
389 | write!(f, ">")?; | ||
390 | } | ||
391 | } | ||
383 | TypeCtor::OpaqueType(opaque_ty_id) => { | 392 | TypeCtor::OpaqueType(opaque_ty_id) => { |
384 | let bounds = match opaque_ty_id { | 393 | match opaque_ty_id { |
385 | OpaqueTyId::ReturnTypeImplTrait(func, idx) => { | 394 | OpaqueTyId::ReturnTypeImplTrait(func, idx) => { |
386 | let datas = | 395 | let datas = |
387 | f.db.return_type_impl_traits(func).expect("impl trait id without data"); | 396 | f.db.return_type_impl_traits(func).expect("impl trait id without data"); |
388 | let data = (*datas) | 397 | let data = (*datas) |
389 | .as_ref() | 398 | .as_ref() |
390 | .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); | 399 | .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); |
391 | data.subst(&self.parameters) | 400 | let bounds = data.subst(&self.parameters); |
401 | write!(f, "impl ")?; | ||
402 | write_bounds_like_dyn_trait(&bounds.value, f)?; | ||
403 | // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution | ||
392 | } | 404 | } |
393 | }; | 405 | OpaqueTyId::AsyncBlockTypeImplTrait(..) => { |
394 | write!(f, "impl ")?; | 406 | write!(f, "impl Future<Output = ")?; |
395 | write_bounds_like_dyn_trait(&bounds.value, f)?; | 407 | self.parameters[0].hir_fmt(f)?; |
396 | // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution | 408 | write!(f, ">")?; |
409 | } | ||
410 | } | ||
397 | } | 411 | } |
398 | TypeCtor::Closure { .. } => { | 412 | TypeCtor::Closure { .. } => { |
399 | let sig = self.parameters[0].callable_sig(f.db); | 413 | let sig = self.parameters[0].callable_sig(f.db); |
@@ -474,18 +488,21 @@ impl HirDisplay for Ty { | |||
474 | write_bounds_like_dyn_trait(predicates, f)?; | 488 | write_bounds_like_dyn_trait(predicates, f)?; |
475 | } | 489 | } |
476 | Ty::Opaque(opaque_ty) => { | 490 | Ty::Opaque(opaque_ty) => { |
477 | let bounds = match opaque_ty.opaque_ty_id { | 491 | match opaque_ty.opaque_ty_id { |
478 | OpaqueTyId::ReturnTypeImplTrait(func, idx) => { | 492 | OpaqueTyId::ReturnTypeImplTrait(func, idx) => { |
479 | let datas = | 493 | let datas = |
480 | f.db.return_type_impl_traits(func).expect("impl trait id without data"); | 494 | f.db.return_type_impl_traits(func).expect("impl trait id without data"); |
481 | let data = (*datas) | 495 | let data = (*datas) |
482 | .as_ref() | 496 | .as_ref() |
483 | .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); | 497 | .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); |
484 | data.subst(&opaque_ty.parameters) | 498 | let bounds = data.subst(&opaque_ty.parameters); |
499 | write!(f, "impl ")?; | ||
500 | write_bounds_like_dyn_trait(&bounds.value, f)?; | ||
501 | } | ||
502 | OpaqueTyId::AsyncBlockTypeImplTrait(..) => { | ||
503 | write!(f, "{{async block}}")?; | ||
485 | } | 504 | } |
486 | }; | 505 | }; |
487 | write!(f, "impl ")?; | ||
488 | write_bounds_like_dyn_trait(&bounds.value, f)?; | ||
489 | } | 506 | } |
490 | Ty::Unknown => write!(f, "{{unknown}}")?, | 507 | Ty::Unknown => write!(f, "{{unknown}}")?, |
491 | Ty::Infer(..) => write!(f, "_")?, | 508 | Ty::Infer(..) => write!(f, "_")?, |
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs index a2f849d02..0a141b9cb 100644 --- a/crates/hir_ty/src/infer/expr.rs +++ b/crates/hir_ty/src/infer/expr.rs | |||
@@ -17,8 +17,8 @@ use crate::{ | |||
17 | autoderef, method_resolution, op, | 17 | autoderef, method_resolution, op, |
18 | traits::{FnTrait, InEnvironment}, | 18 | traits::{FnTrait, InEnvironment}, |
19 | utils::{generics, variant_data, Generics}, | 19 | utils::{generics, variant_data, Generics}, |
20 | ApplicationTy, Binders, CallableDefId, InferTy, IntTy, Mutability, Obligation, Rawness, Substs, | 20 | ApplicationTy, Binders, CallableDefId, InferTy, IntTy, Mutability, Obligation, OpaqueTyId, |
21 | TraitRef, Ty, TypeCtor, | 21 | Rawness, Substs, TraitRef, Ty, TypeCtor, |
22 | }; | 22 | }; |
23 | 23 | ||
24 | use super::{ | 24 | use super::{ |
@@ -146,6 +146,13 @@ impl<'a> InferenceContext<'a> { | |||
146 | // FIXME should be std::result::Result<{inner}, _> | 146 | // FIXME should be std::result::Result<{inner}, _> |
147 | Ty::Unknown | 147 | Ty::Unknown |
148 | } | 148 | } |
149 | Expr::Async { body } => { | ||
150 | // Use the first type parameter as the output type of future. | ||
151 | // existenail type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType> | ||
152 | let inner_ty = self.infer_expr(*body, &Expectation::none()); | ||
153 | let opaque_ty_id = OpaqueTyId::AsyncBlockTypeImplTrait(self.owner, *body); | ||
154 | Ty::apply_one(TypeCtor::OpaqueType(opaque_ty_id), inner_ty) | ||
155 | } | ||
149 | Expr::Loop { body, label } => { | 156 | Expr::Loop { body, label } => { |
150 | self.breakables.push(BreakableContext { | 157 | self.breakables.push(BreakableContext { |
151 | may_break: false, | 158 | may_break: false, |
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs index dde38bc39..cde2ab82b 100644 --- a/crates/hir_ty/src/infer/pat.rs +++ b/crates/hir_ty/src/infer/pat.rs | |||
@@ -209,6 +209,18 @@ impl<'a> InferenceContext<'a> { | |||
209 | end_ty | 209 | end_ty |
210 | } | 210 | } |
211 | Pat::Lit(expr) => self.infer_expr(*expr, &Expectation::has_type(expected.clone())), | 211 | Pat::Lit(expr) => self.infer_expr(*expr, &Expectation::has_type(expected.clone())), |
212 | Pat::Box { inner } => match self.resolve_boxed_box() { | ||
213 | Some(box_adt) => { | ||
214 | let inner_expected = match expected.as_adt() { | ||
215 | Some((adt, substs)) if adt == box_adt => substs.as_single(), | ||
216 | _ => &Ty::Unknown, | ||
217 | }; | ||
218 | |||
219 | let inner_ty = self.infer_pat(*inner, inner_expected, default_bm); | ||
220 | Ty::apply_one(TypeCtor::Adt(box_adt), inner_ty) | ||
221 | } | ||
222 | None => Ty::Unknown, | ||
223 | }, | ||
212 | Pat::Missing => Ty::Unknown, | 224 | Pat::Missing => Ty::Unknown, |
213 | }; | 225 | }; |
214 | // use a new type variable if we got Ty::Unknown here | 226 | // use a new type variable if we got Ty::Unknown here |
@@ -236,6 +248,6 @@ fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool { | |||
236 | Expr::Literal(Literal::String(..)) => false, | 248 | Expr::Literal(Literal::String(..)) => false, |
237 | _ => true, | 249 | _ => true, |
238 | }, | 250 | }, |
239 | Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Missing => false, | 251 | Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => false, |
240 | } | 252 | } |
241 | } | 253 | } |
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs index 1e748476a..768d95eff 100644 --- a/crates/hir_ty/src/lib.rs +++ b/crates/hir_ty/src/lib.rs | |||
@@ -129,10 +129,14 @@ pub enum TypeCtor { | |||
129 | 129 | ||
130 | /// This represents a placeholder for an opaque type in situations where we | 130 | /// This represents a placeholder for an opaque type in situations where we |
131 | /// don't know the hidden type (i.e. currently almost always). This is | 131 | /// don't know the hidden type (i.e. currently almost always). This is |
132 | /// analogous to the `AssociatedType` type constructor. As with that one, | 132 | /// analogous to the `AssociatedType` type constructor. |
133 | /// these are only produced by Chalk. | 133 | /// It is also used as the type of async block, with one type parameter |
134 | /// representing the Future::Output type. | ||
134 | OpaqueType(OpaqueTyId), | 135 | OpaqueType(OpaqueTyId), |
135 | 136 | ||
137 | /// Represents a foreign type declared in external blocks. | ||
138 | ForeignType(TypeAliasId), | ||
139 | |||
136 | /// The type of a specific closure. | 140 | /// The type of a specific closure. |
137 | /// | 141 | /// |
138 | /// The closure signature is stored in a `FnPtr` type in the first type | 142 | /// The closure signature is stored in a `FnPtr` type in the first type |
@@ -167,12 +171,18 @@ impl TypeCtor { | |||
167 | let generic_params = generics(db.upcast(), type_alias.into()); | 171 | let generic_params = generics(db.upcast(), type_alias.into()); |
168 | generic_params.len() | 172 | generic_params.len() |
169 | } | 173 | } |
174 | TypeCtor::ForeignType(type_alias) => { | ||
175 | let generic_params = generics(db.upcast(), type_alias.into()); | ||
176 | generic_params.len() | ||
177 | } | ||
170 | TypeCtor::OpaqueType(opaque_ty_id) => { | 178 | TypeCtor::OpaqueType(opaque_ty_id) => { |
171 | match opaque_ty_id { | 179 | match opaque_ty_id { |
172 | OpaqueTyId::ReturnTypeImplTrait(func, _) => { | 180 | OpaqueTyId::ReturnTypeImplTrait(func, _) => { |
173 | let generic_params = generics(db.upcast(), func.into()); | 181 | let generic_params = generics(db.upcast(), func.into()); |
174 | generic_params.len() | 182 | generic_params.len() |
175 | } | 183 | } |
184 | // 1 param representing Future::Output type. | ||
185 | OpaqueTyId::AsyncBlockTypeImplTrait(..) => 1, | ||
176 | } | 186 | } |
177 | } | 187 | } |
178 | TypeCtor::FnPtr { num_args, is_varargs: _ } => num_args as usize + 1, | 188 | TypeCtor::FnPtr { num_args, is_varargs: _ } => num_args as usize + 1, |
@@ -201,10 +211,14 @@ impl TypeCtor { | |||
201 | TypeCtor::AssociatedType(type_alias) => { | 211 | TypeCtor::AssociatedType(type_alias) => { |
202 | Some(type_alias.lookup(db.upcast()).module(db.upcast()).krate) | 212 | Some(type_alias.lookup(db.upcast()).module(db.upcast()).krate) |
203 | } | 213 | } |
214 | TypeCtor::ForeignType(type_alias) => { | ||
215 | Some(type_alias.lookup(db.upcast()).module(db.upcast()).krate) | ||
216 | } | ||
204 | TypeCtor::OpaqueType(opaque_ty_id) => match opaque_ty_id { | 217 | TypeCtor::OpaqueType(opaque_ty_id) => match opaque_ty_id { |
205 | OpaqueTyId::ReturnTypeImplTrait(func, _) => { | 218 | OpaqueTyId::ReturnTypeImplTrait(func, _) => { |
206 | Some(func.lookup(db.upcast()).module(db.upcast()).krate) | 219 | Some(func.lookup(db.upcast()).module(db.upcast()).krate) |
207 | } | 220 | } |
221 | OpaqueTyId::AsyncBlockTypeImplTrait(def, _) => Some(def.module(db.upcast()).krate), | ||
208 | }, | 222 | }, |
209 | } | 223 | } |
210 | } | 224 | } |
@@ -227,6 +241,7 @@ impl TypeCtor { | |||
227 | TypeCtor::Adt(adt) => Some(adt.into()), | 241 | TypeCtor::Adt(adt) => Some(adt.into()), |
228 | TypeCtor::FnDef(callable) => Some(callable.into()), | 242 | TypeCtor::FnDef(callable) => Some(callable.into()), |
229 | TypeCtor::AssociatedType(type_alias) => Some(type_alias.into()), | 243 | TypeCtor::AssociatedType(type_alias) => Some(type_alias.into()), |
244 | TypeCtor::ForeignType(type_alias) => Some(type_alias.into()), | ||
230 | TypeCtor::OpaqueType(_impl_trait_id) => None, | 245 | TypeCtor::OpaqueType(_impl_trait_id) => None, |
231 | } | 246 | } |
232 | } | 247 | } |
@@ -843,6 +858,29 @@ impl Ty { | |||
843 | 858 | ||
844 | pub fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<GenericPredicate>> { | 859 | pub fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<GenericPredicate>> { |
845 | match self { | 860 | match self { |
861 | Ty::Apply(ApplicationTy { ctor: TypeCtor::OpaqueType(opaque_ty_id), .. }) => { | ||
862 | match opaque_ty_id { | ||
863 | OpaqueTyId::AsyncBlockTypeImplTrait(def, _expr) => { | ||
864 | let krate = def.module(db.upcast()).krate; | ||
865 | if let Some(future_trait) = db | ||
866 | .lang_item(krate, "future_trait".into()) | ||
867 | .and_then(|item| item.as_trait()) | ||
868 | { | ||
869 | // This is only used by type walking. | ||
870 | // Parameters will be walked outside, and projection predicate is not used. | ||
871 | // So just provide the Future trait. | ||
872 | let impl_bound = GenericPredicate::Implemented(TraitRef { | ||
873 | trait_: future_trait, | ||
874 | substs: Substs::empty(), | ||
875 | }); | ||
876 | Some(vec![impl_bound]) | ||
877 | } else { | ||
878 | None | ||
879 | } | ||
880 | } | ||
881 | OpaqueTyId::ReturnTypeImplTrait(..) => None, | ||
882 | } | ||
883 | } | ||
846 | Ty::Opaque(opaque_ty) => { | 884 | Ty::Opaque(opaque_ty) => { |
847 | let predicates = match opaque_ty.opaque_ty_id { | 885 | let predicates = match opaque_ty.opaque_ty_id { |
848 | OpaqueTyId::ReturnTypeImplTrait(func, idx) => { | 886 | OpaqueTyId::ReturnTypeImplTrait(func, idx) => { |
@@ -853,6 +891,8 @@ impl Ty { | |||
853 | data.subst(&opaque_ty.parameters) | 891 | data.subst(&opaque_ty.parameters) |
854 | }) | 892 | }) |
855 | } | 893 | } |
894 | // It always has an parameter for Future::Output type. | ||
895 | OpaqueTyId::AsyncBlockTypeImplTrait(..) => unreachable!(), | ||
856 | }; | 896 | }; |
857 | 897 | ||
858 | predicates.map(|it| it.value) | 898 | predicates.map(|it| it.value) |
@@ -1065,6 +1105,7 @@ impl<T: TypeWalk> TypeWalk for Vec<T> { | |||
1065 | #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] | 1105 | #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] |
1066 | pub enum OpaqueTyId { | 1106 | pub enum OpaqueTyId { |
1067 | ReturnTypeImplTrait(hir_def::FunctionId, u16), | 1107 | ReturnTypeImplTrait(hir_def::FunctionId, u16), |
1108 | AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId), | ||
1068 | } | 1109 | } |
1069 | 1110 | ||
1070 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | 1111 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index cd574e983..708e2af0f 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs | |||
@@ -1101,10 +1101,14 @@ fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> { | |||
1101 | let resolver = t.resolver(db.upcast()); | 1101 | let resolver = t.resolver(db.upcast()); |
1102 | let ctx = | 1102 | let ctx = |
1103 | TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); | 1103 | TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); |
1104 | let type_ref = &db.type_alias_data(t).type_ref; | ||
1105 | let substs = Substs::bound_vars(&generics, DebruijnIndex::INNERMOST); | 1104 | let substs = Substs::bound_vars(&generics, DebruijnIndex::INNERMOST); |
1106 | let inner = Ty::from_hir(&ctx, type_ref.as_ref().unwrap_or(&TypeRef::Error)); | 1105 | if db.type_alias_data(t).is_extern { |
1107 | Binders::new(substs.len(), inner) | 1106 | Binders::new(substs.len(), Ty::apply(TypeCtor::ForeignType(t), substs)) |
1107 | } else { | ||
1108 | let type_ref = &db.type_alias_data(t).type_ref; | ||
1109 | let inner = Ty::from_hir(&ctx, type_ref.as_ref().unwrap_or(&TypeRef::Error)); | ||
1110 | Binders::new(substs.len(), inner) | ||
1111 | } | ||
1108 | } | 1112 | } |
1109 | 1113 | ||
1110 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | 1114 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs index ec59145c7..8961df404 100644 --- a/crates/hir_ty/src/method_resolution.rs +++ b/crates/hir_ty/src/method_resolution.rs | |||
@@ -250,6 +250,14 @@ impl Ty { | |||
250 | TypeCtor::Adt(def_id) => { | 250 | TypeCtor::Adt(def_id) => { |
251 | return Some(std::iter::once(def_id.module(db.upcast()).krate).collect()) | 251 | return Some(std::iter::once(def_id.module(db.upcast()).krate).collect()) |
252 | } | 252 | } |
253 | TypeCtor::ForeignType(type_alias_id) => { | ||
254 | return Some( | ||
255 | std::iter::once( | ||
256 | type_alias_id.lookup(db.upcast()).module(db.upcast()).krate, | ||
257 | ) | ||
258 | .collect(), | ||
259 | ) | ||
260 | } | ||
253 | TypeCtor::Bool => lang_item_crate!("bool"), | 261 | TypeCtor::Bool => lang_item_crate!("bool"), |
254 | TypeCtor::Char => lang_item_crate!("char"), | 262 | TypeCtor::Char => lang_item_crate!("char"), |
255 | TypeCtor::Float(f) => match f.bitness { | 263 | TypeCtor::Float(f) => match f.bitness { |
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs index 23b2601e6..0f17ff151 100644 --- a/crates/hir_ty/src/tests/method_resolution.rs +++ b/crates/hir_ty/src/tests/method_resolution.rs | |||
@@ -1051,3 +1051,39 @@ fn dyn_trait_super_trait_not_in_scope() { | |||
1051 | "#]], | 1051 | "#]], |
1052 | ); | 1052 | ); |
1053 | } | 1053 | } |
1054 | |||
1055 | #[test] | ||
1056 | fn method_resolution_foreign_opaque_type() { | ||
1057 | check_infer( | ||
1058 | r#" | ||
1059 | extern "C" { | ||
1060 | type S; | ||
1061 | fn f() -> &'static S; | ||
1062 | } | ||
1063 | |||
1064 | impl S { | ||
1065 | fn foo(&self) -> bool { | ||
1066 | true | ||
1067 | } | ||
1068 | } | ||
1069 | |||
1070 | fn test() { | ||
1071 | let s = unsafe { f() }; | ||
1072 | s.foo(); | ||
1073 | } | ||
1074 | "#, | ||
1075 | expect![[r#" | ||
1076 | 75..79 'self': &S | ||
1077 | 89..109 '{ ... }': bool | ||
1078 | 99..103 'true': bool | ||
1079 | 123..167 '{ ...o(); }': () | ||
1080 | 133..134 's': &S | ||
1081 | 137..151 'unsafe { f() }': &S | ||
1082 | 144..151 '{ f() }': &S | ||
1083 | 146..147 'f': fn f() -> &S | ||
1084 | 146..149 'f()': &S | ||
1085 | 157..158 's': &S | ||
1086 | 157..164 's.foo()': bool | ||
1087 | "#]], | ||
1088 | ); | ||
1089 | } | ||
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs index aeb191c79..6a965ac4f 100644 --- a/crates/hir_ty/src/tests/patterns.rs +++ b/crates/hir_ty/src/tests/patterns.rs | |||
@@ -654,3 +654,28 @@ fn slice_tail_pattern() { | |||
654 | "#]], | 654 | "#]], |
655 | ); | 655 | ); |
656 | } | 656 | } |
657 | |||
658 | #[test] | ||
659 | fn box_pattern() { | ||
660 | check_infer( | ||
661 | r#" | ||
662 | #[lang = "owned_box"] | ||
663 | pub struct Box<T>(T); | ||
664 | |||
665 | fn foo(params: Box<i32>) { | ||
666 | match params { | ||
667 | box integer => {} | ||
668 | } | ||
669 | } | ||
670 | "#, | ||
671 | expect![[r#" | ||
672 | 52..58 'params': Box<i32> | ||
673 | 70..124 '{ ... } }': () | ||
674 | 76..122 'match ... }': () | ||
675 | 82..88 'params': Box<i32> | ||
676 | 99..110 'box integer': Box<i32> | ||
677 | 103..110 'integer': i32 | ||
678 | 114..116 '{}': () | ||
679 | "#]], | ||
680 | ); | ||
681 | } | ||
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs index 48db23a34..5b07948f3 100644 --- a/crates/hir_ty/src/tests/simple.rs +++ b/crates/hir_ty/src/tests/simple.rs | |||
@@ -1889,31 +1889,40 @@ fn fn_pointer_return() { | |||
1889 | fn effects_smoke_test() { | 1889 | fn effects_smoke_test() { |
1890 | check_infer( | 1890 | check_infer( |
1891 | r#" | 1891 | r#" |
1892 | fn main() { | 1892 | async fn main() { |
1893 | let x = unsafe { 92 }; | 1893 | let x = unsafe { 92 }; |
1894 | let y = async { async { () }.await }; | 1894 | let y = async { async { () }.await }; |
1895 | let z = try { () }; | 1895 | let z = try { () }; |
1896 | let t = 'a: { 92 }; | 1896 | let t = 'a: { 92 }; |
1897 | } | 1897 | } |
1898 | |||
1899 | #[prelude_import] use future::*; | ||
1900 | |||
1901 | mod future { | ||
1902 | #[lang = "future_trait"] | ||
1903 | pub trait Future { type Output; } | ||
1904 | } | ||
1898 | "#, | 1905 | "#, |
1899 | expect![[r#" | 1906 | expect![[r#" |
1900 | 10..130 '{ ...2 }; }': () | 1907 | 16..136 '{ ...2 }; }': () |
1901 | 20..21 'x': i32 | 1908 | 26..27 'x': i32 |
1902 | 24..37 'unsafe { 92 }': i32 | 1909 | 30..43 'unsafe { 92 }': i32 |
1903 | 31..37 '{ 92 }': i32 | 1910 | 37..43 '{ 92 }': i32 |
1904 | 33..35 '92': i32 | 1911 | 39..41 '92': i32 |
1905 | 47..48 'y': {unknown} | 1912 | 53..54 'y': impl Future<Output = ()> |
1906 | 57..79 '{ asyn...wait }': {unknown} | 1913 | 57..85 'async ...wait }': impl Future<Output = ()> |
1907 | 59..77 'async ....await': {unknown} | 1914 | 63..85 '{ asyn...wait }': () |
1908 | 65..71 '{ () }': () | 1915 | 65..77 'async { () }': impl Future<Output = ()> |
1909 | 67..69 '()': () | 1916 | 65..83 'async ....await': () |
1910 | 89..90 'z': {unknown} | 1917 | 71..77 '{ () }': () |
1911 | 93..103 'try { () }': {unknown} | 1918 | 73..75 '()': () |
1912 | 97..103 '{ () }': () | 1919 | 95..96 'z': {unknown} |
1913 | 99..101 '()': () | 1920 | 99..109 'try { () }': {unknown} |
1914 | 113..114 't': i32 | 1921 | 103..109 '{ () }': () |
1915 | 121..127 '{ 92 }': i32 | 1922 | 105..107 '()': () |
1916 | 123..125 '92': i32 | 1923 | 119..120 't': i32 |
1924 | 127..133 '{ 92 }': i32 | ||
1925 | 129..131 '92': i32 | ||
1917 | "#]], | 1926 | "#]], |
1918 | ) | 1927 | ) |
1919 | } | 1928 | } |
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs index 1f1056962..41d097519 100644 --- a/crates/hir_ty/src/tests/traits.rs +++ b/crates/hir_ty/src/tests/traits.rs | |||
@@ -86,6 +86,46 @@ mod future { | |||
86 | } | 86 | } |
87 | 87 | ||
88 | #[test] | 88 | #[test] |
89 | fn infer_async_block() { | ||
90 | check_types( | ||
91 | r#" | ||
92 | //- /main.rs crate:main deps:core | ||
93 | async fn test() { | ||
94 | let a = async { 42 }; | ||
95 | a; | ||
96 | // ^ impl Future<Output = i32> | ||
97 | let x = a.await; | ||
98 | x; | ||
99 | // ^ i32 | ||
100 | let b = async {}.await; | ||
101 | b; | ||
102 | // ^ () | ||
103 | let c = async { | ||
104 | let y = Option::None; | ||
105 | y | ||
106 | // ^ Option<u64> | ||
107 | }; | ||
108 | let _: Option<u64> = c.await; | ||
109 | c; | ||
110 | // ^ impl Future<Output = Option<u64>> | ||
111 | } | ||
112 | |||
113 | enum Option<T> { None, Some(T) } | ||
114 | |||
115 | //- /core.rs crate:core | ||
116 | #[prelude_import] use future::*; | ||
117 | mod future { | ||
118 | #[lang = "future_trait"] | ||
119 | trait Future { | ||
120 | type Output; | ||
121 | } | ||
122 | } | ||
123 | |||
124 | "#, | ||
125 | ); | ||
126 | } | ||
127 | |||
128 | #[test] | ||
89 | fn infer_try() { | 129 | fn infer_try() { |
90 | check_types( | 130 | check_types( |
91 | r#" | 131 | r#" |
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/traits/chalk.rs index 01b5717a3..27f0ed628 100644 --- a/crates/hir_ty/src/traits/chalk.rs +++ b/crates/hir_ty/src/traits/chalk.rs | |||
@@ -11,6 +11,7 @@ use hir_def::{ | |||
11 | lang_item::{lang_attr, LangItemTarget}, | 11 | lang_item::{lang_attr, LangItemTarget}, |
12 | AssocContainerId, AssocItemId, HasModule, Lookup, TypeAliasId, | 12 | AssocContainerId, AssocItemId, HasModule, Lookup, TypeAliasId, |
13 | }; | 13 | }; |
14 | use hir_expand::name::name; | ||
14 | 15 | ||
15 | use super::ChalkContext; | 16 | use super::ChalkContext; |
16 | use crate::{ | 17 | use crate::{ |
@@ -18,10 +19,12 @@ use crate::{ | |||
18 | display::HirDisplay, | 19 | display::HirDisplay, |
19 | method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS}, | 20 | method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS}, |
20 | utils::generics, | 21 | utils::generics, |
21 | CallableDefId, DebruijnIndex, FnSig, GenericPredicate, Substs, Ty, TypeCtor, | 22 | BoundVar, CallableDefId, DebruijnIndex, FnSig, GenericPredicate, ProjectionPredicate, |
23 | ProjectionTy, Substs, TraitRef, Ty, TypeCtor, | ||
22 | }; | 24 | }; |
23 | use mapping::{ | 25 | use mapping::{ |
24 | convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue, | 26 | convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsAssocType, |
27 | TypeAliasAsValue, | ||
25 | }; | 28 | }; |
26 | 29 | ||
27 | pub use self::interner::*; | 30 | pub use self::interner::*; |
@@ -166,27 +169,88 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | |||
166 | fn opaque_ty_data(&self, id: chalk_ir::OpaqueTyId<Interner>) -> Arc<OpaqueTyDatum> { | 169 | fn opaque_ty_data(&self, id: chalk_ir::OpaqueTyId<Interner>) -> Arc<OpaqueTyDatum> { |
167 | let interned_id = crate::db::InternedOpaqueTyId::from(id); | 170 | let interned_id = crate::db::InternedOpaqueTyId::from(id); |
168 | let full_id = self.db.lookup_intern_impl_trait_id(interned_id); | 171 | let full_id = self.db.lookup_intern_impl_trait_id(interned_id); |
169 | let (func, idx) = match full_id { | 172 | let bound = match full_id { |
170 | crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => (func, idx), | 173 | crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => { |
171 | }; | 174 | let datas = self |
172 | let datas = | 175 | .db |
173 | self.db.return_type_impl_traits(func).expect("impl trait id without impl traits"); | 176 | .return_type_impl_traits(func) |
174 | let data = &datas.value.impl_traits[idx as usize]; | 177 | .expect("impl trait id without impl traits"); |
175 | let bound = OpaqueTyDatumBound { | 178 | let data = &datas.value.impl_traits[idx as usize]; |
176 | bounds: make_binders( | 179 | let bound = OpaqueTyDatumBound { |
177 | data.bounds | 180 | bounds: make_binders( |
178 | .value | 181 | data.bounds |
179 | .iter() | 182 | .value |
180 | .cloned() | 183 | .iter() |
181 | .filter(|b| !b.is_error()) | 184 | .cloned() |
182 | .map(|b| b.to_chalk(self.db)) | 185 | .filter(|b| !b.is_error()) |
183 | .collect(), | 186 | .map(|b| b.to_chalk(self.db)) |
184 | 1, | 187 | .collect(), |
185 | ), | 188 | 1, |
186 | where_clauses: make_binders(vec![], 0), | 189 | ), |
190 | where_clauses: make_binders(vec![], 0), | ||
191 | }; | ||
192 | let num_vars = datas.num_binders; | ||
193 | make_binders(bound, num_vars) | ||
194 | } | ||
195 | crate::OpaqueTyId::AsyncBlockTypeImplTrait(..) => { | ||
196 | if let Some((future_trait, future_output)) = self | ||
197 | .db | ||
198 | .lang_item(self.krate, "future_trait".into()) | ||
199 | .and_then(|item| item.as_trait()) | ||
200 | .and_then(|trait_| { | ||
201 | let alias = | ||
202 | self.db.trait_data(trait_).associated_type_by_name(&name![Output])?; | ||
203 | Some((trait_, alias)) | ||
204 | }) | ||
205 | { | ||
206 | // Making up `AsyncBlock<T>: Future<Output = T>` | ||
207 | // | ||
208 | // |--------------------OpaqueTyDatum-------------------| | ||
209 | // |-------------OpaqueTyDatumBound--------------| | ||
210 | // for<T> <Self> [Future<Self>, Future::Output<Self> = T] | ||
211 | // ^1 ^0 ^0 ^0 ^1 | ||
212 | let impl_bound = GenericPredicate::Implemented(TraitRef { | ||
213 | trait_: future_trait, | ||
214 | // Self type as the first parameter. | ||
215 | substs: Substs::single(Ty::Bound(BoundVar { | ||
216 | debruijn: DebruijnIndex::INNERMOST, | ||
217 | index: 0, | ||
218 | })), | ||
219 | }); | ||
220 | let proj_bound = GenericPredicate::Projection(ProjectionPredicate { | ||
221 | // The parameter of the opaque type. | ||
222 | ty: Ty::Bound(BoundVar { debruijn: DebruijnIndex::ONE, index: 0 }), | ||
223 | projection_ty: ProjectionTy { | ||
224 | associated_ty: future_output, | ||
225 | // Self type as the first parameter. | ||
226 | parameters: Substs::single(Ty::Bound(BoundVar::new( | ||
227 | DebruijnIndex::INNERMOST, | ||
228 | 0, | ||
229 | ))), | ||
230 | }, | ||
231 | }); | ||
232 | let bound = OpaqueTyDatumBound { | ||
233 | bounds: make_binders( | ||
234 | vec![impl_bound.to_chalk(self.db), proj_bound.to_chalk(self.db)], | ||
235 | 1, | ||
236 | ), | ||
237 | where_clauses: make_binders(vec![], 0), | ||
238 | }; | ||
239 | // The opaque type has 1 parameter. | ||
240 | make_binders(bound, 1) | ||
241 | } else { | ||
242 | // If failed to find `Future::Output`, return empty bounds as fallback. | ||
243 | let bound = OpaqueTyDatumBound { | ||
244 | bounds: make_binders(vec![], 0), | ||
245 | where_clauses: make_binders(vec![], 0), | ||
246 | }; | ||
247 | // The opaque type has 1 parameter. | ||
248 | make_binders(bound, 1) | ||
249 | } | ||
250 | } | ||
187 | }; | 251 | }; |
188 | let num_vars = datas.num_binders; | 252 | |
189 | Arc::new(OpaqueTyDatum { opaque_ty_id: id, bound: make_binders(bound, num_vars) }) | 253 | Arc::new(OpaqueTyDatum { opaque_ty_id: id, bound }) |
190 | } | 254 | } |
191 | 255 | ||
192 | fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> { | 256 | fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> { |
@@ -277,7 +341,7 @@ pub(crate) fn associated_ty_data_query( | |||
277 | id: AssocTypeId, | 341 | id: AssocTypeId, |
278 | ) -> Arc<AssociatedTyDatum> { | 342 | ) -> Arc<AssociatedTyDatum> { |
279 | debug!("associated_ty_data {:?}", id); | 343 | debug!("associated_ty_data {:?}", id); |
280 | let type_alias: TypeAliasId = from_chalk(db, id); | 344 | let type_alias: TypeAliasId = from_chalk::<TypeAliasAsAssocType, _>(db, id).0; |
281 | let trait_ = match type_alias.lookup(db.upcast()).container { | 345 | let trait_ = match type_alias.lookup(db.upcast()).container { |
282 | AssocContainerId::TraitId(t) => t, | 346 | AssocContainerId::TraitId(t) => t, |
283 | _ => panic!("associated type not in trait"), | 347 | _ => panic!("associated type not in trait"), |
@@ -331,8 +395,10 @@ pub(crate) fn trait_datum_query( | |||
331 | fundamental: false, | 395 | fundamental: false, |
332 | }; | 396 | }; |
333 | let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars); | 397 | let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars); |
334 | let associated_ty_ids = | 398 | let associated_ty_ids = trait_data |
335 | trait_data.associated_types().map(|type_alias| type_alias.to_chalk(db)).collect(); | 399 | .associated_types() |
400 | .map(|type_alias| TypeAliasAsAssocType(type_alias).to_chalk(db)) | ||
401 | .collect(); | ||
336 | let trait_datum_bound = rust_ir::TraitDatumBound { where_clauses }; | 402 | let trait_datum_bound = rust_ir::TraitDatumBound { where_clauses }; |
337 | let well_known = | 403 | let well_known = |
338 | lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name)); | 404 | lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name)); |
@@ -370,6 +436,7 @@ fn lang_attr_from_well_known_trait(attr: WellKnownTrait) -> &'static str { | |||
370 | WellKnownTrait::FnMut => "fn_mut", | 436 | WellKnownTrait::FnMut => "fn_mut", |
371 | WellKnownTrait::Fn => "fn", | 437 | WellKnownTrait::Fn => "fn", |
372 | WellKnownTrait::Unsize => "unsize", | 438 | WellKnownTrait::Unsize => "unsize", |
439 | WellKnownTrait::Unpin => "unpin", | ||
373 | } | 440 | } |
374 | } | 441 | } |
375 | 442 | ||
@@ -513,7 +580,7 @@ fn type_alias_associated_ty_value( | |||
513 | let value_bound = rust_ir::AssociatedTyValueBound { ty: ty.value.to_chalk(db) }; | 580 | let value_bound = rust_ir::AssociatedTyValueBound { ty: ty.value.to_chalk(db) }; |
514 | let value = rust_ir::AssociatedTyValue { | 581 | let value = rust_ir::AssociatedTyValue { |
515 | impl_id: impl_id.to_chalk(db), | 582 | impl_id: impl_id.to_chalk(db), |
516 | associated_ty_id: assoc_ty.to_chalk(db), | 583 | associated_ty_id: TypeAliasAsAssocType(assoc_ty).to_chalk(db), |
517 | value: make_binders(value_bound, ty.num_binders), | 584 | value: make_binders(value_bound, ty.num_binders), |
518 | }; | 585 | }; |
519 | Arc::new(value) | 586 | Arc::new(value) |
@@ -548,9 +615,11 @@ pub(crate) fn fn_def_datum_query( | |||
548 | }; | 615 | }; |
549 | let datum = FnDefDatum { | 616 | let datum = FnDefDatum { |
550 | id: fn_def_id, | 617 | id: fn_def_id, |
551 | abi: (), | 618 | sig: chalk_ir::FnSig { |
552 | safety: chalk_ir::Safety::Safe, | 619 | abi: (), |
553 | variadic: sig.value.is_varargs, | 620 | safety: chalk_ir::Safety::Safe, |
621 | variadic: sig.value.is_varargs, | ||
622 | }, | ||
554 | binders: make_binders(bound, sig.num_binders), | 623 | binders: make_binders(bound, sig.num_binders), |
555 | }; | 624 | }; |
556 | Arc::new(datum) | 625 | Arc::new(datum) |
diff --git a/crates/hir_ty/src/traits/chalk/interner.rs b/crates/hir_ty/src/traits/chalk/interner.rs index eb35db3ff..f9304b7d0 100644 --- a/crates/hir_ty/src/traits/chalk/interner.rs +++ b/crates/hir_ty/src/traits/chalk/interner.rs | |||
@@ -12,6 +12,7 @@ pub struct Interner; | |||
12 | 12 | ||
13 | pub type AssocTypeId = chalk_ir::AssocTypeId<Interner>; | 13 | pub type AssocTypeId = chalk_ir::AssocTypeId<Interner>; |
14 | pub type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum<Interner>; | 14 | pub type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum<Interner>; |
15 | pub type ForeignDefId = chalk_ir::ForeignDefId<Interner>; | ||
15 | pub type TraitId = chalk_ir::TraitId<Interner>; | 16 | pub type TraitId = chalk_ir::TraitId<Interner>; |
16 | pub type TraitDatum = chalk_solve::rust_ir::TraitDatum<Interner>; | 17 | pub type TraitDatum = chalk_solve::rust_ir::TraitDatum<Interner>; |
17 | pub type AdtId = chalk_ir::AdtId<Interner>; | 18 | pub type AdtId = chalk_ir::AdtId<Interner>; |
diff --git a/crates/hir_ty/src/traits/chalk/mapping.rs b/crates/hir_ty/src/traits/chalk/mapping.rs index d6bacba1d..d42f4bba9 100644 --- a/crates/hir_ty/src/traits/chalk/mapping.rs +++ b/crates/hir_ty/src/traits/chalk/mapping.rs | |||
@@ -34,9 +34,11 @@ impl ToChalk for Ty { | |||
34 | let substitution = apply_ty.parameters.to_chalk(db).shifted_in(&Interner); | 34 | let substitution = apply_ty.parameters.to_chalk(db).shifted_in(&Interner); |
35 | chalk_ir::TyData::Function(chalk_ir::FnPointer { | 35 | chalk_ir::TyData::Function(chalk_ir::FnPointer { |
36 | num_binders: 0, | 36 | num_binders: 0, |
37 | abi: (), | 37 | sig: chalk_ir::FnSig { |
38 | safety: chalk_ir::Safety::Safe, | 38 | abi: (), |
39 | variadic: is_varargs, | 39 | safety: chalk_ir::Safety::Safe, |
40 | variadic: is_varargs, | ||
41 | }, | ||
40 | substitution, | 42 | substitution, |
41 | }) | 43 | }) |
42 | .intern(&Interner) | 44 | .intern(&Interner) |
@@ -48,7 +50,7 @@ impl ToChalk for Ty { | |||
48 | } | 50 | } |
49 | }, | 51 | }, |
50 | Ty::Projection(proj_ty) => { | 52 | Ty::Projection(proj_ty) => { |
51 | let associated_ty_id = proj_ty.associated_ty.to_chalk(db); | 53 | let associated_ty_id = TypeAliasAsAssocType(proj_ty.associated_ty).to_chalk(db); |
52 | let substitution = proj_ty.parameters.to_chalk(db); | 54 | let substitution = proj_ty.parameters.to_chalk(db); |
53 | chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { | 55 | chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { |
54 | associated_ty_id, | 56 | associated_ty_id, |
@@ -114,7 +116,8 @@ impl ToChalk for Ty { | |||
114 | Ty::Placeholder(db.lookup_intern_type_param_id(interned_id)) | 116 | Ty::Placeholder(db.lookup_intern_type_param_id(interned_id)) |
115 | } | 117 | } |
116 | chalk_ir::TyData::Alias(chalk_ir::AliasTy::Projection(proj)) => { | 118 | chalk_ir::TyData::Alias(chalk_ir::AliasTy::Projection(proj)) => { |
117 | let associated_ty = from_chalk(db, proj.associated_ty_id); | 119 | let associated_ty = |
120 | from_chalk::<TypeAliasAsAssocType, _>(db, proj.associated_ty_id).0; | ||
118 | let parameters = from_chalk(db, proj.substitution); | 121 | let parameters = from_chalk(db, proj.substitution); |
119 | Ty::Projection(ProjectionTy { associated_ty, parameters }) | 122 | Ty::Projection(ProjectionTy { associated_ty, parameters }) |
120 | } | 123 | } |
@@ -125,7 +128,7 @@ impl ToChalk for Ty { | |||
125 | } | 128 | } |
126 | chalk_ir::TyData::Function(chalk_ir::FnPointer { | 129 | chalk_ir::TyData::Function(chalk_ir::FnPointer { |
127 | num_binders, | 130 | num_binders, |
128 | variadic, | 131 | sig: chalk_ir::FnSig { variadic, .. }, |
129 | substitution, | 132 | substitution, |
130 | .. | 133 | .. |
131 | }) => { | 134 | }) => { |
@@ -290,8 +293,9 @@ impl ToChalk for TypeCtor { | |||
290 | fn to_chalk(self, db: &dyn HirDatabase) -> TypeName<Interner> { | 293 | fn to_chalk(self, db: &dyn HirDatabase) -> TypeName<Interner> { |
291 | match self { | 294 | match self { |
292 | TypeCtor::AssociatedType(type_alias) => { | 295 | TypeCtor::AssociatedType(type_alias) => { |
293 | let type_id = type_alias.to_chalk(db); | 296 | let assoc_type = TypeAliasAsAssocType(type_alias); |
294 | TypeName::AssociatedType(type_id) | 297 | let assoc_type_id = assoc_type.to_chalk(db); |
298 | TypeName::AssociatedType(assoc_type_id) | ||
295 | } | 299 | } |
296 | 300 | ||
297 | TypeCtor::OpaqueType(impl_trait_id) => { | 301 | TypeCtor::OpaqueType(impl_trait_id) => { |
@@ -299,6 +303,12 @@ impl ToChalk for TypeCtor { | |||
299 | TypeName::OpaqueType(id) | 303 | TypeName::OpaqueType(id) |
300 | } | 304 | } |
301 | 305 | ||
306 | TypeCtor::ForeignType(type_alias) => { | ||
307 | let foreign_type = TypeAliasAsForeignType(type_alias); | ||
308 | let foreign_type_id = foreign_type.to_chalk(db); | ||
309 | TypeName::Foreign(foreign_type_id) | ||
310 | } | ||
311 | |||
302 | TypeCtor::Bool => TypeName::Scalar(Scalar::Bool), | 312 | TypeCtor::Bool => TypeName::Scalar(Scalar::Bool), |
303 | TypeCtor::Char => TypeName::Scalar(Scalar::Char), | 313 | TypeCtor::Char => TypeName::Scalar(Scalar::Char), |
304 | TypeCtor::Int(int_ty) => TypeName::Scalar(int_ty_to_chalk(int_ty)), | 314 | TypeCtor::Int(int_ty) => TypeName::Scalar(int_ty_to_chalk(int_ty)), |
@@ -339,7 +349,9 @@ impl ToChalk for TypeCtor { | |||
339 | fn from_chalk(db: &dyn HirDatabase, type_name: TypeName<Interner>) -> TypeCtor { | 349 | fn from_chalk(db: &dyn HirDatabase, type_name: TypeName<Interner>) -> TypeCtor { |
340 | match type_name { | 350 | match type_name { |
341 | TypeName::Adt(struct_id) => TypeCtor::Adt(struct_id.0), | 351 | TypeName::Adt(struct_id) => TypeCtor::Adt(struct_id.0), |
342 | TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)), | 352 | TypeName::AssociatedType(type_id) => { |
353 | TypeCtor::AssociatedType(from_chalk::<TypeAliasAsAssocType, _>(db, type_id).0) | ||
354 | } | ||
343 | TypeName::OpaqueType(opaque_type_id) => { | 355 | TypeName::OpaqueType(opaque_type_id) => { |
344 | TypeCtor::OpaqueType(from_chalk(db, opaque_type_id)) | 356 | TypeCtor::OpaqueType(from_chalk(db, opaque_type_id)) |
345 | } | 357 | } |
@@ -379,6 +391,10 @@ impl ToChalk for TypeCtor { | |||
379 | TypeCtor::Closure { def, expr } | 391 | TypeCtor::Closure { def, expr } |
380 | } | 392 | } |
381 | 393 | ||
394 | TypeName::Foreign(foreign_def_id) => { | ||
395 | TypeCtor::ForeignType(from_chalk::<TypeAliasAsForeignType, _>(db, foreign_def_id).0) | ||
396 | } | ||
397 | |||
382 | TypeName::Error => { | 398 | TypeName::Error => { |
383 | // this should not be reached, since we don't represent TypeName::Error with TypeCtor | 399 | // this should not be reached, since we don't represent TypeName::Error with TypeCtor |
384 | unreachable!() | 400 | unreachable!() |
@@ -488,15 +504,31 @@ impl ToChalk for CallableDefId { | |||
488 | } | 504 | } |
489 | } | 505 | } |
490 | 506 | ||
491 | impl ToChalk for TypeAliasId { | 507 | pub struct TypeAliasAsAssocType(pub TypeAliasId); |
508 | |||
509 | impl ToChalk for TypeAliasAsAssocType { | ||
492 | type Chalk = AssocTypeId; | 510 | type Chalk = AssocTypeId; |
493 | 511 | ||
494 | fn to_chalk(self, _db: &dyn HirDatabase) -> AssocTypeId { | 512 | fn to_chalk(self, _db: &dyn HirDatabase) -> AssocTypeId { |
495 | chalk_ir::AssocTypeId(self.as_intern_id()) | 513 | chalk_ir::AssocTypeId(self.0.as_intern_id()) |
514 | } | ||
515 | |||
516 | fn from_chalk(_db: &dyn HirDatabase, assoc_type_id: AssocTypeId) -> TypeAliasAsAssocType { | ||
517 | TypeAliasAsAssocType(InternKey::from_intern_id(assoc_type_id.0)) | ||
518 | } | ||
519 | } | ||
520 | |||
521 | pub struct TypeAliasAsForeignType(pub TypeAliasId); | ||
522 | |||
523 | impl ToChalk for TypeAliasAsForeignType { | ||
524 | type Chalk = ForeignDefId; | ||
525 | |||
526 | fn to_chalk(self, _db: &dyn HirDatabase) -> ForeignDefId { | ||
527 | chalk_ir::ForeignDefId(self.0.as_intern_id()) | ||
496 | } | 528 | } |
497 | 529 | ||
498 | fn from_chalk(_db: &dyn HirDatabase, type_alias_id: AssocTypeId) -> TypeAliasId { | 530 | fn from_chalk(_db: &dyn HirDatabase, foreign_def_id: ForeignDefId) -> TypeAliasAsForeignType { |
499 | InternKey::from_intern_id(type_alias_id.0) | 531 | TypeAliasAsForeignType(InternKey::from_intern_id(foreign_def_id.0)) |
500 | } | 532 | } |
501 | } | 533 | } |
502 | 534 | ||
@@ -580,7 +612,7 @@ impl ToChalk for ProjectionTy { | |||
580 | 612 | ||
581 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::ProjectionTy<Interner> { | 613 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::ProjectionTy<Interner> { |
582 | chalk_ir::ProjectionTy { | 614 | chalk_ir::ProjectionTy { |
583 | associated_ty_id: self.associated_ty.to_chalk(db), | 615 | associated_ty_id: TypeAliasAsAssocType(self.associated_ty).to_chalk(db), |
584 | substitution: self.parameters.to_chalk(db), | 616 | substitution: self.parameters.to_chalk(db), |
585 | } | 617 | } |
586 | } | 618 | } |
@@ -590,7 +622,11 @@ impl ToChalk for ProjectionTy { | |||
590 | projection_ty: chalk_ir::ProjectionTy<Interner>, | 622 | projection_ty: chalk_ir::ProjectionTy<Interner>, |
591 | ) -> ProjectionTy { | 623 | ) -> ProjectionTy { |
592 | ProjectionTy { | 624 | ProjectionTy { |
593 | associated_ty: from_chalk(db, projection_ty.associated_ty_id), | 625 | associated_ty: from_chalk::<TypeAliasAsAssocType, _>( |
626 | db, | ||
627 | projection_ty.associated_ty_id, | ||
628 | ) | ||
629 | .0, | ||
594 | parameters: from_chalk(db, projection_ty.substitution), | 630 | parameters: from_chalk(db, projection_ty.substitution), |
595 | } | 631 | } |
596 | } | 632 | } |
@@ -789,7 +825,8 @@ pub(super) fn generic_predicate_to_inline_bound( | |||
789 | let alias_eq_bound = rust_ir::AliasEqBound { | 825 | let alias_eq_bound = rust_ir::AliasEqBound { |
790 | value: proj.ty.clone().to_chalk(db), | 826 | value: proj.ty.clone().to_chalk(db), |
791 | trait_bound: rust_ir::TraitBound { trait_id: trait_.to_chalk(db), args_no_self }, | 827 | trait_bound: rust_ir::TraitBound { trait_id: trait_.to_chalk(db), args_no_self }, |
792 | associated_ty_id: proj.projection_ty.associated_ty.to_chalk(db), | 828 | associated_ty_id: TypeAliasAsAssocType(proj.projection_ty.associated_ty) |
829 | .to_chalk(db), | ||
793 | parameters: Vec::new(), // FIXME we don't support generic associated types yet | 830 | parameters: Vec::new(), // FIXME we don't support generic associated types yet |
794 | }; | 831 | }; |
795 | Some(rust_ir::InlineBound::AliasEqBound(alias_eq_bound)) | 832 | Some(rust_ir::InlineBound::AliasEqBound(alias_eq_bound)) |
diff --git a/crates/hir_ty/src/traits/chalk/tls.rs b/crates/hir_ty/src/traits/chalk/tls.rs index db915625c..b4568cff6 100644 --- a/crates/hir_ty/src/traits/chalk/tls.rs +++ b/crates/hir_ty/src/traits/chalk/tls.rs | |||
@@ -4,7 +4,7 @@ use std::fmt; | |||
4 | use chalk_ir::{AliasTy, GenericArg, Goal, Goals, Lifetime, ProgramClauseImplication, TypeName}; | 4 | use chalk_ir::{AliasTy, GenericArg, Goal, Goals, Lifetime, ProgramClauseImplication, TypeName}; |
5 | use itertools::Itertools; | 5 | use itertools::Itertools; |
6 | 6 | ||
7 | use super::{from_chalk, Interner}; | 7 | use super::{from_chalk, Interner, TypeAliasAsAssocType}; |
8 | use crate::{db::HirDatabase, CallableDefId, TypeCtor}; | 8 | use crate::{db::HirDatabase, CallableDefId, TypeCtor}; |
9 | use hir_def::{AdtId, AssocContainerId, DefWithBodyId, Lookup, TypeAliasId}; | 9 | use hir_def::{AdtId, AssocContainerId, DefWithBodyId, Lookup, TypeAliasId}; |
10 | 10 | ||
@@ -73,7 +73,14 @@ impl DebugContext<'_> { | |||
73 | crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => { | 73 | crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => { |
74 | write!(f, "{{impl trait {} of {:?}}}", idx, func)?; | 74 | write!(f, "{{impl trait {} of {:?}}}", idx, func)?; |
75 | } | 75 | } |
76 | crate::OpaqueTyId::AsyncBlockTypeImplTrait(def, idx) => { | ||
77 | write!(f, "{{impl trait of async block {} of {:?}}}", idx.into_raw(), def)?; | ||
78 | } | ||
76 | }, | 79 | }, |
80 | TypeCtor::ForeignType(type_alias) => { | ||
81 | let name = self.0.type_alias_data(type_alias).name.clone(); | ||
82 | write!(f, "{}", name)?; | ||
83 | } | ||
77 | TypeCtor::Closure { def, expr } => { | 84 | TypeCtor::Closure { def, expr } => { |
78 | write!(f, "{{closure {:?} in ", expr.into_raw())?; | 85 | write!(f, "{{closure {:?} in ", expr.into_raw())?; |
79 | match def { | 86 | match def { |
@@ -116,7 +123,7 @@ impl DebugContext<'_> { | |||
116 | id: super::AssocTypeId, | 123 | id: super::AssocTypeId, |
117 | fmt: &mut fmt::Formatter<'_>, | 124 | fmt: &mut fmt::Formatter<'_>, |
118 | ) -> Result<(), fmt::Error> { | 125 | ) -> Result<(), fmt::Error> { |
119 | let type_alias: TypeAliasId = from_chalk(self.0, id); | 126 | let type_alias: TypeAliasId = from_chalk::<TypeAliasAsAssocType, _>(self.0, id).0; |
120 | let type_alias_data = self.0.type_alias_data(type_alias); | 127 | let type_alias_data = self.0.type_alias_data(type_alias); |
121 | let trait_ = match type_alias.lookup(self.0.upcast()).container { | 128 | let trait_ = match type_alias.lookup(self.0.upcast()).container { |
122 | AssocContainerId::TraitId(t) => t, | 129 | AssocContainerId::TraitId(t) => t, |
@@ -150,7 +157,8 @@ impl DebugContext<'_> { | |||
150 | projection_ty: &chalk_ir::ProjectionTy<Interner>, | 157 | projection_ty: &chalk_ir::ProjectionTy<Interner>, |
151 | fmt: &mut fmt::Formatter<'_>, | 158 | fmt: &mut fmt::Formatter<'_>, |
152 | ) -> Result<(), fmt::Error> { | 159 | ) -> Result<(), fmt::Error> { |
153 | let type_alias: TypeAliasId = from_chalk(self.0, projection_ty.associated_ty_id); | 160 | let type_alias: TypeAliasId = |
161 | from_chalk::<TypeAliasAsAssocType, _>(self.0, projection_ty.associated_ty_id).0; | ||
154 | let type_alias_data = self.0.type_alias_data(type_alias); | 162 | let type_alias_data = self.0.type_alias_data(type_alias); |
155 | let trait_ = match type_alias.lookup(self.0.upcast()).container { | 163 | let trait_ = match type_alias.lookup(self.0.upcast()).container { |
156 | AssocContainerId::TraitId(t) => t, | 164 | AssocContainerId::TraitId(t) => t, |
diff --git a/crates/ide/src/completion/complete_keyword.rs b/crates/ide/src/completion/complete_keyword.rs index 53ba76e0e..5645b41fa 100644 --- a/crates/ide/src/completion/complete_keyword.rs +++ b/crates/ide/src/completion/complete_keyword.rs | |||
@@ -510,6 +510,28 @@ pub mod future { | |||
510 | expect![[r#" | 510 | expect![[r#" |
511 | kw await expr.await | 511 | kw await expr.await |
512 | "#]], | 512 | "#]], |
513 | ); | ||
514 | |||
515 | check( | ||
516 | r#" | ||
517 | //- /main.rs | ||
518 | use std::future::*; | ||
519 | fn foo() { | ||
520 | let a = async {}; | ||
521 | a.<|> | ||
522 | } | ||
523 | |||
524 | //- /std/lib.rs | ||
525 | pub mod future { | ||
526 | #[lang = "future_trait"] | ||
527 | pub trait Future { | ||
528 | type Output; | ||
529 | } | ||
530 | } | ||
531 | "#, | ||
532 | expect![[r#" | ||
533 | kw await expr.await | ||
534 | "#]], | ||
513 | ) | 535 | ) |
514 | } | 536 | } |
515 | 537 | ||
diff --git a/crates/ide/src/completion/complete_qualified_path.rs b/crates/ide/src/completion/complete_qualified_path.rs index 79de50792..00e89f0fd 100644 --- a/crates/ide/src/completion/complete_qualified_path.rs +++ b/crates/ide/src/completion/complete_qualified_path.rs | |||
@@ -730,4 +730,26 @@ fn f() {} | |||
730 | expect![[""]], | 730 | expect![[""]], |
731 | ); | 731 | ); |
732 | } | 732 | } |
733 | |||
734 | #[test] | ||
735 | fn completes_function() { | ||
736 | check( | ||
737 | r#" | ||
738 | fn foo( | ||
739 | a: i32, | ||
740 | b: i32 | ||
741 | ) { | ||
742 | |||
743 | } | ||
744 | |||
745 | fn main() { | ||
746 | fo<|> | ||
747 | } | ||
748 | "#, | ||
749 | expect![[r#" | ||
750 | fn foo(…) fn foo(a: i32, b: i32) | ||
751 | fn main() fn main() | ||
752 | "#]], | ||
753 | ); | ||
754 | } | ||
733 | } | 755 | } |
diff --git a/crates/ide/src/completion/complete_trait_impl.rs b/crates/ide/src/completion/complete_trait_impl.rs index 26f268bd1..ff115df92 100644 --- a/crates/ide/src/completion/complete_trait_impl.rs +++ b/crates/ide/src/completion/complete_trait_impl.rs | |||
@@ -46,76 +46,86 @@ use crate::{ | |||
46 | display::function_declaration, | 46 | display::function_declaration, |
47 | }; | 47 | }; |
48 | 48 | ||
49 | #[derive(Debug, PartialEq, Eq)] | ||
50 | enum ImplCompletionKind { | ||
51 | All, | ||
52 | Fn, | ||
53 | TypeAlias, | ||
54 | Const, | ||
55 | } | ||
56 | |||
49 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { | 57 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { |
50 | if let Some((trigger, impl_def)) = completion_match(ctx) { | 58 | if let Some((kind, trigger, impl_def)) = completion_match(ctx) { |
51 | match trigger.kind() { | 59 | get_missing_assoc_items(&ctx.sema, &impl_def).into_iter().for_each(|item| match item { |
52 | SyntaxKind::NAME_REF => get_missing_assoc_items(&ctx.sema, &impl_def) | 60 | hir::AssocItem::Function(fn_item) |
53 | .into_iter() | 61 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Fn => |
54 | .for_each(|item| match item { | 62 | { |
55 | hir::AssocItem::Function(fn_item) => { | 63 | add_function_impl(&trigger, acc, ctx, fn_item) |
56 | add_function_impl(&trigger, acc, ctx, fn_item) | ||
57 | } | ||
58 | hir::AssocItem::TypeAlias(type_item) => { | ||
59 | add_type_alias_impl(&trigger, acc, ctx, type_item) | ||
60 | } | ||
61 | hir::AssocItem::Const(const_item) => { | ||
62 | add_const_impl(&trigger, acc, ctx, const_item) | ||
63 | } | ||
64 | }), | ||
65 | |||
66 | SyntaxKind::FN => { | ||
67 | for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def) | ||
68 | .into_iter() | ||
69 | .filter_map(|item| match item { | ||
70 | hir::AssocItem::Function(fn_item) => Some(fn_item), | ||
71 | _ => None, | ||
72 | }) | ||
73 | { | ||
74 | add_function_impl(&trigger, acc, ctx, missing_fn); | ||
75 | } | ||
76 | } | 64 | } |
77 | 65 | hir::AssocItem::TypeAlias(type_item) | |
78 | SyntaxKind::TYPE_ALIAS => { | 66 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::TypeAlias => |
79 | for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def) | 67 | { |
80 | .into_iter() | 68 | add_type_alias_impl(&trigger, acc, ctx, type_item) |
81 | .filter_map(|item| match item { | ||
82 | hir::AssocItem::TypeAlias(type_item) => Some(type_item), | ||
83 | _ => None, | ||
84 | }) | ||
85 | { | ||
86 | add_type_alias_impl(&trigger, acc, ctx, missing_fn); | ||
87 | } | ||
88 | } | 69 | } |
89 | 70 | hir::AssocItem::Const(const_item) | |
90 | SyntaxKind::CONST => { | 71 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Const => |
91 | for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def) | 72 | { |
92 | .into_iter() | 73 | add_const_impl(&trigger, acc, ctx, const_item) |
93 | .filter_map(|item| match item { | ||
94 | hir::AssocItem::Const(const_item) => Some(const_item), | ||
95 | _ => None, | ||
96 | }) | ||
97 | { | ||
98 | add_const_impl(&trigger, acc, ctx, missing_fn); | ||
99 | } | ||
100 | } | 74 | } |
101 | |||
102 | _ => {} | 75 | _ => {} |
103 | } | 76 | }); |
104 | } | 77 | } |
105 | } | 78 | } |
106 | 79 | ||
107 | fn completion_match(ctx: &CompletionContext) -> Option<(SyntaxNode, Impl)> { | 80 | fn completion_match(ctx: &CompletionContext) -> Option<(ImplCompletionKind, SyntaxNode, Impl)> { |
108 | let (trigger, impl_def_offset) = ctx.token.ancestors().find_map(|p| match p.kind() { | 81 | let mut token = ctx.token.clone(); |
109 | SyntaxKind::FN | SyntaxKind::TYPE_ALIAS | SyntaxKind::CONST | SyntaxKind::BLOCK_EXPR => { | 82 | // For keywork without name like `impl .. { fn <|> }`, the current position is inside |
110 | Some((p, 2)) | 83 | // the whitespace token, which is outside `FN` syntax node. |
111 | } | 84 | // We need to follow the previous token in this case. |
112 | SyntaxKind::NAME_REF => Some((p, 5)), | 85 | if token.kind() == SyntaxKind::WHITESPACE { |
113 | _ => None, | 86 | token = token.prev_token()?; |
114 | })?; | 87 | } |
115 | let impl_def = (0..impl_def_offset - 1) | 88 | |
116 | .try_fold(trigger.parent()?, |t, _| t.parent()) | 89 | let impl_item_offset = match token.kind() { |
117 | .and_then(ast::Impl::cast)?; | 90 | // `impl .. { const <|> }` |
118 | Some((trigger, impl_def)) | 91 | // ERROR 0 |
92 | // CONST_KW <- * | ||
93 | SyntaxKind::CONST_KW => 0, | ||
94 | // `impl .. { fn/type <|> }` | ||
95 | // FN/TYPE_ALIAS 0 | ||
96 | // FN_KW <- * | ||
97 | SyntaxKind::FN_KW | SyntaxKind::TYPE_KW => 0, | ||
98 | // `impl .. { fn/type/const foo<|> }` | ||
99 | // FN/TYPE_ALIAS/CONST 1 | ||
100 | // NAME 0 | ||
101 | // IDENT <- * | ||
102 | SyntaxKind::IDENT if token.parent().kind() == SyntaxKind::NAME => 1, | ||
103 | // `impl .. { foo<|> }` | ||
104 | // MACRO_CALL 3 | ||
105 | // PATH 2 | ||
106 | // PATH_SEGMENT 1 | ||
107 | // NAME_REF 0 | ||
108 | // IDENT <- * | ||
109 | SyntaxKind::IDENT if token.parent().kind() == SyntaxKind::NAME_REF => 3, | ||
110 | _ => return None, | ||
111 | }; | ||
112 | |||
113 | let impl_item = token.ancestors().nth(impl_item_offset)?; | ||
114 | // Must directly belong to an impl block. | ||
115 | // IMPL | ||
116 | // ASSOC_ITEM_LIST | ||
117 | // <item> | ||
118 | let impl_def = ast::Impl::cast(impl_item.parent()?.parent()?)?; | ||
119 | let kind = match impl_item.kind() { | ||
120 | // `impl ... { const <|> fn/type/const }` | ||
121 | _ if token.kind() == SyntaxKind::CONST_KW => ImplCompletionKind::Const, | ||
122 | SyntaxKind::CONST | SyntaxKind::ERROR => ImplCompletionKind::Const, | ||
123 | SyntaxKind::TYPE_ALIAS => ImplCompletionKind::TypeAlias, | ||
124 | SyntaxKind::FN => ImplCompletionKind::Fn, | ||
125 | SyntaxKind::MACRO_CALL => ImplCompletionKind::All, | ||
126 | _ => return None, | ||
127 | }; | ||
128 | Some((kind, impl_item, impl_def)) | ||
119 | } | 129 | } |
120 | 130 | ||
121 | fn add_function_impl( | 131 | fn add_function_impl( |
@@ -261,19 +271,191 @@ ta type TestType = \n\ | |||
261 | } | 271 | } |
262 | 272 | ||
263 | #[test] | 273 | #[test] |
264 | fn no_nested_fn_completions() { | 274 | fn no_completion_inside_fn() { |
265 | check( | 275 | check( |
266 | r" | 276 | r" |
267 | trait Test { | 277 | trait Test { fn test(); fn test2(); } |
268 | fn test(); | 278 | struct T; |
269 | fn test2(); | 279 | |
280 | impl Test for T { | ||
281 | fn test() { | ||
282 | t<|> | ||
283 | } | ||
284 | } | ||
285 | ", | ||
286 | expect![[""]], | ||
287 | ); | ||
288 | |||
289 | check( | ||
290 | r" | ||
291 | trait Test { fn test(); fn test2(); } | ||
292 | struct T; | ||
293 | |||
294 | impl Test for T { | ||
295 | fn test() { | ||
296 | fn t<|> | ||
297 | } | ||
298 | } | ||
299 | ", | ||
300 | expect![[""]], | ||
301 | ); | ||
302 | |||
303 | check( | ||
304 | r" | ||
305 | trait Test { fn test(); fn test2(); } | ||
306 | struct T; | ||
307 | |||
308 | impl Test for T { | ||
309 | fn test() { | ||
310 | fn <|> | ||
311 | } | ||
270 | } | 312 | } |
313 | ", | ||
314 | expect![[""]], | ||
315 | ); | ||
316 | |||
317 | // https://github.com/rust-analyzer/rust-analyzer/pull/5976#issuecomment-692332191 | ||
318 | check( | ||
319 | r" | ||
320 | trait Test { fn test(); fn test2(); } | ||
271 | struct T; | 321 | struct T; |
272 | 322 | ||
273 | impl Test for T { | 323 | impl Test for T { |
274 | fn test() { | 324 | fn test() { |
325 | foo.<|> | ||
326 | } | ||
327 | } | ||
328 | ", | ||
329 | expect![[""]], | ||
330 | ); | ||
331 | |||
332 | check( | ||
333 | r" | ||
334 | trait Test { fn test(_: i32); fn test2(); } | ||
335 | struct T; | ||
336 | |||
337 | impl Test for T { | ||
338 | fn test(t<|>) | ||
339 | } | ||
340 | ", | ||
341 | expect![[""]], | ||
342 | ); | ||
343 | |||
344 | check( | ||
345 | r" | ||
346 | trait Test { fn test(_: fn()); fn test2(); } | ||
347 | struct T; | ||
348 | |||
349 | impl Test for T { | ||
350 | fn test(f: fn <|>) | ||
351 | } | ||
352 | ", | ||
353 | expect![[""]], | ||
354 | ); | ||
355 | } | ||
356 | |||
357 | #[test] | ||
358 | fn no_completion_inside_const() { | ||
359 | check( | ||
360 | r" | ||
361 | trait Test { const TEST: fn(); const TEST2: u32; type Test; fn test(); } | ||
362 | struct T; | ||
363 | |||
364 | impl Test for T { | ||
365 | const TEST: fn <|> | ||
366 | } | ||
367 | ", | ||
368 | expect![[""]], | ||
369 | ); | ||
370 | |||
371 | check( | ||
372 | r" | ||
373 | trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } | ||
374 | struct T; | ||
375 | |||
376 | impl Test for T { | ||
377 | const TEST: T<|> | ||
378 | } | ||
379 | ", | ||
380 | expect![[""]], | ||
381 | ); | ||
382 | |||
383 | check( | ||
384 | r" | ||
385 | trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } | ||
386 | struct T; | ||
387 | |||
388 | impl Test for T { | ||
389 | const TEST: u32 = f<|> | ||
390 | } | ||
391 | ", | ||
392 | expect![[""]], | ||
393 | ); | ||
394 | |||
395 | check( | ||
396 | r" | ||
397 | trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } | ||
398 | struct T; | ||
399 | |||
400 | impl Test for T { | ||
401 | const TEST: u32 = { | ||
275 | t<|> | 402 | t<|> |
403 | }; | ||
404 | } | ||
405 | ", | ||
406 | expect![[""]], | ||
407 | ); | ||
408 | |||
409 | check( | ||
410 | r" | ||
411 | trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } | ||
412 | struct T; | ||
413 | |||
414 | impl Test for T { | ||
415 | const TEST: u32 = { | ||
416 | fn <|> | ||
417 | }; | ||
418 | } | ||
419 | ", | ||
420 | expect![[""]], | ||
421 | ); | ||
422 | |||
423 | check( | ||
424 | r" | ||
425 | trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } | ||
426 | struct T; | ||
427 | |||
428 | impl Test for T { | ||
429 | const TEST: u32 = { | ||
430 | fn t<|> | ||
431 | }; | ||
432 | } | ||
433 | ", | ||
434 | expect![[""]], | ||
435 | ); | ||
276 | } | 436 | } |
437 | |||
438 | #[test] | ||
439 | fn no_completion_inside_type() { | ||
440 | check( | ||
441 | r" | ||
442 | trait Test { type Test; type Test2; fn test(); } | ||
443 | struct T; | ||
444 | |||
445 | impl Test for T { | ||
446 | type Test = T<|>; | ||
447 | } | ||
448 | ", | ||
449 | expect![[""]], | ||
450 | ); | ||
451 | |||
452 | check( | ||
453 | r" | ||
454 | trait Test { type Test; type Test2; fn test(); } | ||
455 | struct T; | ||
456 | |||
457 | impl Test for T { | ||
458 | type Test = fn <|>; | ||
277 | } | 459 | } |
278 | ", | 460 | ", |
279 | expect![[""]], | 461 | expect![[""]], |
@@ -485,4 +667,67 @@ impl Test for () { | |||
485 | ", | 667 | ", |
486 | ); | 668 | ); |
487 | } | 669 | } |
670 | |||
671 | #[test] | ||
672 | fn complete_without_name() { | ||
673 | let test = |completion: &str, hint: &str, completed: &str, next_sibling: &str| { | ||
674 | println!( | ||
675 | "completion='{}', hint='{}', next_sibling='{}'", | ||
676 | completion, hint, next_sibling | ||
677 | ); | ||
678 | |||
679 | check_edit( | ||
680 | completion, | ||
681 | &format!( | ||
682 | r#" | ||
683 | trait Test {{ | ||
684 | type Foo; | ||
685 | const CONST: u16; | ||
686 | fn bar(); | ||
687 | }} | ||
688 | struct T; | ||
689 | |||
690 | impl Test for T {{ | ||
691 | {} | ||
692 | {} | ||
693 | }} | ||
694 | "#, | ||
695 | hint, next_sibling | ||
696 | ), | ||
697 | &format!( | ||
698 | r#" | ||
699 | trait Test {{ | ||
700 | type Foo; | ||
701 | const CONST: u16; | ||
702 | fn bar(); | ||
703 | }} | ||
704 | struct T; | ||
705 | |||
706 | impl Test for T {{ | ||
707 | {} | ||
708 | {} | ||
709 | }} | ||
710 | "#, | ||
711 | completed, next_sibling | ||
712 | ), | ||
713 | ) | ||
714 | }; | ||
715 | |||
716 | // Enumerate some possible next siblings. | ||
717 | for next_sibling in &[ | ||
718 | "", | ||
719 | "fn other_fn() {}", // `const <|> fn` -> `const fn` | ||
720 | "type OtherType = i32;", | ||
721 | "const OTHER_CONST: i32 = 0;", | ||
722 | "async fn other_fn() {}", | ||
723 | "unsafe fn other_fn() {}", | ||
724 | "default fn other_fn() {}", | ||
725 | "default type OtherType = i32;", | ||
726 | "default const OTHER_CONST: i32 = 0;", | ||
727 | ] { | ||
728 | test("bar", "fn <|>", "fn bar() {\n $0\n}", next_sibling); | ||
729 | test("Foo", "type <|>", "type Foo = ", next_sibling); | ||
730 | test("CONST", "const <|>", "const CONST: u16 = ", next_sibling); | ||
731 | } | ||
732 | } | ||
488 | } | 733 | } |
diff --git a/crates/ide/src/display.rs b/crates/ide/src/display.rs index 41b5bdc49..2484dbbf1 100644 --- a/crates/ide/src/display.rs +++ b/crates/ide/src/display.rs | |||
@@ -41,7 +41,14 @@ pub(crate) fn function_declaration(node: &ast::Fn) -> String { | |||
41 | format_to!(buf, "{}", type_params); | 41 | format_to!(buf, "{}", type_params); |
42 | } | 42 | } |
43 | if let Some(param_list) = node.param_list() { | 43 | if let Some(param_list) = node.param_list() { |
44 | format_to!(buf, "{}", param_list); | 44 | let params: Vec<String> = param_list |
45 | .self_param() | ||
46 | .into_iter() | ||
47 | .map(|self_param| self_param.to_string()) | ||
48 | .chain(param_list.params().map(|param| param.to_string())) | ||
49 | .collect(); | ||
50 | // Useful to inline parameters | ||
51 | format_to!(buf, "({})", params.join(", ")); | ||
45 | } | 52 | } |
46 | if let Some(ret_type) = node.ret_type() { | 53 | if let Some(ret_type) = node.ret_type() { |
47 | if ret_type.ty().is_some() { | 54 | if ret_type.ty().is_some() { |
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index efec0184e..37171cbef 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -2647,6 +2647,70 @@ fn foo(ar<|>g: &impl Foo + Bar<S>) {} | |||
2647 | } | 2647 | } |
2648 | 2648 | ||
2649 | #[test] | 2649 | #[test] |
2650 | fn test_hover_async_block_impl_trait_has_goto_type_action() { | ||
2651 | check_actions( | ||
2652 | r#" | ||
2653 | struct S; | ||
2654 | fn foo() { | ||
2655 | let fo<|>o = async { S }; | ||
2656 | } | ||
2657 | |||
2658 | #[prelude_import] use future::*; | ||
2659 | mod future { | ||
2660 | #[lang = "future_trait"] | ||
2661 | pub trait Future { type Output; } | ||
2662 | } | ||
2663 | "#, | ||
2664 | expect![[r#" | ||
2665 | [ | ||
2666 | GoToType( | ||
2667 | [ | ||
2668 | HoverGotoTypeData { | ||
2669 | mod_path: "test::future::Future", | ||
2670 | nav: NavigationTarget { | ||
2671 | file_id: FileId( | ||
2672 | 1, | ||
2673 | ), | ||
2674 | full_range: 101..163, | ||
2675 | focus_range: Some( | ||
2676 | 140..146, | ||
2677 | ), | ||
2678 | name: "Future", | ||
2679 | kind: TRAIT, | ||
2680 | container_name: None, | ||
2681 | description: Some( | ||
2682 | "pub trait Future", | ||
2683 | ), | ||
2684 | docs: None, | ||
2685 | }, | ||
2686 | }, | ||
2687 | HoverGotoTypeData { | ||
2688 | mod_path: "test::S", | ||
2689 | nav: NavigationTarget { | ||
2690 | file_id: FileId( | ||
2691 | 1, | ||
2692 | ), | ||
2693 | full_range: 0..9, | ||
2694 | focus_range: Some( | ||
2695 | 7..8, | ||
2696 | ), | ||
2697 | name: "S", | ||
2698 | kind: STRUCT, | ||
2699 | container_name: None, | ||
2700 | description: Some( | ||
2701 | "struct S", | ||
2702 | ), | ||
2703 | docs: None, | ||
2704 | }, | ||
2705 | }, | ||
2706 | ], | ||
2707 | ), | ||
2708 | ] | ||
2709 | "#]], | ||
2710 | ); | ||
2711 | } | ||
2712 | |||
2713 | #[test] | ||
2650 | fn test_hover_arg_generic_impl_trait_has_goto_type_action() { | 2714 | fn test_hover_arg_generic_impl_trait_has_goto_type_action() { |
2651 | check_actions( | 2715 | check_actions( |
2652 | r#" | 2716 | r#" |
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 570790384..3b97e087f 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -81,7 +81,9 @@ pub use crate::{ | |||
81 | }, | 81 | }, |
82 | }; | 82 | }; |
83 | 83 | ||
84 | pub use assists::{Assist, AssistConfig, AssistId, AssistKind, ResolvedAssist}; | 84 | pub use assists::{ |
85 | utils::MergeBehaviour, Assist, AssistConfig, AssistId, AssistKind, ResolvedAssist, | ||
86 | }; | ||
85 | pub use base_db::{ | 87 | pub use base_db::{ |
86 | Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot, | 88 | Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot, |
87 | SourceRootId, | 89 | SourceRootId, |
diff --git a/crates/project_model/src/project_json.rs b/crates/project_model/src/project_json.rs index 979e90058..545f254aa 100644 --- a/crates/project_model/src/project_json.rs +++ b/crates/project_model/src/project_json.rs | |||
@@ -13,6 +13,7 @@ use crate::cfg_flag::CfgFlag; | |||
13 | #[derive(Clone, Debug, Eq, PartialEq)] | 13 | #[derive(Clone, Debug, Eq, PartialEq)] |
14 | pub struct ProjectJson { | 14 | pub struct ProjectJson { |
15 | pub(crate) sysroot_src: Option<AbsPathBuf>, | 15 | pub(crate) sysroot_src: Option<AbsPathBuf>, |
16 | project_root: Option<AbsPathBuf>, | ||
16 | crates: Vec<Crate>, | 17 | crates: Vec<Crate>, |
17 | } | 18 | } |
18 | 19 | ||
@@ -36,6 +37,7 @@ impl ProjectJson { | |||
36 | pub fn new(base: &AbsPath, data: ProjectJsonData) -> ProjectJson { | 37 | pub fn new(base: &AbsPath, data: ProjectJsonData) -> ProjectJson { |
37 | ProjectJson { | 38 | ProjectJson { |
38 | sysroot_src: data.sysroot_src.map(|it| base.join(it)), | 39 | sysroot_src: data.sysroot_src.map(|it| base.join(it)), |
40 | project_root: base.parent().map(AbsPath::to_path_buf), | ||
39 | crates: data | 41 | crates: data |
40 | .crates | 42 | .crates |
41 | .into_iter() | 43 | .into_iter() |
@@ -89,6 +91,12 @@ impl ProjectJson { | |||
89 | pub fn crates(&self) -> impl Iterator<Item = (CrateId, &Crate)> + '_ { | 91 | pub fn crates(&self) -> impl Iterator<Item = (CrateId, &Crate)> + '_ { |
90 | self.crates.iter().enumerate().map(|(idx, krate)| (CrateId(idx as u32), krate)) | 92 | self.crates.iter().enumerate().map(|(idx, krate)| (CrateId(idx as u32), krate)) |
91 | } | 93 | } |
94 | pub fn path(&self) -> Option<&AbsPath> { | ||
95 | match &self.project_root { | ||
96 | Some(p) => Some(p.as_path()), | ||
97 | None => None, | ||
98 | } | ||
99 | } | ||
92 | } | 100 | } |
93 | 101 | ||
94 | #[derive(Deserialize)] | 102 | #[derive(Deserialize)] |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 187273bbc..1a74286f5 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -10,7 +10,10 @@ | |||
10 | use std::{ffi::OsString, path::PathBuf}; | 10 | use std::{ffi::OsString, path::PathBuf}; |
11 | 11 | ||
12 | use flycheck::FlycheckConfig; | 12 | use flycheck::FlycheckConfig; |
13 | use ide::{AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig}; | 13 | use ide::{ |
14 | AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig, | ||
15 | MergeBehaviour, | ||
16 | }; | ||
14 | use lsp_types::ClientCapabilities; | 17 | use lsp_types::ClientCapabilities; |
15 | use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest}; | 18 | use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest}; |
16 | use rustc_hash::FxHashSet; | 19 | use rustc_hash::FxHashSet; |
@@ -263,6 +266,12 @@ impl Config { | |||
263 | self.completion.add_call_parenthesis = data.completion_addCallParenthesis; | 266 | self.completion.add_call_parenthesis = data.completion_addCallParenthesis; |
264 | self.completion.add_call_argument_snippets = data.completion_addCallArgumentSnippets; | 267 | self.completion.add_call_argument_snippets = data.completion_addCallArgumentSnippets; |
265 | 268 | ||
269 | self.assist.insert_use.merge = match data.assist_importMergeBehaviour { | ||
270 | MergeBehaviourDef::None => None, | ||
271 | MergeBehaviourDef::Full => Some(MergeBehaviour::Full), | ||
272 | MergeBehaviourDef::Last => Some(MergeBehaviour::Last), | ||
273 | }; | ||
274 | |||
266 | self.call_info_full = data.callInfo_full; | 275 | self.call_info_full = data.callInfo_full; |
267 | 276 | ||
268 | self.lens = LensConfig { | 277 | self.lens = LensConfig { |
@@ -370,6 +379,14 @@ enum ManifestOrProjectJson { | |||
370 | ProjectJson(ProjectJsonData), | 379 | ProjectJson(ProjectJsonData), |
371 | } | 380 | } |
372 | 381 | ||
382 | #[derive(Deserialize)] | ||
383 | #[serde(rename_all = "lowercase")] | ||
384 | enum MergeBehaviourDef { | ||
385 | None, | ||
386 | Full, | ||
387 | Last, | ||
388 | } | ||
389 | |||
373 | macro_rules! config_data { | 390 | macro_rules! config_data { |
374 | (struct $name:ident { $($field:ident: $ty:ty = $default:expr,)*}) => { | 391 | (struct $name:ident { $($field:ident: $ty:ty = $default:expr,)*}) => { |
375 | #[allow(non_snake_case)] | 392 | #[allow(non_snake_case)] |
@@ -393,6 +410,8 @@ macro_rules! config_data { | |||
393 | 410 | ||
394 | config_data! { | 411 | config_data! { |
395 | struct ConfigData { | 412 | struct ConfigData { |
413 | assist_importMergeBehaviour: MergeBehaviourDef = MergeBehaviourDef::None, | ||
414 | |||
396 | callInfo_full: bool = true, | 415 | callInfo_full: bool = true, |
397 | 416 | ||
398 | cargo_autoreload: bool = true, | 417 | cargo_autoreload: bool = true, |
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index bab6f8a71..b819618cb 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs | |||
@@ -2,7 +2,7 @@ | |||
2 | use std::{mem, sync::Arc}; | 2 | use std::{mem, sync::Arc}; |
3 | 3 | ||
4 | use base_db::{CrateGraph, SourceRoot, VfsPath}; | 4 | use base_db::{CrateGraph, SourceRoot, VfsPath}; |
5 | use flycheck::FlycheckHandle; | 5 | use flycheck::{FlycheckConfig, FlycheckHandle}; |
6 | use ide::AnalysisChange; | 6 | use ide::AnalysisChange; |
7 | use project_model::{ProcMacroClient, ProjectWorkspace}; | 7 | use project_model::{ProcMacroClient, ProjectWorkspace}; |
8 | use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind}; | 8 | use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind}; |
@@ -244,13 +244,17 @@ impl GlobalState { | |||
244 | .iter() | 244 | .iter() |
245 | // FIXME: Figure out the multi-workspace situation | 245 | // FIXME: Figure out the multi-workspace situation |
246 | .find_map(|w| match w { | 246 | .find_map(|w| match w { |
247 | ProjectWorkspace::Cargo { cargo, sysroot: _ } => Some(cargo), | 247 | ProjectWorkspace::Cargo { cargo, sysroot: _ } => Some(cargo.workspace_root()), |
248 | ProjectWorkspace::Json { .. } => None, | 248 | ProjectWorkspace::Json { project, .. } => { |
249 | }) | 249 | // Enable flychecks for json projects if a custom flycheck command was supplied |
250 | .map(move |cargo| { | 250 | // in the workspace configuration. |
251 | let cargo_project_root = cargo.workspace_root().to_path_buf(); | 251 | match config { |
252 | FlycheckHandle::spawn(sender, config, cargo_project_root.into()) | 252 | FlycheckConfig::CustomCommand { .. } => project.path(), |
253 | _ => None, | ||
254 | } | ||
255 | } | ||
253 | }) | 256 | }) |
257 | .map(move |root| FlycheckHandle::spawn(sender, config, root.to_path_buf().into())) | ||
254 | } | 258 | } |
255 | } | 259 | } |
256 | 260 | ||