aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock46
-rw-r--r--crates/ra_assists/src/assists/add_derive.rs18
-rw-r--r--crates/ra_assists/src/assists/add_explicit_type.rs16
-rw-r--r--crates/ra_assists/src/assists/add_impl.rs19
-rw-r--r--crates/ra_assists/src/assists/add_missing_impl_members.rs58
-rw-r--r--crates/ra_assists/src/assists/apply_demorgan.rs26
-rw-r--r--crates/ra_assists/src/doc_tests.rs6
-rw-r--r--crates/ra_assists/src/doc_tests/generated.rs139
-rw-r--r--crates/ra_hir/Cargo.toml6
-rw-r--r--crates/ra_hir/src/ty/traits.rs6
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs110
-rw-r--r--docs/user/assists.md137
-rw-r--r--docs/user/features.md91
-rw-r--r--xtask/src/codegen.rs13
-rw-r--r--xtask/src/codegen/gen_assists_docs.rs10
15 files changed, 518 insertions, 183 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 382eb92e4..6f8a4431d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -126,9 +126,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
126[[package]] 126[[package]]
127name = "chalk-engine" 127name = "chalk-engine"
128version = "0.9.0" 128version = "0.9.0"
129source = "git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9#13303bb0067c6ed0572322080ae367ee38f9e7c9" 129source = "git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae#1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae"
130dependencies = [ 130dependencies = [
131 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", 131 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)",
132 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 132 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
133 "stacker 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 133 "stacker 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
134] 134]
@@ -136,17 +136,17 @@ dependencies = [
136[[package]] 136[[package]]
137name = "chalk-ir" 137name = "chalk-ir"
138version = "0.1.0" 138version = "0.1.0"
139source = "git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9#13303bb0067c6ed0572322080ae367ee38f9e7c9" 139source = "git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae#1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae"
140dependencies = [ 140dependencies = [
141 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", 141 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)",
142 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", 142 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)",
143 "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", 143 "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
144] 144]
145 145
146[[package]] 146[[package]]
147name = "chalk-macros" 147name = "chalk-macros"
148version = "0.1.1" 148version = "0.1.1"
149source = "git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9#13303bb0067c6ed0572322080ae367ee38f9e7c9" 149source = "git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae#1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae"
150dependencies = [ 150dependencies = [
151 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 151 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
152] 152]
@@ -154,22 +154,22 @@ dependencies = [
154[[package]] 154[[package]]
155name = "chalk-rust-ir" 155name = "chalk-rust-ir"
156version = "0.1.0" 156version = "0.1.0"
157source = "git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9#13303bb0067c6ed0572322080ae367ee38f9e7c9" 157source = "git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae#1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae"
158dependencies = [ 158dependencies = [
159 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", 159 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)",
160 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", 160 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)",
161 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", 161 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)",
162] 162]
163 163
164[[package]] 164[[package]]
165name = "chalk-solve" 165name = "chalk-solve"
166version = "0.1.0" 166version = "0.1.0"
167source = "git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9#13303bb0067c6ed0572322080ae367ee38f9e7c9" 167source = "git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae#1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae"
168dependencies = [ 168dependencies = [
169 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", 169 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)",
170 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", 170 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)",
171 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", 171 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)",
172 "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", 172 "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)",
173 "ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", 173 "ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
174 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 174 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
175 "petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", 175 "petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -979,9 +979,9 @@ name = "ra_hir"
979version = "0.1.0" 979version = "0.1.0"
980dependencies = [ 980dependencies = [
981 "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 981 "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
982 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", 982 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)",
983 "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", 983 "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)",
984 "chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", 984 "chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)",
985 "ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", 985 "ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
986 "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", 986 "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
987 "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", 987 "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1794,11 +1794,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1794"checksum cargo_metadata 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8d2d1617e838936c0d2323a65cc151e03ae19a7678dd24f72bccf27119b90a5d" 1794"checksum cargo_metadata 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8d2d1617e838936c0d2323a65cc151e03ae19a7678dd24f72bccf27119b90a5d"
1795"checksum cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c" 1795"checksum cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c"
1796"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 1796"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
1797"checksum chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)" = "<none>" 1797"checksum chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)" = "<none>"
1798"checksum chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)" = "<none>" 1798"checksum chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)" = "<none>"
1799"checksum chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)" = "<none>" 1799"checksum chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)" = "<none>"
1800"checksum chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)" = "<none>" 1800"checksum chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)" = "<none>"
1801"checksum chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)" = "<none>" 1801"checksum chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)" = "<none>"
1802"checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68" 1802"checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68"
1803"checksum clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e" 1803"checksum clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e"
1804"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" 1804"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
diff --git a/crates/ra_assists/src/assists/add_derive.rs b/crates/ra_assists/src/assists/add_derive.rs
index 77ecc33c9..d3ba634c4 100644
--- a/crates/ra_assists/src/assists/add_derive.rs
+++ b/crates/ra_assists/src/assists/add_derive.rs
@@ -1,5 +1,3 @@
1//! FIXME: write short doc here
2
3use hir::db::HirDatabase; 1use hir::db::HirDatabase;
4use ra_syntax::{ 2use ra_syntax::{
5 ast::{self, AstNode, AttrsOwner}, 3 ast::{self, AstNode, AttrsOwner},
@@ -9,6 +7,22 @@ use ra_syntax::{
9 7
10use crate::{Assist, AssistCtx, AssistId}; 8use crate::{Assist, AssistCtx, AssistId};
11 9
10// Assist: add_derive
11// Adds a new `#[derive()]` clause to a struct or enum.
12// ```
13// struct Point {
14// x: u32,
15// y: u32,<|>
16// }
17// ```
18// ->
19// ```
20// #[derive()]
21// struct Point {
22// x: u32,
23// y: u32,
24// }
25// ```
12pub(crate) fn add_derive(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 26pub(crate) fn add_derive(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
13 let nominal = ctx.node_at_offset::<ast::NominalDef>()?; 27 let nominal = ctx.node_at_offset::<ast::NominalDef>()?;
14 let node_start = derive_insertion_offset(&nominal)?; 28 let node_start = derive_insertion_offset(&nominal)?;
diff --git a/crates/ra_assists/src/assists/add_explicit_type.rs b/crates/ra_assists/src/assists/add_explicit_type.rs
index 8c83dc987..33b7bea7f 100644
--- a/crates/ra_assists/src/assists/add_explicit_type.rs
+++ b/crates/ra_assists/src/assists/add_explicit_type.rs
@@ -1,5 +1,3 @@
1//! FIXME: write short doc here
2
3use hir::{db::HirDatabase, HirDisplay, Ty}; 1use hir::{db::HirDatabase, HirDisplay, Ty};
4use ra_syntax::{ 2use ra_syntax::{
5 ast::{self, AstNode, LetStmt, NameOwner}, 3 ast::{self, AstNode, LetStmt, NameOwner},
@@ -8,7 +6,19 @@ use ra_syntax::{
8 6
9use crate::{Assist, AssistCtx, AssistId}; 7use crate::{Assist, AssistCtx, AssistId};
10 8
11/// Add explicit type assist. 9// Assist: add_explicit_type
10// Specify type for a let binding
11// ```
12// fn main() {
13// let x<|> = 92;
14// }
15// ```
16// ->
17// ```
18// fn main() {
19// let x: i32 = 92;
20// }
21// ```
12pub(crate) fn add_explicit_type(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 22pub(crate) fn add_explicit_type(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
13 let stmt = ctx.node_at_offset::<LetStmt>()?; 23 let stmt = ctx.node_at_offset::<LetStmt>()?;
14 let expr = stmt.initializer()?; 24 let expr = stmt.initializer()?;
diff --git a/crates/ra_assists/src/assists/add_impl.rs b/crates/ra_assists/src/assists/add_impl.rs
index 94801fbc9..40bc5c464 100644
--- a/crates/ra_assists/src/assists/add_impl.rs
+++ b/crates/ra_assists/src/assists/add_impl.rs
@@ -1,5 +1,3 @@
1//! FIXME: write short doc here
2
3use format_buf::format; 1use format_buf::format;
4use hir::db::HirDatabase; 2use hir::db::HirDatabase;
5use join_to_string::join; 3use join_to_string::join;
@@ -10,6 +8,23 @@ use ra_syntax::{
10 8
11use crate::{Assist, AssistCtx, AssistId}; 9use crate::{Assist, AssistCtx, AssistId};
12 10
11// Assist: add_impl
12// Adds a new inherent impl for a type
13// ```
14// struct Ctx<T: Clone> {
15// data: T,<|>
16// }
17// ```
18// ->
19// ```
20// struct Ctx<T: Clone> {
21// data: T,
22// }
23//
24// impl<T: Clone> Ctx<T> {
25//
26// }
27// ```
13pub(crate) fn add_impl(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 28pub(crate) fn add_impl(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
14 let nominal = ctx.node_at_offset::<ast::NominalDef>()?; 29 let nominal = ctx.node_at_offset::<ast::NominalDef>()?;
15 let name = nominal.name()?; 30 let name = nominal.name()?;
diff --git a/crates/ra_assists/src/assists/add_missing_impl_members.rs b/crates/ra_assists/src/assists/add_missing_impl_members.rs
index 565b96fb5..36fa6f9ea 100644
--- a/crates/ra_assists/src/assists/add_missing_impl_members.rs
+++ b/crates/ra_assists/src/assists/add_missing_impl_members.rs
@@ -1,5 +1,3 @@
1//! FIXME: write short doc here
2
3use hir::{db::HirDatabase, HasSource}; 1use hir::{db::HirDatabase, HasSource};
4use ra_syntax::{ 2use ra_syntax::{
5 ast::{self, edit, make, AstNode, NameOwner}, 3 ast::{self, edit, make, AstNode, NameOwner},
@@ -14,6 +12,32 @@ enum AddMissingImplMembersMode {
14 NoDefaultMethods, 12 NoDefaultMethods,
15} 13}
16 14
15// Assist: add_impl_missing_members
16// Adds scaffold for required impl members
17// ```
18// trait T {
19// Type X;
20// fn foo(&self);
21// fn bar(&self) {}
22// }
23//
24// impl T for () {<|>
25//
26// }
27// ```
28// ->
29// ```
30// trait T {
31// Type X;
32// fn foo(&self);
33// fn bar(&self) {}
34// }
35//
36// impl T for () {
37// fn foo(&self) { unimplemented!() }
38//
39// }
40// ```
17pub(crate) fn add_missing_impl_members(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 41pub(crate) fn add_missing_impl_members(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
18 add_missing_impl_members_inner( 42 add_missing_impl_members_inner(
19 ctx, 43 ctx,
@@ -23,6 +47,36 @@ pub(crate) fn add_missing_impl_members(ctx: AssistCtx<impl HirDatabase>) -> Opti
23 ) 47 )
24} 48}
25 49
50// Assist: add_impl_default_members
51// Adds scaffold for overriding default impl members
52// ```
53// trait T {
54// Type X;
55// fn foo(&self);
56// fn bar(&self) {}
57// }
58//
59// impl T for () {
60// Type X = ();
61// fn foo(&self) {}<|>
62//
63// }
64// ```
65// ->
66// ```
67// trait T {
68// Type X;
69// fn foo(&self);
70// fn bar(&self) {}
71// }
72//
73// impl T for () {
74// Type X = ();
75// fn foo(&self) {}
76// fn bar(&self) {}
77//
78// }
79// ```
26pub(crate) fn add_missing_default_members(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 80pub(crate) fn add_missing_default_members(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
27 add_missing_impl_members_inner( 81 add_missing_impl_members_inner(
28 ctx, 82 ctx,
diff --git a/crates/ra_assists/src/assists/apply_demorgan.rs b/crates/ra_assists/src/assists/apply_demorgan.rs
index 5f2b0dd18..a072f63e7 100644
--- a/crates/ra_assists/src/assists/apply_demorgan.rs
+++ b/crates/ra_assists/src/assists/apply_demorgan.rs
@@ -1,18 +1,26 @@
1//! This contains the functions associated with the demorgan assist.
2//! This assist transforms boolean expressions of the form `!a || !b` into
3//! `!(a && b)`.
4use hir::db::HirDatabase; 1use hir::db::HirDatabase;
5use ra_syntax::ast::{self, AstNode}; 2use ra_syntax::ast::{self, AstNode};
6use ra_syntax::SyntaxNode; 3use ra_syntax::SyntaxNode;
7 4
8use crate::{Assist, AssistCtx, AssistId}; 5use crate::{Assist, AssistCtx, AssistId};
9 6
10/// Assist for applying demorgan's law 7// Assist: apply_demorgan
11/// 8// Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws).
12/// This transforms expressions of the form `!l || !r` into `!(l && r)`. 9// This transforms expressions of the form `!l || !r` into `!(l && r)`.
13/// This also works with `&&`. This assist can only be applied with the cursor 10// This also works with `&&`. This assist can only be applied with the cursor
14/// on either `||` or `&&`, with both operands being a negation of some kind. 11// on either `||` or `&&`, with both operands being a negation of some kind.
15/// This means something of the form `!x` or `x != y`. 12// This means something of the form `!x` or `x != y`.
13// ```
14// fn main() {
15// if x != 4 ||<|> !y {}
16// }
17// ```
18// ->
19// ```
20// fn main() {
21// if !(x == 4 && y) {}
22// }
23// ```
16pub(crate) fn apply_demorgan(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 24pub(crate) fn apply_demorgan(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
17 let expr = ctx.node_at_offset::<ast::BinExpr>()?; 25 let expr = ctx.node_at_offset::<ast::BinExpr>()?;
18 let op = expr.op_kind()?; 26 let op = expr.op_kind()?;
diff --git a/crates/ra_assists/src/doc_tests.rs b/crates/ra_assists/src/doc_tests.rs
index 88e901517..872bbdf17 100644
--- a/crates/ra_assists/src/doc_tests.rs
+++ b/crates/ra_assists/src/doc_tests.rs
@@ -15,8 +15,10 @@ fn check(assist_id: &str, before: &str, after: &str) {
15 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); 15 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
16 let frange = FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; 16 let frange = FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
17 17
18 let (_assist_id, action) = 18 let (_assist_id, action) = crate::assists(&db, frange)
19 crate::assists(&db, frange).into_iter().find(|(id, _)| id.id.0 == assist_id).unwrap(); 19 .into_iter()
20 .find(|(id, _)| id.id.0 == assist_id)
21 .unwrap_or_else(|| panic!("Assist {:?} is not applicable", assist_id));
20 22
21 let actual = action.edit.apply(&before); 23 let actual = action.edit.apply(&before);
22 assert_eq_text!(after, &actual); 24 assert_eq_text!(after, &actual);
diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs
index e5f6910f1..76d86b93d 100644
--- a/crates/ra_assists/src/doc_tests/generated.rs
+++ b/crates/ra_assists/src/doc_tests/generated.rs
@@ -3,6 +3,145 @@
3use super::check; 3use super::check;
4 4
5#[test] 5#[test]
6fn doctest_add_derive() {
7 check(
8 "add_derive",
9 r#####"
10struct Point {
11 x: u32,
12 y: u32,<|>
13}
14"#####,
15 r#####"
16#[derive()]
17struct Point {
18 x: u32,
19 y: u32,
20}
21"#####,
22 )
23}
24
25#[test]
26fn doctest_add_explicit_type() {
27 check(
28 "add_explicit_type",
29 r#####"
30fn main() {
31 let x<|> = 92;
32}
33"#####,
34 r#####"
35fn main() {
36 let x: i32 = 92;
37}
38"#####,
39 )
40}
41
42#[test]
43fn doctest_add_impl() {
44 check(
45 "add_impl",
46 r#####"
47struct Ctx<T: Clone> {
48 data: T,<|>
49}
50"#####,
51 r#####"
52struct Ctx<T: Clone> {
53 data: T,
54}
55
56impl<T: Clone> Ctx<T> {
57
58}
59"#####,
60 )
61}
62
63#[test]
64fn doctest_add_impl_default_members() {
65 check(
66 "add_impl_default_members",
67 r#####"
68trait T {
69 Type X;
70 fn foo(&self);
71 fn bar(&self) {}
72}
73
74impl T for () {
75 Type X = ();
76 fn foo(&self) {}<|>
77
78}
79"#####,
80 r#####"
81trait T {
82 Type X;
83 fn foo(&self);
84 fn bar(&self) {}
85}
86
87impl T for () {
88 Type X = ();
89 fn foo(&self) {}
90 fn bar(&self) {}
91
92}
93"#####,
94 )
95}
96
97#[test]
98fn doctest_add_impl_missing_members() {
99 check(
100 "add_impl_missing_members",
101 r#####"
102trait T {
103 Type X;
104 fn foo(&self);
105 fn bar(&self) {}
106}
107
108impl T for () {<|>
109
110}
111"#####,
112 r#####"
113trait T {
114 Type X;
115 fn foo(&self);
116 fn bar(&self) {}
117}
118
119impl T for () {
120 fn foo(&self) { unimplemented!() }
121
122}
123"#####,
124 )
125}
126
127#[test]
128fn doctest_apply_demorgan() {
129 check(
130 "apply_demorgan",
131 r#####"
132fn main() {
133 if x != 4 ||<|> !y {}
134}
135"#####,
136 r#####"
137fn main() {
138 if !(x == 4 && y) {}
139}
140"#####,
141 )
142}
143
144#[test]
6fn doctest_convert_to_guarded_return() { 145fn doctest_convert_to_guarded_return() {
7 check( 146 check(
8 "convert_to_guarded_return", 147 "convert_to_guarded_return",
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml
index dce897d30..f05ec0b8a 100644
--- a/crates/ra_hir/Cargo.toml
+++ b/crates/ra_hir/Cargo.toml
@@ -22,9 +22,9 @@ tt = { path = "../ra_tt", package = "ra_tt" }
22test_utils = { path = "../test_utils" } 22test_utils = { path = "../test_utils" }
23ra_prof = { path = "../ra_prof" } 23ra_prof = { path = "../ra_prof" }
24 24
25chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "13303bb0067c6ed0572322080ae367ee38f9e7c9" } 25chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae" }
26chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "13303bb0067c6ed0572322080ae367ee38f9e7c9" } 26chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae" }
27chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "13303bb0067c6ed0572322080ae367ee38f9e7c9" } 27chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae" }
28lalrpop-intern = "0.15.1" 28lalrpop-intern = "0.15.1"
29 29
30[dev-dependencies] 30[dev-dependencies]
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs
index 0cb5c3798..4f1eab150 100644
--- a/crates/ra_hir/src/ty/traits.rs
+++ b/crates/ra_hir/src/ty/traits.rs
@@ -1,7 +1,7 @@
1//! Trait solving using Chalk. 1//! Trait solving using Chalk.
2use std::sync::{Arc, Mutex}; 2use std::sync::{Arc, Mutex};
3 3
4use chalk_ir::cast::Cast; 4use chalk_ir::{cast::Cast, family::ChalkIr};
5use log::debug; 5use log::debug;
6use ra_db::salsa; 6use ra_db::salsa;
7use ra_prof::profile; 7use ra_prof::profile;
@@ -33,7 +33,7 @@ impl TraitSolver {
33 fn solve( 33 fn solve(
34 &self, 34 &self,
35 db: &impl HirDatabase, 35 db: &impl HirDatabase,
36 goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal>>, 36 goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<ChalkIr>>>,
37 ) -> Option<chalk_solve::Solution> { 37 ) -> Option<chalk_solve::Solution> {
38 let context = ChalkContext { db, krate: self.krate }; 38 let context = ChalkContext { db, krate: self.krate };
39 debug!("solve goal: {:?}", goal); 39 debug!("solve goal: {:?}", goal);
@@ -196,7 +196,7 @@ pub(crate) fn trait_solve_query(
196} 196}
197 197
198fn solution_from_chalk(db: &impl HirDatabase, solution: chalk_solve::Solution) -> Solution { 198fn solution_from_chalk(db: &impl HirDatabase, solution: chalk_solve::Solution) -> Solution {
199 let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution>| { 199 let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution<ChalkIr>>| {
200 let value = subst 200 let value = subst
201 .value 201 .value
202 .parameters 202 .parameters
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 00aaf65d9..ad7c11a5a 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -4,8 +4,8 @@ use std::sync::Arc;
4use log::debug; 4use log::debug;
5 5
6use chalk_ir::{ 6use chalk_ir::{
7 cast::Cast, Identifier, ImplId, Parameter, PlaceholderIndex, TypeId, TypeKindId, TypeName, 7 cast::Cast, family::ChalkIr, Identifier, ImplId, Parameter, PlaceholderIndex, TypeId,
8 UniverseIndex, 8 TypeKindId, TypeName, UniverseIndex,
9}; 9};
10use chalk_rust_ir::{AssociatedTyDatum, ImplDatum, StructDatum, TraitDatum}; 10use chalk_rust_ir::{AssociatedTyDatum, ImplDatum, StructDatum, TraitDatum};
11 11
@@ -38,8 +38,8 @@ where
38} 38}
39 39
40impl ToChalk for Ty { 40impl ToChalk for Ty {
41 type Chalk = chalk_ir::Ty; 41 type Chalk = chalk_ir::Ty<ChalkIr>;
42 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty { 42 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty<ChalkIr> {
43 match self { 43 match self {
44 Ty::Apply(apply_ty) => { 44 Ty::Apply(apply_ty) => {
45 let name = match apply_ty.ctor { 45 let name = match apply_ty.ctor {
@@ -62,21 +62,21 @@ impl ToChalk for Ty {
62 chalk_ir::ProjectionTy { associated_ty_id, parameters }.cast() 62 chalk_ir::ProjectionTy { associated_ty_id, parameters }.cast()
63 } 63 }
64 Ty::Param { idx, .. } => { 64 Ty::Param { idx, .. } => {
65 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty() 65 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty::<ChalkIr>()
66 } 66 }
67 Ty::Bound(idx) => chalk_ir::Ty::BoundVar(idx as usize), 67 Ty::Bound(idx) => chalk_ir::Ty::BoundVar(idx as usize),
68 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), 68 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"),
69 // FIXME this is clearly incorrect, but probably not too incorrect 69 // FIXME this is clearly incorrect, but probably not too incorrect
70 // and I'm not sure what to actually do with Ty::Unknown 70 // and I'm not sure what to actually do with Ty::Unknown
71 // maybe an alternative would be `for<T> T`? (meaningless in rust, but expressible in chalk's Ty) 71 // maybe an alternative would be `for<T> T`? (meaningless in rust, but expressible in chalk's Ty)
72 // 72 // FIXME use Chalk's Dyn/Opaque once the bugs with that are fixed
73 // FIXME also dyn and impl Trait are currently handled like Unknown because Chalk doesn't have them yet
74 Ty::Unknown | Ty::Dyn(_) | Ty::Opaque(_) => { 73 Ty::Unknown | Ty::Dyn(_) | Ty::Opaque(_) => {
75 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::max_value() }.to_ty() 74 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::max_value() }
75 .to_ty::<ChalkIr>()
76 } 76 }
77 } 77 }
78 } 78 }
79 fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self { 79 fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty<ChalkIr>) -> Self {
80 match chalk { 80 match chalk {
81 chalk_ir::Ty::Apply(apply_ty) => { 81 chalk_ir::Ty::Apply(apply_ty) => {
82 // FIXME this is kind of hacky due to the fact that 82 // FIXME this is kind of hacky due to the fact that
@@ -108,18 +108,30 @@ impl ToChalk for Ty {
108 chalk_ir::Ty::ForAll(_) => unimplemented!(), 108 chalk_ir::Ty::ForAll(_) => unimplemented!(),
109 chalk_ir::Ty::BoundVar(idx) => Ty::Bound(idx as u32), 109 chalk_ir::Ty::BoundVar(idx) => Ty::Bound(idx as u32),
110 chalk_ir::Ty::InferenceVar(_iv) => Ty::Unknown, 110 chalk_ir::Ty::InferenceVar(_iv) => Ty::Unknown,
111 chalk_ir::Ty::Dyn(where_clauses) => {
112 assert_eq!(where_clauses.binders.len(), 1);
113 let predicates =
114 where_clauses.value.into_iter().map(|c| from_chalk(db, c)).collect();
115 Ty::Dyn(predicates)
116 }
117 chalk_ir::Ty::Opaque(where_clauses) => {
118 assert_eq!(where_clauses.binders.len(), 1);
119 let predicates =
120 where_clauses.value.into_iter().map(|c| from_chalk(db, c)).collect();
121 Ty::Opaque(predicates)
122 }
111 } 123 }
112 } 124 }
113} 125}
114 126
115impl ToChalk for Substs { 127impl ToChalk for Substs {
116 type Chalk = Vec<chalk_ir::Parameter>; 128 type Chalk = Vec<chalk_ir::Parameter<ChalkIr>>;
117 129
118 fn to_chalk(self, db: &impl HirDatabase) -> Vec<Parameter> { 130 fn to_chalk(self, db: &impl HirDatabase) -> Vec<Parameter<ChalkIr>> {
119 self.iter().map(|ty| ty.clone().to_chalk(db).cast()).collect() 131 self.iter().map(|ty| ty.clone().to_chalk(db).cast()).collect()
120 } 132 }
121 133
122 fn from_chalk(db: &impl HirDatabase, parameters: Vec<chalk_ir::Parameter>) -> Substs { 134 fn from_chalk(db: &impl HirDatabase, parameters: Vec<chalk_ir::Parameter<ChalkIr>>) -> Substs {
123 let tys = parameters 135 let tys = parameters
124 .into_iter() 136 .into_iter()
125 .map(|p| match p { 137 .map(|p| match p {
@@ -132,15 +144,15 @@ impl ToChalk for Substs {
132} 144}
133 145
134impl ToChalk for TraitRef { 146impl ToChalk for TraitRef {
135 type Chalk = chalk_ir::TraitRef; 147 type Chalk = chalk_ir::TraitRef<ChalkIr>;
136 148
137 fn to_chalk(self: TraitRef, db: &impl HirDatabase) -> chalk_ir::TraitRef { 149 fn to_chalk(self: TraitRef, db: &impl HirDatabase) -> chalk_ir::TraitRef<ChalkIr> {
138 let trait_id = self.trait_.to_chalk(db); 150 let trait_id = self.trait_.to_chalk(db);
139 let parameters = self.substs.to_chalk(db); 151 let parameters = self.substs.to_chalk(db);
140 chalk_ir::TraitRef { trait_id, parameters } 152 chalk_ir::TraitRef { trait_id, parameters }
141 } 153 }
142 154
143 fn from_chalk(db: &impl HirDatabase, trait_ref: chalk_ir::TraitRef) -> Self { 155 fn from_chalk(db: &impl HirDatabase, trait_ref: chalk_ir::TraitRef<ChalkIr>) -> Self {
144 let trait_ = from_chalk(db, trait_ref.trait_id); 156 let trait_ = from_chalk(db, trait_ref.trait_id);
145 let substs = from_chalk(db, trait_ref.parameters); 157 let substs = from_chalk(db, trait_ref.parameters);
146 TraitRef { trait_, substs } 158 TraitRef { trait_, substs }
@@ -196,9 +208,9 @@ impl ToChalk for TypeAlias {
196} 208}
197 209
198impl ToChalk for GenericPredicate { 210impl ToChalk for GenericPredicate {
199 type Chalk = chalk_ir::QuantifiedWhereClause; 211 type Chalk = chalk_ir::QuantifiedWhereClause<ChalkIr>;
200 212
201 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::QuantifiedWhereClause { 213 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::QuantifiedWhereClause<ChalkIr> {
202 match self { 214 match self {
203 GenericPredicate::Implemented(trait_ref) => { 215 GenericPredicate::Implemented(trait_ref) => {
204 make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0) 216 make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0)
@@ -221,25 +233,40 @@ impl ToChalk for GenericPredicate {
221 } 233 }
222 234
223 fn from_chalk( 235 fn from_chalk(
224 _db: &impl HirDatabase, 236 db: &impl HirDatabase,
225 _where_clause: chalk_ir::QuantifiedWhereClause, 237 where_clause: chalk_ir::QuantifiedWhereClause<ChalkIr>,
226 ) -> GenericPredicate { 238 ) -> GenericPredicate {
227 // This should never need to be called 239 match where_clause.value {
228 unimplemented!() 240 chalk_ir::WhereClause::Implemented(tr) => {
241 if tr.trait_id == UNKNOWN_TRAIT {
242 // FIXME we need an Error enum on the Chalk side to avoid this
243 return GenericPredicate::Error;
244 }
245 GenericPredicate::Implemented(from_chalk(db, tr))
246 }
247 chalk_ir::WhereClause::ProjectionEq(projection_eq) => {
248 let projection_ty = from_chalk(db, projection_eq.projection);
249 let ty = from_chalk(db, projection_eq.ty);
250 GenericPredicate::Projection(super::ProjectionPredicate { projection_ty, ty })
251 }
252 }
229 } 253 }
230} 254}
231 255
232impl ToChalk for ProjectionTy { 256impl ToChalk for ProjectionTy {
233 type Chalk = chalk_ir::ProjectionTy; 257 type Chalk = chalk_ir::ProjectionTy<ChalkIr>;
234 258
235 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ProjectionTy { 259 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ProjectionTy<ChalkIr> {
236 chalk_ir::ProjectionTy { 260 chalk_ir::ProjectionTy {
237 associated_ty_id: self.associated_ty.to_chalk(db), 261 associated_ty_id: self.associated_ty.to_chalk(db),
238 parameters: self.parameters.to_chalk(db), 262 parameters: self.parameters.to_chalk(db),
239 } 263 }
240 } 264 }
241 265
242 fn from_chalk(db: &impl HirDatabase, projection_ty: chalk_ir::ProjectionTy) -> ProjectionTy { 266 fn from_chalk(
267 db: &impl HirDatabase,
268 projection_ty: chalk_ir::ProjectionTy<ChalkIr>,
269 ) -> ProjectionTy {
243 ProjectionTy { 270 ProjectionTy {
244 associated_ty: from_chalk(db, projection_ty.associated_ty_id), 271 associated_ty: from_chalk(db, projection_ty.associated_ty_id),
245 parameters: from_chalk(db, projection_ty.parameters), 272 parameters: from_chalk(db, projection_ty.parameters),
@@ -248,31 +275,31 @@ impl ToChalk for ProjectionTy {
248} 275}
249 276
250impl ToChalk for super::ProjectionPredicate { 277impl ToChalk for super::ProjectionPredicate {
251 type Chalk = chalk_ir::Normalize; 278 type Chalk = chalk_ir::Normalize<ChalkIr>;
252 279
253 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Normalize { 280 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Normalize<ChalkIr> {
254 chalk_ir::Normalize { 281 chalk_ir::Normalize {
255 projection: self.projection_ty.to_chalk(db), 282 projection: self.projection_ty.to_chalk(db),
256 ty: self.ty.to_chalk(db), 283 ty: self.ty.to_chalk(db),
257 } 284 }
258 } 285 }
259 286
260 fn from_chalk(_db: &impl HirDatabase, _normalize: chalk_ir::Normalize) -> Self { 287 fn from_chalk(_db: &impl HirDatabase, _normalize: chalk_ir::Normalize<ChalkIr>) -> Self {
261 unimplemented!() 288 unimplemented!()
262 } 289 }
263} 290}
264 291
265impl ToChalk for Obligation { 292impl ToChalk for Obligation {
266 type Chalk = chalk_ir::DomainGoal; 293 type Chalk = chalk_ir::DomainGoal<ChalkIr>;
267 294
268 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::DomainGoal { 295 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::DomainGoal<ChalkIr> {
269 match self { 296 match self {
270 Obligation::Trait(tr) => tr.to_chalk(db).cast(), 297 Obligation::Trait(tr) => tr.to_chalk(db).cast(),
271 Obligation::Projection(pr) => pr.to_chalk(db).cast(), 298 Obligation::Projection(pr) => pr.to_chalk(db).cast(),
272 } 299 }
273 } 300 }
274 301
275 fn from_chalk(_db: &impl HirDatabase, _goal: chalk_ir::DomainGoal) -> Self { 302 fn from_chalk(_db: &impl HirDatabase, _goal: chalk_ir::DomainGoal<ChalkIr>) -> Self {
276 unimplemented!() 303 unimplemented!()
277 } 304 }
278} 305}
@@ -296,16 +323,16 @@ where
296} 323}
297 324
298impl ToChalk for Arc<super::TraitEnvironment> { 325impl ToChalk for Arc<super::TraitEnvironment> {
299 type Chalk = Arc<chalk_ir::Environment>; 326 type Chalk = Arc<chalk_ir::Environment<ChalkIr>>;
300 327
301 fn to_chalk(self, db: &impl HirDatabase) -> Arc<chalk_ir::Environment> { 328 fn to_chalk(self, db: &impl HirDatabase) -> Arc<chalk_ir::Environment<ChalkIr>> {
302 let mut clauses = Vec::new(); 329 let mut clauses = Vec::new();
303 for pred in &self.predicates { 330 for pred in &self.predicates {
304 if pred.is_error() { 331 if pred.is_error() {
305 // for env, we just ignore errors 332 // for env, we just ignore errors
306 continue; 333 continue;
307 } 334 }
308 let program_clause: chalk_ir::ProgramClause = pred.clone().to_chalk(db).cast(); 335 let program_clause: chalk_ir::ProgramClause<ChalkIr> = pred.clone().to_chalk(db).cast();
309 clauses.push(program_clause.into_from_env_clause()); 336 clauses.push(program_clause.into_from_env_clause());
310 } 337 }
311 chalk_ir::Environment::new().add_clauses(clauses) 338 chalk_ir::Environment::new().add_clauses(clauses)
@@ -313,13 +340,16 @@ impl ToChalk for Arc<super::TraitEnvironment> {
313 340
314 fn from_chalk( 341 fn from_chalk(
315 _db: &impl HirDatabase, 342 _db: &impl HirDatabase,
316 _env: Arc<chalk_ir::Environment>, 343 _env: Arc<chalk_ir::Environment<ChalkIr>>,
317 ) -> Arc<super::TraitEnvironment> { 344 ) -> Arc<super::TraitEnvironment> {
318 unimplemented!() 345 unimplemented!()
319 } 346 }
320} 347}
321 348
322impl<T: ToChalk> ToChalk for super::InEnvironment<T> { 349impl<T: ToChalk> ToChalk for super::InEnvironment<T>
350where
351 T::Chalk: chalk_ir::family::HasTypeFamily<TypeFamily = ChalkIr>,
352{
323 type Chalk = chalk_ir::InEnvironment<T::Chalk>; 353 type Chalk = chalk_ir::InEnvironment<T::Chalk>;
324 354
325 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::InEnvironment<T::Chalk> { 355 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::InEnvironment<T::Chalk> {
@@ -351,7 +381,7 @@ fn convert_where_clauses(
351 db: &impl HirDatabase, 381 db: &impl HirDatabase,
352 def: GenericDef, 382 def: GenericDef,
353 substs: &Substs, 383 substs: &Substs,
354) -> Vec<chalk_ir::QuantifiedWhereClause> { 384) -> Vec<chalk_ir::QuantifiedWhereClause<ChalkIr>> {
355 let generic_predicates = db.generic_predicates(def); 385 let generic_predicates = db.generic_predicates(def);
356 let mut result = Vec::with_capacity(generic_predicates.len()); 386 let mut result = Vec::with_capacity(generic_predicates.len());
357 for pred in generic_predicates.iter() { 387 for pred in generic_predicates.iter() {
@@ -384,7 +414,7 @@ where
384 fn impls_for_trait( 414 fn impls_for_trait(
385 &self, 415 &self,
386 trait_id: chalk_ir::TraitId, 416 trait_id: chalk_ir::TraitId,
387 parameters: &[Parameter], 417 parameters: &[Parameter<ChalkIr>],
388 ) -> Vec<ImplId> { 418 ) -> Vec<ImplId> {
389 debug!("impls_for_trait {:?}", trait_id); 419 debug!("impls_for_trait {:?}", trait_id);
390 if trait_id == UNKNOWN_TRAIT { 420 if trait_id == UNKNOWN_TRAIT {
@@ -430,13 +460,13 @@ where
430 } 460 }
431 fn split_projection<'p>( 461 fn split_projection<'p>(
432 &self, 462 &self,
433 projection: &'p chalk_ir::ProjectionTy, 463 projection: &'p chalk_ir::ProjectionTy<ChalkIr>,
434 ) -> (Arc<AssociatedTyDatum>, &'p [Parameter], &'p [Parameter]) { 464 ) -> (Arc<AssociatedTyDatum>, &'p [Parameter<ChalkIr>], &'p [Parameter<ChalkIr>]) {
435 debug!("split_projection {:?}", projection); 465 debug!("split_projection {:?}", projection);
436 // we don't support GATs, so I think this should always be correct currently 466 // we don't support GATs, so I think this should always be correct currently
437 (self.db.associated_ty_data(projection.associated_ty_id), &projection.parameters, &[]) 467 (self.db.associated_ty_data(projection.associated_ty_id), &projection.parameters, &[])
438 } 468 }
439 fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause> { 469 fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<ChalkIr>> {
440 vec![] 470 vec![]
441 } 471 }
442 fn local_impls_to_coherence_check( 472 fn local_impls_to_coherence_check(
diff --git a/docs/user/assists.md b/docs/user/assists.md
index cb4b0b9fb..eeb486832 100644
--- a/docs/user/assists.md
+++ b/docs/user/assists.md
@@ -1,5 +1,142 @@
1# Assists 1# Assists
2 2
3## `add_derive`
4
5Adds a new `#[derive()]` clause to a struct or enum.
6
7```rust
8// BEFORE
9struct Point {
10 x: u32,
11 y: u32,<|>
12}
13
14// AFTER
15#[derive()]
16struct Point {
17 x: u32,
18 y: u32,
19}
20```
21
22## `add_explicit_type`
23
24Specify type for a let binding
25
26```rust
27// BEFORE
28fn main() {
29 let x<|> = 92;
30}
31
32// AFTER
33fn main() {
34 let x: i32 = 92;
35}
36```
37
38## `add_impl`
39
40Adds a new inherent impl for a type
41
42```rust
43// BEFORE
44struct Ctx<T: Clone> {
45 data: T,<|>
46}
47
48// AFTER
49struct Ctx<T: Clone> {
50 data: T,
51}
52
53impl<T: Clone> Ctx<T> {
54
55}
56```
57
58## `add_impl_default_members`
59
60Adds scaffold for overriding default impl members
61
62```rust
63// BEFORE
64trait T {
65 Type X;
66 fn foo(&self);
67 fn bar(&self) {}
68}
69
70impl T for () {
71 Type X = ();
72 fn foo(&self) {}<|>
73
74}
75
76// AFTER
77trait T {
78 Type X;
79 fn foo(&self);
80 fn bar(&self) {}
81}
82
83impl T for () {
84 Type X = ();
85 fn foo(&self) {}
86 fn bar(&self) {}
87
88}
89```
90
91## `add_impl_missing_members`
92
93Adds scaffold for required impl members
94
95```rust
96// BEFORE
97trait T {
98 Type X;
99 fn foo(&self);
100 fn bar(&self) {}
101}
102
103impl T for () {<|>
104
105}
106
107// AFTER
108trait T {
109 Type X;
110 fn foo(&self);
111 fn bar(&self) {}
112}
113
114impl T for () {
115 fn foo(&self) { unimplemented!() }
116
117}
118```
119
120## `apply_demorgan`
121
122Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws).
123This transforms expressions of the form `!l || !r` into `!(l && r)`.
124This also works with `&&`. This assist can only be applied with the cursor
125on either `||` or `&&`, with both operands being a negation of some kind.
126This means something of the form `!x` or `x != y`.
127
128```rust
129// BEFORE
130fn main() {
131 if x != 4 ||<|> !y {}
132}
133
134// AFTER
135fn main() {
136 if !(x == 4 && y) {}
137}
138```
139
3## `convert_to_guarded_return` 140## `convert_to_guarded_return`
4 141
5Replace a large conditional with a guarded return. 142Replace a large conditional with a guarded return.
diff --git a/docs/user/features.md b/docs/user/features.md
index a94b65ad4..acf092cec 100644
--- a/docs/user/features.md
+++ b/docs/user/features.md
@@ -104,84 +104,6 @@ the VS Code side to be able to position cursor. `<|>` signifies cursor
104 104
105See [assists.md](./assists.md) 105See [assists.md](./assists.md)
106 106
107- Add `#[derive]`
108
109```rust
110// before:
111struct Foo {
112 <|>x: i32
113}
114// after:
115#[derive(<|>)]
116struct Foo {
117 x: i32
118}
119```
120
121- Add `impl`
122
123```rust
124// before:
125struct Foo<'a, T: Debug> {
126 <|>t: T
127}
128// after:
129struct Foo<'a, T: Debug> {
130 t: T
131}
132
133impl<'a, T: Debug> Foo<'a, T> {
134 <|>
135}
136```
137
138- Add missing `impl` members
139
140```rust
141// before:
142trait Foo {
143 fn foo(&self);
144 fn bar(&self);
145 fn baz(&self);
146}
147
148struct S;
149
150impl Foo for S {
151 fn bar(&self) {}
152 <|>
153}
154
155// after:
156trait Foo {
157 fn foo(&self);
158 fn bar(&self);
159 fn baz(&self);
160}
161
162struct S;
163
164impl Foo for S {
165 fn bar(&self) {}
166 fn foo(&self) { unimplemented!() }
167 fn baz(&self) { unimplemented!() }<|>
168}
169```
170
171- Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws)
172
173```rust
174// before:
175fn example(x: bool) -> bool {
176 !x || !x
177}
178
179// after:
180fn example(x: bool) -> bool {
181 !(x && x)
182}
183```
184
185- Import path 107- Import path
186 108
187```rust 109```rust
@@ -391,19 +313,6 @@ fn foo() {
391} 313}
392``` 314```
393 315
394- Add explicit type
395
396```rust
397// before:
398fn foo() {
399 let t<|> = (&2, Some(1));
400}
401// after:
402fn foo() {
403 let t<|>: (&i32, Option<i32>) = (&2, Some(1));
404}
405```
406
407- Move guard expression to match arm body 316- Move guard expression to match arm body
408```rust 317```rust
409// before: 318// before:
diff --git a/xtask/src/codegen.rs b/xtask/src/codegen.rs
index 44729cd57..4ec8ab75a 100644
--- a/xtask/src/codegen.rs
+++ b/xtask/src/codegen.rs
@@ -74,6 +74,14 @@ fn reformat(text: impl std::fmt::Display) -> Result<String> {
74} 74}
75 75
76fn extract_comment_blocks(text: &str) -> Vec<Vec<String>> { 76fn extract_comment_blocks(text: &str) -> Vec<Vec<String>> {
77 do_extract_comment_blocks(text, false)
78}
79
80fn extract_comment_blocks_with_empty_lines(text: &str) -> Vec<Vec<String>> {
81 do_extract_comment_blocks(text, true)
82}
83
84fn do_extract_comment_blocks(text: &str, allow_blocks_with_empty_lins: bool) -> Vec<Vec<String>> {
77 let mut res = Vec::new(); 85 let mut res = Vec::new();
78 86
79 let prefix = "// "; 87 let prefix = "// ";
@@ -81,6 +89,11 @@ fn extract_comment_blocks(text: &str) -> Vec<Vec<String>> {
81 89
82 let mut block = vec![]; 90 let mut block = vec![];
83 for line in lines { 91 for line in lines {
92 if line == "//" && allow_blocks_with_empty_lins {
93 block.push(String::new());
94 continue;
95 }
96
84 let is_comment = line.starts_with(prefix); 97 let is_comment = line.starts_with(prefix);
85 if is_comment { 98 if is_comment {
86 block.push(line[prefix.len()..].to_string()); 99 block.push(line[prefix.len()..].to_string());
diff --git a/xtask/src/codegen/gen_assists_docs.rs b/xtask/src/codegen/gen_assists_docs.rs
index 654ae09d6..e313820d1 100644
--- a/xtask/src/codegen/gen_assists_docs.rs
+++ b/xtask/src/codegen/gen_assists_docs.rs
@@ -1,7 +1,7 @@
1use std::{fs, path::Path}; 1use std::{fs, path::Path};
2 2
3use crate::{ 3use crate::{
4 codegen::{self, extract_comment_blocks, Mode}, 4 codegen::{self, extract_comment_blocks_with_empty_lines, Mode},
5 project_root, Result, 5 project_root, Result,
6}; 6};
7 7
@@ -34,7 +34,7 @@ fn collect_assists() -> Result<Vec<Assist>> {
34 34
35 fn collect_file(acc: &mut Vec<Assist>, path: &Path) -> Result<()> { 35 fn collect_file(acc: &mut Vec<Assist>, path: &Path) -> Result<()> {
36 let text = fs::read_to_string(path)?; 36 let text = fs::read_to_string(path)?;
37 let comment_blocks = extract_comment_blocks(&text); 37 let comment_blocks = extract_comment_blocks_with_empty_lines(&text);
38 38
39 for block in comment_blocks { 39 for block in comment_blocks {
40 // FIXME: doesn't support blank lines yet, need to tweak 40 // FIXME: doesn't support blank lines yet, need to tweak
@@ -45,7 +45,11 @@ fn collect_assists() -> Result<Vec<Assist>> {
45 continue; 45 continue;
46 } 46 }
47 let id = first_line["Assist: ".len()..].to_string(); 47 let id = first_line["Assist: ".len()..].to_string();
48 assert!(id.chars().all(|it| it.is_ascii_lowercase() || it == '_')); 48 assert!(
49 id.chars().all(|it| it.is_ascii_lowercase() || it == '_'),
50 "invalid assist id: {:?}",
51 id
52 );
49 53
50 let doc = take_until(lines.by_ref(), "```"); 54 let doc = take_until(lines.by_ref(), "```");
51 let before = take_until(lines.by_ref(), "```"); 55 let before = take_until(lines.by_ref(), "```");