aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir_expand/src/db.rs44
-rw-r--r--docs/dev/style.md33
2 files changed, 50 insertions, 27 deletions
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index 935c547b0..8f27a7fc9 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -122,16 +122,27 @@ pub fn expand_hypothetical(
122 hypothetical_args: &ast::TokenTree, 122 hypothetical_args: &ast::TokenTree,
123 token_to_map: SyntaxToken, 123 token_to_map: SyntaxToken,
124) -> Option<(SyntaxNode, SyntaxToken)> { 124) -> Option<(SyntaxNode, SyntaxToken)> {
125 let macro_file = MacroFile { macro_call_id: actual_macro_call };
126 let (tt, tmap_1) = mbe::syntax_node_to_token_tree(hypothetical_args.syntax()); 125 let (tt, tmap_1) = mbe::syntax_node_to_token_tree(hypothetical_args.syntax());
127 let range = 126 let range =
128 token_to_map.text_range().checked_sub(hypothetical_args.syntax().text_range().start())?; 127 token_to_map.text_range().checked_sub(hypothetical_args.syntax().text_range().start())?;
129 let token_id = tmap_1.token_by_range(range)?; 128 let token_id = tmap_1.token_by_range(range)?;
130 let macro_def = expander(db, actual_macro_call)?;
131 129
132 let hypothetical_expansion = 130 let lazy_id = match actual_macro_call {
133 macro_expand_with_arg(db, macro_file.macro_call_id, Some(Arc::new((tt, tmap_1)))); 131 MacroCallId::LazyMacro(id) => id,
134 let (node, tmap_2) = expansion_to_syntax(db, macro_file, hypothetical_expansion).value?; 132 MacroCallId::EagerMacro(_) => return None,
133 };
134
135 let macro_def = {
136 let loc = db.lookup_intern_macro(lazy_id);
137 db.macro_def(loc.def)?
138 };
139
140 let hypothetical_expansion = macro_def.expand(db, lazy_id, &tt);
141
142 let fragment_kind = to_fragment_kind(db, actual_macro_call);
143
144 let (node, tmap_2) =
145 mbe::token_tree_to_syntax_node(&hypothetical_expansion.value, fragment_kind).ok()?;
135 146
136 let token_id = macro_def.map_id_down(token_id); 147 let token_id = macro_def.map_id_down(token_id);
137 let range = tmap_2.range_by_token(token_id)?.by_kind(token_to_map.kind())?; 148 let range = tmap_2.range_by_token(token_id)?.by_kind(token_to_map.kind())?;
@@ -157,16 +168,8 @@ fn parse_macro_expansion(
157 db: &dyn AstDatabase, 168 db: &dyn AstDatabase,
158 macro_file: MacroFile, 169 macro_file: MacroFile,
159) -> ExpandResult<Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>> { 170) -> ExpandResult<Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>> {
160 let result = db.macro_expand(macro_file.macro_call_id);
161 expansion_to_syntax(db, macro_file, result)
162}
163
164fn expansion_to_syntax(
165 db: &dyn AstDatabase,
166 macro_file: MacroFile,
167 result: ExpandResult<Option<Arc<tt::Subtree>>>,
168) -> ExpandResult<Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>> {
169 let _p = profile::span("parse_macro_expansion"); 171 let _p = profile::span("parse_macro_expansion");
172 let result = db.macro_expand(macro_file.macro_call_id);
170 173
171 if let Some(err) = &result.err { 174 if let Some(err) = &result.err {
172 // Note: 175 // Note:
@@ -309,19 +312,6 @@ fn macro_expand_error(db: &dyn AstDatabase, macro_call: MacroCallId) -> Option<E
309 db.macro_expand(macro_call).err 312 db.macro_expand(macro_call).err
310} 313}
311 314
312fn expander(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<TokenExpander>> {
313 let lazy_id = match id {
314 MacroCallId::LazyMacro(id) => id,
315 MacroCallId::EagerMacro(_id) => {
316 return None;
317 }
318 };
319
320 let loc = db.lookup_intern_macro(lazy_id);
321 let macro_rules = db.macro_def(loc.def)?;
322 Some(macro_rules)
323}
324
325fn macro_expand_with_arg( 315fn macro_expand_with_arg(
326 db: &dyn AstDatabase, 316 db: &dyn AstDatabase,
327 id: MacroCallId, 317 id: MacroCallId,
diff --git a/docs/dev/style.md b/docs/dev/style.md
index 6ab60b50e..00de7a711 100644
--- a/docs/dev/style.md
+++ b/docs/dev/style.md
@@ -449,6 +449,39 @@ fn query_all(name: String, case_sensitive: bool) -> Vec<Item> { ... }
449fn query_first(name: String, case_sensitive: bool) -> Option<Item> { ... } 449fn query_first(name: String, case_sensitive: bool) -> Option<Item> { ... }
450``` 450```
451 451
452## Prefer Separate Functions Over Parameters
453
454If a function has a `bool` or an `Option` parameter, and it is always called with `true`, `false`, `Some` and `None` literals, split the function in two.
455
456```rust
457// GOOD
458fn caller_a() {
459 foo()
460}
461
462fn caller_b() {
463 foo_with_bar(Bar::new())
464}
465
466fn foo() { ... }
467fn foo_with_bar(bar: Bar) { ... }
468
469// BAD
470fn caller_a() {
471 foo(None)
472}
473
474fn caller_b() {
475 foo(Some(Bar::new()))
476}
477
478fn foo(bar: Option<Bar>) { ... }
479```
480
481**Rationale:** more often than not, such functions display "`false sharing`" -- they have additional `if` branching inside for two different cases.
482Splitting the two different control flows into two functions simplifies each path, and remove cross-dependencies between the two paths.
483If there's common code between `foo` and `foo_with_bar`, extract *that* into a common helper.
484
452## Avoid Monomorphization 485## Avoid Monomorphization
453 486
454Avoid making a lot of code type parametric, *especially* on the boundaries between crates. 487Avoid making a lot of code type parametric, *especially* on the boundaries between crates.