diff options
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/code_model/attrs.rs | 92 | ||||
-rw-r--r-- | crates/ra_hir/src/db.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/complete_postfix.rs | 109 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/presentation.rs | 27 | ||||
-rw-r--r-- | crates/ra_parser/src/grammar/types.rs | 6 | ||||
-rw-r--r-- | xtask/src/codegen.rs | 8 |
8 files changed, 177 insertions, 71 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 4e273d9e4..9d0db8024 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | pub(crate) mod src; | 3 | pub(crate) mod src; |
4 | pub(crate) mod docs; | 4 | pub(crate) mod docs; |
5 | pub(crate) mod attrs; | ||
5 | 6 | ||
6 | use std::sync::Arc; | 7 | use std::sync::Arc; |
7 | 8 | ||
diff --git a/crates/ra_hir/src/code_model/attrs.rs b/crates/ra_hir/src/code_model/attrs.rs new file mode 100644 index 000000000..f7db36b66 --- /dev/null +++ b/crates/ra_hir/src/code_model/attrs.rs | |||
@@ -0,0 +1,92 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use crate::{ | ||
4 | db::{AstDatabase, DefDatabase, HirDatabase}, | ||
5 | Adt, Const, Enum, EnumVariant, FieldSource, Function, HasSource, MacroDef, Module, Static, | ||
6 | Struct, StructField, Trait, TypeAlias, Union, | ||
7 | }; | ||
8 | use hir_def::attr::Attr; | ||
9 | use hir_expand::hygiene::Hygiene; | ||
10 | use ra_syntax::ast; | ||
11 | use std::sync::Arc; | ||
12 | |||
13 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
14 | pub enum AttrDef { | ||
15 | Module(Module), | ||
16 | StructField(StructField), | ||
17 | Adt(Adt), | ||
18 | Function(Function), | ||
19 | EnumVariant(EnumVariant), | ||
20 | Static(Static), | ||
21 | Const(Const), | ||
22 | Trait(Trait), | ||
23 | TypeAlias(TypeAlias), | ||
24 | MacroDef(MacroDef), | ||
25 | } | ||
26 | |||
27 | impl_froms!( | ||
28 | AttrDef: Module, | ||
29 | StructField, | ||
30 | Adt(Struct, Enum, Union), | ||
31 | EnumVariant, | ||
32 | Static, | ||
33 | Const, | ||
34 | Function, | ||
35 | Trait, | ||
36 | TypeAlias, | ||
37 | MacroDef | ||
38 | ); | ||
39 | |||
40 | pub trait Attrs { | ||
41 | fn attrs(&self, db: &impl HirDatabase) -> Option<Arc<[Attr]>>; | ||
42 | } | ||
43 | |||
44 | pub(crate) fn attributes_query( | ||
45 | db: &(impl DefDatabase + AstDatabase), | ||
46 | def: AttrDef, | ||
47 | ) -> Option<Arc<[Attr]>> { | ||
48 | match def { | ||
49 | AttrDef::Module(it) => { | ||
50 | let src = it.declaration_source(db)?; | ||
51 | let hygiene = Hygiene::new(db, src.file_id); | ||
52 | Attr::from_attrs_owner(&src.ast, &hygiene) | ||
53 | } | ||
54 | AttrDef::StructField(it) => match it.source(db).ast { | ||
55 | FieldSource::Named(named) => { | ||
56 | let src = it.source(db); | ||
57 | let hygiene = Hygiene::new(db, src.file_id); | ||
58 | Attr::from_attrs_owner(&named, &hygiene) | ||
59 | } | ||
60 | FieldSource::Pos(..) => None, | ||
61 | }, | ||
62 | AttrDef::Adt(it) => match it { | ||
63 | Adt::Struct(it) => attrs_from_ast(it, db), | ||
64 | Adt::Enum(it) => attrs_from_ast(it, db), | ||
65 | Adt::Union(it) => attrs_from_ast(it, db), | ||
66 | }, | ||
67 | AttrDef::EnumVariant(it) => attrs_from_ast(it, db), | ||
68 | AttrDef::Static(it) => attrs_from_ast(it, db), | ||
69 | AttrDef::Const(it) => attrs_from_ast(it, db), | ||
70 | AttrDef::Function(it) => attrs_from_ast(it, db), | ||
71 | AttrDef::Trait(it) => attrs_from_ast(it, db), | ||
72 | AttrDef::TypeAlias(it) => attrs_from_ast(it, db), | ||
73 | AttrDef::MacroDef(it) => attrs_from_ast(it, db), | ||
74 | } | ||
75 | } | ||
76 | |||
77 | fn attrs_from_ast<T, D>(node: T, db: &D) -> Option<Arc<[Attr]>> | ||
78 | where | ||
79 | T: HasSource, | ||
80 | T::Ast: ast::AttrsOwner, | ||
81 | D: DefDatabase + AstDatabase, | ||
82 | { | ||
83 | let src = node.source(db); | ||
84 | let hygiene = Hygiene::new(db, src.file_id); | ||
85 | Attr::from_attrs_owner(&src.ast, &hygiene) | ||
86 | } | ||
87 | |||
88 | impl<T: Into<AttrDef> + Copy> Attrs for T { | ||
89 | fn attrs(&self, db: &impl HirDatabase) -> Option<Arc<[Attr]>> { | ||
90 | db.attrs((*self).into()) | ||
91 | } | ||
92 | } | ||
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 11b3f94ae..75c322c99 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use hir_def::attr::Attr; | ||
5 | use ra_db::salsa; | 6 | use ra_db::salsa; |
6 | use ra_syntax::SmolStr; | 7 | use ra_syntax::SmolStr; |
7 | 8 | ||
@@ -75,6 +76,9 @@ pub trait DefDatabase: HirDebugDatabase + DefDatabase2 { | |||
75 | 76 | ||
76 | #[salsa::invoke(crate::code_model::docs::documentation_query)] | 77 | #[salsa::invoke(crate::code_model::docs::documentation_query)] |
77 | fn documentation(&self, def: crate::DocDef) -> Option<crate::Documentation>; | 78 | fn documentation(&self, def: crate::DocDef) -> Option<crate::Documentation>; |
79 | |||
80 | #[salsa::invoke(crate::code_model::attrs::attributes_query)] | ||
81 | fn attrs(&self, def: crate::AttrDef) -> Option<Arc<[Attr]>>; | ||
78 | } | 82 | } |
79 | 83 | ||
80 | #[salsa::query_group(HirDatabaseStorage)] | 84 | #[salsa::query_group(HirDatabaseStorage)] |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 5f2a05e76..131f6c797 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -61,6 +61,7 @@ use crate::{ids::MacroFileKind, resolve::Resolver}; | |||
61 | pub use crate::{ | 61 | pub use crate::{ |
62 | adt::VariantDef, | 62 | adt::VariantDef, |
63 | code_model::{ | 63 | code_model::{ |
64 | attrs::{AttrDef, Attrs}, | ||
64 | docs::{DocDef, Docs, Documentation}, | 65 | docs::{DocDef, Docs, Documentation}, |
65 | src::{HasBodySource, HasSource}, | 66 | src::{HasBodySource, HasSource}, |
66 | Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum, | 67 | Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum, |
diff --git a/crates/ra_ide_api/src/completion/complete_postfix.rs b/crates/ra_ide_api/src/completion/complete_postfix.rs index 60ed3518b..4f9565441 100644 --- a/crates/ra_ide_api/src/completion/complete_postfix.rs +++ b/crates/ra_ide_api/src/completion/complete_postfix.rs | |||
@@ -1,5 +1,9 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir::{Ty, TypeCtor}; | ||
4 | use ra_syntax::{ast::AstNode, TextRange, TextUnit}; | ||
5 | use ra_text_edit::TextEdit; | ||
6 | |||
3 | use crate::{ | 7 | use crate::{ |
4 | completion::{ | 8 | completion::{ |
5 | completion_context::CompletionContext, | 9 | completion_context::CompletionContext, |
@@ -7,9 +11,53 @@ use crate::{ | |||
7 | }, | 11 | }, |
8 | CompletionItem, | 12 | CompletionItem, |
9 | }; | 13 | }; |
10 | use hir::{Ty, TypeCtor}; | 14 | |
11 | use ra_syntax::{ast::AstNode, TextRange, TextUnit}; | 15 | pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { |
12 | use ra_text_edit::TextEdit; | 16 | let dot_receiver = match &ctx.dot_receiver { |
17 | Some(it) => it, | ||
18 | None => return, | ||
19 | }; | ||
20 | |||
21 | let receiver_text = if ctx.dot_receiver_is_ambiguous_float_literal { | ||
22 | let text = dot_receiver.syntax().text(); | ||
23 | let without_dot = ..text.len() - TextUnit::of_char('.'); | ||
24 | text.slice(without_dot).to_string() | ||
25 | } else { | ||
26 | dot_receiver.syntax().text().to_string() | ||
27 | }; | ||
28 | |||
29 | let receiver_ty = ctx.analyzer.type_of(ctx.db, &dot_receiver); | ||
30 | |||
31 | if is_bool_or_unknown(receiver_ty) { | ||
32 | postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text)) | ||
33 | .add_to(acc); | ||
34 | postfix_snippet( | ||
35 | ctx, | ||
36 | "while", | ||
37 | "while expr {}", | ||
38 | &format!("while {} {{\n$0\n}}", receiver_text), | ||
39 | ) | ||
40 | .add_to(acc); | ||
41 | } | ||
42 | |||
43 | postfix_snippet(ctx, "not", "!expr", &format!("!{}", receiver_text)).add_to(acc); | ||
44 | |||
45 | postfix_snippet(ctx, "ref", "&expr", &format!("&{}", receiver_text)).add_to(acc); | ||
46 | postfix_snippet(ctx, "refm", "&mut expr", &format!("&mut {}", receiver_text)).add_to(acc); | ||
47 | |||
48 | postfix_snippet( | ||
49 | ctx, | ||
50 | "match", | ||
51 | "match expr {}", | ||
52 | &format!("match {} {{\n ${{1:_}} => {{$0\\}},\n}}", receiver_text), | ||
53 | ) | ||
54 | .add_to(acc); | ||
55 | |||
56 | postfix_snippet(ctx, "dbg", "dbg!(expr)", &format!("dbg!({})", receiver_text)).add_to(acc); | ||
57 | |||
58 | postfix_snippet(ctx, "box", "Box::new(expr)", &format!("Box::new({})", receiver_text)) | ||
59 | .add_to(acc); | ||
60 | } | ||
13 | 61 | ||
14 | fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder { | 62 | fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder { |
15 | let edit = { | 63 | let edit = { |
@@ -24,62 +72,19 @@ fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: | |||
24 | } | 72 | } |
25 | 73 | ||
26 | fn is_bool_or_unknown(ty: Option<Ty>) -> bool { | 74 | fn is_bool_or_unknown(ty: Option<Ty>) -> bool { |
27 | if let Some(ty) = ty { | 75 | match &ty { |
28 | match ty { | 76 | Some(Ty::Apply(app)) if app.ctor == TypeCtor::Bool => true, |
29 | Ty::Apply(at) => match at.ctor { | 77 | Some(Ty::Unknown) | None => true, |
30 | TypeCtor::Bool => true, | 78 | Some(_) => false, |
31 | _ => false, | ||
32 | }, | ||
33 | Ty::Unknown => true, | ||
34 | _ => false, | ||
35 | } | ||
36 | } else { | ||
37 | true | ||
38 | } | ||
39 | } | ||
40 | |||
41 | pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | ||
42 | if let Some(dot_receiver) = &ctx.dot_receiver { | ||
43 | let receiver_text = if ctx.dot_receiver_is_ambiguous_float_literal { | ||
44 | let text = dot_receiver.syntax().text(); | ||
45 | let without_dot = ..text.len() - TextUnit::of_char('.'); | ||
46 | text.slice(without_dot).to_string() | ||
47 | } else { | ||
48 | dot_receiver.syntax().text().to_string() | ||
49 | }; | ||
50 | let receiver_ty = ctx.analyzer.type_of(ctx.db, &dot_receiver); | ||
51 | if is_bool_or_unknown(receiver_ty) { | ||
52 | postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text)) | ||
53 | .add_to(acc); | ||
54 | postfix_snippet( | ||
55 | ctx, | ||
56 | "while", | ||
57 | "while expr {}", | ||
58 | &format!("while {} {{\n$0\n}}", receiver_text), | ||
59 | ) | ||
60 | .add_to(acc); | ||
61 | } | ||
62 | postfix_snippet(ctx, "not", "!expr", &format!("!{}", receiver_text)).add_to(acc); | ||
63 | postfix_snippet(ctx, "ref", "&expr", &format!("&{}", receiver_text)).add_to(acc); | ||
64 | postfix_snippet(ctx, "refm", "&mut expr", &format!("&mut {}", receiver_text)).add_to(acc); | ||
65 | postfix_snippet( | ||
66 | ctx, | ||
67 | "match", | ||
68 | "match expr {}", | ||
69 | &format!("match {} {{\n ${{1:_}} => {{$0\\}},\n}}", receiver_text), | ||
70 | ) | ||
71 | .add_to(acc); | ||
72 | postfix_snippet(ctx, "dbg", "dbg!(expr)", &format!("dbg!({})", receiver_text)).add_to(acc); | ||
73 | postfix_snippet(ctx, "box", "Box::new(expr)", &format!("Box::new({})", receiver_text)) | ||
74 | .add_to(acc); | ||
75 | } | 79 | } |
76 | } | 80 | } |
77 | 81 | ||
78 | #[cfg(test)] | 82 | #[cfg(test)] |
79 | mod tests { | 83 | mod tests { |
80 | use crate::completion::{do_completion, CompletionItem, CompletionKind}; | ||
81 | use insta::assert_debug_snapshot; | 84 | use insta::assert_debug_snapshot; |
82 | 85 | ||
86 | use crate::completion::{do_completion, CompletionItem, CompletionKind}; | ||
87 | |||
83 | fn do_postfix_completion(code: &str) -> Vec<CompletionItem> { | 88 | fn do_postfix_completion(code: &str) -> Vec<CompletionItem> { |
84 | do_completion(code, CompletionKind::Postfix) | 89 | do_completion(code, CompletionKind::Postfix) |
85 | } | 90 | } |
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs index cb55d1875..d861303b7 100644 --- a/crates/ra_ide_api/src/completion/presentation.rs +++ b/crates/ra_ide_api/src/completion/presentation.rs | |||
@@ -1,8 +1,8 @@ | |||
1 | //! This modules takes care of rendering various definitions as completion items. | 1 | //! This modules takes care of rendering various definitions as completion items. |
2 | 2 | ||
3 | use hir::{db::HirDatabase, Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk}; | 3 | use hir::{db::HirDatabase, Attrs, Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk}; |
4 | use join_to_string::join; | 4 | use join_to_string::join; |
5 | use ra_syntax::ast::{AttrsOwner, NameOwner}; | 5 | use ra_syntax::ast::NameOwner; |
6 | use test_utils::tested_by; | 6 | use test_utils::tested_by; |
7 | 7 | ||
8 | use crate::completion::{ | 8 | use crate::completion::{ |
@@ -18,11 +18,7 @@ impl Completions { | |||
18 | field: hir::StructField, | 18 | field: hir::StructField, |
19 | substs: &hir::Substs, | 19 | substs: &hir::Substs, |
20 | ) { | 20 | ) { |
21 | let ast_node = field.source(ctx.db).ast; | 21 | let is_deprecated = is_deprecated(field, ctx.db); |
22 | let is_deprecated = match ast_node { | ||
23 | hir::FieldSource::Named(m) => is_deprecated(m), | ||
24 | hir::FieldSource::Pos(m) => is_deprecated(m), | ||
25 | }; | ||
26 | CompletionItem::new( | 22 | CompletionItem::new( |
27 | CompletionKind::Reference, | 23 | CompletionKind::Reference, |
28 | ctx.source_range(), | 24 | ctx.source_range(), |
@@ -185,7 +181,7 @@ impl Completions { | |||
185 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), ¯o_declaration) | 181 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), ¯o_declaration) |
186 | .kind(CompletionItemKind::Macro) | 182 | .kind(CompletionItemKind::Macro) |
187 | .set_documentation(docs.clone()) | 183 | .set_documentation(docs.clone()) |
188 | .set_deprecated(is_deprecated(ast_node)) | 184 | .set_deprecated(is_deprecated(macro_, ctx.db)) |
189 | .detail(detail); | 185 | .detail(detail); |
190 | 186 | ||
191 | builder = if ctx.use_item_syntax.is_some() { | 187 | builder = if ctx.use_item_syntax.is_some() { |
@@ -218,7 +214,7 @@ impl Completions { | |||
218 | CompletionItemKind::Function | 214 | CompletionItemKind::Function |
219 | }) | 215 | }) |
220 | .set_documentation(func.docs(ctx.db)) | 216 | .set_documentation(func.docs(ctx.db)) |
221 | .set_deprecated(is_deprecated(ast_node)) | 217 | .set_deprecated(is_deprecated(func, ctx.db)) |
222 | .detail(detail); | 218 | .detail(detail); |
223 | 219 | ||
224 | // Add `<>` for generic types | 220 | // Add `<>` for generic types |
@@ -250,7 +246,7 @@ impl Completions { | |||
250 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string()) | 246 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string()) |
251 | .kind(CompletionItemKind::Const) | 247 | .kind(CompletionItemKind::Const) |
252 | .set_documentation(constant.docs(ctx.db)) | 248 | .set_documentation(constant.docs(ctx.db)) |
253 | .set_deprecated(is_deprecated(ast_node)) | 249 | .set_deprecated(is_deprecated(constant, ctx.db)) |
254 | .detail(detail) | 250 | .detail(detail) |
255 | .add_to(self); | 251 | .add_to(self); |
256 | } | 252 | } |
@@ -266,13 +262,13 @@ impl Completions { | |||
266 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string()) | 262 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string()) |
267 | .kind(CompletionItemKind::TypeAlias) | 263 | .kind(CompletionItemKind::TypeAlias) |
268 | .set_documentation(type_alias.docs(ctx.db)) | 264 | .set_documentation(type_alias.docs(ctx.db)) |
269 | .set_deprecated(is_deprecated(type_def)) | 265 | .set_deprecated(is_deprecated(type_alias, ctx.db)) |
270 | .detail(detail) | 266 | .detail(detail) |
271 | .add_to(self); | 267 | .add_to(self); |
272 | } | 268 | } |
273 | 269 | ||
274 | pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) { | 270 | pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) { |
275 | let is_deprecated = is_deprecated(variant.source(ctx.db).ast); | 271 | let is_deprecated = is_deprecated(variant, ctx.db); |
276 | let name = match variant.name(ctx.db) { | 272 | let name = match variant.name(ctx.db) { |
277 | Some(it) => it, | 273 | Some(it) => it, |
278 | None => return, | 274 | None => return, |
@@ -291,8 +287,11 @@ impl Completions { | |||
291 | } | 287 | } |
292 | } | 288 | } |
293 | 289 | ||
294 | fn is_deprecated(node: impl AttrsOwner) -> bool { | 290 | fn is_deprecated(node: impl Attrs, db: &impl HirDatabase) -> bool { |
295 | node.attrs().filter_map(|x| x.simple_name()).any(|x| x == "deprecated") | 291 | match node.attrs(db) { |
292 | None => false, | ||
293 | Some(attrs) => attrs.iter().any(|x| x.is_simple_atom("deprecated")), | ||
294 | } | ||
296 | } | 295 | } |
297 | 296 | ||
298 | fn has_non_default_type_params(def: hir::GenericDef, db: &db::RootDatabase) -> bool { | 297 | fn has_non_default_type_params(def: hir::GenericDef, db: &db::RootDatabase) -> bool { |
diff --git a/crates/ra_parser/src/grammar/types.rs b/crates/ra_parser/src/grammar/types.rs index d4ca94fca..9b2e440fb 100644 --- a/crates/ra_parser/src/grammar/types.rs +++ b/crates/ra_parser/src/grammar/types.rs | |||
@@ -28,7 +28,7 @@ fn type_with_bounds_cond(p: &mut Parser, allow_bounds: bool) { | |||
28 | T![fn] | T![unsafe] | T![extern] => fn_pointer_type(p), | 28 | T![fn] | T![unsafe] | T![extern] => fn_pointer_type(p), |
29 | T![for] => for_type(p), | 29 | T![for] => for_type(p), |
30 | T![impl] => impl_trait_type(p), | 30 | T![impl] => impl_trait_type(p), |
31 | T![dyn ] => dyn_trait_type(p), | 31 | T![dyn] => dyn_trait_type(p), |
32 | // Some path types are not allowed to have bounds (no plus) | 32 | // Some path types are not allowed to have bounds (no plus) |
33 | T![<] => path_type_(p, allow_bounds), | 33 | T![<] => path_type_(p, allow_bounds), |
34 | _ if paths::is_use_path_start(p) => path_or_macro_type_(p, allow_bounds), | 34 | _ if paths::is_use_path_start(p) => path_or_macro_type_(p, allow_bounds), |
@@ -234,9 +234,9 @@ fn impl_trait_type(p: &mut Parser) { | |||
234 | // test dyn_trait_type | 234 | // test dyn_trait_type |
235 | // type A = dyn Iterator<Item=Foo<'a>> + 'a; | 235 | // type A = dyn Iterator<Item=Foo<'a>> + 'a; |
236 | fn dyn_trait_type(p: &mut Parser) { | 236 | fn dyn_trait_type(p: &mut Parser) { |
237 | assert!(p.at(T![dyn ])); | 237 | assert!(p.at(T![dyn])); |
238 | let m = p.start(); | 238 | let m = p.start(); |
239 | p.bump(T![dyn ]); | 239 | p.bump(T![dyn]); |
240 | type_params::bounds_without_colon(p); | 240 | type_params::bounds_without_colon(p); |
241 | m.complete(p, DYN_TRAIT_TYPE); | 241 | m.complete(p, DYN_TRAIT_TYPE); |
242 | } | 242 | } |
diff --git a/xtask/src/codegen.rs b/xtask/src/codegen.rs index 4ec8ab75a..770b55a9a 100644 --- a/xtask/src/codegen.rs +++ b/xtask/src/codegen.rs | |||
@@ -46,7 +46,7 @@ pub enum Mode { | |||
46 | /// With verify = false, | 46 | /// With verify = false, |
47 | fn update(path: &Path, contents: &str, mode: Mode) -> Result<()> { | 47 | fn update(path: &Path, contents: &str, mode: Mode) -> Result<()> { |
48 | match fs::read_to_string(path) { | 48 | match fs::read_to_string(path) { |
49 | Ok(ref old_contents) if old_contents == contents => { | 49 | Ok(ref old_contents) if normalize(old_contents) == normalize(contents) => { |
50 | return Ok(()); | 50 | return Ok(()); |
51 | } | 51 | } |
52 | _ => (), | 52 | _ => (), |
@@ -56,7 +56,11 @@ fn update(path: &Path, contents: &str, mode: Mode) -> Result<()> { | |||
56 | } | 56 | } |
57 | eprintln!("updating {}", path.display()); | 57 | eprintln!("updating {}", path.display()); |
58 | fs::write(path, contents)?; | 58 | fs::write(path, contents)?; |
59 | Ok(()) | 59 | return Ok(()); |
60 | |||
61 | fn normalize(s: &str) -> String { | ||
62 | s.replace("\r\n", "\n") | ||
63 | } | ||
60 | } | 64 | } |
61 | 65 | ||
62 | fn reformat(text: impl std::fmt::Display) -> Result<String> { | 66 | fn reformat(text: impl std::fmt::Display) -> Result<String> { |