//! A bunch of methods and structures more or less related to resolving macros and
//! interface provided by `Resolver` to macro expander.

use crate::{AmbiguityError, AmbiguityKind, AmbiguityErrorMisc, Determinacy};
use crate::{CrateLint, Resolver, ResolutionError, Scope, ScopeSet, ParentScope, Weak};
use crate::{ModuleKind, NameBinding, PathResult, Segment, ToNameBinding};
use crate::{ModuleOrUniformRoot, KNOWN_TOOLS};
use crate::Namespace::*;
use crate::resolve_imports::ImportResolver;
use rustc::hir::def::{self, DefKind, NonMacroAttrKind};
use rustc::hir::def_id;
use rustc::middle::stability;
use rustc::{ty, lint, span_bug};
use syntax::ast::{self, NodeId, Ident};
use syntax::attr::StabilityLevel;
use syntax::edition::Edition;
use syntax::ext::base::{self, InvocationRes, Indeterminate, SpecialDerives};
use syntax::ext::base::{MacroKind, SyntaxExtension};
use syntax::ext::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind};
use syntax::ext::hygiene::{self, ExpnId, ExpnData, ExpnKind};
use syntax::ext::tt::macro_rules;
use syntax::feature_gate::{emit_feature_err, is_builtin_attr_name};
use syntax::feature_gate::GateIssue;
use syntax::symbol::{Symbol, kw, sym};
use syntax_pos::{Span, DUMMY_SP};

use std::{mem, ptr};
use rustc_data_structures::sync::Lrc;
use syntax_pos::hygiene::AstPass;

type Res = def::Res<NodeId>;

/// Binding produced by a `macro_rules` item.
/// Not modularized, can shadow previous legacy bindings, etc.
#[derive(Debug)]
pub struct LegacyBinding<'a> {
    crate binding: &'a NameBinding<'a>,
    /// Legacy scope into which the `macro_rules` item was planted.
    crate parent_legacy_scope: LegacyScope<'a>,
    crate ident: Ident,
}

/// The scope introduced by a `macro_rules!` macro.
/// This starts at the macro's definition and ends at the end of the macro's parent
/// module (named or unnamed), or even further if it escapes with `#[macro_use]`.
/// Some macro invocations need to introduce legacy scopes too because they
/// can potentially expand into macro definitions.
#[derive(Copy, Clone, Debug)]
pub enum LegacyScope<'a> {
    /// Empty "root" scope at the crate start containing no names.
    Empty,
    /// The scope introduced by a `macro_rules!` macro definition.
    Binding(&'a LegacyBinding<'a>),
    /// The scope introduced by a macro invocation that can potentially
    /// create a `macro_rules!` macro definition.
    Invocation(ExpnId),
}

// Macro namespace is separated into two sub-namespaces, one for bang macros and
// one for attribute-like macros (attributes, derives).
// We ignore resolutions from one sub-namespace when searching names in scope for another.
fn sub_namespace_match(candidate: Option<MacroKind>, requirement: Option<MacroKind>) -> bool {
    #[derive(PartialEq)]
    enum SubNS { Bang, AttrLike }
    let sub_ns = |kind| match kind {
        MacroKind::Bang => SubNS::Bang,
        MacroKind::Attr | MacroKind::Derive => SubNS::AttrLike,
    };
    let candidate = candidate.map(sub_ns);
    let requirement = requirement.map(sub_ns);
    // "No specific sub-namespace" means "matches anything" for both requirements and candidates.
    candidate.is_none() || requirement.is_none() || candidate == requirement
}

// We don't want to format a path using pretty-printing,
// `format!("{}", path)`, because that tries to insert
// line-breaks and is slow.
fn fast_print_path(path: &ast::Path) -> Symbol {
    if path.segments.len() == 1 {
        return path.segments[0].ident.name
    } else {
        let mut path_str = String::with_capacity(64);
        for (i, segment) in path.segments.iter().enumerate() {
            if i != 0 {
                path_str.push_str("::");
            }
            if segment.ident.name != kw::PathRoot {
                path_str.push_str(&segment.ident.as_str())
            }
        }
        Symbol::intern(&path_str)
    }
}

impl<'a> base::Resolver for Resolver<'a> {
    fn next_node_id(&mut self) -> NodeId {
        self.session.next_node_id()
    }

    fn resolve_dollar_crates(&mut self) {
        hygiene::update_dollar_crate_names(|ctxt| {
            let ident = Ident::new(kw::DollarCrate, DUMMY_SP.with_ctxt(ctxt));
            match self.resolve_crate_root(ident).kind {
                ModuleKind::Def(.., name) if name != kw::Invalid => name,
                _ => kw::Crate,
            }
        });
    }

    // FIXME: `extra_placeholders` should be included into the `fragment` as regular placeholders.
    fn visit_ast_fragment_with_placeholders(
        &mut self, expansion: ExpnId, fragment: &AstFragment, extra_placeholders: &[NodeId]
    ) {
        // Integrate the new AST fragment into all the definition and module structures.
        // We are inside the `expansion` now, but other parent scope components are still the same.
        let parent_scope = ParentScope { expansion, ..self.invocation_parent_scopes[&expansion] };
        let output_legacy_scope =
            self.build_reduced_graph(fragment, extra_placeholders, parent_scope);
        self.output_legacy_scopes.insert(expansion, output_legacy_scope);

        parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion);
    }

    fn register_builtin_macro(&mut self, ident: ast::Ident, ext: SyntaxExtension) {
        if self.builtin_macros.insert(ident.name, ext).is_some() {
            self.session.span_err(ident.span,
                                  &format!("built-in macro `{}` was already defined", ident));
        }
    }

    // Create a new Expansion with a definition site of the provided module, or
    // a fake empty `#[no_implicit_prelude]` module if no module is provided.
    fn expansion_for_ast_pass(
        &mut self,
        call_site: Span,
        pass: AstPass,
        features: &[Symbol],
        parent_module_id: Option<NodeId>,
    ) -> ExpnId {
        let expn_id = ExpnId::fresh(Some(ExpnData::allow_unstable(
            ExpnKind::AstPass(pass),
            call_site,
            self.session.edition(),
            features.into(),
        )));

        let parent_scope = if let Some(module_id) = parent_module_id {
            let parent_def_id = self.definitions.local_def_id(module_id);
            self.definitions.add_parent_module_of_macro_def(expn_id, parent_def_id);
            self.module_map[&parent_def_id]
        } else {
            self.definitions.add_parent_module_of_macro_def(
                expn_id,
                def_id::DefId::local(def_id::CRATE_DEF_INDEX),
            );
            self.empty_module
        };
        self.ast_transform_scopes.insert(expn_id, parent_scope);
        expn_id
    }

    fn resolve_imports(&mut self) {
        ImportResolver { r: self }.resolve_imports()
    }

    fn resolve_macro_invocation(
        &mut self, invoc: &Invocation, eager_expansion_root: ExpnId, force: bool
    ) -> Result<InvocationRes, Indeterminate> {
        let invoc_id = invoc.expansion_data.id;
        let parent_scope = match self.invocation_parent_scopes.get(&invoc_id) {
            Some(parent_scope) => *parent_scope,
            None => {
                // If there's no entry in the table, then we are resolving an eagerly expanded
                // macro, which should inherit its parent scope from its eager expansion root -
                // the macro that requested this eager expansion.
                let parent_scope = *self.invocation_parent_scopes.get(&eager_expansion_root)
                    .expect("non-eager expansion without a parent scope");
                self.invocation_parent_scopes.insert(invoc_id, parent_scope);
                parent_scope
            }
        };

        let (path, kind, derives, after_derive) = match invoc.kind {
            InvocationKind::Attr { ref attr, ref derives, after_derive, .. } =>
                (&attr.path, MacroKind::Attr, self.arenas.alloc_ast_paths(derives), after_derive),
            InvocationKind::Bang { ref mac, .. } =>
                (&mac.path, MacroKind::Bang, &[][..], false),
            InvocationKind::Derive { ref path, .. } =>
                (path, MacroKind::Derive, &[][..], false),
            InvocationKind::DeriveContainer { ref derives, .. } => {
                // Block expansion of the container until we resolve all derives in it.
                // This is required for two reasons:
                // - Derive helper attributes are in scope for the item to which the `#[derive]`
                //   is applied, so they have to be produced by the container's expansion rather
                //   than by individual derives.
                // - Derives in the container need to know whether one of them is a built-in `Copy`.
                // FIXME: Try to avoid repeated resolutions for derives here and in expansion.
                let mut exts = Vec::new();
                for path in derives {
                    exts.push(match self.resolve_macro_path(
                        path, Some(MacroKind::Derive), &parent_scope, true, force
                    ) {
                        Ok((Some(ext), _)) => ext,
                        Ok(_) | Err(Determinacy::Determined) => self.dummy_ext(MacroKind::Derive),
                        Err(Determinacy::Undetermined) => return Err(Indeterminate),
                    })
                }
                return Ok(InvocationRes::DeriveContainer(exts));
            }
        };

        // Derives are not included when `invocations` are collected, so we have to add them here.
        let parent_scope = &ParentScope { derives, ..parent_scope };
        let (ext, res) = self.smart_resolve_macro_path(path, kind, parent_scope, force)?;

        let span = invoc.span();
        invoc_id.set_expn_data(ext.expn_data(parent_scope.expansion, span, fast_print_path(path)));

        if let Res::Def(_, def_id) = res {
            if after_derive {
                self.session.span_err(span, "macro attributes must be placed before `#[derive]`");
            }
            self.macro_defs.insert(invoc_id, def_id);
            let normal_module_def_id = self.macro_def_scope(invoc_id).normal_ancestor_id;
            self.definitions.add_parent_module_of_macro_def(invoc_id, normal_module_def_id);
        }

        match invoc.fragment_kind {
            AstFragmentKind::Arms
                | AstFragmentKind::Fields
                | AstFragmentKind::FieldPats
                | AstFragmentKind::GenericParams
                | AstFragmentKind::Params
                | AstFragmentKind::StructFields
                | AstFragmentKind::Variants =>
            {
                if let Res::Def(..) = res {
                    self.session.span_err(
                        span,
                        &format!("expected an inert attribute, found {} {}",
                                 res.article(), res.descr()),
                    );
                    return Ok(InvocationRes::Single(self.dummy_ext(kind)));
                }
            },
            _ => {}
        }

        Ok(InvocationRes::Single(ext))
    }

    fn check_unused_macros(&self) {
        for (&node_id, &span) in self.unused_macros.iter() {
            self.session.buffer_lint(
                lint::builtin::UNUSED_MACROS, node_id, span, "unused macro definition"
            );
        }
    }

    fn has_derives(&self, expn_id: ExpnId, derives: SpecialDerives) -> bool {
        self.has_derives(expn_id, derives)
    }

    fn add_derives(&mut self, expn_id: ExpnId, derives: SpecialDerives) {
        *self.special_derives.entry(expn_id).or_default() |= derives;
    }
}

impl<'a> Resolver<'a> {
    /// Resolve macro path with error reporting and recovery.
    fn smart_resolve_macro_path(
        &mut self,
        path: &ast::Path,
        kind: MacroKind,
        parent_scope: &ParentScope<'a>,
        force: bool,
    ) -> Result<(Lrc<SyntaxExtension>, Res), Indeterminate> {
        let (ext, res) = match self.resolve_macro_path(path, Some(kind), parent_scope,
                                                       true, force) {
            Ok((Some(ext), res)) => (ext, res),
            // Use dummy syntax extensions for unresolved macros for better recovery.
            Ok((None, res)) => (self.dummy_ext(kind), res),
            Err(Determinacy::Determined) => (self.dummy_ext(kind), Res::Err),
            Err(Determinacy::Undetermined) => return Err(Indeterminate),
        };

        // Report errors and enforce feature gates for the resolved macro.
        let features = self.session.features_untracked();
        for segment in &path.segments {
            if let Some(args) = &segment.args {
                self.session.span_err(args.span(), "generic arguments in macro path");
            }
            if kind == MacroKind::Attr && !features.rustc_attrs &&
               segment.ident.as_str().starts_with("rustc") {
                let msg =
                    "attributes starting with `rustc` are reserved for use by the `rustc` compiler";
                emit_feature_err(
                    &self.session.parse_sess,
                    sym::rustc_attrs,
                    segment.ident.span,
                    GateIssue::Language,
                    msg,
                );
            }
        }

        match res {
            Res::Def(DefKind::Macro(_), def_id) => {
                if let Some(node_id) = self.definitions.as_local_node_id(def_id) {
                    self.unused_macros.remove(&node_id);
                    if self.proc_macro_stubs.contains(&node_id) {
                        self.session.span_err(
                            path.span,
                            "can't use a procedural macro from the same crate that defines it",
                        );
                    }
                }
            }
            Res::NonMacroAttr(..) | Res::Err => {}
            _ => panic!("expected `DefKind::Macro` or `Res::NonMacroAttr`"),
        };

        self.check_stability_and_deprecation(&ext, path);

        Ok(if ext.macro_kind() != kind {
            let expected = kind.descr_expected();
            let msg = format!("expected {}, found {} `{}`", expected, res.descr(), path);
            self.session.struct_span_err(path.span, &msg)
                        .span_label(path.span, format!("not {} {}", kind.article(), expected))
                        .emit();
            // Use dummy syntax extensions for unexpected macro kinds for better recovery.
            (self.dummy_ext(kind), Res::Err)
        } else {
            (ext, res)
        })
    }

    pub fn resolve_macro_path(
        &mut self,
        path: &ast::Path,
        kind: Option<MacroKind>,
        parent_scope: &ParentScope<'a>,
        trace: bool,
        force: bool,
    ) -> Result<(Option<Lrc<SyntaxExtension>>, Res), Determinacy> {
        let path_span = path.span;
        let mut path = Segment::from_path(path);

        // Possibly apply the macro helper hack
        if kind == Some(MacroKind::Bang) && path.len() == 1 &&
           path[0].ident.span.ctxt().outer_expn_data().local_inner_macros {
            let root = Ident::new(kw::DollarCrate, path[0].ident.span);
            path.insert(0, Segment::from_ident(root));
        }

        let res = if path.len() > 1 {
            let res = match self.resolve_path(&path, Some(MacroNS), parent_scope,
                                              false, path_span, CrateLint::No) {
                PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
                    Ok(path_res.base_res())
                }
                PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined),
                PathResult::NonModule(..)
                | PathResult::Indeterminate
                | PathResult::Failed { .. } => Err(Determinacy::Determined),
                PathResult::Module(..) => unreachable!(),
            };

            if trace {
                let kind = kind.expect("macro kind must be specified if tracing is enabled");
                self.multi_segment_macro_resolutions
                    .push((path, path_span, kind, *parent_scope, res.ok()));
            }

            self.prohibit_imported_non_macro_attrs(None, res.ok(), path_span);
            res
        } else {
            let scope_set = kind.map_or(ScopeSet::All(MacroNS, false), ScopeSet::Macro);
            let binding = self.early_resolve_ident_in_lexical_scope(
                path[0].ident, scope_set, parent_scope, false, force, path_span
            );
            if let Err(Determinacy::Undetermined) = binding {
                return Err(Determinacy::Undetermined);
            }

            if trace {
                let kind = kind.expect("macro kind must be specified if tracing is enabled");
                self.single_segment_macro_resolutions
                    .push((path[0].ident, kind, *parent_scope, binding.ok()));
            }

            let res = binding.map(|binding| binding.res());
            self.prohibit_imported_non_macro_attrs(binding.ok(), res.ok(), path_span);
            res
        };

        res.map(|res| (self.get_macro(res), res))
    }

    // Resolve an identifier in lexical scope.
    // This is a variation of `fn resolve_ident_in_lexical_scope` that can be run during
    // expansion and import resolution (perhaps they can be merged in the future).
    // The function is used for resolving initial segments of macro paths (e.g., `foo` in
    // `foo::bar!(); or `foo!();`) and also for import paths on 2018 edition.
    crate fn early_resolve_ident_in_lexical_scope(
        &mut self,
        orig_ident: Ident,
        scope_set: ScopeSet,
        parent_scope: &ParentScope<'a>,
        record_used: bool,
        force: bool,
        path_span: Span,
    ) -> Result<&'a NameBinding<'a>, Determinacy> {
        bitflags::bitflags! {
            struct Flags: u8 {
                const MACRO_RULES        = 1 << 0;
                const MODULE             = 1 << 1;
                const PRELUDE            = 1 << 2;
                const MISC_SUGGEST_CRATE = 1 << 3;
                const MISC_SUGGEST_SELF  = 1 << 4;
                const MISC_FROM_PRELUDE  = 1 << 5;
            }
        }

        assert!(force || !record_used); // `record_used` implies `force`

        // Make sure `self`, `super` etc produce an error when passed to here.
        if orig_ident.is_path_segment_keyword() {
            return Err(Determinacy::Determined);
        }

        let (ns, macro_kind, is_import) = match scope_set {
            ScopeSet::All(ns, is_import) => (ns, None, is_import),
            ScopeSet::AbsolutePath(ns) => (ns, None, false),
            ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false),
        };

        // This is *the* result, resolution from the scope closest to the resolved identifier.
        // However, sometimes this result is "weak" because it comes from a glob import or
        // a macro expansion, and in this case it cannot shadow names from outer scopes, e.g.
        // mod m { ... } // solution in outer scope
        // {
        //     use prefix::*; // imports another `m` - innermost solution
        //                    // weak, cannot shadow the outer `m`, need to report ambiguity error
        //     m::mac!();
        // }
        // So we have to save the innermost solution and continue searching in outer scopes
        // to detect potential ambiguities.
        let mut innermost_result: Option<(&NameBinding<'_>, Flags)> = None;
        let mut determinacy = Determinacy::Determined;

        // Go through all the scopes and try to resolve the name.
        let break_result = self.visit_scopes(scope_set, parent_scope, orig_ident,
                                             |this, scope, use_prelude, ident| {
            let result = match scope {
                Scope::DeriveHelpers => {
                    let mut result = Err(Determinacy::Determined);
                    for derive in parent_scope.derives {
                        let parent_scope = &ParentScope { derives: &[], ..*parent_scope };
                        match this.resolve_macro_path(derive, Some(MacroKind::Derive),
                                                      parent_scope, true, force) {
                            Ok((Some(ext), _)) => if ext.helper_attrs.contains(&ident.name) {
                                let binding = (Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
                                               ty::Visibility::Public, derive.span, ExpnId::root())
                                               .to_name_binding(this.arenas);
                                result = Ok((binding, Flags::empty()));
                                break;
                            }
                            Ok(_) | Err(Determinacy::Determined) => {}
                            Err(Determinacy::Undetermined) =>
                                result = Err(Determinacy::Undetermined),
                        }
                    }
                    result
                }
                Scope::MacroRules(legacy_scope) => match legacy_scope {
                    LegacyScope::Binding(legacy_binding) if ident == legacy_binding.ident =>
                        Ok((legacy_binding.binding, Flags::MACRO_RULES)),
                    LegacyScope::Invocation(invoc_id)
                        if !this.output_legacy_scopes.contains_key(&invoc_id) =>
                            Err(Determinacy::Undetermined),
                    _ => Err(Determinacy::Determined),
                }
                Scope::CrateRoot => {
                    let root_ident = Ident::new(kw::PathRoot, ident.span);
                    let root_module = this.resolve_crate_root(root_ident);
                    let binding = this.resolve_ident_in_module_ext(
                        ModuleOrUniformRoot::Module(root_module),
                        ident,
                        ns,
                        parent_scope,
                        record_used,
                        path_span,
                    );
                    match binding {
                        Ok(binding) => Ok((binding, Flags::MODULE | Flags::MISC_SUGGEST_CRATE)),
                        Err((Determinacy::Undetermined, Weak::No)) =>
                            return Some(Err(Determinacy::determined(force))),
                        Err((Determinacy::Undetermined, Weak::Yes)) =>
                            Err(Determinacy::Undetermined),
                        Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
                    }
                }
                Scope::Module(module) => {
                    let adjusted_parent_scope = &ParentScope { module, ..*parent_scope };
                    let binding = this.resolve_ident_in_module_unadjusted_ext(
                        ModuleOrUniformRoot::Module(module),
                        ident,
                        ns,
                        adjusted_parent_scope,
                        true,
                        record_used,
                        path_span,
                    );
                    match binding {
                        Ok(binding) => {
                            let misc_flags = if ptr::eq(module, this.graph_root) {
                                Flags::MISC_SUGGEST_CRATE
                            } else if module.is_normal() {
                                Flags::MISC_SUGGEST_SELF
                            } else {
                                Flags::empty()
                            };
                            Ok((binding, Flags::MODULE | misc_flags))
                        }
                        Err((Determinacy::Undetermined, Weak::No)) =>
                            return Some(Err(Determinacy::determined(force))),
                        Err((Determinacy::Undetermined, Weak::Yes)) =>
                            Err(Determinacy::Undetermined),
                        Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
                    }
                }
                Scope::MacroUsePrelude => match this.macro_use_prelude.get(&ident.name).cloned() {
                    Some(binding) => Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE)),
                    None => Err(Determinacy::determined(
                        this.graph_root.unexpanded_invocations.borrow().is_empty()
                    ))
                }
                Scope::BuiltinAttrs => if is_builtin_attr_name(ident.name) {
                    let binding = (Res::NonMacroAttr(NonMacroAttrKind::Builtin),
                                   ty::Visibility::Public, DUMMY_SP, ExpnId::root())
                                   .to_name_binding(this.arenas);
                    Ok((binding, Flags::PRELUDE))
                } else {
                    Err(Determinacy::Determined)
                }
                Scope::LegacyPluginHelpers => if this.session.plugin_attributes.borrow().iter()
                                                     .any(|(name, _)| ident.name == *name) {
                    let binding = (Res::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper),
                                   ty::Visibility::Public, DUMMY_SP, ExpnId::root())
                                   .to_name_binding(this.arenas);
                    Ok((binding, Flags::PRELUDE))
                } else {
                    Err(Determinacy::Determined)
                }
                Scope::ExternPrelude => match this.extern_prelude_get(ident, !record_used) {
                    Some(binding) => Ok((binding, Flags::PRELUDE)),
                    None => Err(Determinacy::determined(
                        this.graph_root.unexpanded_invocations.borrow().is_empty()
                    )),
                }
                Scope::ToolPrelude => if KNOWN_TOOLS.contains(&ident.name) {
                    let binding = (Res::ToolMod, ty::Visibility::Public, DUMMY_SP, ExpnId::root())
                                   .to_name_binding(this.arenas);
                    Ok((binding, Flags::PRELUDE))
                } else {
                    Err(Determinacy::Determined)
                }
                Scope::StdLibPrelude => {
                    let mut result = Err(Determinacy::Determined);
                    if let Some(prelude) = this.prelude {
                        if let Ok(binding) = this.resolve_ident_in_module_unadjusted(
                            ModuleOrUniformRoot::Module(prelude),
                            ident,
                            ns,
                            parent_scope,
                            false,
                            path_span,
                        ) {
                            if use_prelude || this.is_builtin_macro(binding.res()) {
                                result = Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE));
                            }
                        }
                    }
                    result
                }
                Scope::BuiltinTypes => match this.primitive_type_table.primitive_types
                                                 .get(&ident.name).cloned() {
                    Some(prim_ty) => {
                        let binding = (Res::PrimTy(prim_ty), ty::Visibility::Public,
                                       DUMMY_SP, ExpnId::root()).to_name_binding(this.arenas);
                        Ok((binding, Flags::PRELUDE))
                    }
                    None => Err(Determinacy::Determined)
                }
            };

            match result {
                Ok((binding, flags)) if sub_namespace_match(binding.macro_kind(), macro_kind) => {
                    if !record_used {
                        return Some(Ok(binding));
                    }

                    if let Some((innermost_binding, innermost_flags)) = innermost_result {
                        // Found another solution, if the first one was "weak", report an error.
                        let (res, innermost_res) = (binding.res(), innermost_binding.res());
                        if res != innermost_res {
                            let builtin = Res::NonMacroAttr(NonMacroAttrKind::Builtin);
                            let derive_helper = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
                            let legacy_helper =
                                Res::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper);

                            let ambiguity_error_kind = if is_import {
                                Some(AmbiguityKind::Import)
                            } else if innermost_res == builtin || res == builtin {
                                Some(AmbiguityKind::BuiltinAttr)
                            } else if innermost_res == derive_helper || res == derive_helper {
                                Some(AmbiguityKind::DeriveHelper)
                            } else if innermost_res == legacy_helper &&
                                      flags.contains(Flags::PRELUDE) ||
                                      res == legacy_helper &&
                                      innermost_flags.contains(Flags::PRELUDE) {
                                Some(AmbiguityKind::LegacyHelperVsPrelude)
                            } else if innermost_flags.contains(Flags::MACRO_RULES) &&
                                      flags.contains(Flags::MODULE) &&
                                      !this.disambiguate_legacy_vs_modern(innermost_binding,
                                                                          binding) ||
                                      flags.contains(Flags::MACRO_RULES) &&
                                      innermost_flags.contains(Flags::MODULE) &&
                                      !this.disambiguate_legacy_vs_modern(binding,
                                                                          innermost_binding) {
                                Some(AmbiguityKind::LegacyVsModern)
                            } else if innermost_binding.is_glob_import() {
                                Some(AmbiguityKind::GlobVsOuter)
                            } else if innermost_binding.may_appear_after(parent_scope.expansion,
                                                                         binding) {
                                Some(AmbiguityKind::MoreExpandedVsOuter)
                            } else {
                                None
                            };
                            if let Some(kind) = ambiguity_error_kind {
                                let misc = |f: Flags| if f.contains(Flags::MISC_SUGGEST_CRATE) {
                                    AmbiguityErrorMisc::SuggestCrate
                                } else if f.contains(Flags::MISC_SUGGEST_SELF) {
                                    AmbiguityErrorMisc::SuggestSelf
                                } else if f.contains(Flags::MISC_FROM_PRELUDE) {
                                    AmbiguityErrorMisc::FromPrelude
                                } else {
                                    AmbiguityErrorMisc::None
                                };
                                this.ambiguity_errors.push(AmbiguityError {
                                    kind,
                                    ident: orig_ident,
                                    b1: innermost_binding,
                                    b2: binding,
                                    misc1: misc(innermost_flags),
                                    misc2: misc(flags),
                                });
                                return Some(Ok(innermost_binding));
                            }
                        }
                    } else {
                        // Found the first solution.
                        innermost_result = Some((binding, flags));
                    }
                }
                Ok(..) | Err(Determinacy::Determined) => {}
                Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined
            }

            None
        });

        if let Some(break_result) = break_result {
            return break_result;
        }

        // The first found solution was the only one, return it.
        if let Some((binding, _)) = innermost_result {
            return Ok(binding);
        }

        let determinacy = Determinacy::determined(determinacy == Determinacy::Determined || force);
        if determinacy == Determinacy::Determined && macro_kind == Some(MacroKind::Attr) &&
           self.session.features_untracked().custom_attribute {
            // For single-segment attributes interpret determinate "no resolution" as a custom
            // attribute. (Lexical resolution implies the first segment and attr kind should imply
            // the last segment, so we are certainly working with a single-segment attribute here.)
            assert!(ns == MacroNS);
            let binding = (Res::NonMacroAttr(NonMacroAttrKind::Custom),
                           ty::Visibility::Public, orig_ident.span, ExpnId::root())
                           .to_name_binding(self.arenas);
            Ok(binding)
        } else {
            Err(determinacy)
        }
    }

    crate fn finalize_macro_resolutions(&mut self) {
        let check_consistency = |this: &mut Self, path: &[Segment], span, kind: MacroKind,
                                 initial_res: Option<Res>, res: Res| {
            if let Some(initial_res) = initial_res {
                if res != initial_res && res != Res::Err && this.ambiguity_errors.is_empty() {
                    // Make sure compilation does not succeed if preferred macro resolution
                    // has changed after the macro had been expanded. In theory all such
                    // situations should be reported as ambiguity errors, so this is a bug.
                    if initial_res == Res::NonMacroAttr(NonMacroAttrKind::Custom) {
                        // Yeah, legacy custom attributes are implemented using forced resolution
                        // (which is a best effort error recovery tool, basically), so we can't
                        // promise their resolution won't change later.
                        let msg = format!("inconsistent resolution for a macro: first {}, then {}",
                                          initial_res.descr(), res.descr());
                        this.session.span_err(span, &msg);
                    } else {
                        span_bug!(span, "inconsistent resolution for a macro");
                    }
                }
            } else {
                // It's possible that the macro was unresolved (indeterminate) and silently
                // expanded into a dummy fragment for recovery during expansion.
                // Now, post-expansion, the resolution may succeed, but we can't change the
                // past and need to report an error.
                // However, non-speculative `resolve_path` can successfully return private items
                // even if speculative `resolve_path` returned nothing previously, so we skip this
                // less informative error if the privacy error is reported elsewhere.
                if this.privacy_errors.is_empty() {
                    let msg = format!("cannot determine resolution for the {} `{}`",
                                        kind.descr(), Segment::names_to_string(path));
                    let msg_note = "import resolution is stuck, try simplifying macro imports";
                    this.session.struct_span_err(span, &msg).note(msg_note).emit();
                }
            }
        };

        let macro_resolutions = mem::take(&mut self.multi_segment_macro_resolutions);
        for (mut path, path_span, kind, parent_scope, initial_res) in macro_resolutions {
            // FIXME: Path resolution will ICE if segment IDs present.
            for seg in &mut path { seg.id = None; }
            match self.resolve_path(
                &path, Some(MacroNS), &parent_scope, true, path_span, CrateLint::No
            ) {
                PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
                    let res = path_res.base_res();
                    check_consistency(self, &path, path_span, kind, initial_res, res);
                }
                path_res @ PathResult::NonModule(..) | path_res @ PathResult::Failed { .. } => {
                    let (span, label) = if let PathResult::Failed { span, label, .. } = path_res {
                        (span, label)
                    } else {
                        (path_span, format!("partially resolved path in {} {}",
                                            kind.article(), kind.descr()))
                    };
                    self.report_error(span, ResolutionError::FailedToResolve {
                        label,
                        suggestion: None
                    });
                }
                PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),
            }
        }

        let macro_resolutions = mem::take(&mut self.single_segment_macro_resolutions);
        for (ident, kind, parent_scope, initial_binding) in macro_resolutions {
            match self.early_resolve_ident_in_lexical_scope(ident, ScopeSet::Macro(kind),
                                                            &parent_scope, true, true, ident.span) {
                Ok(binding) => {
                    let initial_res = initial_binding.map(|initial_binding| {
                        self.record_use(ident, MacroNS, initial_binding, false);
                        initial_binding.res()
                    });
                    let res = binding.res();
                    let seg = Segment::from_ident(ident);
                    check_consistency(self, &[seg], ident.span, kind, initial_res, res);
                }
                Err(..) => {
                    assert!(initial_binding.is_none());
                    let expected = kind.descr_expected();
                    let msg = format!("cannot find {} `{}` in this scope", expected, ident);
                    let mut err = self.session.struct_span_err(ident.span, &msg);
                    self.unresolved_macro_suggestions(&mut err, kind, &parent_scope, ident);
                    err.emit();
                }
            }
        }

        let builtin_attrs = mem::take(&mut self.builtin_attrs);
        for (ident, parent_scope) in builtin_attrs {
            let _ = self.early_resolve_ident_in_lexical_scope(
                ident, ScopeSet::Macro(MacroKind::Attr), &parent_scope, true, true, ident.span
            );
        }
    }

    fn check_stability_and_deprecation(&self, ext: &SyntaxExtension, path: &ast::Path) {
        let span = path.span;
        if let Some(stability) = &ext.stability {
            if let StabilityLevel::Unstable { reason, issue, is_soft } = stability.level {
                let feature = stability.feature;
                if !self.active_features.contains(&feature) && !span.allows_unstable(feature) {
                    stability::report_unstable(self.session, feature, reason, issue, is_soft, span);
                }
            }
            if let Some(depr) = &stability.rustc_depr {
                let (message, lint) = stability::rustc_deprecation_message(depr, &path.to_string());
                stability::early_report_deprecation(
                    self.session, &message, depr.suggestion, lint, span
                );
            }
        }
        if let Some(depr) = &ext.deprecation {
            let (message, lint) = stability::deprecation_message(depr, &path.to_string());
            stability::early_report_deprecation(self.session, &message, None, lint, span);
        }
    }

    fn prohibit_imported_non_macro_attrs(&self, binding: Option<&'a NameBinding<'a>>,
                                         res: Option<Res>, span: Span) {
        if let Some(Res::NonMacroAttr(kind)) = res {
            if kind != NonMacroAttrKind::Tool && binding.map_or(true, |b| b.is_import()) {
                let msg = format!("cannot use a {} through an import", kind.descr());
                let mut err = self.session.struct_span_err(span, &msg);
                if let Some(binding) = binding {
                    err.span_note(binding.span, &format!("the {} imported here", kind.descr()));
                }
                err.emit();
            }
        }
    }

    crate fn check_reserved_macro_name(&mut self, ident: Ident, res: Res) {
        // Reserve some names that are not quite covered by the general check
        // performed on `Resolver::builtin_attrs`.
        if ident.name == sym::cfg || ident.name == sym::cfg_attr || ident.name == sym::derive {
            let macro_kind = self.get_macro(res).map(|ext| ext.macro_kind());
            if macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr)) {
                self.session.span_err(
                    ident.span, &format!("name `{}` is reserved in attribute namespace", ident)
                );
            }
        }
    }

    /// Compile the macro into a `SyntaxExtension` and possibly replace it with a pre-defined
    /// extension partially or entirely for built-in macros and legacy plugin macros.
    crate fn compile_macro(&mut self, item: &ast::Item, edition: Edition) -> SyntaxExtension {
        let mut result = macro_rules::compile(
            &self.session.parse_sess, self.session.features_untracked(), item, edition
        );

        if result.is_builtin {
            // The macro was marked with `#[rustc_builtin_macro]`.
            if let Some(ext) = self.builtin_macros.remove(&item.ident.name) {
                if ext.is_builtin {
                    // The macro is a built-in, replace only the expander function.
                    result.kind = ext.kind;
                } else {
                    // The macro is from a plugin, the in-source definition is dummy,
                    // take all the data from the resolver.
                    result = ext;
                }
            } else {
                let msg = format!("cannot find a built-in macro with name `{}`", item.ident);
                self.session.span_err(item.span, &msg);
            }
        }

        result
    }
}
