]> git.lizzy.rs Git - rust.git/blob - src/libsyntax_pos/hygiene.rs
Auto merge of #54080 - PramodBisht:issue/53692, r=estebank
[rust.git] / src / libsyntax_pos / hygiene.rs
1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Machinery for hygienic macros, inspired by the `MTWT[1]` paper.
12 //!
13 //! `[1]` Matthew Flatt, Ryan Culpepper, David Darais, and Robert Bruce Findler. 2012.
14 //! *Macros that work together: Compile-time bindings, partial expansion,
15 //! and definition contexts*. J. Funct. Program. 22, 2 (March 2012), 181-216.
16 //! DOI=10.1017/S0956796812000093 <https://doi.org/10.1017/S0956796812000093>
17
18 use GLOBALS;
19 use Span;
20 use edition::Edition;
21 use symbol::Symbol;
22
23 use serialize::{Encodable, Decodable, Encoder, Decoder};
24 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
25 use std::fmt;
26
27 /// A SyntaxContext represents a chain of macro expansions (represented by marks).
28 #[derive(Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
29 pub struct SyntaxContext(u32);
30
31 #[derive(Copy, Clone, Debug)]
32 struct SyntaxContextData {
33     outer_mark: Mark,
34     transparency: Transparency,
35     prev_ctxt: SyntaxContext,
36     // This context, but with all transparent and semi-transparent marks filtered away.
37     opaque: SyntaxContext,
38     // This context, but with all transparent marks filtered away.
39     opaque_and_semitransparent: SyntaxContext,
40 }
41
42 /// A mark is a unique id associated with a macro expansion.
43 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
44 pub struct Mark(u32);
45
46 #[derive(Clone, Debug)]
47 struct MarkData {
48     parent: Mark,
49     default_transparency: Transparency,
50     is_builtin: bool,
51     expn_info: Option<ExpnInfo>,
52 }
53
54 /// A property of a macro expansion that determines how identifiers
55 /// produced by that expansion are resolved.
56 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
57 pub enum Transparency {
58     /// Identifier produced by a transparent expansion is always resolved at call-site.
59     /// Call-site spans in procedural macros, hygiene opt-out in `macro` should use this.
60     Transparent,
61     /// Identifier produced by a semi-transparent expansion may be resolved
62     /// either at call-site or at definition-site.
63     /// If it's a local variable, label or `$crate` then it's resolved at def-site.
64     /// Otherwise it's resolved at call-site.
65     /// `macro_rules` macros behave like this, built-in macros currently behave like this too,
66     /// but that's an implementation detail.
67     SemiTransparent,
68     /// Identifier produced by an opaque expansion is always resolved at definition-site.
69     /// Def-site spans in procedural macros, identifiers from `macro` by default use this.
70     Opaque,
71 }
72
73 impl Mark {
74     pub fn fresh(parent: Mark) -> Self {
75         HygieneData::with(|data| {
76             data.marks.push(MarkData {
77                 parent,
78                 // By default expansions behave like `macro_rules`.
79                 default_transparency: Transparency::SemiTransparent,
80                 is_builtin: false,
81                 expn_info: None,
82             });
83             Mark(data.marks.len() as u32 - 1)
84         })
85     }
86
87     /// The mark of the theoretical expansion that generates freshly parsed, unexpanded AST.
88     #[inline]
89     pub fn root() -> Self {
90         Mark(0)
91     }
92
93     #[inline]
94     pub fn as_u32(self) -> u32 {
95         self.0
96     }
97
98     #[inline]
99     pub fn from_u32(raw: u32) -> Mark {
100         Mark(raw)
101     }
102
103     #[inline]
104     pub fn parent(self) -> Mark {
105         HygieneData::with(|data| data.marks[self.0 as usize].parent)
106     }
107
108     #[inline]
109     pub fn expn_info(self) -> Option<ExpnInfo> {
110         HygieneData::with(|data| data.marks[self.0 as usize].expn_info.clone())
111     }
112
113     #[inline]
114     pub fn set_expn_info(self, info: ExpnInfo) {
115         HygieneData::with(|data| data.marks[self.0 as usize].expn_info = Some(info))
116     }
117
118     #[inline]
119     pub fn set_default_transparency(self, transparency: Transparency) {
120         assert_ne!(self, Mark::root());
121         HygieneData::with(|data| data.marks[self.0 as usize].default_transparency = transparency)
122     }
123
124     #[inline]
125     pub fn is_builtin(self) -> bool {
126         assert_ne!(self, Mark::root());
127         HygieneData::with(|data| data.marks[self.0 as usize].is_builtin)
128     }
129
130     #[inline]
131     pub fn set_is_builtin(self, is_builtin: bool) {
132         assert_ne!(self, Mark::root());
133         HygieneData::with(|data| data.marks[self.0 as usize].is_builtin = is_builtin)
134     }
135
136     pub fn is_descendant_of(mut self, ancestor: Mark) -> bool {
137         HygieneData::with(|data| {
138             while self != ancestor {
139                 if self == Mark::root() {
140                     return false;
141                 }
142                 self = data.marks[self.0 as usize].parent;
143             }
144             true
145         })
146     }
147
148     /// Computes a mark such that both input marks are descendants of (or equal to) the returned
149     /// mark. That is, the following holds:
150     ///
151     /// ```rust
152     /// let la = least_ancestor(a, b);
153     /// assert!(a.is_descendant_of(la))
154     /// assert!(b.is_descendant_of(la))
155     /// ```
156     pub fn least_ancestor(mut a: Mark, mut b: Mark) -> Mark {
157         HygieneData::with(|data| {
158             // Compute the path from a to the root
159             let mut a_path = FxHashSet::<Mark>();
160             while a != Mark::root() {
161                 a_path.insert(a);
162                 a = data.marks[a.0 as usize].parent;
163             }
164
165             // While the path from b to the root hasn't intersected, move up the tree
166             while !a_path.contains(&b) {
167                 b = data.marks[b.0 as usize].parent;
168             }
169
170             b
171         })
172     }
173
174     // Used for enabling some compatibility fallback in resolve.
175     #[inline]
176     pub fn looks_like_proc_macro_derive(self) -> bool {
177         HygieneData::with(|data| {
178             let mark_data = &data.marks[self.0 as usize];
179             if mark_data.default_transparency == Transparency::Opaque {
180                 if let Some(expn_info) = &mark_data.expn_info {
181                     if let ExpnFormat::MacroAttribute(name) = expn_info.format {
182                         if name.as_str().starts_with("derive(") {
183                             return true;
184                         }
185                     }
186                 }
187             }
188             false
189         })
190     }
191 }
192
193 #[derive(Debug)]
194 crate struct HygieneData {
195     marks: Vec<MarkData>,
196     syntax_contexts: Vec<SyntaxContextData>,
197     markings: FxHashMap<(SyntaxContext, Mark, Transparency), SyntaxContext>,
198     default_edition: Edition,
199 }
200
201 impl HygieneData {
202     crate fn new() -> Self {
203         HygieneData {
204             marks: vec![MarkData {
205                 parent: Mark::root(),
206                 // If the root is opaque, then loops searching for an opaque mark
207                 // will automatically stop after reaching it.
208                 default_transparency: Transparency::Opaque,
209                 is_builtin: true,
210                 expn_info: None,
211             }],
212             syntax_contexts: vec![SyntaxContextData {
213                 outer_mark: Mark::root(),
214                 transparency: Transparency::Opaque,
215                 prev_ctxt: SyntaxContext(0),
216                 opaque: SyntaxContext(0),
217                 opaque_and_semitransparent: SyntaxContext(0),
218             }],
219             markings: FxHashMap::default(),
220             default_edition: Edition::Edition2015,
221         }
222     }
223
224     fn with<T, F: FnOnce(&mut HygieneData) -> T>(f: F) -> T {
225         GLOBALS.with(|globals| f(&mut *globals.hygiene_data.borrow_mut()))
226     }
227 }
228
229 pub fn default_edition() -> Edition {
230     HygieneData::with(|data| data.default_edition)
231 }
232
233 pub fn set_default_edition(edition: Edition) {
234     HygieneData::with(|data| data.default_edition = edition);
235 }
236
237 pub fn clear_markings() {
238     HygieneData::with(|data| data.markings = FxHashMap::default());
239 }
240
241 impl SyntaxContext {
242     pub const fn empty() -> Self {
243         SyntaxContext(0)
244     }
245
246     crate fn as_u32(self) -> u32 {
247         self.0
248     }
249
250     crate fn from_u32(raw: u32) -> SyntaxContext {
251         SyntaxContext(raw)
252     }
253
254     // Allocate a new SyntaxContext with the given ExpnInfo. This is used when
255     // deserializing Spans from the incr. comp. cache.
256     // FIXME(mw): This method does not restore MarkData::parent or
257     // SyntaxContextData::prev_ctxt or SyntaxContextData::opaque. These things
258     // don't seem to be used after HIR lowering, so everything should be fine
259     // as long as incremental compilation does not kick in before that.
260     pub fn allocate_directly(expansion_info: ExpnInfo) -> Self {
261         HygieneData::with(|data| {
262             data.marks.push(MarkData {
263                 parent: Mark::root(),
264                 default_transparency: Transparency::SemiTransparent,
265                 is_builtin: false,
266                 expn_info: Some(expansion_info),
267             });
268
269             let mark = Mark(data.marks.len() as u32 - 1);
270
271             data.syntax_contexts.push(SyntaxContextData {
272                 outer_mark: mark,
273                 transparency: Transparency::SemiTransparent,
274                 prev_ctxt: SyntaxContext::empty(),
275                 opaque: SyntaxContext::empty(),
276                 opaque_and_semitransparent: SyntaxContext::empty(),
277             });
278             SyntaxContext(data.syntax_contexts.len() as u32 - 1)
279         })
280     }
281
282     /// Extend a syntax context with a given mark and default transparency for that mark.
283     pub fn apply_mark(self, mark: Mark) -> SyntaxContext {
284         assert_ne!(mark, Mark::root());
285         self.apply_mark_with_transparency(
286             mark, HygieneData::with(|data| data.marks[mark.0 as usize].default_transparency)
287         )
288     }
289
290     /// Extend a syntax context with a given mark and transparency
291     pub fn apply_mark_with_transparency(self, mark: Mark, transparency: Transparency)
292                                         -> SyntaxContext {
293         assert_ne!(mark, Mark::root());
294         if transparency == Transparency::Opaque {
295             return self.apply_mark_internal(mark, transparency);
296         }
297
298         let call_site_ctxt =
299             mark.expn_info().map_or(SyntaxContext::empty(), |info| info.call_site.ctxt());
300         let call_site_ctxt = if transparency == Transparency::SemiTransparent {
301             call_site_ctxt.modern()
302         } else {
303             call_site_ctxt.modern_and_legacy()
304         };
305
306         if call_site_ctxt == SyntaxContext::empty() {
307             return self.apply_mark_internal(mark, transparency);
308         }
309
310         // Otherwise, `mark` is a macros 1.0 definition and the call site is in a
311         // macros 2.0 expansion, i.e. a macros 1.0 invocation is in a macros 2.0 definition.
312         //
313         // In this case, the tokens from the macros 1.0 definition inherit the hygiene
314         // at their invocation. That is, we pretend that the macros 1.0 definition
315         // was defined at its invocation (i.e. inside the macros 2.0 definition)
316         // so that the macros 2.0 definition remains hygienic.
317         //
318         // See the example at `test/run-pass/hygiene/legacy_interaction.rs`.
319         let mut ctxt = call_site_ctxt;
320         for (mark, transparency) in self.marks() {
321             ctxt = ctxt.apply_mark_internal(mark, transparency);
322         }
323         ctxt.apply_mark_internal(mark, transparency)
324     }
325
326     fn apply_mark_internal(self, mark: Mark, transparency: Transparency) -> SyntaxContext {
327         HygieneData::with(|data| {
328             let syntax_contexts = &mut data.syntax_contexts;
329             let mut opaque = syntax_contexts[self.0 as usize].opaque;
330             let mut opaque_and_semitransparent =
331                 syntax_contexts[self.0 as usize].opaque_and_semitransparent;
332
333             if transparency >= Transparency::Opaque {
334                 let prev_ctxt = opaque;
335                 opaque = *data.markings.entry((prev_ctxt, mark, transparency)).or_insert_with(|| {
336                     let new_opaque = SyntaxContext(syntax_contexts.len() as u32);
337                     syntax_contexts.push(SyntaxContextData {
338                         outer_mark: mark,
339                         transparency,
340                         prev_ctxt,
341                         opaque: new_opaque,
342                         opaque_and_semitransparent: new_opaque,
343                     });
344                     new_opaque
345                 });
346             }
347
348             if transparency >= Transparency::SemiTransparent {
349                 let prev_ctxt = opaque_and_semitransparent;
350                 opaque_and_semitransparent =
351                         *data.markings.entry((prev_ctxt, mark, transparency)).or_insert_with(|| {
352                     let new_opaque_and_semitransparent =
353                         SyntaxContext(syntax_contexts.len() as u32);
354                     syntax_contexts.push(SyntaxContextData {
355                         outer_mark: mark,
356                         transparency,
357                         prev_ctxt,
358                         opaque,
359                         opaque_and_semitransparent: new_opaque_and_semitransparent,
360                     });
361                     new_opaque_and_semitransparent
362                 });
363             }
364
365             let prev_ctxt = self;
366             *data.markings.entry((prev_ctxt, mark, transparency)).or_insert_with(|| {
367                 let new_opaque_and_semitransparent_and_transparent =
368                     SyntaxContext(syntax_contexts.len() as u32);
369                 syntax_contexts.push(SyntaxContextData {
370                     outer_mark: mark,
371                     transparency,
372                     prev_ctxt,
373                     opaque,
374                     opaque_and_semitransparent,
375                 });
376                 new_opaque_and_semitransparent_and_transparent
377             })
378         })
379     }
380
381     /// Pulls a single mark off of the syntax context. This effectively moves the
382     /// context up one macro definition level. That is, if we have a nested macro
383     /// definition as follows:
384     ///
385     /// ```rust
386     /// macro_rules! f {
387     ///    macro_rules! g {
388     ///        ...
389     ///    }
390     /// }
391     /// ```
392     ///
393     /// and we have a SyntaxContext that is referring to something declared by an invocation
394     /// of g (call it g1), calling remove_mark will result in the SyntaxContext for the
395     /// invocation of f that created g1.
396     /// Returns the mark that was removed.
397     pub fn remove_mark(&mut self) -> Mark {
398         HygieneData::with(|data| {
399             let outer_mark = data.syntax_contexts[self.0 as usize].outer_mark;
400             *self = data.syntax_contexts[self.0 as usize].prev_ctxt;
401             outer_mark
402         })
403     }
404
405     pub fn marks(mut self) -> Vec<(Mark, Transparency)> {
406         HygieneData::with(|data| {
407             let mut marks = Vec::new();
408             while self != SyntaxContext::empty() {
409                 let ctxt_data = &data.syntax_contexts[self.0 as usize];
410                 marks.push((ctxt_data.outer_mark, ctxt_data.transparency));
411                 self = ctxt_data.prev_ctxt;
412             }
413             marks.reverse();
414             marks
415         })
416     }
417
418     /// Adjust this context for resolution in a scope created by the given expansion.
419     /// For example, consider the following three resolutions of `f`:
420     ///
421     /// ```rust
422     /// mod foo { pub fn f() {} } // `f`'s `SyntaxContext` is empty.
423     /// m!(f);
424     /// macro m($f:ident) {
425     ///     mod bar {
426     ///         pub fn f() {} // `f`'s `SyntaxContext` has a single `Mark` from `m`.
427     ///         pub fn $f() {} // `$f`'s `SyntaxContext` is empty.
428     ///     }
429     ///     foo::f(); // `f`'s `SyntaxContext` has a single `Mark` from `m`
430     ///     //^ Since `mod foo` is outside this expansion, `adjust` removes the mark from `f`,
431     ///     //| and it resolves to `::foo::f`.
432     ///     bar::f(); // `f`'s `SyntaxContext` has a single `Mark` from `m`
433     ///     //^ Since `mod bar` not outside this expansion, `adjust` does not change `f`,
434     ///     //| and it resolves to `::bar::f`.
435     ///     bar::$f(); // `f`'s `SyntaxContext` is empty.
436     ///     //^ Since `mod bar` is not outside this expansion, `adjust` does not change `$f`,
437     ///     //| and it resolves to `::bar::$f`.
438     /// }
439     /// ```
440     /// This returns the expansion whose definition scope we use to privacy check the resolution,
441     /// or `None` if we privacy check as usual (i.e. not w.r.t. a macro definition scope).
442     pub fn adjust(&mut self, expansion: Mark) -> Option<Mark> {
443         let mut scope = None;
444         while !expansion.is_descendant_of(self.outer()) {
445             scope = Some(self.remove_mark());
446         }
447         scope
448     }
449
450     /// Adjust this context for resolution in a scope created by the given expansion
451     /// via a glob import with the given `SyntaxContext`.
452     /// For example:
453     ///
454     /// ```rust
455     /// m!(f);
456     /// macro m($i:ident) {
457     ///     mod foo {
458     ///         pub fn f() {} // `f`'s `SyntaxContext` has a single `Mark` from `m`.
459     ///         pub fn $i() {} // `$i`'s `SyntaxContext` is empty.
460     ///     }
461     ///     n(f);
462     ///     macro n($j:ident) {
463     ///         use foo::*;
464     ///         f(); // `f`'s `SyntaxContext` has a mark from `m` and a mark from `n`
465     ///         //^ `glob_adjust` removes the mark from `n`, so this resolves to `foo::f`.
466     ///         $i(); // `$i`'s `SyntaxContext` has a mark from `n`
467     ///         //^ `glob_adjust` removes the mark from `n`, so this resolves to `foo::$i`.
468     ///         $j(); // `$j`'s `SyntaxContext` has a mark from `m`
469     ///         //^ This cannot be glob-adjusted, so this is a resolution error.
470     ///     }
471     /// }
472     /// ```
473     /// This returns `None` if the context cannot be glob-adjusted.
474     /// Otherwise, it returns the scope to use when privacy checking (see `adjust` for details).
475     pub fn glob_adjust(&mut self, expansion: Mark, mut glob_ctxt: SyntaxContext)
476                        -> Option<Option<Mark>> {
477         let mut scope = None;
478         while !expansion.is_descendant_of(glob_ctxt.outer()) {
479             scope = Some(glob_ctxt.remove_mark());
480             if self.remove_mark() != scope.unwrap() {
481                 return None;
482             }
483         }
484         if self.adjust(expansion).is_some() {
485             return None;
486         }
487         Some(scope)
488     }
489
490     /// Undo `glob_adjust` if possible:
491     ///
492     /// ```rust
493     /// if let Some(privacy_checking_scope) = self.reverse_glob_adjust(expansion, glob_ctxt) {
494     ///     assert!(self.glob_adjust(expansion, glob_ctxt) == Some(privacy_checking_scope));
495     /// }
496     /// ```
497     pub fn reverse_glob_adjust(&mut self, expansion: Mark, mut glob_ctxt: SyntaxContext)
498                                -> Option<Option<Mark>> {
499         if self.adjust(expansion).is_some() {
500             return None;
501         }
502
503         let mut marks = Vec::new();
504         while !expansion.is_descendant_of(glob_ctxt.outer()) {
505             marks.push(glob_ctxt.remove_mark());
506         }
507
508         let scope = marks.last().cloned();
509         while let Some(mark) = marks.pop() {
510             *self = self.apply_mark(mark);
511         }
512         Some(scope)
513     }
514
515     #[inline]
516     pub fn modern(self) -> SyntaxContext {
517         HygieneData::with(|data| data.syntax_contexts[self.0 as usize].opaque)
518     }
519
520     #[inline]
521     pub fn modern_and_legacy(self) -> SyntaxContext {
522         HygieneData::with(|data| data.syntax_contexts[self.0 as usize].opaque_and_semitransparent)
523     }
524
525     #[inline]
526     pub fn outer(self) -> Mark {
527         HygieneData::with(|data| data.syntax_contexts[self.0 as usize].outer_mark)
528     }
529 }
530
531 impl fmt::Debug for SyntaxContext {
532     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
533         write!(f, "#{}", self.0)
534     }
535 }
536
537 /// Extra information for tracking spans of macro and syntax sugar expansion
538 #[derive(Clone, Hash, Debug, RustcEncodable, RustcDecodable)]
539 pub struct ExpnInfo {
540     /// The location of the actual macro invocation or syntax sugar , e.g.
541     /// `let x = foo!();` or `if let Some(y) = x {}`
542     ///
543     /// This may recursively refer to other macro invocations, e.g. if
544     /// `foo!()` invoked `bar!()` internally, and there was an
545     /// expression inside `bar!`; the call_site of the expression in
546     /// the expansion would point to the `bar!` invocation; that
547     /// call_site span would have its own ExpnInfo, with the call_site
548     /// pointing to the `foo!` invocation.
549     pub call_site: Span,
550     /// The span of the macro definition itself. The macro may not
551     /// have a sensible definition span (e.g. something defined
552     /// completely inside libsyntax) in which case this is None.
553     /// This span serves only informational purpose and is not used for resolution.
554     pub def_site: Option<Span>,
555     /// The format with which the macro was invoked.
556     pub format: ExpnFormat,
557     /// Whether the macro is allowed to use #[unstable]/feature-gated
558     /// features internally without forcing the whole crate to opt-in
559     /// to them.
560     pub allow_internal_unstable: bool,
561     /// Whether the macro is allowed to use `unsafe` internally
562     /// even if the user crate has `#![forbid(unsafe_code)]`.
563     pub allow_internal_unsafe: bool,
564     /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`)
565     /// for a given macro.
566     pub local_inner_macros: bool,
567     /// Edition of the crate in which the macro is defined.
568     pub edition: Edition,
569 }
570
571 /// The source of expansion.
572 #[derive(Clone, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
573 pub enum ExpnFormat {
574     /// e.g. #[derive(...)] <item>
575     MacroAttribute(Symbol),
576     /// e.g. `format!()`
577     MacroBang(Symbol),
578     /// Desugaring done by the compiler during HIR lowering.
579     CompilerDesugaring(CompilerDesugaringKind)
580 }
581
582 impl ExpnFormat {
583     pub fn name(&self) -> Symbol {
584         match *self {
585             ExpnFormat::MacroBang(name) | ExpnFormat::MacroAttribute(name) => name,
586             ExpnFormat::CompilerDesugaring(kind) => kind.name(),
587         }
588     }
589 }
590
591 /// The kind of compiler desugaring.
592 #[derive(Clone, Copy, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
593 pub enum CompilerDesugaringKind {
594     QuestionMark,
595     TryBlock,
596     /// Desugaring of an `impl Trait` in return type position
597     /// to an `existential type Foo: Trait;` + replacing the
598     /// `impl Trait` with `Foo`.
599     ExistentialReturnType,
600     Async,
601     ForLoop,
602 }
603
604 impl CompilerDesugaringKind {
605     pub fn name(self) -> Symbol {
606         Symbol::intern(match self {
607             CompilerDesugaringKind::Async => "async",
608             CompilerDesugaringKind::QuestionMark => "?",
609             CompilerDesugaringKind::TryBlock => "try block",
610             CompilerDesugaringKind::ExistentialReturnType => "existential type",
611             CompilerDesugaringKind::ForLoop => "for loop",
612         })
613     }
614 }
615
616 impl Encodable for SyntaxContext {
617     fn encode<E: Encoder>(&self, _: &mut E) -> Result<(), E::Error> {
618         Ok(()) // FIXME(jseyfried) intercrate hygiene
619     }
620 }
621
622 impl Decodable for SyntaxContext {
623     fn decode<D: Decoder>(_: &mut D) -> Result<SyntaxContext, D::Error> {
624         Ok(SyntaxContext::empty()) // FIXME(jseyfried) intercrate hygiene
625     }
626 }