aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_expand
diff options
context:
space:
mode:
authorJonas Schievink <[email protected]>2020-11-30 18:21:25 +0000
committerJonas Schievink <[email protected]>2020-11-30 18:21:25 +0000
commit92f52c5c9ad5acb104c6ce5a042950349a48c532 (patch)
tree9c2cf858405e41d753b2060521bbaf6bbc64e2cb /crates/hir_expand
parent70eb17027151b4e85cbda2765f7289585b26a823 (diff)
builtin_macro: move to `mbe::ExpandResult`
Diffstat (limited to 'crates/hir_expand')
-rw-r--r--crates/hir_expand/src/builtin_macro.rs129
-rw-r--r--crates/hir_expand/src/db.rs2
-rw-r--r--crates/hir_expand/src/eager.rs2
3 files changed, 81 insertions, 52 deletions
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index aebbfc4df..7f4db106d 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -6,7 +6,7 @@ use crate::{
6 6
7use base_db::FileId; 7use base_db::FileId;
8use either::Either; 8use either::Either;
9use mbe::parse_to_token_tree; 9use mbe::{parse_to_token_tree, ExpandResult};
10use parser::FragmentKind; 10use parser::FragmentKind;
11use syntax::ast::{self, AstToken}; 11use syntax::ast::{self, AstToken};
12 12
@@ -28,7 +28,7 @@ macro_rules! register_builtin {
28 db: &dyn AstDatabase, 28 db: &dyn AstDatabase,
29 id: LazyMacroId, 29 id: LazyMacroId,
30 tt: &tt::Subtree, 30 tt: &tt::Subtree,
31 ) -> Result<tt::Subtree, mbe::ExpandError> { 31 ) -> ExpandResult<tt::Subtree> {
32 let expander = match *self { 32 let expander = match *self {
33 $( BuiltinFnLikeExpander::$kind => $expand, )* 33 $( BuiltinFnLikeExpander::$kind => $expand, )*
34 }; 34 };
@@ -42,7 +42,7 @@ macro_rules! register_builtin {
42 db: &dyn AstDatabase, 42 db: &dyn AstDatabase,
43 arg_id: EagerMacroId, 43 arg_id: EagerMacroId,
44 tt: &tt::Subtree, 44 tt: &tt::Subtree,
45 ) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { 45 ) -> ExpandResult<Option<(tt::Subtree, FragmentKind)>> {
46 let expander = match *self { 46 let expander = match *self {
47 $( EagerExpander::$e_kind => $e_expand, )* 47 $( EagerExpander::$e_kind => $e_expand, )*
48 }; 48 };
@@ -109,25 +109,28 @@ fn line_expand(
109 _db: &dyn AstDatabase, 109 _db: &dyn AstDatabase,
110 _id: LazyMacroId, 110 _id: LazyMacroId,
111 _tt: &tt::Subtree, 111 _tt: &tt::Subtree,
112) -> Result<tt::Subtree, mbe::ExpandError> { 112) -> ExpandResult<tt::Subtree> {
113 // dummy implementation for type-checking purposes 113 // dummy implementation for type-checking purposes
114 let line_num = 0; 114 let line_num = 0;
115 let expanded = quote! { 115 let expanded = quote! {
116 #line_num 116 #line_num
117 }; 117 };
118 118
119 Ok(expanded) 119 ExpandResult::ok(expanded)
120} 120}
121 121
122fn stringify_expand( 122fn stringify_expand(
123 db: &dyn AstDatabase, 123 db: &dyn AstDatabase,
124 id: LazyMacroId, 124 id: LazyMacroId,
125 _tt: &tt::Subtree, 125 _tt: &tt::Subtree,
126) -> Result<tt::Subtree, mbe::ExpandError> { 126) -> ExpandResult<tt::Subtree> {
127 let loc = db.lookup_intern_macro(id); 127 let loc = db.lookup_intern_macro(id);
128 128
129 let macro_content = { 129 let macro_content = {
130 let arg = loc.kind.arg(db).ok_or_else(|| mbe::ExpandError::UnexpectedToken)?; 130 let arg = match loc.kind.arg(db) {
131 Some(arg) => arg,
132 None => return ExpandResult::only_err(mbe::ExpandError::UnexpectedToken),
133 };
131 let macro_args = arg; 134 let macro_args = arg;
132 let text = macro_args.text(); 135 let text = macro_args.text();
133 let without_parens = TextSize::of('(')..text.len() - TextSize::of(')'); 136 let without_parens = TextSize::of('(')..text.len() - TextSize::of(')');
@@ -138,28 +141,28 @@ fn stringify_expand(
138 #macro_content 141 #macro_content
139 }; 142 };
140 143
141 Ok(expanded) 144 ExpandResult::ok(expanded)
142} 145}
143 146
144fn column_expand( 147fn column_expand(
145 _db: &dyn AstDatabase, 148 _db: &dyn AstDatabase,
146 _id: LazyMacroId, 149 _id: LazyMacroId,
147 _tt: &tt::Subtree, 150 _tt: &tt::Subtree,
148) -> Result<tt::Subtree, mbe::ExpandError> { 151) -> ExpandResult<tt::Subtree> {
149 // dummy implementation for type-checking purposes 152 // dummy implementation for type-checking purposes
150 let col_num = 0; 153 let col_num = 0;
151 let expanded = quote! { 154 let expanded = quote! {
152 #col_num 155 #col_num
153 }; 156 };
154 157
155 Ok(expanded) 158 ExpandResult::ok(expanded)
156} 159}
157 160
158fn assert_expand( 161fn assert_expand(
159 _db: &dyn AstDatabase, 162 _db: &dyn AstDatabase,
160 _id: LazyMacroId, 163 _id: LazyMacroId,
161 tt: &tt::Subtree, 164 tt: &tt::Subtree,
162) -> Result<tt::Subtree, mbe::ExpandError> { 165) -> ExpandResult<tt::Subtree> {
163 // A hacky implementation for goto def and hover 166 // A hacky implementation for goto def and hover
164 // We expand `assert!(cond, arg1, arg2)` to 167 // We expand `assert!(cond, arg1, arg2)` to
165 // ``` 168 // ```
@@ -191,14 +194,14 @@ fn assert_expand(
191 let expanded = quote! { 194 let expanded = quote! {
192 { { (##arg_tts); } } 195 { { (##arg_tts); } }
193 }; 196 };
194 Ok(expanded) 197 ExpandResult::ok(expanded)
195} 198}
196 199
197fn file_expand( 200fn file_expand(
198 _db: &dyn AstDatabase, 201 _db: &dyn AstDatabase,
199 _id: LazyMacroId, 202 _id: LazyMacroId,
200 _tt: &tt::Subtree, 203 _tt: &tt::Subtree,
201) -> Result<tt::Subtree, mbe::ExpandError> { 204) -> ExpandResult<tt::Subtree> {
202 // FIXME: RA purposefully lacks knowledge of absolute file names 205 // FIXME: RA purposefully lacks knowledge of absolute file names
203 // so just return "". 206 // so just return "".
204 let file_name = ""; 207 let file_name = "";
@@ -207,31 +210,33 @@ fn file_expand(
207 #file_name 210 #file_name
208 }; 211 };
209 212
210 Ok(expanded) 213 ExpandResult::ok(expanded)
211} 214}
212 215
213fn compile_error_expand( 216fn compile_error_expand(
214 _db: &dyn AstDatabase, 217 _db: &dyn AstDatabase,
215 _id: LazyMacroId, 218 _id: LazyMacroId,
216 tt: &tt::Subtree, 219 tt: &tt::Subtree,
217) -> Result<tt::Subtree, mbe::ExpandError> { 220) -> ExpandResult<tt::Subtree> {
218 if tt.count() == 1 { 221 if tt.count() == 1 {
219 if let tt::TokenTree::Leaf(tt::Leaf::Literal(it)) = &tt.token_trees[0] { 222 if let tt::TokenTree::Leaf(tt::Leaf::Literal(it)) = &tt.token_trees[0] {
220 let s = it.text.as_str(); 223 let s = it.text.as_str();
221 if s.contains('"') { 224 if s.contains('"') {
222 return Ok(quote! { loop { #it }}); 225 return ExpandResult::ok(quote! { loop { #it }});
223 } 226 }
224 }; 227 };
225 } 228 }
226 229
227 Err(mbe::ExpandError::BindingError("Must be a string".into())) 230 ExpandResult::only_err(mbe::ExpandError::BindingError(
231 "`compile_error!` argument be a string".into(),
232 ))
228} 233}
229 234
230fn format_args_expand( 235fn format_args_expand(
231 _db: &dyn AstDatabase, 236 _db: &dyn AstDatabase,
232 _id: LazyMacroId, 237 _id: LazyMacroId,
233 tt: &tt::Subtree, 238 tt: &tt::Subtree,
234) -> Result<tt::Subtree, mbe::ExpandError> { 239) -> ExpandResult<tt::Subtree> {
235 // We expand `format_args!("", a1, a2)` to 240 // We expand `format_args!("", a1, a2)` to
236 // ``` 241 // ```
237 // std::fmt::Arguments::new_v1(&[], &[ 242 // std::fmt::Arguments::new_v1(&[], &[
@@ -257,7 +262,7 @@ fn format_args_expand(
257 args.push(current); 262 args.push(current);
258 } 263 }
259 if args.is_empty() { 264 if args.is_empty() {
260 return Err(mbe::ExpandError::NoMatchingRule); 265 return ExpandResult::only_err(mbe::ExpandError::NoMatchingRule);
261 } 266 }
262 let _format_string = args.remove(0); 267 let _format_string = args.remove(0);
263 let arg_tts = args.into_iter().flat_map(|arg| { 268 let arg_tts = args.into_iter().flat_map(|arg| {
@@ -266,7 +271,7 @@ fn format_args_expand(
266 let expanded = quote! { 271 let expanded = quote! {
267 std::fmt::Arguments::new_v1(&[], &[##arg_tts]) 272 std::fmt::Arguments::new_v1(&[], &[##arg_tts])
268 }; 273 };
269 Ok(expanded) 274 ExpandResult::ok(expanded)
270} 275}
271 276
272fn unquote_str(lit: &tt::Literal) -> Option<String> { 277fn unquote_str(lit: &tt::Literal) -> Option<String> {
@@ -279,19 +284,24 @@ fn concat_expand(
279 _db: &dyn AstDatabase, 284 _db: &dyn AstDatabase,
280 _arg_id: EagerMacroId, 285 _arg_id: EagerMacroId,
281 tt: &tt::Subtree, 286 tt: &tt::Subtree,
282) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { 287) -> ExpandResult<Option<(tt::Subtree, FragmentKind)>> {
283 let mut text = String::new(); 288 let mut text = String::new();
284 for (i, t) in tt.token_trees.iter().enumerate() { 289 for (i, t) in tt.token_trees.iter().enumerate() {
285 match t { 290 match t {
286 tt::TokenTree::Leaf(tt::Leaf::Literal(it)) if i % 2 == 0 => { 291 tt::TokenTree::Leaf(tt::Leaf::Literal(it)) if i % 2 == 0 => {
287 text += &unquote_str(&it).ok_or_else(|| mbe::ExpandError::ConversionError)?; 292 text += &match unquote_str(&it) {
293 Some(s) => s,
294 None => {
295 return ExpandResult::only_err(mbe::ExpandError::ConversionError);
296 }
297 };
288 } 298 }
289 tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (), 299 tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (),
290 _ => return Err(mbe::ExpandError::UnexpectedToken), 300 _ => return ExpandResult::only_err(mbe::ExpandError::UnexpectedToken),
291 } 301 }
292 } 302 }
293 303
294 Ok((quote!(#text), FragmentKind::Expr)) 304 ExpandResult::ok(Some((quote!(#text), FragmentKind::Expr)))
295} 305}
296 306
297fn relative_file( 307fn relative_file(
@@ -324,26 +334,35 @@ fn include_expand(
324 db: &dyn AstDatabase, 334 db: &dyn AstDatabase,
325 arg_id: EagerMacroId, 335 arg_id: EagerMacroId,
326 tt: &tt::Subtree, 336 tt: &tt::Subtree,
327) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { 337) -> ExpandResult<Option<(tt::Subtree, FragmentKind)>> {
328 let path = parse_string(tt)?; 338 let res = (|| {
329 let file_id = relative_file(db, arg_id.into(), &path, false) 339 let path = parse_string(tt)?;
330 .ok_or_else(|| mbe::ExpandError::ConversionError)?; 340 let file_id = relative_file(db, arg_id.into(), &path, false)
331 341 .ok_or_else(|| mbe::ExpandError::ConversionError)?;
332 // FIXME: 342
333 // Handle include as expression 343 Ok(parse_to_token_tree(&db.file_text(file_id))
334 let res = parse_to_token_tree(&db.file_text(file_id)) 344 .ok_or_else(|| mbe::ExpandError::ConversionError)?
335 .ok_or_else(|| mbe::ExpandError::ConversionError)? 345 .0)
336 .0; 346 })();
337 347
338 Ok((res, FragmentKind::Items)) 348 match res {
349 Ok(res) => {
350 // FIXME:
351 // Handle include as expression
352 ExpandResult::ok(Some((res, FragmentKind::Items)))
353 }
354 Err(e) => ExpandResult::only_err(e),
355 }
339} 356}
340 357
341fn include_bytes_expand( 358fn include_bytes_expand(
342 _db: &dyn AstDatabase, 359 _db: &dyn AstDatabase,
343 _arg_id: EagerMacroId, 360 _arg_id: EagerMacroId,
344 tt: &tt::Subtree, 361 tt: &tt::Subtree,
345) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { 362) -> ExpandResult<Option<(tt::Subtree, FragmentKind)>> {
346 let _path = parse_string(tt)?; 363 if let Err(e) = parse_string(tt) {
364 return ExpandResult::only_err(e);
365 }
347 366
348 // FIXME: actually read the file here if the user asked for macro expansion 367 // FIXME: actually read the file here if the user asked for macro expansion
349 let res = tt::Subtree { 368 let res = tt::Subtree {
@@ -353,15 +372,18 @@ fn include_bytes_expand(
353 id: tt::TokenId::unspecified(), 372 id: tt::TokenId::unspecified(),
354 }))], 373 }))],
355 }; 374 };
356 Ok((res, FragmentKind::Expr)) 375 ExpandResult::ok(Some((res, FragmentKind::Expr)))
357} 376}
358 377
359fn include_str_expand( 378fn include_str_expand(
360 db: &dyn AstDatabase, 379 db: &dyn AstDatabase,
361 arg_id: EagerMacroId, 380 arg_id: EagerMacroId,
362 tt: &tt::Subtree, 381 tt: &tt::Subtree,
363) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { 382) -> ExpandResult<Option<(tt::Subtree, FragmentKind)>> {
364 let path = parse_string(tt)?; 383 let path = match parse_string(tt) {
384 Ok(it) => it,
385 Err(e) => return ExpandResult::only_err(e),
386 };
365 387
366 // FIXME: we're not able to read excluded files (which is most of them because 388 // FIXME: we're not able to read excluded files (which is most of them because
367 // it's unusual to `include_str!` a Rust file), but we can return an empty string. 389 // it's unusual to `include_str!` a Rust file), but we can return an empty string.
@@ -370,14 +392,14 @@ fn include_str_expand(
370 let file_id = match relative_file(db, arg_id.into(), &path, true) { 392 let file_id = match relative_file(db, arg_id.into(), &path, true) {
371 Some(file_id) => file_id, 393 Some(file_id) => file_id,
372 None => { 394 None => {
373 return Ok((quote!(""), FragmentKind::Expr)); 395 return ExpandResult::ok(Some((quote!(""), FragmentKind::Expr)));
374 } 396 }
375 }; 397 };
376 398
377 let text = db.file_text(file_id); 399 let text = db.file_text(file_id);
378 let text = &*text; 400 let text = &*text;
379 401
380 Ok((quote!(#text), FragmentKind::Expr)) 402 ExpandResult::ok(Some((quote!(#text), FragmentKind::Expr)))
381} 403}
382 404
383fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> { 405fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> {
@@ -389,8 +411,11 @@ fn env_expand(
389 db: &dyn AstDatabase, 411 db: &dyn AstDatabase,
390 arg_id: EagerMacroId, 412 arg_id: EagerMacroId,
391 tt: &tt::Subtree, 413 tt: &tt::Subtree,
392) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { 414) -> ExpandResult<Option<(tt::Subtree, FragmentKind)>> {
393 let key = parse_string(tt)?; 415 let key = match parse_string(tt) {
416 Ok(it) => it,
417 Err(e) => return ExpandResult::only_err(e),
418 };
394 419
395 // FIXME: 420 // FIXME:
396 // If the environment variable is not defined int rustc, then a compilation error will be emitted. 421 // If the environment variable is not defined int rustc, then a compilation error will be emitted.
@@ -402,21 +427,25 @@ fn env_expand(
402 let s = get_env_inner(db, arg_id, &key).unwrap_or_else(|| "__RA_UNIMPLEMENTED__".to_string()); 427 let s = get_env_inner(db, arg_id, &key).unwrap_or_else(|| "__RA_UNIMPLEMENTED__".to_string());
403 let expanded = quote! { #s }; 428 let expanded = quote! { #s };
404 429
405 Ok((expanded, FragmentKind::Expr)) 430 ExpandResult::ok(Some((expanded, FragmentKind::Expr)))
406} 431}
407 432
408fn option_env_expand( 433fn option_env_expand(
409 db: &dyn AstDatabase, 434 db: &dyn AstDatabase,
410 arg_id: EagerMacroId, 435 arg_id: EagerMacroId,
411 tt: &tt::Subtree, 436 tt: &tt::Subtree,
412) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { 437) -> ExpandResult<Option<(tt::Subtree, FragmentKind)>> {
413 let key = parse_string(tt)?; 438 let key = match parse_string(tt) {
439 Ok(it) => it,
440 Err(e) => return ExpandResult::only_err(e),
441 };
442
414 let expanded = match get_env_inner(db, arg_id, &key) { 443 let expanded = match get_env_inner(db, arg_id, &key) {
415 None => quote! { std::option::Option::None::<&str> }, 444 None => quote! { std::option::Option::None::<&str> },
416 Some(s) => quote! { std::option::Some(#s) }, 445 Some(s) => quote! { std::option::Some(#s) },
417 }; 446 };
418 447
419 Ok((expanded, FragmentKind::Expr)) 448 ExpandResult::ok(Some((expanded, FragmentKind::Expr)))
420} 449}
421 450
422#[cfg(test)] 451#[cfg(test)]
@@ -485,7 +514,7 @@ mod tests {
485 } 514 }
486 }); 515 });
487 516
488 let (subtree, fragment) = expander.expand(&db, arg_id, &parsed_args).unwrap(); 517 let (subtree, fragment) = expander.expand(&db, arg_id, &parsed_args).value.unwrap();
489 let eager = EagerCallLoc { 518 let eager = EagerCallLoc {
490 def, 519 def,
491 fragment, 520 fragment,
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index ff50bfd82..4fd0ba290 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -30,8 +30,8 @@ impl TokenExpander {
30 ) -> mbe::ExpandResult<tt::Subtree> { 30 ) -> mbe::ExpandResult<tt::Subtree> {
31 match self { 31 match self {
32 TokenExpander::MacroRules(it) => it.expand(tt), 32 TokenExpander::MacroRules(it) => it.expand(tt),
33 TokenExpander::Builtin(it) => it.expand(db, id, tt),
33 // FIXME switch these to ExpandResult as well 34 // FIXME switch these to ExpandResult as well
34 TokenExpander::Builtin(it) => it.expand(db, id, tt).into(),
35 TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt).into(), 35 TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt).into(),
36 TokenExpander::ProcMacro(_) => { 36 TokenExpander::ProcMacro(_) => {
37 // We store the result in salsa db to prevent non-determinisc behavior in 37 // We store the result in salsa db to prevent non-determinisc behavior in
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs
index 2f37d7189..ab6b4477c 100644
--- a/crates/hir_expand/src/eager.rs
+++ b/crates/hir_expand/src/eager.rs
@@ -65,7 +65,7 @@ pub fn expand_eager_macro(
65 let subtree = to_subtree(&result)?; 65 let subtree = to_subtree(&result)?;
66 66
67 if let MacroDefKind::BuiltInEager(eager) = def.kind { 67 if let MacroDefKind::BuiltInEager(eager) = def.kind {
68 let (subtree, fragment) = eager.expand(db, arg_id, &subtree).ok()?; 68 let (subtree, fragment) = eager.expand(db, arg_id, &subtree).value?;
69 let eager = EagerCallLoc { 69 let eager = EagerCallLoc {
70 def, 70 def,
71 fragment, 71 fragment,