use crate::{AmbiguityError, AmbiguityKind, AmbiguityErrorMisc, Determinacy};
use crate::{CrateLint, Resolver, ResolutionError, Scope, ScopeSet, ParentScope, Weak};
use crate::{Module, ModuleKind, NameBinding, PathResult, Segment, ToNameBinding};
use crate::{ModuleOrUniformRoot, KNOWN_TOOLS};
use crate::Namespace::*;
use crate::build_reduced_graph::BuildReducedGraphVisitor;
use crate::resolve_imports::ImportResolver;
use rustc::hir::def::{self, DefKind, NonMacroAttrKind};
use rustc::hir::map::DefCollector;
use rustc::middle::stability;
use rustc::{ty, lint, span_bug};
use syntax::ast::{self, Ident};
use syntax::attr::StabilityLevel;
use syntax::edition::Edition;
use syntax::ext::base::{self, Indeterminate, SpecialDerives};
use syntax::ext::base::{MacroKind, SyntaxExtension};
use syntax::ext::expand::{AstFragment, Invocation, InvocationKind};
use syntax::ext::hygiene::{self, ExpnId, ExpnInfo, 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::cell::Cell;
use std::{mem, ptr};
use rustc_data_structures::sync::Lrc;

type Res = def::Res<ast::NodeId>;

// FIXME: Merge this with `ParentScope`.
#[derive(Clone, Debug)]
pub struct InvocationData<'a> {
    /// The module in which the macro was invoked.
    crate module: Module<'a>,
    /// The legacy scope in which the macro was invoked.
    /// The invocation path is resolved in this scope.
    crate parent_legacy_scope: LegacyScope<'a>,
    /// The legacy scope *produced* by expanding this macro invocation,
    /// includes all the macro_rules items, other invocations, etc generated by it.
    /// `None` if the macro is not expanded yet.
    crate output_legacy_scope: Cell<Option<LegacyScope<'a>>>,
}

impl<'a> InvocationData<'a> {
    pub fn root(graph_root: Module<'a>) -> Self {
        InvocationData {
            module: graph_root,
            parent_legacy_scope: LegacyScope::Empty,
            output_legacy_scope: Cell::new(None),
        }
    }
}

/// 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(&'a InvocationData<'a>),
}

// 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) -> ast::NodeId {
        self.session.next_node_id()
    }

    fn get_module_scope(&mut self, id: ast::NodeId) -> ExpnId {
        let span = DUMMY_SP.fresh_expansion(ExpnId::root(), ExpnInfo::default(
            ExpnKind::Macro(MacroKind::Attr, sym::test_case), DUMMY_SP, self.session.edition()
        ));
        let expn_id = span.ctxt().outer_expn();
        let module = self.module_map[&self.definitions.local_def_id(id)];
        self.definitions.set_invocation_parent(expn_id, module.def_id().unwrap().index);
        self.invocations.insert(expn_id, self.arenas.alloc_invocation_data(InvocationData {
            module,
            parent_legacy_scope: LegacyScope::Empty,
            output_legacy_scope: Cell::new(None),
        }));
        expn_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,
            }
        });
    }

    fn visit_ast_fragment_with_placeholders(&mut self, expn_id: ExpnId, fragment: &AstFragment,
                                            derives: &[ExpnId]) {
        fragment.visit_with(&mut DefCollector::new(&mut self.definitions, expn_id));

        let invocation = self.invocations[&expn_id];
        invocation.module.unresolved_invocations.borrow_mut().remove(&expn_id);
        invocation.module.unresolved_invocations.borrow_mut().extend(derives);
        let parent_def = self.definitions.invocation_parent(expn_id);
        for &derive_invoc_id in derives {
            self.definitions.set_invocation_parent(derive_invoc_id, parent_def);
        }
        self.invocations.extend(derives.iter().map(|&derive| (derive, invocation)));
        let mut visitor = BuildReducedGraphVisitor {
            r: self,
            parent_scope: ParentScope {
                module: invocation.module,
                expansion: expn_id,
                legacy: invocation.parent_legacy_scope,
                derives: Vec::new(),
            },
        };
        fragment.visit_with(&mut visitor);
        invocation.output_legacy_scope.set(Some(visitor.parent_scope.legacy));
    }

    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));
        }
    }

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

    fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: ExpnId, force: bool)
                                -> Result<Option<Lrc<SyntaxExtension>>, Indeterminate> {
        if !self.invocations.contains_key(&invoc.expansion_data.id) {
            self.invocations.insert(invoc.expansion_data.id, self.invocations[&invoc_id]);
        }
        let invoc_id = invoc.expansion_data.id;
        let (path, kind, derives_in_scope, after_derive) = match invoc.kind {
            InvocationKind::Attr { ref attr, ref derives, after_derive, .. } =>
                (&attr.path, MacroKind::Attr, derives.clone(), after_derive),
            InvocationKind::Bang { ref mac, .. } =>
                (&mac.node.path, MacroKind::Bang, Vec::new(), false),
            InvocationKind::Derive { ref path, .. } =>
                (path, MacroKind::Derive, Vec::new(), false),
            InvocationKind::DeriveContainer { ref derives, .. } => {
                // Block expansion of derives in the container until we know whether one of them
                // is a built-in `Copy`. Skip the resolution if there's only one derive - either
                // it's not a `Copy` and we don't need to do anything, or it's a `Copy` and it
                // will automatically knows about itself.
                let mut result = Ok(None);
                if derives.len() > 1 {
                    let parent_scope = &self.invoc_parent_scope(invoc_id, Vec::new());
                    for path in derives {
                        match self.resolve_macro_path(path, Some(MacroKind::Derive),
                                                      parent_scope, true, force) {
                            Ok((Some(ref ext), _)) if ext.is_derive_copy => {
                                self.add_derives(invoc_id, SpecialDerives::COPY);
                                return Ok(None);
                            }
                            Err(Determinacy::Undetermined) => result = Err(Indeterminate),
                            _ => {}
                        }
                    }
                }
                return result;
            }
        };

        let parent_scope = &self.invoc_parent_scope(invoc_id, derives_in_scope);
        let (ext, res) = self.smart_resolve_macro_path(path, kind, parent_scope, force)?;

        let span = invoc.span();
        invoc_id.set_expn_info(ext.expn_info(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);
        }

        Ok(Some(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> {
    pub fn dummy_parent_scope(&self) -> ParentScope<'a> {
        self.invoc_parent_scope(ExpnId::root(), Vec::new())
    }

    fn invoc_parent_scope(&self, invoc_id: ExpnId, derives: Vec<ast::Path>) -> ParentScope<'a> {
        let invoc = self.invocations[&invoc_id];
        ParentScope {
            module: invoc.module.nearest_item_scope(),
            expansion: invoc_id.parent(),
            legacy: invoc.parent_legacy_scope,
            derives,
        }
    }

    /// 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 = if kind == MacroKind::Attr { "attribute" } else  { kind.descr() };
            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_info()
               .map_or(false, |info| info.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");
                parent_scope.module.multi_segment_macro_resolutions.borrow_mut()
                    .push((path, path_span, kind, parent_scope.clone(), 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");
                parent_scope.module.single_segment_macro_resolutions.borrow_mut()
                    .push((path[0].ident, kind, parent_scope.clone(), 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: Vec::new(), ..*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) if invoc.output_legacy_scope.get().is_none() =>
                        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.clone() };
                    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.unresolved_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.unresolved_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().opt_def_id()) {
                                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)
        }
    }

    pub fn finalize_current_module_macro_resolutions(&mut self, module: Module<'a>) {
        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 *module.multi_segment_macro_resolutions.borrow_mut());
        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 *module.single_segment_macro_resolutions.borrow_mut());
        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 bang = if kind == MacroKind::Bang { "!" } else { "" };
                    let msg =
                        format!("cannot find {} `{}{}` in this scope", kind.descr(), ident, bang);
                    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 *module.builtin_attrs.borrow_mut());
        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) -> Lrc<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);
            }
        }

        Lrc::new(result)
    }
}
