diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_assists/src/ast_transform.rs | 2 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/fill_match_arms.rs | 50 | ||||
-rw-r--r-- | crates/ra_hir_def/src/path.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/_match.rs | 255 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/completion_context.rs | 1 | ||||
-rw-r--r-- | crates/ra_ide/src/snapshots/highlighting.html | 8 | ||||
-rw-r--r-- | crates/ra_ide/src/syntax_highlighting.rs | 37 | ||||
-rw-r--r-- | crates/ra_ide/src/syntax_highlighting/tests.rs | 8 | ||||
-rw-r--r-- | crates/ra_parser/src/grammar/expressions.rs | 6 | ||||
-rw-r--r-- | crates/ra_syntax/src/lib.rs | 3 | ||||
-rw-r--r-- | crates/ra_syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rast | 1 | ||||
-rw-r--r-- | crates/test_utils/src/lib.rs | 12 |
12 files changed, 240 insertions, 145 deletions
diff --git a/crates/ra_assists/src/ast_transform.rs b/crates/ra_assists/src/ast_transform.rs index 3079a02a2..00fa95b6c 100644 --- a/crates/ra_assists/src/ast_transform.rs +++ b/crates/ra_assists/src/ast_transform.rs | |||
@@ -106,6 +106,7 @@ impl<'a> SubstituteTypeParams<'a> { | |||
106 | _ => return None, | 106 | _ => return None, |
107 | }; | 107 | }; |
108 | // FIXME: use `hir::Path::from_src` instead. | 108 | // FIXME: use `hir::Path::from_src` instead. |
109 | #[allow(deprecated)] | ||
109 | let path = hir::Path::from_ast(path)?; | 110 | let path = hir::Path::from_ast(path)?; |
110 | let resolution = self.source_scope.resolve_hir_path(&path)?; | 111 | let resolution = self.source_scope.resolve_hir_path(&path)?; |
111 | match resolution { | 112 | match resolution { |
@@ -150,6 +151,7 @@ impl<'a> QualifyPaths<'a> { | |||
150 | return None; | 151 | return None; |
151 | } | 152 | } |
152 | // FIXME: use `hir::Path::from_src` instead. | 153 | // FIXME: use `hir::Path::from_src` instead. |
154 | #[allow(deprecated)] | ||
153 | let hir_path = hir::Path::from_ast(p.clone()); | 155 | let hir_path = hir::Path::from_ast(p.clone()); |
154 | let resolution = self.source_scope.resolve_hir_path(&hir_path?)?; | 156 | let resolution = self.source_scope.resolve_hir_path(&hir_path?)?; |
155 | match resolution { | 157 | match resolution { |
diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs index cc303285b..569efb768 100644 --- a/crates/ra_assists/src/handlers/fill_match_arms.rs +++ b/crates/ra_assists/src/handlers/fill_match_arms.rs | |||
@@ -136,8 +136,20 @@ fn is_variant_missing(existing_arms: &mut Vec<MatchArm>, var: &Pat) -> bool { | |||
136 | } | 136 | } |
137 | 137 | ||
138 | fn does_pat_match_variant(pat: &Pat, var: &Pat) -> bool { | 138 | fn does_pat_match_variant(pat: &Pat, var: &Pat) -> bool { |
139 | let pat_head = pat.syntax().first_child().map(|node| node.text()); | 139 | let first_node_text = |pat: &Pat| pat.syntax().first_child().map(|node| node.text()); |
140 | let var_head = var.syntax().first_child().map(|node| node.text()); | 140 | |
141 | let pat_head = match pat { | ||
142 | Pat::BindPat(bind_pat) => { | ||
143 | if let Some(p) = bind_pat.pat() { | ||
144 | first_node_text(&p) | ||
145 | } else { | ||
146 | return false; | ||
147 | } | ||
148 | } | ||
149 | pat => first_node_text(pat), | ||
150 | }; | ||
151 | |||
152 | let var_head = first_node_text(var); | ||
141 | 153 | ||
142 | pat_head == var_head | 154 | pat_head == var_head |
143 | } | 155 | } |
@@ -351,6 +363,40 @@ mod tests { | |||
351 | } | 363 | } |
352 | 364 | ||
353 | #[test] | 365 | #[test] |
366 | fn partial_fill_bind_pat() { | ||
367 | check_assist( | ||
368 | fill_match_arms, | ||
369 | r#" | ||
370 | enum A { | ||
371 | As, | ||
372 | Bs, | ||
373 | Cs(Option<i32>), | ||
374 | } | ||
375 | fn main() { | ||
376 | match A::As<|> { | ||
377 | A::As(_) => {} | ||
378 | a @ A::Bs(_) => {} | ||
379 | } | ||
380 | } | ||
381 | "#, | ||
382 | r#" | ||
383 | enum A { | ||
384 | As, | ||
385 | Bs, | ||
386 | Cs(Option<i32>), | ||
387 | } | ||
388 | fn main() { | ||
389 | match A::As { | ||
390 | A::As(_) => {} | ||
391 | a @ A::Bs(_) => {} | ||
392 | $0A::Cs(_) => {} | ||
393 | } | ||
394 | } | ||
395 | "#, | ||
396 | ); | ||
397 | } | ||
398 | |||
399 | #[test] | ||
354 | fn fill_match_arms_empty_body() { | 400 | fn fill_match_arms_empty_body() { |
355 | check_assist( | 401 | check_assist( |
356 | fill_match_arms, | 402 | fill_match_arms, |
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index ba16442bd..190d6d98d 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs | |||
@@ -154,7 +154,7 @@ pub enum GenericArg { | |||
154 | 154 | ||
155 | impl Path { | 155 | impl Path { |
156 | /// Converts an `ast::Path` to `Path`. Works with use trees. | 156 | /// Converts an `ast::Path` to `Path`. Works with use trees. |
157 | /// DEPRECATED: It does not handle `$crate` from macro call. | 157 | #[deprecated = "Doesn't handle hygiene, don't add new calls, remove old ones"] |
158 | pub fn from_ast(path: ast::Path) -> Option<Path> { | 158 | pub fn from_ast(path: ast::Path) -> Option<Path> { |
159 | lower::lower_path(path, &Hygiene::new_unhygienic()) | 159 | lower::lower_path(path, &Hygiene::new_unhygienic()) |
160 | } | 160 | } |
diff --git a/crates/ra_hir_ty/src/_match.rs b/crates/ra_hir_ty/src/_match.rs index 3e6e1e333..fff257193 100644 --- a/crates/ra_hir_ty/src/_match.rs +++ b/crates/ra_hir_ty/src/_match.rs | |||
@@ -8,11 +8,11 @@ | |||
8 | //! This file includes the logic for exhaustiveness and usefulness checking for | 8 | //! This file includes the logic for exhaustiveness and usefulness checking for |
9 | //! pattern-matching. Specifically, given a list of patterns for a type, we can | 9 | //! pattern-matching. Specifically, given a list of patterns for a type, we can |
10 | //! tell whether: | 10 | //! tell whether: |
11 | //! (a) the patterns cover every possible constructor for the type [exhaustiveness] | 11 | //! - (a) the patterns cover every possible constructor for the type (exhaustiveness). |
12 | //! (b) each pattern is necessary [usefulness] | 12 | //! - (b) each pattern is necessary (usefulness). |
13 | //! | 13 | //! |
14 | //! The algorithm implemented here is a modified version of the one described in: | 14 | //! The algorithm implemented here is a modified version of the one described in |
15 | //! http://moscova.inria.fr/~maranget/papers/warn/index.html | 15 | //! <http://moscova.inria.fr/~maranget/papers/warn/index.html>. |
16 | //! However, to save future implementors from reading the original paper, we | 16 | //! However, to save future implementors from reading the original paper, we |
17 | //! summarise the algorithm here to hopefully save time and be a little clearer | 17 | //! summarise the algorithm here to hopefully save time and be a little clearer |
18 | //! (without being so rigorous). | 18 | //! (without being so rigorous). |
@@ -37,20 +37,26 @@ | |||
37 | //! new pattern `p`. | 37 | //! new pattern `p`. |
38 | //! | 38 | //! |
39 | //! For example, say we have the following: | 39 | //! For example, say we have the following: |
40 | //! | ||
41 | //! ```ignore | ||
42 | //! // x: (Option<bool>, Result<()>) | ||
43 | //! match x { | ||
44 | //! (Some(true), _) => {} | ||
45 | //! (None, Err(())) => {} | ||
46 | //! (None, Err(_)) => {} | ||
47 | //! } | ||
40 | //! ``` | 48 | //! ``` |
41 | //! // x: (Option<bool>, Result<()>) | 49 | //! |
42 | //! match x { | ||
43 | //! (Some(true), _) => {} | ||
44 | //! (None, Err(())) => {} | ||
45 | //! (None, Err(_)) => {} | ||
46 | //! } | ||
47 | //! ``` | ||
48 | //! Here, the matrix `P` starts as: | 50 | //! Here, the matrix `P` starts as: |
51 | //! | ||
52 | //! ```text | ||
49 | //! [ | 53 | //! [ |
50 | //! [(Some(true), _)], | 54 | //! [(Some(true), _)], |
51 | //! [(None, Err(()))], | 55 | //! [(None, Err(()))], |
52 | //! [(None, Err(_))], | 56 | //! [(None, Err(_))], |
53 | //! ] | 57 | //! ] |
58 | //! ``` | ||
59 | //! | ||
54 | //! We can tell it's not exhaustive, because `U(P, _)` is true (we're not covering | 60 | //! We can tell it's not exhaustive, because `U(P, _)` is true (we're not covering |
55 | //! `[(Some(false), _)]`, for instance). In addition, row 3 is not useful, because | 61 | //! `[(Some(false), _)]`, for instance). In addition, row 3 is not useful, because |
56 | //! all the values it covers are already covered by row 2. | 62 | //! all the values it covers are already covered by row 2. |
@@ -60,53 +66,61 @@ | |||
60 | //! To match the paper, the top of the stack is at the beginning / on the left. | 66 | //! To match the paper, the top of the stack is at the beginning / on the left. |
61 | //! | 67 | //! |
62 | //! There are two important operations on pattern-stacks necessary to understand the algorithm: | 68 | //! There are two important operations on pattern-stacks necessary to understand the algorithm: |
63 | //! 1. We can pop a given constructor off the top of a stack. This operation is called | ||
64 | //! `specialize`, and is denoted `S(c, p)` where `c` is a constructor (like `Some` or | ||
65 | //! `None`) and `p` a pattern-stack. | ||
66 | //! If the pattern on top of the stack can cover `c`, this removes the constructor and | ||
67 | //! pushes its arguments onto the stack. It also expands OR-patterns into distinct patterns. | ||
68 | //! Otherwise the pattern-stack is discarded. | ||
69 | //! This essentially filters those pattern-stacks whose top covers the constructor `c` and | ||
70 | //! discards the others. | ||
71 | //! | 69 | //! |
72 | //! For example, the first pattern above initially gives a stack `[(Some(true), _)]`. If we | 70 | //! 1. We can pop a given constructor off the top of a stack. This operation is called |
73 | //! pop the tuple constructor, we are left with `[Some(true), _]`, and if we then pop the | 71 | //! `specialize`, and is denoted `S(c, p)` where `c` is a constructor (like `Some` or |
74 | //! `Some` constructor we get `[true, _]`. If we had popped `None` instead, we would get | 72 | //! `None`) and `p` a pattern-stack. |
75 | //! nothing back. | 73 | //! If the pattern on top of the stack can cover `c`, this removes the constructor and |
74 | //! pushes its arguments onto the stack. It also expands OR-patterns into distinct patterns. | ||
75 | //! Otherwise the pattern-stack is discarded. | ||
76 | //! This essentially filters those pattern-stacks whose top covers the constructor `c` and | ||
77 | //! discards the others. | ||
78 | //! | ||
79 | //! For example, the first pattern above initially gives a stack `[(Some(true), _)]`. If we | ||
80 | //! pop the tuple constructor, we are left with `[Some(true), _]`, and if we then pop the | ||
81 | //! `Some` constructor we get `[true, _]`. If we had popped `None` instead, we would get | ||
82 | //! nothing back. | ||
83 | //! | ||
84 | //! This returns zero or more new pattern-stacks, as follows. We look at the pattern `p_1` | ||
85 | //! on top of the stack, and we have four cases: | ||
86 | //! | ||
87 | //! * 1.1. `p_1 = c(r_1, .., r_a)`, i.e. the top of the stack has constructor `c`. We push onto | ||
88 | //! the stack the arguments of this constructor, and return the result: | ||
89 | //! | ||
90 | //! r_1, .., r_a, p_2, .., p_n | ||
91 | //! | ||
92 | //! * 1.2. `p_1 = c'(r_1, .., r_a')` where `c ≠c'`. We discard the current stack and return | ||
93 | //! nothing. | ||
94 | //! * 1.3. `p_1 = _`. We push onto the stack as many wildcards as the constructor `c` has | ||
95 | //! arguments (its arity), and return the resulting stack: | ||
76 | //! | 96 | //! |
77 | //! This returns zero or more new pattern-stacks, as follows. We look at the pattern `p_1` | 97 | //! _, .., _, p_2, .., p_n |
78 | //! on top of the stack, and we have four cases: | ||
79 | //! 1.1. `p_1 = c(r_1, .., r_a)`, i.e. the top of the stack has constructor `c`. We | ||
80 | //! push onto the stack the arguments of this constructor, and return the result: | ||
81 | //! r_1, .., r_a, p_2, .., p_n | ||
82 | //! 1.2. `p_1 = c'(r_1, .., r_a')` where `c ≠c'`. We discard the current stack and | ||
83 | //! return nothing. | ||
84 | //! 1.3. `p_1 = _`. We push onto the stack as many wildcards as the constructor `c` has | ||
85 | //! arguments (its arity), and return the resulting stack: | ||
86 | //! _, .., _, p_2, .., p_n | ||
87 | //! 1.4. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting | ||
88 | //! stack: | ||
89 | //! S(c, (r_1, p_2, .., p_n)) | ||
90 | //! S(c, (r_2, p_2, .., p_n)) | ||
91 | //! | 98 | //! |
92 | //! 2. We can pop a wildcard off the top of the stack. This is called `D(p)`, where `p` is | 99 | //! * 1.4. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting stack: |
93 | //! a pattern-stack. | ||
94 | //! This is used when we know there are missing constructor cases, but there might be | ||
95 | //! existing wildcard patterns, so to check the usefulness of the matrix, we have to check | ||
96 | //! all its *other* components. | ||
97 | //! | 100 | //! |
98 | //! It is computed as follows. We look at the pattern `p_1` on top of the stack, | 101 | //! S(c, (r_1, p_2, .., p_n)) |
99 | //! and we have three cases: | 102 | //! S(c, (r_2, p_2, .., p_n)) |
100 | //! 1.1. `p_1 = c(r_1, .., r_a)`. We discard the current stack and return nothing. | ||
101 | //! 1.2. `p_1 = _`. We return the rest of the stack: | ||
102 | //! p_2, .., p_n | ||
103 | //! 1.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting | ||
104 | //! stack. | ||
105 | //! D((r_1, p_2, .., p_n)) | ||
106 | //! D((r_2, p_2, .., p_n)) | ||
107 | //! | 103 | //! |
108 | //! Note that the OR-patterns are not always used directly in Rust, but are used to derive the | 104 | //! 2. We can pop a wildcard off the top of the stack. This is called `D(p)`, where `p` is |
109 | //! exhaustive integer matching rules, so they're written here for posterity. | 105 | //! a pattern-stack. |
106 | //! This is used when we know there are missing constructor cases, but there might be | ||
107 | //! existing wildcard patterns, so to check the usefulness of the matrix, we have to check | ||
108 | //! all its *other* components. | ||
109 | //! | ||
110 | //! It is computed as follows. We look at the pattern `p_1` on top of the stack, | ||
111 | //! and we have three cases: | ||
112 | //! * 1.1. `p_1 = c(r_1, .., r_a)`. We discard the current stack and return nothing. | ||
113 | //! * 1.2. `p_1 = _`. We return the rest of the stack: | ||
114 | //! | ||
115 | //! p_2, .., p_n | ||
116 | //! | ||
117 | //! * 1.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting stack: | ||
118 | //! | ||
119 | //! D((r_1, p_2, .., p_n)) | ||
120 | //! D((r_2, p_2, .., p_n)) | ||
121 | //! | ||
122 | //! Note that the OR-patterns are not always used directly in Rust, but are used to derive the | ||
123 | //! exhaustive integer matching rules, so they're written here for posterity. | ||
110 | //! | 124 | //! |
111 | //! Both those operations extend straightforwardly to a list or pattern-stacks, i.e. a matrix, by | 125 | //! Both those operations extend straightforwardly to a list or pattern-stacks, i.e. a matrix, by |
112 | //! working row-by-row. Popping a constructor ends up keeping only the matrix rows that start with | 126 | //! working row-by-row. Popping a constructor ends up keeping only the matrix rows that start with |
@@ -120,73 +134,88 @@ | |||
120 | //! operates principally on the first component of the matrix and new pattern-stack `p`. | 134 | //! operates principally on the first component of the matrix and new pattern-stack `p`. |
121 | //! This algorithm is realised in the `is_useful` function. | 135 | //! This algorithm is realised in the `is_useful` function. |
122 | //! | 136 | //! |
123 | //! Base case. (`n = 0`, i.e., an empty tuple pattern) | 137 | //! Base case (`n = 0`, i.e., an empty tuple pattern): |
124 | //! - If `P` already contains an empty pattern (i.e., if the number of patterns `m > 0`), | 138 | //! - If `P` already contains an empty pattern (i.e., if the number of patterns `m > 0`), then |
125 | //! then `U(P, p)` is false. | 139 | //! `U(P, p)` is false. |
126 | //! - Otherwise, `P` must be empty, so `U(P, p)` is true. | 140 | //! - Otherwise, `P` must be empty, so `U(P, p)` is true. |
141 | //! | ||
142 | //! Inductive step (`n > 0`, i.e., whether there's at least one column [which may then be expanded | ||
143 | //! into further columns later]). We're going to match on the top of the new pattern-stack, `p_1`: | ||
144 | //! | ||
145 | //! - If `p_1 == c(r_1, .., r_a)`, i.e. we have a constructor pattern. | ||
146 | //! Then, the usefulness of `p_1` can be reduced to whether it is useful when | ||
147 | //! we ignore all the patterns in the first column of `P` that involve other constructors. | ||
148 | //! This is where `S(c, P)` comes in: | ||
149 | //! | ||
150 | //! ```text | ||
151 | //! U(P, p) := U(S(c, P), S(c, p)) | ||
152 | //! ``` | ||
153 | //! | ||
154 | //! This special case is handled in `is_useful_specialized`. | ||
155 | //! | ||
156 | //! For example, if `P` is: | ||
157 | //! | ||
158 | //! ```text | ||
159 | //! [ | ||
160 | //! [Some(true), _], | ||
161 | //! [None, 0], | ||
162 | //! ] | ||
163 | //! ``` | ||
127 | //! | 164 | //! |
128 | //! Inductive step. (`n > 0`, i.e., whether there's at least one column | 165 | //! and `p` is `[Some(false), 0]`, then we don't care about row 2 since we know `p` only |
129 | //! [which may then be expanded into further columns later]) | 166 | //! matches values that row 2 doesn't. For row 1 however, we need to dig into the |
130 | //! We're going to match on the top of the new pattern-stack, `p_1`. | 167 | //! arguments of `Some` to know whether some new value is covered. So we compute |
131 | //! - If `p_1 == c(r_1, .., r_a)`, i.e. we have a constructor pattern. | 168 | //! `U([[true, _]], [false, 0])`. |
132 | //! Then, the usefulness of `p_1` can be reduced to whether it is useful when | ||
133 | //! we ignore all the patterns in the first column of `P` that involve other constructors. | ||
134 | //! This is where `S(c, P)` comes in: | ||
135 | //! `U(P, p) := U(S(c, P), S(c, p))` | ||
136 | //! This special case is handled in `is_useful_specialized`. | ||
137 | //! | 169 | //! |
138 | //! For example, if `P` is: | 170 | //! - If `p_1 == _`, then we look at the list of constructors that appear in the first component of |
139 | //! [ | 171 | //! the rows of `P`: |
140 | //! [Some(true), _], | 172 | //! - If there are some constructors that aren't present, then we might think that the |
141 | //! [None, 0], | 173 | //! wildcard `_` is useful, since it covers those constructors that weren't covered |
142 | //! ] | 174 | //! before. |
143 | //! and `p` is [Some(false), 0], then we don't care about row 2 since we know `p` only | 175 | //! That's almost correct, but only works if there were no wildcards in those first |
144 | //! matches values that row 2 doesn't. For row 1 however, we need to dig into the | 176 | //! components. So we need to check that `p` is useful with respect to the rows that |
145 | //! arguments of `Some` to know whether some new value is covered. So we compute | 177 | //! start with a wildcard, if there are any. This is where `D` comes in: |
146 | //! `U([[true, _]], [false, 0])`. | 178 | //! `U(P, p) := U(D(P), D(p))` |
147 | //! | 179 | //! |
148 | //! - If `p_1 == _`, then we look at the list of constructors that appear in the first | 180 | //! For example, if `P` is: |
149 | //! component of the rows of `P`: | 181 | //! ```text |
150 | //! + If there are some constructors that aren't present, then we might think that the | 182 | //! [ |
151 | //! wildcard `_` is useful, since it covers those constructors that weren't covered | 183 | //! [_, true, _], |
152 | //! before. | 184 | //! [None, false, 1], |
153 | //! That's almost correct, but only works if there were no wildcards in those first | 185 | //! ] |
154 | //! components. So we need to check that `p` is useful with respect to the rows that | 186 | //! ``` |
155 | //! start with a wildcard, if there are any. This is where `D` comes in: | 187 | //! and `p` is `[_, false, _]`, the `Some` constructor doesn't appear in `P`. So if we |
156 | //! `U(P, p) := U(D(P), D(p))` | 188 | //! only had row 2, we'd know that `p` is useful. However row 1 starts with a |
189 | //! wildcard, so we need to check whether `U([[true, _]], [false, 1])`. | ||
157 | //! | 190 | //! |
158 | //! For example, if `P` is: | 191 | //! - Otherwise, all possible constructors (for the relevant type) are present. In this |
159 | //! [ | 192 | //! case we must check whether the wildcard pattern covers any unmatched value. For |
160 | //! [_, true, _], | 193 | //! that, we can think of the `_` pattern as a big OR-pattern that covers all |
161 | //! [None, false, 1], | 194 | //! possible constructors. For `Option`, that would mean `_ = None | Some(_)` for |
162 | //! ] | 195 | //! example. The wildcard pattern is useful in this case if it is useful when |
163 | //! and `p` is [_, false, _], the `Some` constructor doesn't appear in `P`. So if we | 196 | //! specialized to one of the possible constructors. So we compute: |
164 | //! only had row 2, we'd know that `p` is useful. However row 1 starts with a | 197 | //! `U(P, p) := ∃(k ϵ constructors) U(S(k, P), S(k, p))` |
165 | //! wildcard, so we need to check whether `U([[true, _]], [false, 1])`. | ||
166 | //! | 198 | //! |
167 | //! + Otherwise, all possible constructors (for the relevant type) are present. In this | 199 | //! For example, if `P` is: |
168 | //! case we must check whether the wildcard pattern covers any unmatched value. For | 200 | //! ```text |
169 | //! that, we can think of the `_` pattern as a big OR-pattern that covers all | 201 | //! [ |
170 | //! possible constructors. For `Option`, that would mean `_ = None | Some(_)` for | 202 | //! [Some(true), _], |
171 | //! example. The wildcard pattern is useful in this case if it is useful when | 203 | //! [None, false], |
172 | //! specialized to one of the possible constructors. So we compute: | 204 | //! ] |
173 | //! `U(P, p) := ∃(k ϵ constructors) U(S(k, P), S(k, p))` | 205 | //! ``` |
206 | //! and `p` is `[_, false]`, both `None` and `Some` constructors appear in the first | ||
207 | //! components of `P`. We will therefore try popping both constructors in turn: we | ||
208 | //! compute `U([[true, _]], [_, false])` for the `Some` constructor, and `U([[false]], | ||
209 | //! [false])` for the `None` constructor. The first case returns true, so we know that | ||
210 | //! `p` is useful for `P`. Indeed, it matches `[Some(false), _]` that wasn't matched | ||
211 | //! before. | ||
174 | //! | 212 | //! |
175 | //! For example, if `P` is: | 213 | //! - If `p_1 == r_1 | r_2`, then the usefulness depends on each `r_i` separately: |
176 | //! [ | ||
177 | //! [Some(true), _], | ||
178 | //! [None, false], | ||
179 | //! ] | ||
180 | //! and `p` is [_, false], both `None` and `Some` constructors appear in the first | ||
181 | //! components of `P`. We will therefore try popping both constructors in turn: we | ||
182 | //! compute U([[true, _]], [_, false]) for the `Some` constructor, and U([[false]], | ||
183 | //! [false]) for the `None` constructor. The first case returns true, so we know that | ||
184 | //! `p` is useful for `P`. Indeed, it matches `[Some(false), _]` that wasn't matched | ||
185 | //! before. | ||
186 | //! | 214 | //! |
187 | //! - If `p_1 == r_1 | r_2`, then the usefulness depends on each `r_i` separately: | 215 | //! ```text |
188 | //! `U(P, p) := U(P, (r_1, p_2, .., p_n)) | 216 | //! U(P, p) := U(P, (r_1, p_2, .., p_n)) |
189 | //! || U(P, (r_2, p_2, .., p_n))` | 217 | //! || U(P, (r_2, p_2, .., p_n)) |
218 | //! ``` | ||
190 | use std::sync::Arc; | 219 | use std::sync::Arc; |
191 | 220 | ||
192 | use smallvec::{smallvec, SmallVec}; | 221 | use smallvec::{smallvec, SmallVec}; |
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs index 9f4c582d0..560fb19e6 100644 --- a/crates/ra_ide/src/completion/completion_context.rs +++ b/crates/ra_ide/src/completion/completion_context.rs | |||
@@ -381,6 +381,7 @@ impl<'a> CompletionContext<'a> { | |||
381 | self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some(); | 381 | self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some(); |
382 | self.has_type_args = segment.type_arg_list().is_some(); | 382 | self.has_type_args = segment.type_arg_list().is_some(); |
383 | 383 | ||
384 | #[allow(deprecated)] | ||
384 | if let Some(path) = hir::Path::from_ast(path.clone()) { | 385 | if let Some(path) = hir::Path::from_ast(path.clone()) { |
385 | if let Some(path_prefix) = path.qualifier() { | 386 | if let Some(path_prefix) = path.qualifier() { |
386 | self.path_prefix = Some(path_prefix); | 387 | self.path_prefix = Some(path_prefix); |
diff --git a/crates/ra_ide/src/snapshots/highlighting.html b/crates/ra_ide/src/snapshots/highlighting.html index 33548d43c..5c2ff6ab5 100644 --- a/crates/ra_ide/src/snapshots/highlighting.html +++ b/crates/ra_ide/src/snapshots/highlighting.html | |||
@@ -62,6 +62,12 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
62 | } | 62 | } |
63 | } | 63 | } |
64 | 64 | ||
65 | <span class="macro">macro_rules!</span> <span class="macro declaration">noop</span> { | ||
66 | ($expr:expr) => { | ||
67 | $expr | ||
68 | } | ||
69 | } | ||
70 | |||
65 | <span class="comment">// comment</span> | 71 | <span class="comment">// comment</span> |
66 | <span class="keyword">fn</span> <span class="function declaration">main</span>() { | 72 | <span class="keyword">fn</span> <span class="function declaration">main</span>() { |
67 | <span class="macro">println!</span>(<span class="string_literal">"Hello, {}!"</span>, <span class="numeric_literal">92</span>); | 73 | <span class="macro">println!</span>(<span class="string_literal">"Hello, {}!"</span>, <span class="numeric_literal">92</span>); |
@@ -80,6 +86,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
80 | <span class="comment">// Do nothing</span> | 86 | <span class="comment">// Do nothing</span> |
81 | } | 87 | } |
82 | 88 | ||
89 | <span class="macro">noop!</span>(<span class="macro">noop</span><span class="macro">!</span>(<span class="numeric_literal">1</span>)); | ||
90 | |||
83 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">x</span> = <span class="numeric_literal">42</span>; | 91 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">x</span> = <span class="numeric_literal">42</span>; |
84 | <span class="keyword">let</span> <span class="variable declaration mutable">y</span> = &<span class="keyword">mut</span> <span class="variable mutable">x</span>; | 92 | <span class="keyword">let</span> <span class="variable declaration mutable">y</span> = &<span class="keyword">mut</span> <span class="variable mutable">x</span>; |
85 | <span class="keyword">let</span> <span class="variable declaration">z</span> = &<span class="variable mutable">y</span>; | 93 | <span class="keyword">let</span> <span class="variable declaration">z</span> = &<span class="variable mutable">y</span>; |
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index ab45c364a..bbcd52a1c 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs | |||
@@ -160,23 +160,25 @@ pub(crate) fn highlight( | |||
160 | // Check if macro takes a format string and remember it for highlighting later. | 160 | // Check if macro takes a format string and remember it for highlighting later. |
161 | // The macros that accept a format string expand to a compiler builtin macros | 161 | // The macros that accept a format string expand to a compiler builtin macros |
162 | // `format_args` and `format_args_nl`. | 162 | // `format_args` and `format_args_nl`. |
163 | if let Some(fmt_macro_call) = parent.parent().and_then(ast::MacroCall::cast) { | 163 | if let Some(name) = parent |
164 | if let Some(name) = | 164 | .parent() |
165 | fmt_macro_call.path().and_then(|p| p.segment()).and_then(|s| s.name_ref()) | 165 | .and_then(ast::MacroCall::cast) |
166 | { | 166 | .and_then(|mc| mc.path()) |
167 | match name.text().as_str() { | 167 | .and_then(|p| p.segment()) |
168 | "format_args" | "format_args_nl" => { | 168 | .and_then(|s| s.name_ref()) |
169 | format_string = parent | 169 | { |
170 | .children_with_tokens() | 170 | match name.text().as_str() { |
171 | .filter(|t| t.kind() != WHITESPACE) | 171 | "format_args" | "format_args_nl" => { |
172 | .nth(1) | 172 | format_string = parent |
173 | .filter(|e| { | 173 | .children_with_tokens() |
174 | ast::String::can_cast(e.kind()) | 174 | .filter(|t| t.kind() != WHITESPACE) |
175 | || ast::RawString::can_cast(e.kind()) | 175 | .nth(1) |
176 | }) | 176 | .filter(|e| { |
177 | } | 177 | ast::String::can_cast(e.kind()) |
178 | _ => {} | 178 | || ast::RawString::can_cast(e.kind()) |
179 | }) | ||
179 | } | 180 | } |
181 | _ => {} | ||
180 | } | 182 | } |
181 | } | 183 | } |
182 | 184 | ||
@@ -493,6 +495,9 @@ fn highlight_element( | |||
493 | h |= HighlightModifier::Unsafe; | 495 | h |= HighlightModifier::Unsafe; |
494 | h | 496 | h |
495 | } | 497 | } |
498 | T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => { | ||
499 | Highlight::new(HighlightTag::Macro) | ||
500 | } | ||
496 | 501 | ||
497 | k if k.is_keyword() => { | 502 | k if k.is_keyword() => { |
498 | let h = Highlight::new(HighlightTag::Keyword); | 503 | let h = Highlight::new(HighlightTag::Keyword); |
diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs index 949bf59a0..070b24f45 100644 --- a/crates/ra_ide/src/syntax_highlighting/tests.rs +++ b/crates/ra_ide/src/syntax_highlighting/tests.rs | |||
@@ -43,6 +43,12 @@ def_fn! { | |||
43 | } | 43 | } |
44 | } | 44 | } |
45 | 45 | ||
46 | macro_rules! noop { | ||
47 | ($expr:expr) => { | ||
48 | $expr | ||
49 | } | ||
50 | } | ||
51 | |||
46 | // comment | 52 | // comment |
47 | fn main() { | 53 | fn main() { |
48 | println!("Hello, {}!", 92); | 54 | println!("Hello, {}!", 92); |
@@ -61,6 +67,8 @@ fn main() { | |||
61 | // Do nothing | 67 | // Do nothing |
62 | } | 68 | } |
63 | 69 | ||
70 | noop!(noop!(1)); | ||
71 | |||
64 | let mut x = 42; | 72 | let mut x = 42; |
65 | let y = &mut x; | 73 | let y = &mut x; |
66 | let z = &y; | 74 | let z = &y; |
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs index d6e8df32a..6e72eea66 100644 --- a/crates/ra_parser/src/grammar/expressions.rs +++ b/crates/ra_parser/src/grammar/expressions.rs | |||
@@ -50,10 +50,8 @@ fn expr_no_struct(p: &mut Parser) { | |||
50 | } | 50 | } |
51 | 51 | ||
52 | fn is_expr_stmt_attr_allowed(kind: SyntaxKind) -> bool { | 52 | fn is_expr_stmt_attr_allowed(kind: SyntaxKind) -> bool { |
53 | match kind { | 53 | let forbid = matches!(kind, BIN_EXPR | RANGE_EXPR); |
54 | BIN_EXPR | RANGE_EXPR | IF_EXPR => false, | 54 | !forbid |
55 | _ => true, | ||
56 | } | ||
57 | } | 55 | } |
58 | 56 | ||
59 | pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi) { | 57 | pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi) { |
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs index 61e686da5..a33a35cc1 100644 --- a/crates/ra_syntax/src/lib.rs +++ b/crates/ra_syntax/src/lib.rs | |||
@@ -51,7 +51,8 @@ pub use crate::{ | |||
51 | ptr::{AstPtr, SyntaxNodePtr}, | 51 | ptr::{AstPtr, SyntaxNodePtr}, |
52 | syntax_error::SyntaxError, | 52 | syntax_error::SyntaxError, |
53 | syntax_node::{ | 53 | syntax_node::{ |
54 | Direction, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxToken, SyntaxTreeBuilder, | 54 | Direction, NodeOrToken, SyntaxElement, SyntaxElementChildren, SyntaxNode, |
55 | SyntaxNodeChildren, SyntaxToken, SyntaxTreeBuilder, | ||
55 | }, | 56 | }, |
56 | }; | 57 | }; |
57 | pub use ra_parser::{SyntaxKind, T}; | 58 | pub use ra_parser::{SyntaxKind, T}; |
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rast b/crates/ra_syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rast index 0656fdf73..4e3fa704e 100644 --- a/crates/ra_syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rast +++ b/crates/ra_syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rast | |||
@@ -56,4 +56,3 @@ [email protected] | |||
56 | [email protected] "}" | 56 | [email protected] "}" |
57 | [email protected] "\n" | 57 | [email protected] "\n" |
58 | error 24..24: attributes are not allowed on BIN_EXPR | 58 | error 24..24: attributes are not allowed on BIN_EXPR |
59 | error 44..44: attributes are not allowed on IF_EXPR | ||
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index 2141bfc20..981565cd7 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs | |||
@@ -10,17 +10,17 @@ | |||
10 | pub mod mark; | 10 | pub mod mark; |
11 | 11 | ||
12 | use std::{ | 12 | use std::{ |
13 | fs, | 13 | env, fs, |
14 | path::{Path, PathBuf}, | 14 | path::{Path, PathBuf}, |
15 | }; | 15 | }; |
16 | 16 | ||
17 | pub use ra_cfg::CfgOptions; | 17 | use serde_json::Value; |
18 | use stdx::split1; | 18 | use stdx::split1; |
19 | use text_size::{TextRange, TextSize}; | ||
19 | 20 | ||
21 | pub use ra_cfg::CfgOptions; | ||
20 | pub use relative_path::{RelativePath, RelativePathBuf}; | 22 | pub use relative_path::{RelativePath, RelativePathBuf}; |
21 | pub use rustc_hash::FxHashMap; | 23 | pub use rustc_hash::FxHashMap; |
22 | use serde_json::Value; | ||
23 | use text_size::{TextRange, TextSize}; | ||
24 | 24 | ||
25 | pub use difference::Changeset as __Changeset; | 25 | pub use difference::Changeset as __Changeset; |
26 | 26 | ||
@@ -625,8 +625,6 @@ pub fn skip_slow_tests() -> bool { | |||
625 | should_skip | 625 | should_skip |
626 | } | 626 | } |
627 | 627 | ||
628 | const REWRITE: bool = false; | ||
629 | |||
630 | /// Asserts that `expected` and `actual` strings are equal. If they differ only | 628 | /// Asserts that `expected` and `actual` strings are equal. If they differ only |
631 | /// in trailing or leading whitespace the test won't fail and | 629 | /// in trailing or leading whitespace the test won't fail and |
632 | /// the contents of `actual` will be written to the file located at `path`. | 630 | /// the contents of `actual` will be written to the file located at `path`. |
@@ -642,7 +640,7 @@ fn assert_equal_text(expected: &str, actual: &str, path: &Path) { | |||
642 | fs::write(path, actual).unwrap(); | 640 | fs::write(path, actual).unwrap(); |
643 | return; | 641 | return; |
644 | } | 642 | } |
645 | if REWRITE { | 643 | if env::var("UPDATE_EXPECTATIONS").is_ok() { |
646 | println!("rewriting {}", pretty_path.display()); | 644 | println!("rewriting {}", pretty_path.display()); |
647 | fs::write(path, actual).unwrap(); | 645 | fs::write(path, actual).unwrap(); |
648 | return; | 646 | return; |