diff options
20 files changed, 624 insertions, 113 deletions
diff --git a/crates/ra_hir/src/diagnostics.rs b/crates/ra_hir/src/diagnostics.rs index 301109cb8..475dd5766 100644 --- a/crates/ra_hir/src/diagnostics.rs +++ b/crates/ra_hir/src/diagnostics.rs | |||
@@ -143,3 +143,31 @@ impl AstDiagnostic for MissingFields { | |||
143 | ast::RecordFieldList::cast(node).unwrap() | 143 | ast::RecordFieldList::cast(node).unwrap() |
144 | } | 144 | } |
145 | } | 145 | } |
146 | |||
147 | #[derive(Debug)] | ||
148 | pub struct MissingOkInTailExpr { | ||
149 | pub file: HirFileId, | ||
150 | pub expr: AstPtr<ast::Expr>, | ||
151 | } | ||
152 | |||
153 | impl Diagnostic for MissingOkInTailExpr { | ||
154 | fn message(&self) -> String { | ||
155 | "wrap return expression in Ok".to_string() | ||
156 | } | ||
157 | fn source(&self) -> Source<SyntaxNodePtr> { | ||
158 | Source { file_id: self.file, ast: self.expr.into() } | ||
159 | } | ||
160 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
161 | self | ||
162 | } | ||
163 | } | ||
164 | |||
165 | impl AstDiagnostic for MissingOkInTailExpr { | ||
166 | type AST = ast::Expr; | ||
167 | |||
168 | fn ast(&self, db: &impl HirDatabase) -> Self::AST { | ||
169 | let root = db.parse_or_expand(self.file).unwrap(); | ||
170 | let node = self.source().ast.to_node(&root); | ||
171 | ast::Expr::cast(node).unwrap() | ||
172 | } | ||
173 | } | ||
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 9e8584908..7cdc7555c 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs | |||
@@ -1020,6 +1020,7 @@ where | |||
1020 | } | 1020 | } |
1021 | 1021 | ||
1022 | // FIXME: implement | 1022 | // FIXME: implement |
1023 | ast::Pat::BoxPat(_) => Pat::Missing, | ||
1023 | ast::Pat::LiteralPat(_) => Pat::Missing, | 1024 | ast::Pat::LiteralPat(_) => Pat::Missing, |
1024 | ast::Pat::SlicePat(_) | ast::Pat::RangePat(_) => Pat::Missing, | 1025 | ast::Pat::SlicePat(_) | ast::Pat::RangePat(_) => Pat::Missing, |
1025 | }; | 1026 | }; |
diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs index 62f7d41f5..5d9d59ff8 100644 --- a/crates/ra_hir/src/expr/validation.rs +++ b/crates/ra_hir/src/expr/validation.rs | |||
@@ -6,11 +6,14 @@ use ra_syntax::ast::{AstNode, RecordLit}; | |||
6 | use super::{Expr, ExprId, RecordLitField}; | 6 | use super::{Expr, ExprId, RecordLitField}; |
7 | use crate::{ | 7 | use crate::{ |
8 | adt::AdtDef, | 8 | adt::AdtDef, |
9 | diagnostics::{DiagnosticSink, MissingFields}, | 9 | diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr}, |
10 | expr::AstPtr, | 10 | expr::AstPtr, |
11 | ty::InferenceResult, | 11 | name, |
12 | Function, HasSource, HirDatabase, Name, Path, | 12 | path::{PathKind, PathSegment}, |
13 | ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, | ||
14 | Function, HasSource, HirDatabase, ModuleDef, Name, Path, PerNs, Resolution, | ||
13 | }; | 15 | }; |
16 | use ra_syntax::ast; | ||
14 | 17 | ||
15 | pub(crate) struct ExprValidator<'a, 'b: 'a> { | 18 | pub(crate) struct ExprValidator<'a, 'b: 'a> { |
16 | func: Function, | 19 | func: Function, |
@@ -29,11 +32,17 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
29 | 32 | ||
30 | pub(crate) fn validate_body(&mut self, db: &impl HirDatabase) { | 33 | pub(crate) fn validate_body(&mut self, db: &impl HirDatabase) { |
31 | let body = self.func.body(db); | 34 | let body = self.func.body(db); |
35 | |||
32 | for e in body.exprs() { | 36 | for e in body.exprs() { |
33 | if let (id, Expr::RecordLit { path, fields, spread }) = e { | 37 | if let (id, Expr::RecordLit { path, fields, spread }) = e { |
34 | self.validate_record_literal(id, path, fields, *spread, db); | 38 | self.validate_record_literal(id, path, fields, *spread, db); |
35 | } | 39 | } |
36 | } | 40 | } |
41 | |||
42 | let body_expr = &body[body.body_expr()]; | ||
43 | if let Expr::Block { statements: _, tail: Some(t) } = body_expr { | ||
44 | self.validate_results_in_tail_expr(*t, db); | ||
45 | } | ||
37 | } | 46 | } |
38 | 47 | ||
39 | fn validate_record_literal( | 48 | fn validate_record_literal( |
@@ -87,4 +96,42 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
87 | }) | 96 | }) |
88 | } | 97 | } |
89 | } | 98 | } |
99 | |||
100 | fn validate_results_in_tail_expr(&mut self, id: ExprId, db: &impl HirDatabase) { | ||
101 | let mismatch = match self.infer.type_mismatch_for_expr(id) { | ||
102 | Some(m) => m, | ||
103 | None => return, | ||
104 | }; | ||
105 | |||
106 | let std_result_path = Path { | ||
107 | kind: PathKind::Abs, | ||
108 | segments: vec![ | ||
109 | PathSegment { name: name::STD, args_and_bindings: None }, | ||
110 | PathSegment { name: name::RESULT_MOD, args_and_bindings: None }, | ||
111 | PathSegment { name: name::RESULT_TYPE, args_and_bindings: None }, | ||
112 | ], | ||
113 | }; | ||
114 | |||
115 | let resolver = self.func.resolver(db); | ||
116 | let std_result_enum = | ||
117 | match resolver.resolve_path_segments(db, &std_result_path).into_fully_resolved() { | ||
118 | PerNs { types: Some(Resolution::Def(ModuleDef::Enum(e))), .. } => e, | ||
119 | _ => return, | ||
120 | }; | ||
121 | |||
122 | let std_result_ctor = TypeCtor::Adt(AdtDef::Enum(std_result_enum)); | ||
123 | let params = match &mismatch.expected { | ||
124 | Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &std_result_ctor => parameters, | ||
125 | _ => return, | ||
126 | }; | ||
127 | |||
128 | if params.len() == 2 && ¶ms[0] == &mismatch.actual { | ||
129 | let source_map = self.func.body_source_map(db); | ||
130 | let file_id = self.func.source(db).file_id; | ||
131 | |||
132 | if let Some(expr) = source_map.expr_syntax(id).and_then(|n| n.cast::<ast::Expr>()) { | ||
133 | self.sink.push(MissingOkInTailExpr { file: file_id, expr }); | ||
134 | } | ||
135 | } | ||
136 | } | ||
90 | } | 137 | } |
diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs index 6d14eea8e..9c4822d91 100644 --- a/crates/ra_hir/src/name.rs +++ b/crates/ra_hir/src/name.rs | |||
@@ -120,6 +120,8 @@ pub(crate) const TRY: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"Try") | |||
120 | pub(crate) const OK: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"Ok")); | 120 | pub(crate) const OK: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"Ok")); |
121 | pub(crate) const FUTURE_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"future")); | 121 | pub(crate) const FUTURE_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"future")); |
122 | pub(crate) const FUTURE_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Future")); | 122 | pub(crate) const FUTURE_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Future")); |
123 | pub(crate) const RESULT_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"result")); | ||
124 | pub(crate) const RESULT_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Result")); | ||
123 | pub(crate) const OUTPUT: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Output")); | 125 | pub(crate) const OUTPUT: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Output")); |
124 | 126 | ||
125 | fn resolve_name(text: &SmolStr) -> SmolStr { | 127 | fn resolve_name(text: &SmolStr) -> SmolStr { |
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index b33de5687..d94e8154b 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -106,6 +106,13 @@ impl Default for BindingMode { | |||
106 | } | 106 | } |
107 | } | 107 | } |
108 | 108 | ||
109 | /// A mismatch between an expected and an inferred type. | ||
110 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | ||
111 | pub struct TypeMismatch { | ||
112 | pub expected: Ty, | ||
113 | pub actual: Ty, | ||
114 | } | ||
115 | |||
109 | /// The result of type inference: A mapping from expressions and patterns to types. | 116 | /// The result of type inference: A mapping from expressions and patterns to types. |
110 | #[derive(Clone, PartialEq, Eq, Debug, Default)] | 117 | #[derive(Clone, PartialEq, Eq, Debug, Default)] |
111 | pub struct InferenceResult { | 118 | pub struct InferenceResult { |
@@ -120,6 +127,7 @@ pub struct InferenceResult { | |||
120 | diagnostics: Vec<InferenceDiagnostic>, | 127 | diagnostics: Vec<InferenceDiagnostic>, |
121 | pub(super) type_of_expr: ArenaMap<ExprId, Ty>, | 128 | pub(super) type_of_expr: ArenaMap<ExprId, Ty>, |
122 | pub(super) type_of_pat: ArenaMap<PatId, Ty>, | 129 | pub(super) type_of_pat: ArenaMap<PatId, Ty>, |
130 | pub(super) type_mismatches: ArenaMap<ExprId, TypeMismatch>, | ||
123 | } | 131 | } |
124 | 132 | ||
125 | impl InferenceResult { | 133 | impl InferenceResult { |
@@ -141,6 +149,9 @@ impl InferenceResult { | |||
141 | pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<ImplItem> { | 149 | pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<ImplItem> { |
142 | self.assoc_resolutions.get(&id.into()).copied() | 150 | self.assoc_resolutions.get(&id.into()).copied() |
143 | } | 151 | } |
152 | pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> { | ||
153 | self.type_mismatches.get(expr) | ||
154 | } | ||
144 | pub(crate) fn add_diagnostics( | 155 | pub(crate) fn add_diagnostics( |
145 | &self, | 156 | &self, |
146 | db: &impl HirDatabase, | 157 | db: &impl HirDatabase, |
@@ -1345,9 +1356,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1345 | }; | 1356 | }; |
1346 | // use a new type variable if we got Ty::Unknown here | 1357 | // use a new type variable if we got Ty::Unknown here |
1347 | let ty = self.insert_type_vars_shallow(ty); | 1358 | let ty = self.insert_type_vars_shallow(ty); |
1348 | self.unify(&ty, &expected.ty); | 1359 | let could_unify = self.unify(&ty, &expected.ty); |
1349 | let ty = self.resolve_ty_as_possible(&mut vec![], ty); | 1360 | let ty = self.resolve_ty_as_possible(&mut vec![], ty); |
1350 | self.write_expr_ty(tgt_expr, ty.clone()); | 1361 | self.write_expr_ty(tgt_expr, ty.clone()); |
1362 | if !could_unify { | ||
1363 | self.result.type_mismatches.insert( | ||
1364 | tgt_expr, | ||
1365 | TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() }, | ||
1366 | ); | ||
1367 | } | ||
1351 | ty | 1368 | ty |
1352 | } | 1369 | } |
1353 | 1370 | ||
diff --git a/crates/ra_ide_api/src/diagnostics.rs b/crates/ra_ide_api/src/diagnostics.rs index c2b959cb3..1a4882824 100644 --- a/crates/ra_ide_api/src/diagnostics.rs +++ b/crates/ra_ide_api/src/diagnostics.rs | |||
@@ -75,6 +75,19 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic> | |||
75 | severity: Severity::Error, | 75 | severity: Severity::Error, |
76 | fix: Some(fix), | 76 | fix: Some(fix), |
77 | }) | 77 | }) |
78 | }) | ||
79 | .on::<hir::diagnostics::MissingOkInTailExpr, _>(|d| { | ||
80 | let node = d.ast(db); | ||
81 | let mut builder = TextEditBuilder::default(); | ||
82 | let replacement = format!("Ok({})", node.syntax()); | ||
83 | builder.replace(node.syntax().text_range(), replacement); | ||
84 | let fix = SourceChange::source_file_edit_from("wrap with ok", file_id, builder.finish()); | ||
85 | res.borrow_mut().push(Diagnostic { | ||
86 | range: d.highlight_range(), | ||
87 | message: d.message(), | ||
88 | severity: Severity::Error, | ||
89 | fix: Some(fix), | ||
90 | }) | ||
78 | }); | 91 | }); |
79 | if let Some(m) = source_binder::module_from_file_id(db, file_id) { | 92 | if let Some(m) = source_binder::module_from_file_id(db, file_id) { |
80 | m.diagnostics(db, &mut sink); | 93 | m.diagnostics(db, &mut sink); |
@@ -171,10 +184,11 @@ fn check_struct_shorthand_initialization( | |||
171 | #[cfg(test)] | 184 | #[cfg(test)] |
172 | mod tests { | 185 | mod tests { |
173 | use insta::assert_debug_snapshot_matches; | 186 | use insta::assert_debug_snapshot_matches; |
187 | use join_to_string::join; | ||
174 | use ra_syntax::SourceFile; | 188 | use ra_syntax::SourceFile; |
175 | use test_utils::assert_eq_text; | 189 | use test_utils::assert_eq_text; |
176 | 190 | ||
177 | use crate::mock_analysis::single_file; | 191 | use crate::mock_analysis::{analysis_and_position, single_file}; |
178 | 192 | ||
179 | use super::*; | 193 | use super::*; |
180 | 194 | ||
@@ -203,6 +217,48 @@ mod tests { | |||
203 | assert_eq_text!(after, &actual); | 217 | assert_eq_text!(after, &actual); |
204 | } | 218 | } |
205 | 219 | ||
220 | /// Takes a multi-file input fixture with annotated cursor positions, | ||
221 | /// and checks that: | ||
222 | /// * a diagnostic is produced | ||
223 | /// * this diagnostic touches the input cursor position | ||
224 | /// * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied | ||
225 | fn check_apply_diagnostic_fix_from_position(fixture: &str, after: &str) { | ||
226 | let (analysis, file_position) = analysis_and_position(fixture); | ||
227 | let diagnostic = analysis.diagnostics(file_position.file_id).unwrap().pop().unwrap(); | ||
228 | let mut fix = diagnostic.fix.unwrap(); | ||
229 | let edit = fix.source_file_edits.pop().unwrap().edit; | ||
230 | let target_file_contents = analysis.file_text(file_position.file_id).unwrap(); | ||
231 | let actual = edit.apply(&target_file_contents); | ||
232 | |||
233 | // Strip indent and empty lines from `after`, to match the behaviour of | ||
234 | // `parse_fixture` called from `analysis_and_position`. | ||
235 | let margin = fixture | ||
236 | .lines() | ||
237 | .filter(|it| it.trim_start().starts_with("//-")) | ||
238 | .map(|it| it.len() - it.trim_start().len()) | ||
239 | .next() | ||
240 | .expect("empty fixture"); | ||
241 | let after = join(after.lines().filter_map(|line| { | ||
242 | if line.len() > margin { | ||
243 | Some(&line[margin..]) | ||
244 | } else { | ||
245 | None | ||
246 | } | ||
247 | })) | ||
248 | .separator("\n") | ||
249 | .suffix("\n") | ||
250 | .to_string(); | ||
251 | |||
252 | assert_eq_text!(&after, &actual); | ||
253 | assert!( | ||
254 | diagnostic.range.start() <= file_position.offset | ||
255 | && diagnostic.range.end() >= file_position.offset, | ||
256 | "diagnostic range {} does not touch cursor position {}", | ||
257 | diagnostic.range, | ||
258 | file_position.offset | ||
259 | ); | ||
260 | } | ||
261 | |||
206 | fn check_apply_diagnostic_fix(before: &str, after: &str) { | 262 | fn check_apply_diagnostic_fix(before: &str, after: &str) { |
207 | let (analysis, file_id) = single_file(before); | 263 | let (analysis, file_id) = single_file(before); |
208 | let diagnostic = analysis.diagnostics(file_id).unwrap().pop().unwrap(); | 264 | let diagnostic = analysis.diagnostics(file_id).unwrap().pop().unwrap(); |
@@ -212,6 +268,14 @@ mod tests { | |||
212 | assert_eq_text!(after, &actual); | 268 | assert_eq_text!(after, &actual); |
213 | } | 269 | } |
214 | 270 | ||
271 | /// Takes a multi-file input fixture with annotated cursor position and checks that no diagnostics | ||
272 | /// apply to the file containing the cursor. | ||
273 | fn check_no_diagnostic_for_target_file(fixture: &str) { | ||
274 | let (analysis, file_position) = analysis_and_position(fixture); | ||
275 | let diagnostics = analysis.diagnostics(file_position.file_id).unwrap(); | ||
276 | assert_eq!(diagnostics.len(), 0); | ||
277 | } | ||
278 | |||
215 | fn check_no_diagnostic(content: &str) { | 279 | fn check_no_diagnostic(content: &str) { |
216 | let (analysis, file_id) = single_file(content); | 280 | let (analysis, file_id) = single_file(content); |
217 | let diagnostics = analysis.diagnostics(file_id).unwrap(); | 281 | let diagnostics = analysis.diagnostics(file_id).unwrap(); |
@@ -219,6 +283,155 @@ mod tests { | |||
219 | } | 283 | } |
220 | 284 | ||
221 | #[test] | 285 | #[test] |
286 | fn test_wrap_return_type() { | ||
287 | let before = r#" | ||
288 | //- /main.rs | ||
289 | use std::{string::String, result::Result::{self, Ok, Err}}; | ||
290 | |||
291 | fn div(x: i32, y: i32) -> Result<i32, String> { | ||
292 | if y == 0 { | ||
293 | return Err("div by zero".into()); | ||
294 | } | ||
295 | x / y<|> | ||
296 | } | ||
297 | |||
298 | //- /std/lib.rs | ||
299 | pub mod string { | ||
300 | pub struct String { } | ||
301 | } | ||
302 | pub mod result { | ||
303 | pub enum Result<T, E> { Ok(T), Err(E) } | ||
304 | } | ||
305 | "#; | ||
306 | let after = r#" | ||
307 | use std::{string::String, result::Result::{self, Ok, Err}}; | ||
308 | |||
309 | fn div(x: i32, y: i32) -> Result<i32, String> { | ||
310 | if y == 0 { | ||
311 | return Err("div by zero".into()); | ||
312 | } | ||
313 | Ok(x / y) | ||
314 | } | ||
315 | "#; | ||
316 | check_apply_diagnostic_fix_from_position(before, after); | ||
317 | } | ||
318 | |||
319 | #[test] | ||
320 | fn test_wrap_return_type_handles_generic_functions() { | ||
321 | let before = r#" | ||
322 | //- /main.rs | ||
323 | use std::result::Result::{self, Ok, Err}; | ||
324 | |||
325 | fn div<T>(x: T) -> Result<T, i32> { | ||
326 | if x == 0 { | ||
327 | return Err(7); | ||
328 | } | ||
329 | <|>x | ||
330 | } | ||
331 | |||
332 | //- /std/lib.rs | ||
333 | pub mod result { | ||
334 | pub enum Result<T, E> { Ok(T), Err(E) } | ||
335 | } | ||
336 | "#; | ||
337 | let after = r#" | ||
338 | use std::result::Result::{self, Ok, Err}; | ||
339 | |||
340 | fn div<T>(x: T) -> Result<T, i32> { | ||
341 | if x == 0 { | ||
342 | return Err(7); | ||
343 | } | ||
344 | Ok(x) | ||
345 | } | ||
346 | "#; | ||
347 | check_apply_diagnostic_fix_from_position(before, after); | ||
348 | } | ||
349 | |||
350 | #[test] | ||
351 | fn test_wrap_return_type_handles_type_aliases() { | ||
352 | let before = r#" | ||
353 | //- /main.rs | ||
354 | use std::{string::String, result::Result::{self, Ok, Err}}; | ||
355 | |||
356 | type MyResult<T> = Result<T, String>; | ||
357 | |||
358 | fn div(x: i32, y: i32) -> MyResult<i32> { | ||
359 | if y == 0 { | ||
360 | return Err("div by zero".into()); | ||
361 | } | ||
362 | x <|>/ y | ||
363 | } | ||
364 | |||
365 | //- /std/lib.rs | ||
366 | pub mod string { | ||
367 | pub struct String { } | ||
368 | } | ||
369 | pub mod result { | ||
370 | pub enum Result<T, E> { Ok(T), Err(E) } | ||
371 | } | ||
372 | "#; | ||
373 | let after = r#" | ||
374 | use std::{string::String, result::Result::{self, Ok, Err}}; | ||
375 | |||
376 | type MyResult<T> = Result<T, String>; | ||
377 | fn div(x: i32, y: i32) -> MyResult<i32> { | ||
378 | if y == 0 { | ||
379 | return Err("div by zero".into()); | ||
380 | } | ||
381 | Ok(x / y) | ||
382 | } | ||
383 | "#; | ||
384 | check_apply_diagnostic_fix_from_position(before, after); | ||
385 | } | ||
386 | |||
387 | #[test] | ||
388 | fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() { | ||
389 | let content = r#" | ||
390 | //- /main.rs | ||
391 | use std::{string::String, result::Result::{self, Ok, Err}}; | ||
392 | |||
393 | fn foo() -> Result<String, i32> { | ||
394 | 0<|> | ||
395 | } | ||
396 | |||
397 | //- /std/lib.rs | ||
398 | pub mod string { | ||
399 | pub struct String { } | ||
400 | } | ||
401 | pub mod result { | ||
402 | pub enum Result<T, E> { Ok(T), Err(E) } | ||
403 | } | ||
404 | "#; | ||
405 | check_no_diagnostic_for_target_file(content); | ||
406 | } | ||
407 | |||
408 | #[test] | ||
409 | fn test_wrap_return_type_not_applicable_when_return_type_is_not_result() { | ||
410 | let content = r#" | ||
411 | //- /main.rs | ||
412 | use std::{string::String, result::Result::{self, Ok, Err}}; | ||
413 | |||
414 | enum SomeOtherEnum { | ||
415 | Ok(i32), | ||
416 | Err(String), | ||
417 | } | ||
418 | |||
419 | fn foo() -> SomeOtherEnum { | ||
420 | 0<|> | ||
421 | } | ||
422 | |||
423 | //- /std/lib.rs | ||
424 | pub mod string { | ||
425 | pub struct String { } | ||
426 | } | ||
427 | pub mod result { | ||
428 | pub enum Result<T, E> { Ok(T), Err(E) } | ||
429 | } | ||
430 | "#; | ||
431 | check_no_diagnostic_for_target_file(content); | ||
432 | } | ||
433 | |||
434 | #[test] | ||
222 | fn test_fill_struct_fields_empty() { | 435 | fn test_fill_struct_fields_empty() { |
223 | let before = r" | 436 | let before = r" |
224 | struct TestStruct { | 437 | struct TestStruct { |
diff --git a/crates/ra_parser/src/grammar/expressions/atom.rs b/crates/ra_parser/src/grammar/expressions/atom.rs index ab8fb9f6e..bc942ae01 100644 --- a/crates/ra_parser/src/grammar/expressions/atom.rs +++ b/crates/ra_parser/src/grammar/expressions/atom.rs | |||
@@ -414,8 +414,6 @@ pub(crate) fn match_arm_list(p: &mut Parser) { | |||
414 | // X | Y if Z => (), | 414 | // X | Y if Z => (), |
415 | // | X | Y if Z => (), | 415 | // | X | Y if Z => (), |
416 | // | X => (), | 416 | // | X => (), |
417 | // box X => (), | ||
418 | // Some(box X) => (), | ||
419 | // }; | 417 | // }; |
420 | // } | 418 | // } |
421 | fn match_arm(p: &mut Parser) -> BlockLike { | 419 | fn match_arm(p: &mut Parser) -> BlockLike { |
diff --git a/crates/ra_parser/src/grammar/patterns.rs b/crates/ra_parser/src/grammar/patterns.rs index 8979aa499..eae70ab85 100644 --- a/crates/ra_parser/src/grammar/patterns.rs +++ b/crates/ra_parser/src/grammar/patterns.rs | |||
@@ -56,37 +56,33 @@ const PAT_RECOVERY_SET: TokenSet = | |||
56 | token_set![LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA]; | 56 | token_set![LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA]; |
57 | 57 | ||
58 | fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> { | 58 | fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> { |
59 | let la0 = p.nth(0); | 59 | // Checks the token after an IDENT to see if a pattern is a path (Struct { .. }) or macro |
60 | let la1 = p.nth(1); | 60 | // (T![x]). |
61 | if la0 == T![ref] | 61 | let is_path_or_macro_pat = |
62 | || la0 == T![mut] | 62 | |la1| la1 == T![::] || la1 == T!['('] || la1 == T!['{'] || la1 == T![!]; |
63 | || la0 == T![box] | ||
64 | || (la0 == IDENT && !(la1 == T![::] || la1 == T!['('] || la1 == T!['{'] || la1 == T![!])) | ||
65 | { | ||
66 | return Some(bind_pat(p, true)); | ||
67 | } | ||
68 | if paths::is_use_path_start(p) { | ||
69 | return Some(path_pat(p)); | ||
70 | } | ||
71 | 63 | ||
72 | if is_literal_pat_start(p) { | 64 | let m = match p.nth(0) { |
73 | return Some(literal_pat(p)); | 65 | T![box] => box_pat(p), |
74 | } | 66 | T![ref] | T![mut] | IDENT if !is_path_or_macro_pat(p.nth(1)) => bind_pat(p, true), |
67 | |||
68 | _ if paths::is_use_path_start(p) => path_pat(p), | ||
69 | _ if is_literal_pat_start(p) => literal_pat(p), | ||
75 | 70 | ||
76 | let m = match la0 { | ||
77 | T![_] => placeholder_pat(p), | 71 | T![_] => placeholder_pat(p), |
78 | T![&] => ref_pat(p), | 72 | T![&] => ref_pat(p), |
79 | T!['('] => tuple_pat(p), | 73 | T!['('] => tuple_pat(p), |
80 | T!['['] => slice_pat(p), | 74 | T!['['] => slice_pat(p), |
75 | |||
81 | _ => { | 76 | _ => { |
82 | p.err_recover("expected pattern", recovery_set); | 77 | p.err_recover("expected pattern", recovery_set); |
83 | return None; | 78 | return None; |
84 | } | 79 | } |
85 | }; | 80 | }; |
81 | |||
86 | Some(m) | 82 | Some(m) |
87 | } | 83 | } |
88 | 84 | ||
89 | fn is_literal_pat_start(p: &mut Parser) -> bool { | 85 | fn is_literal_pat_start(p: &Parser) -> bool { |
90 | p.at(T![-]) && (p.nth(1) == INT_NUMBER || p.nth(1) == FLOAT_NUMBER) | 86 | p.at(T![-]) && (p.nth(1) == INT_NUMBER || p.nth(1) == FLOAT_NUMBER) |
91 | || p.at_ts(expressions::LITERAL_FIRST) | 87 | || p.at_ts(expressions::LITERAL_FIRST) |
92 | } | 88 | } |
@@ -165,6 +161,9 @@ fn record_field_pat_list(p: &mut Parser) { | |||
165 | T![..] => p.bump(), | 161 | T![..] => p.bump(), |
166 | IDENT if p.nth(1) == T![:] => record_field_pat(p), | 162 | IDENT if p.nth(1) == T![:] => record_field_pat(p), |
167 | T!['{'] => error_block(p, "expected ident"), | 163 | T!['{'] => error_block(p, "expected ident"), |
164 | T![box] => { | ||
165 | box_pat(p); | ||
166 | } | ||
168 | _ => { | 167 | _ => { |
169 | bind_pat(p, false); | 168 | bind_pat(p, false); |
170 | } | 169 | } |
@@ -261,11 +260,9 @@ fn pat_list(p: &mut Parser, ket: SyntaxKind) { | |||
261 | // let ref mut d = (); | 260 | // let ref mut d = (); |
262 | // let e @ _ = (); | 261 | // let e @ _ = (); |
263 | // let ref mut f @ g @ _ = (); | 262 | // let ref mut f @ g @ _ = (); |
264 | // let box i = Box::new(1i32); | ||
265 | // } | 263 | // } |
266 | fn bind_pat(p: &mut Parser, with_at: bool) -> CompletedMarker { | 264 | fn bind_pat(p: &mut Parser, with_at: bool) -> CompletedMarker { |
267 | let m = p.start(); | 265 | let m = p.start(); |
268 | p.eat(T![box]); | ||
269 | p.eat(T![ref]); | 266 | p.eat(T![ref]); |
270 | p.eat(T![mut]); | 267 | p.eat(T![mut]); |
271 | name(p); | 268 | name(p); |
@@ -274,3 +271,17 @@ fn bind_pat(p: &mut Parser, with_at: bool) -> CompletedMarker { | |||
274 | } | 271 | } |
275 | m.complete(p, BIND_PAT) | 272 | m.complete(p, BIND_PAT) |
276 | } | 273 | } |
274 | |||
275 | // test box_pat | ||
276 | // fn main() { | ||
277 | // let box i = (); | ||
278 | // let box Outer { box i, j: box Inner(box &x) } = (); | ||
279 | // let box ref mut i = (); | ||
280 | // } | ||
281 | fn box_pat(p: &mut Parser) -> CompletedMarker { | ||
282 | assert!(p.at(T![box])); | ||
283 | let m = p.start(); | ||
284 | p.bump(); | ||
285 | pattern(p); | ||
286 | m.complete(p, BOX_PAT) | ||
287 | } | ||
diff --git a/crates/ra_parser/src/syntax_kind/generated.rs b/crates/ra_parser/src/syntax_kind/generated.rs index f15e98e68..8ba29ebf8 100644 --- a/crates/ra_parser/src/syntax_kind/generated.rs +++ b/crates/ra_parser/src/syntax_kind/generated.rs | |||
@@ -149,6 +149,7 @@ pub enum SyntaxKind { | |||
149 | IMPL_TRAIT_TYPE, | 149 | IMPL_TRAIT_TYPE, |
150 | DYN_TRAIT_TYPE, | 150 | DYN_TRAIT_TYPE, |
151 | REF_PAT, | 151 | REF_PAT, |
152 | BOX_PAT, | ||
152 | BIND_PAT, | 153 | BIND_PAT, |
153 | PLACEHOLDER_PAT, | 154 | PLACEHOLDER_PAT, |
154 | PATH_PAT, | 155 | PATH_PAT, |
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 07cc3e0db..90480b6ca 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs | |||
@@ -307,6 +307,33 @@ impl BlockExpr { | |||
307 | } | 307 | } |
308 | } | 308 | } |
309 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 309 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
310 | pub struct BoxPat { | ||
311 | pub(crate) syntax: SyntaxNode, | ||
312 | } | ||
313 | impl AstNode for BoxPat { | ||
314 | fn can_cast(kind: SyntaxKind) -> bool { | ||
315 | match kind { | ||
316 | BOX_PAT => true, | ||
317 | _ => false, | ||
318 | } | ||
319 | } | ||
320 | fn cast(syntax: SyntaxNode) -> Option<Self> { | ||
321 | if Self::can_cast(syntax.kind()) { | ||
322 | Some(Self { syntax }) | ||
323 | } else { | ||
324 | None | ||
325 | } | ||
326 | } | ||
327 | fn syntax(&self) -> &SyntaxNode { | ||
328 | &self.syntax | ||
329 | } | ||
330 | } | ||
331 | impl BoxPat { | ||
332 | pub fn pat(&self) -> Option<Pat> { | ||
333 | AstChildren::new(&self.syntax).next() | ||
334 | } | ||
335 | } | ||
336 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
310 | pub struct BreakExpr { | 337 | pub struct BreakExpr { |
311 | pub(crate) syntax: SyntaxNode, | 338 | pub(crate) syntax: SyntaxNode, |
312 | } | 339 | } |
@@ -2063,6 +2090,7 @@ impl ParenType { | |||
2063 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 2090 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
2064 | pub enum Pat { | 2091 | pub enum Pat { |
2065 | RefPat(RefPat), | 2092 | RefPat(RefPat), |
2093 | BoxPat(BoxPat), | ||
2066 | BindPat(BindPat), | 2094 | BindPat(BindPat), |
2067 | PlaceholderPat(PlaceholderPat), | 2095 | PlaceholderPat(PlaceholderPat), |
2068 | PathPat(PathPat), | 2096 | PathPat(PathPat), |
@@ -2078,6 +2106,11 @@ impl From<RefPat> for Pat { | |||
2078 | Pat::RefPat(node) | 2106 | Pat::RefPat(node) |
2079 | } | 2107 | } |
2080 | } | 2108 | } |
2109 | impl From<BoxPat> for Pat { | ||
2110 | fn from(node: BoxPat) -> Pat { | ||
2111 | Pat::BoxPat(node) | ||
2112 | } | ||
2113 | } | ||
2081 | impl From<BindPat> for Pat { | 2114 | impl From<BindPat> for Pat { |
2082 | fn from(node: BindPat) -> Pat { | 2115 | fn from(node: BindPat) -> Pat { |
2083 | Pat::BindPat(node) | 2116 | Pat::BindPat(node) |
@@ -2126,14 +2159,15 @@ impl From<LiteralPat> for Pat { | |||
2126 | impl AstNode for Pat { | 2159 | impl AstNode for Pat { |
2127 | fn can_cast(kind: SyntaxKind) -> bool { | 2160 | fn can_cast(kind: SyntaxKind) -> bool { |
2128 | match kind { | 2161 | match kind { |
2129 | REF_PAT | BIND_PAT | PLACEHOLDER_PAT | PATH_PAT | RECORD_PAT | TUPLE_STRUCT_PAT | 2162 | REF_PAT | BOX_PAT | BIND_PAT | PLACEHOLDER_PAT | PATH_PAT | RECORD_PAT |
2130 | | TUPLE_PAT | SLICE_PAT | RANGE_PAT | LITERAL_PAT => true, | 2163 | | TUPLE_STRUCT_PAT | TUPLE_PAT | SLICE_PAT | RANGE_PAT | LITERAL_PAT => true, |
2131 | _ => false, | 2164 | _ => false, |
2132 | } | 2165 | } |
2133 | } | 2166 | } |
2134 | fn cast(syntax: SyntaxNode) -> Option<Self> { | 2167 | fn cast(syntax: SyntaxNode) -> Option<Self> { |
2135 | let res = match syntax.kind() { | 2168 | let res = match syntax.kind() { |
2136 | REF_PAT => Pat::RefPat(RefPat { syntax }), | 2169 | REF_PAT => Pat::RefPat(RefPat { syntax }), |
2170 | BOX_PAT => Pat::BoxPat(BoxPat { syntax }), | ||
2137 | BIND_PAT => Pat::BindPat(BindPat { syntax }), | 2171 | BIND_PAT => Pat::BindPat(BindPat { syntax }), |
2138 | PLACEHOLDER_PAT => Pat::PlaceholderPat(PlaceholderPat { syntax }), | 2172 | PLACEHOLDER_PAT => Pat::PlaceholderPat(PlaceholderPat { syntax }), |
2139 | PATH_PAT => Pat::PathPat(PathPat { syntax }), | 2173 | PATH_PAT => Pat::PathPat(PathPat { syntax }), |
@@ -2150,6 +2184,7 @@ impl AstNode for Pat { | |||
2150 | fn syntax(&self) -> &SyntaxNode { | 2184 | fn syntax(&self) -> &SyntaxNode { |
2151 | match self { | 2185 | match self { |
2152 | Pat::RefPat(it) => &it.syntax, | 2186 | Pat::RefPat(it) => &it.syntax, |
2187 | Pat::BoxPat(it) => &it.syntax, | ||
2153 | Pat::BindPat(it) => &it.syntax, | 2188 | Pat::BindPat(it) => &it.syntax, |
2154 | Pat::PlaceholderPat(it) => &it.syntax, | 2189 | Pat::PlaceholderPat(it) => &it.syntax, |
2155 | Pat::PathPat(it) => &it.syntax, | 2190 | Pat::PathPat(it) => &it.syntax, |
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 4659192cd..1836862fe 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron | |||
@@ -158,6 +158,7 @@ Grammar( | |||
158 | "DYN_TRAIT_TYPE", | 158 | "DYN_TRAIT_TYPE", |
159 | 159 | ||
160 | "REF_PAT", | 160 | "REF_PAT", |
161 | "BOX_PAT", | ||
161 | "BIND_PAT", | 162 | "BIND_PAT", |
162 | "PLACEHOLDER_PAT", | 163 | "PLACEHOLDER_PAT", |
163 | "PATH_PAT", | 164 | "PATH_PAT", |
@@ -523,6 +524,7 @@ Grammar( | |||
523 | ), | 524 | ), |
524 | 525 | ||
525 | "RefPat": ( options: [ "Pat" ]), | 526 | "RefPat": ( options: [ "Pat" ]), |
527 | "BoxPat": ( options: [ "Pat" ]), | ||
526 | "BindPat": ( | 528 | "BindPat": ( |
527 | options: [ "Pat" ], | 529 | options: [ "Pat" ], |
528 | traits: ["NameOwner"] | 530 | traits: ["NameOwner"] |
@@ -552,6 +554,7 @@ Grammar( | |||
552 | "Pat": ( | 554 | "Pat": ( |
553 | enum: [ | 555 | enum: [ |
554 | "RefPat", | 556 | "RefPat", |
557 | "BoxPat", | ||
555 | "BindPat", | 558 | "BindPat", |
556 | "PlaceholderPat", | 559 | "PlaceholderPat", |
557 | "PathPat", | 560 | "PathPat", |
diff --git a/crates/ra_syntax/src/ptr.rs b/crates/ra_syntax/src/ptr.rs index d24660ac3..992034ef0 100644 --- a/crates/ra_syntax/src/ptr.rs +++ b/crates/ra_syntax/src/ptr.rs | |||
@@ -31,6 +31,13 @@ impl SyntaxNodePtr { | |||
31 | pub fn kind(self) -> SyntaxKind { | 31 | pub fn kind(self) -> SyntaxKind { |
32 | self.kind | 32 | self.kind |
33 | } | 33 | } |
34 | |||
35 | pub fn cast<N: AstNode>(self) -> Option<AstPtr<N>> { | ||
36 | if !N::can_cast(self.kind()) { | ||
37 | return None; | ||
38 | } | ||
39 | Some(AstPtr { raw: self, _ty: PhantomData }) | ||
40 | } | ||
34 | } | 41 | } |
35 | 42 | ||
36 | /// Like `SyntaxNodePtr`, but remembers the type of node | 43 | /// Like `SyntaxNodePtr`, but remembers the type of node |
diff --git a/crates/ra_syntax/test_data/parser/err/0034_bad_box_pattern.rs b/crates/ra_syntax/test_data/parser/err/0034_bad_box_pattern.rs new file mode 100644 index 000000000..d3fa2e468 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/err/0034_bad_box_pattern.rs | |||
@@ -0,0 +1,6 @@ | |||
1 | fn main() { | ||
2 | let ref box i = (); | ||
3 | let mut box i = (); | ||
4 | let ref mut box i = (); | ||
5 | } | ||
6 | |||
diff --git a/crates/ra_syntax/test_data/parser/err/0034_bad_box_pattern.txt b/crates/ra_syntax/test_data/parser/err/0034_bad_box_pattern.txt new file mode 100644 index 000000000..0cdca4b55 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/err/0034_bad_box_pattern.txt | |||
@@ -0,0 +1,95 @@ | |||
1 | SOURCE_FILE@[0; 91) | ||
2 | FN_DEF@[0; 89) | ||
3 | FN_KW@[0; 2) "fn" | ||
4 | WHITESPACE@[2; 3) " " | ||
5 | NAME@[3; 7) | ||
6 | IDENT@[3; 7) "main" | ||
7 | PARAM_LIST@[7; 9) | ||
8 | L_PAREN@[7; 8) "(" | ||
9 | R_PAREN@[8; 9) ")" | ||
10 | WHITESPACE@[9; 10) " " | ||
11 | BLOCK@[10; 89) | ||
12 | L_CURLY@[10; 11) "{" | ||
13 | WHITESPACE@[11; 16) "\n " | ||
14 | LET_STMT@[16; 27) | ||
15 | LET_KW@[16; 19) "let" | ||
16 | WHITESPACE@[19; 20) " " | ||
17 | BIND_PAT@[20; 27) | ||
18 | REF_KW@[20; 23) "ref" | ||
19 | WHITESPACE@[23; 24) " " | ||
20 | ERROR@[24; 27) | ||
21 | BOX_KW@[24; 27) "box" | ||
22 | WHITESPACE@[27; 28) " " | ||
23 | EXPR_STMT@[28; 35) | ||
24 | BIN_EXPR@[28; 34) | ||
25 | PATH_EXPR@[28; 29) | ||
26 | PATH@[28; 29) | ||
27 | PATH_SEGMENT@[28; 29) | ||
28 | NAME_REF@[28; 29) | ||
29 | IDENT@[28; 29) "i" | ||
30 | WHITESPACE@[29; 30) " " | ||
31 | EQ@[30; 31) "=" | ||
32 | WHITESPACE@[31; 32) " " | ||
33 | TUPLE_EXPR@[32; 34) | ||
34 | L_PAREN@[32; 33) "(" | ||
35 | R_PAREN@[33; 34) ")" | ||
36 | SEMI@[34; 35) ";" | ||
37 | WHITESPACE@[35; 40) "\n " | ||
38 | LET_STMT@[40; 51) | ||
39 | LET_KW@[40; 43) "let" | ||
40 | WHITESPACE@[43; 44) " " | ||
41 | BIND_PAT@[44; 51) | ||
42 | MUT_KW@[44; 47) "mut" | ||
43 | WHITESPACE@[47; 48) " " | ||
44 | ERROR@[48; 51) | ||
45 | BOX_KW@[48; 51) "box" | ||
46 | WHITESPACE@[51; 52) " " | ||
47 | EXPR_STMT@[52; 59) | ||
48 | BIN_EXPR@[52; 58) | ||
49 | PATH_EXPR@[52; 53) | ||
50 | PATH@[52; 53) | ||
51 | PATH_SEGMENT@[52; 53) | ||
52 | NAME_REF@[52; 53) | ||
53 | IDENT@[52; 53) "i" | ||
54 | WHITESPACE@[53; 54) " " | ||
55 | EQ@[54; 55) "=" | ||
56 | WHITESPACE@[55; 56) " " | ||
57 | TUPLE_EXPR@[56; 58) | ||
58 | L_PAREN@[56; 57) "(" | ||
59 | R_PAREN@[57; 58) ")" | ||
60 | SEMI@[58; 59) ";" | ||
61 | WHITESPACE@[59; 64) "\n " | ||
62 | LET_STMT@[64; 79) | ||
63 | LET_KW@[64; 67) "let" | ||
64 | WHITESPACE@[67; 68) " " | ||
65 | BIND_PAT@[68; 79) | ||
66 | REF_KW@[68; 71) "ref" | ||
67 | WHITESPACE@[71; 72) " " | ||
68 | MUT_KW@[72; 75) "mut" | ||
69 | WHITESPACE@[75; 76) " " | ||
70 | ERROR@[76; 79) | ||
71 | BOX_KW@[76; 79) "box" | ||
72 | WHITESPACE@[79; 80) " " | ||
73 | EXPR_STMT@[80; 87) | ||
74 | BIN_EXPR@[80; 86) | ||
75 | PATH_EXPR@[80; 81) | ||
76 | PATH@[80; 81) | ||
77 | PATH_SEGMENT@[80; 81) | ||
78 | NAME_REF@[80; 81) | ||
79 | IDENT@[80; 81) "i" | ||
80 | WHITESPACE@[81; 82) " " | ||
81 | EQ@[82; 83) "=" | ||
82 | WHITESPACE@[83; 84) " " | ||
83 | TUPLE_EXPR@[84; 86) | ||
84 | L_PAREN@[84; 85) "(" | ||
85 | R_PAREN@[85; 86) ")" | ||
86 | SEMI@[86; 87) ";" | ||
87 | WHITESPACE@[87; 88) "\n" | ||
88 | R_CURLY@[88; 89) "}" | ||
89 | WHITESPACE@[89; 91) "\n\n" | ||
90 | error 24: expected a name | ||
91 | error 27: expected SEMI | ||
92 | error 48: expected a name | ||
93 | error 51: expected SEMI | ||
94 | error 76: expected a name | ||
95 | error 79: expected SEMI | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.rs b/crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.rs index 2d476278d..9e009e24f 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.rs +++ b/crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.rs | |||
@@ -5,7 +5,5 @@ fn foo() { | |||
5 | X | Y if Z => (), | 5 | X | Y if Z => (), |
6 | | X | Y if Z => (), | 6 | | X | Y if Z => (), |
7 | | X => (), | 7 | | X => (), |
8 | box X => (), | ||
9 | Some(box X) => (), | ||
10 | }; | 8 | }; |
11 | } | 9 | } |
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.txt b/crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.txt index 35f023782..c2f256ac3 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.txt +++ b/crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.txt | |||
@@ -1,5 +1,5 @@ | |||
1 | SOURCE_FILE@[0; 215) | 1 | SOURCE_FILE@[0; 167) |
2 | FN_DEF@[0; 214) | 2 | FN_DEF@[0; 166) |
3 | FN_KW@[0; 2) "fn" | 3 | FN_KW@[0; 2) "fn" |
4 | WHITESPACE@[2; 3) " " | 4 | WHITESPACE@[2; 3) " " |
5 | NAME@[3; 6) | 5 | NAME@[3; 6) |
@@ -8,18 +8,18 @@ SOURCE_FILE@[0; 215) | |||
8 | L_PAREN@[6; 7) "(" | 8 | L_PAREN@[6; 7) "(" |
9 | R_PAREN@[7; 8) ")" | 9 | R_PAREN@[7; 8) ")" |
10 | WHITESPACE@[8; 9) " " | 10 | WHITESPACE@[8; 9) " " |
11 | BLOCK@[9; 214) | 11 | BLOCK@[9; 166) |
12 | L_CURLY@[9; 10) "{" | 12 | L_CURLY@[9; 10) "{" |
13 | WHITESPACE@[10; 15) "\n " | 13 | WHITESPACE@[10; 15) "\n " |
14 | EXPR_STMT@[15; 212) | 14 | EXPR_STMT@[15; 164) |
15 | MATCH_EXPR@[15; 211) | 15 | MATCH_EXPR@[15; 163) |
16 | MATCH_KW@[15; 20) "match" | 16 | MATCH_KW@[15; 20) "match" |
17 | WHITESPACE@[20; 21) " " | 17 | WHITESPACE@[20; 21) " " |
18 | TUPLE_EXPR@[21; 23) | 18 | TUPLE_EXPR@[21; 23) |
19 | L_PAREN@[21; 22) "(" | 19 | L_PAREN@[21; 22) "(" |
20 | R_PAREN@[22; 23) ")" | 20 | R_PAREN@[22; 23) ")" |
21 | WHITESPACE@[23; 24) " " | 21 | WHITESPACE@[23; 24) " " |
22 | MATCH_ARM_LIST@[24; 211) | 22 | MATCH_ARM_LIST@[24; 163) |
23 | L_CURLY@[24; 25) "{" | 23 | L_CURLY@[24; 25) "{" |
24 | WHITESPACE@[25; 34) "\n " | 24 | WHITESPACE@[25; 34) "\n " |
25 | MATCH_ARM@[34; 41) | 25 | MATCH_ARM@[34; 41) |
@@ -141,44 +141,9 @@ SOURCE_FILE@[0; 215) | |||
141 | L_PAREN@[154; 155) "(" | 141 | L_PAREN@[154; 155) "(" |
142 | R_PAREN@[155; 156) ")" | 142 | R_PAREN@[155; 156) ")" |
143 | COMMA@[156; 157) "," | 143 | COMMA@[156; 157) "," |
144 | WHITESPACE@[157; 166) "\n " | 144 | WHITESPACE@[157; 162) "\n " |
145 | MATCH_ARM@[166; 177) | 145 | R_CURLY@[162; 163) "}" |
146 | BIND_PAT@[166; 171) | 146 | SEMI@[163; 164) ";" |
147 | BOX_KW@[166; 169) "box" | 147 | WHITESPACE@[164; 165) "\n" |
148 | WHITESPACE@[169; 170) " " | 148 | R_CURLY@[165; 166) "}" |
149 | NAME@[170; 171) | 149 | WHITESPACE@[166; 167) "\n" |
150 | IDENT@[170; 171) "X" | ||
151 | WHITESPACE@[171; 172) " " | ||
152 | FAT_ARROW@[172; 174) "=>" | ||
153 | WHITESPACE@[174; 175) " " | ||
154 | TUPLE_EXPR@[175; 177) | ||
155 | L_PAREN@[175; 176) "(" | ||
156 | R_PAREN@[176; 177) ")" | ||
157 | COMMA@[177; 178) "," | ||
158 | WHITESPACE@[178; 187) "\n " | ||
159 | MATCH_ARM@[187; 204) | ||
160 | TUPLE_STRUCT_PAT@[187; 198) | ||
161 | PATH@[187; 191) | ||
162 | PATH_SEGMENT@[187; 191) | ||
163 | NAME_REF@[187; 191) | ||
164 | IDENT@[187; 191) "Some" | ||
165 | L_PAREN@[191; 192) "(" | ||
166 | BIND_PAT@[192; 197) | ||
167 | BOX_KW@[192; 195) "box" | ||
168 | WHITESPACE@[195; 196) " " | ||
169 | NAME@[196; 197) | ||
170 | IDENT@[196; 197) "X" | ||
171 | R_PAREN@[197; 198) ")" | ||
172 | WHITESPACE@[198; 199) " " | ||
173 | FAT_ARROW@[199; 201) "=>" | ||
174 | WHITESPACE@[201; 202) " " | ||
175 | TUPLE_EXPR@[202; 204) | ||
176 | L_PAREN@[202; 203) "(" | ||
177 | R_PAREN@[203; 204) ")" | ||
178 | COMMA@[204; 205) "," | ||
179 | WHITESPACE@[205; 210) "\n " | ||
180 | R_CURLY@[210; 211) "}" | ||
181 | SEMI@[211; 212) ";" | ||
182 | WHITESPACE@[212; 213) "\n" | ||
183 | R_CURLY@[213; 214) "}" | ||
184 | WHITESPACE@[214; 215) "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0112_bind_pat.rs b/crates/ra_syntax/test_data/parser/inline/ok/0112_bind_pat.rs index 5a93469af..820a9e72c 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0112_bind_pat.rs +++ b/crates/ra_syntax/test_data/parser/inline/ok/0112_bind_pat.rs | |||
@@ -5,5 +5,4 @@ fn main() { | |||
5 | let ref mut d = (); | 5 | let ref mut d = (); |
6 | let e @ _ = (); | 6 | let e @ _ = (); |
7 | let ref mut f @ g @ _ = (); | 7 | let ref mut f @ g @ _ = (); |
8 | let box i = Box::new(1i32); | ||
9 | } | 8 | } |
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0112_bind_pat.txt b/crates/ra_syntax/test_data/parser/inline/ok/0112_bind_pat.txt index 189254a19..ab0f88507 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0112_bind_pat.txt +++ b/crates/ra_syntax/test_data/parser/inline/ok/0112_bind_pat.txt | |||
@@ -1,5 +1,5 @@ | |||
1 | SOURCE_FILE@[0; 178) | 1 | SOURCE_FILE@[0; 146) |
2 | FN_DEF@[0; 177) | 2 | FN_DEF@[0; 145) |
3 | FN_KW@[0; 2) "fn" | 3 | FN_KW@[0; 2) "fn" |
4 | WHITESPACE@[2; 3) " " | 4 | WHITESPACE@[2; 3) " " |
5 | NAME@[3; 7) | 5 | NAME@[3; 7) |
@@ -8,7 +8,7 @@ SOURCE_FILE@[0; 178) | |||
8 | L_PAREN@[7; 8) "(" | 8 | L_PAREN@[7; 8) "(" |
9 | R_PAREN@[8; 9) ")" | 9 | R_PAREN@[8; 9) ")" |
10 | WHITESPACE@[9; 10) " " | 10 | WHITESPACE@[9; 10) " " |
11 | BLOCK@[10; 177) | 11 | BLOCK@[10; 145) |
12 | L_CURLY@[10; 11) "{" | 12 | L_CURLY@[10; 11) "{" |
13 | WHITESPACE@[11; 16) "\n " | 13 | WHITESPACE@[11; 16) "\n " |
14 | LET_STMT@[16; 27) | 14 | LET_STMT@[16; 27) |
@@ -122,35 +122,6 @@ SOURCE_FILE@[0; 178) | |||
122 | L_PAREN@[140; 141) "(" | 122 | L_PAREN@[140; 141) "(" |
123 | R_PAREN@[141; 142) ")" | 123 | R_PAREN@[141; 142) ")" |
124 | SEMI@[142; 143) ";" | 124 | SEMI@[142; 143) ";" |
125 | WHITESPACE@[143; 148) "\n " | 125 | WHITESPACE@[143; 144) "\n" |
126 | LET_STMT@[148; 175) | 126 | R_CURLY@[144; 145) "}" |
127 | LET_KW@[148; 151) "let" | 127 | WHITESPACE@[145; 146) "\n" |
128 | WHITESPACE@[151; 152) " " | ||
129 | BIND_PAT@[152; 157) | ||
130 | BOX_KW@[152; 155) "box" | ||
131 | WHITESPACE@[155; 156) " " | ||
132 | NAME@[156; 157) | ||
133 | IDENT@[156; 157) "i" | ||
134 | WHITESPACE@[157; 158) " " | ||
135 | EQ@[158; 159) "=" | ||
136 | WHITESPACE@[159; 160) " " | ||
137 | CALL_EXPR@[160; 174) | ||
138 | PATH_EXPR@[160; 168) | ||
139 | PATH@[160; 168) | ||
140 | PATH@[160; 163) | ||
141 | PATH_SEGMENT@[160; 163) | ||
142 | NAME_REF@[160; 163) | ||
143 | IDENT@[160; 163) "Box" | ||
144 | COLONCOLON@[163; 165) "::" | ||
145 | PATH_SEGMENT@[165; 168) | ||
146 | NAME_REF@[165; 168) | ||
147 | IDENT@[165; 168) "new" | ||
148 | ARG_LIST@[168; 174) | ||
149 | L_PAREN@[168; 169) "(" | ||
150 | LITERAL@[169; 173) | ||
151 | INT_NUMBER@[169; 173) "1i32" | ||
152 | R_PAREN@[173; 174) ")" | ||
153 | SEMI@[174; 175) ";" | ||
154 | WHITESPACE@[175; 176) "\n" | ||
155 | R_CURLY@[176; 177) "}" | ||
156 | WHITESPACE@[177; 178) "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0143_box_pat.rs b/crates/ra_syntax/test_data/parser/inline/ok/0143_box_pat.rs new file mode 100644 index 000000000..9d458aa1e --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0143_box_pat.rs | |||
@@ -0,0 +1,5 @@ | |||
1 | fn main() { | ||
2 | let box i = (); | ||
3 | let box Outer { box i, j: box Inner(box &x) } = (); | ||
4 | let box ref mut i = (); | ||
5 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0143_box_pat.txt b/crates/ra_syntax/test_data/parser/inline/ok/0143_box_pat.txt new file mode 100644 index 000000000..f0db58143 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0143_box_pat.txt | |||
@@ -0,0 +1,109 @@ | |||
1 | SOURCE_FILE@[0; 118) | ||
2 | FN_DEF@[0; 117) | ||
3 | FN_KW@[0; 2) "fn" | ||
4 | WHITESPACE@[2; 3) " " | ||
5 | NAME@[3; 7) | ||
6 | IDENT@[3; 7) "main" | ||
7 | PARAM_LIST@[7; 9) | ||
8 | L_PAREN@[7; 8) "(" | ||
9 | R_PAREN@[8; 9) ")" | ||
10 | WHITESPACE@[9; 10) " " | ||
11 | BLOCK@[10; 117) | ||
12 | L_CURLY@[10; 11) "{" | ||
13 | WHITESPACE@[11; 16) "\n " | ||
14 | LET_STMT@[16; 31) | ||
15 | LET_KW@[16; 19) "let" | ||
16 | WHITESPACE@[19; 20) " " | ||
17 | BOX_PAT@[20; 25) | ||
18 | BOX_KW@[20; 23) "box" | ||
19 | WHITESPACE@[23; 24) " " | ||
20 | BIND_PAT@[24; 25) | ||
21 | NAME@[24; 25) | ||
22 | IDENT@[24; 25) "i" | ||
23 | WHITESPACE@[25; 26) " " | ||
24 | EQ@[26; 27) "=" | ||
25 | WHITESPACE@[27; 28) " " | ||
26 | TUPLE_EXPR@[28; 30) | ||
27 | L_PAREN@[28; 29) "(" | ||
28 | R_PAREN@[29; 30) ")" | ||
29 | SEMI@[30; 31) ";" | ||
30 | WHITESPACE@[31; 36) "\n " | ||
31 | LET_STMT@[36; 87) | ||
32 | LET_KW@[36; 39) "let" | ||
33 | WHITESPACE@[39; 40) " " | ||
34 | BOX_PAT@[40; 81) | ||
35 | BOX_KW@[40; 43) "box" | ||
36 | WHITESPACE@[43; 44) " " | ||
37 | RECORD_PAT@[44; 81) | ||
38 | PATH@[44; 49) | ||
39 | PATH_SEGMENT@[44; 49) | ||
40 | NAME_REF@[44; 49) | ||
41 | IDENT@[44; 49) "Outer" | ||
42 | WHITESPACE@[49; 50) " " | ||
43 | RECORD_FIELD_PAT_LIST@[50; 81) | ||
44 | L_CURLY@[50; 51) "{" | ||
45 | WHITESPACE@[51; 52) " " | ||
46 | BOX_PAT@[52; 57) | ||
47 | BOX_KW@[52; 55) "box" | ||
48 | WHITESPACE@[55; 56) " " | ||
49 | BIND_PAT@[56; 57) | ||
50 | NAME@[56; 57) | ||
51 | IDENT@[56; 57) "i" | ||
52 | COMMA@[57; 58) "," | ||
53 | WHITESPACE@[58; 59) " " | ||
54 | RECORD_FIELD_PAT@[59; 79) | ||
55 | NAME@[59; 60) | ||
56 | IDENT@[59; 60) "j" | ||
57 | COLON@[60; 61) ":" | ||
58 | WHITESPACE@[61; 62) " " | ||
59 | BOX_PAT@[62; 79) | ||
60 | BOX_KW@[62; 65) "box" | ||
61 | WHITESPACE@[65; 66) " " | ||
62 | TUPLE_STRUCT_PAT@[66; 79) | ||
63 | PATH@[66; 71) | ||
64 | PATH_SEGMENT@[66; 71) | ||
65 | NAME_REF@[66; 71) | ||
66 | IDENT@[66; 71) "Inner" | ||
67 | L_PAREN@[71; 72) "(" | ||
68 | BOX_PAT@[72; 78) | ||
69 | BOX_KW@[72; 75) "box" | ||
70 | WHITESPACE@[75; 76) " " | ||
71 | REF_PAT@[76; 78) | ||
72 | AMP@[76; 77) "&" | ||
73 | BIND_PAT@[77; 78) | ||
74 | NAME@[77; 78) | ||
75 | IDENT@[77; 78) "x" | ||
76 | R_PAREN@[78; 79) ")" | ||
77 | WHITESPACE@[79; 80) " " | ||
78 | R_CURLY@[80; 81) "}" | ||
79 | WHITESPACE@[81; 82) " " | ||
80 | EQ@[82; 83) "=" | ||
81 | WHITESPACE@[83; 84) " " | ||
82 | TUPLE_EXPR@[84; 86) | ||
83 | L_PAREN@[84; 85) "(" | ||
84 | R_PAREN@[85; 86) ")" | ||
85 | SEMI@[86; 87) ";" | ||
86 | WHITESPACE@[87; 92) "\n " | ||
87 | LET_STMT@[92; 115) | ||
88 | LET_KW@[92; 95) "let" | ||
89 | WHITESPACE@[95; 96) " " | ||
90 | BOX_PAT@[96; 109) | ||
91 | BOX_KW@[96; 99) "box" | ||
92 | WHITESPACE@[99; 100) " " | ||
93 | BIND_PAT@[100; 109) | ||
94 | REF_KW@[100; 103) "ref" | ||
95 | WHITESPACE@[103; 104) " " | ||
96 | MUT_KW@[104; 107) "mut" | ||
97 | WHITESPACE@[107; 108) " " | ||
98 | NAME@[108; 109) | ||
99 | IDENT@[108; 109) "i" | ||
100 | WHITESPACE@[109; 110) " " | ||
101 | EQ@[110; 111) "=" | ||
102 | WHITESPACE@[111; 112) " " | ||
103 | TUPLE_EXPR@[112; 114) | ||
104 | L_PAREN@[112; 113) "(" | ||
105 | R_PAREN@[113; 114) ")" | ||
106 | SEMI@[114; 115) ";" | ||
107 | WHITESPACE@[115; 116) "\n" | ||
108 | R_CURLY@[116; 117) "}" | ||
109 | WHITESPACE@[117; 118) "\n" | ||