mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-03 10:33:34 +00:00
Auto merge of #14781 - lowr:patch/macro-subns-and-prelude, r=Veykril
Introduce macro sub-namespaces and `macro_use` prelude This PR implements two mechanisms needed for correct macro name resolution: macro sub-namespace and `macro_use` prelude. - [macro sub-namespaces][subns-ref] Macros have two sub-namespaces: one for function-like macro and the other for those in attributes (including custom derive macros). When we're resolving a macro name for function-like macro, we should ignore non-function-like macros, and vice versa. This helps resolve single-segment macro names because we can (and should, as rustc does) fallback to names in preludes when the name in the current module scope is in different sub-namespace. - [`macro_use` prelude][prelude-ref] `#[macro_use]`'d extern crate declarations (including the standard library) bring their macros into scope, but they should not be prioritized over local macros (those defined in place and those explicitly imported). We have been bringing them into legacy (textual) macro scope, which has the highest precedence in name resolution. This PR introduces the `macro_use` prelude in crate-level `DefMap`s, whose precedence is lower than local macros but higher than the standard library prelude. The first 3 commits are drive-by fixes/refactors. Fixes #8828 (prelude) Fixes #12505 (prelude) Fixes #12734 (prelude) Fixes #13683 (prelude) Fixes #13821 (prelude) Fixes #13974 (prelude) Fixes #14254 (namespace) [subns-ref]: https://doc.rust-lang.org/reference/names/namespaces.html#sub-namespaces [prelude-ref]: https://doc.rust-lang.org/reference/names/preludes.html#macro_use-prelude
This commit is contained in:
commit
9b3387454d
@ -37,7 +37,7 @@ use crate::{
|
||||
item_scope::BuiltinShadowMode,
|
||||
lang_item::LangItem,
|
||||
lower::LowerCtx,
|
||||
nameres::DefMap,
|
||||
nameres::{DefMap, MacroSubNs},
|
||||
path::{GenericArgs, Path},
|
||||
type_ref::{Mutability, Rawness, TypeRef},
|
||||
AdtId, BlockId, BlockLoc, ModuleDefId, UnresolvedMacro,
|
||||
@ -800,7 +800,13 @@ impl ExprCollector<'_> {
|
||||
let module = self.expander.module.local_id;
|
||||
let res = self.expander.enter_expand(self.db, mcall, |path| {
|
||||
self.def_map
|
||||
.resolve_path(self.db, module, &path, crate::item_scope::BuiltinShadowMode::Other)
|
||||
.resolve_path(
|
||||
self.db,
|
||||
module,
|
||||
&path,
|
||||
crate::item_scope::BuiltinShadowMode::Other,
|
||||
Some(MacroSubNs::Bang),
|
||||
)
|
||||
.0
|
||||
.take_macros()
|
||||
});
|
||||
@ -1056,6 +1062,7 @@ impl ExprCollector<'_> {
|
||||
self.expander.module.local_id,
|
||||
&name.clone().into(),
|
||||
BuiltinShadowMode::Other,
|
||||
None,
|
||||
);
|
||||
match resolved.take_values() {
|
||||
Some(ModuleDefId::ConstId(_)) => (None, Pat::Path(name.into())),
|
||||
|
@ -22,7 +22,7 @@ use crate::{
|
||||
attr_resolution::ResolvedAttr,
|
||||
diagnostics::DefDiagnostic,
|
||||
proc_macro::{parse_macro_name_and_helper_attrs, ProcMacroKind},
|
||||
DefMap,
|
||||
DefMap, MacroSubNs,
|
||||
},
|
||||
type_ref::{TraitRef, TypeBound, TypeRef},
|
||||
visibility::RawVisibility,
|
||||
@ -673,6 +673,7 @@ impl<'a> AssocItemCollector<'a> {
|
||||
module,
|
||||
&path,
|
||||
crate::item_scope::BuiltinShadowMode::Other,
|
||||
Some(MacroSubNs::Bang),
|
||||
)
|
||||
.0
|
||||
.take_macros()
|
||||
|
@ -543,6 +543,7 @@ mod tests {
|
||||
module.local_id,
|
||||
&mod_path,
|
||||
crate::item_scope::BuiltinShadowMode::Module,
|
||||
None,
|
||||
)
|
||||
.0
|
||||
.take_types()
|
||||
|
@ -22,7 +22,7 @@ use crate::{
|
||||
dyn_map::{keys, DynMap},
|
||||
expander::Expander,
|
||||
lower::LowerCtx,
|
||||
nameres::DefMap,
|
||||
nameres::{DefMap, MacroSubNs},
|
||||
src::{HasChildSource, HasSource},
|
||||
type_ref::{LifetimeRef, TypeBound, TypeRef},
|
||||
AdtId, ConstParamId, GenericDefId, HasModule, LifetimeParamId, LocalLifetimeParamId,
|
||||
@ -361,6 +361,7 @@ impl GenericParams {
|
||||
module,
|
||||
&path,
|
||||
crate::item_scope::BuiltinShadowMode::Other,
|
||||
Some(MacroSubNs::Bang),
|
||||
)
|
||||
.0
|
||||
.take_macros()
|
||||
|
@ -13,12 +13,12 @@ macro_rules! column {() => {}}
|
||||
|
||||
fn main() { column!(); }
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! column {() => {}}
|
||||
|
||||
fn main() { 0; }
|
||||
"##]],
|
||||
fn main() { 0 as u32; }
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
@ -31,12 +31,12 @@ macro_rules! line {() => {}}
|
||||
|
||||
fn main() { line!() }
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! line {() => {}}
|
||||
|
||||
fn main() { 0 }
|
||||
"##]],
|
||||
fn main() { 0 as u32 }
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -922,7 +922,7 @@ macro_rules! m {
|
||||
|
||||
fn bar() -> &'a Baz<u8> {}
|
||||
|
||||
fn bar() -> extern "Rust"fn() -> Ret {}
|
||||
fn bar() -> extern "Rust" fn() -> Ret {}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -1333,7 +1333,7 @@ macro_rules! matches {
|
||||
}
|
||||
fn main() {
|
||||
match 0 {
|
||||
0|1if true =>true , _=>false
|
||||
0|1 if true =>true , _=>false
|
||||
};
|
||||
}
|
||||
"#]],
|
||||
|
@ -73,7 +73,7 @@ fn main() {
|
||||
macro_rules! asi { ($($stmt:stmt)*) => ($($stmt)*); }
|
||||
|
||||
fn main() {
|
||||
let a = 2let b = 5drop(b-a)println!("{}", a+b)
|
||||
let a = 2 let b = 5 drop(b-a)println!("{}", a+b)
|
||||
}
|
||||
"#]],
|
||||
)
|
||||
|
@ -297,55 +297,55 @@ macro_rules! impl_fn_for_zst {
|
||||
|
||||
#[derive(Clone)] struct CharEscapeDebugContinue;
|
||||
impl Fn<(char, )> for CharEscapeDebugContinue {
|
||||
#[inline] extern "rust-call"fn call(&self , (c, ): (char, )) -> char::EscapeDebug { {
|
||||
#[inline] extern "rust-call" fn call(&self , (c, ): (char, )) -> char::EscapeDebug { {
|
||||
c.escape_debug_ext(false )
|
||||
}
|
||||
}
|
||||
}
|
||||
impl FnMut<(char, )> for CharEscapeDebugContinue {
|
||||
#[inline] extern "rust-call"fn call_mut(&mut self , (c, ): (char, )) -> char::EscapeDebug {
|
||||
#[inline] extern "rust-call" fn call_mut(&mut self , (c, ): (char, )) -> char::EscapeDebug {
|
||||
Fn::call(&*self , (c, ))
|
||||
}
|
||||
}
|
||||
impl FnOnce<(char, )> for CharEscapeDebugContinue {
|
||||
type Output = char::EscapeDebug;
|
||||
#[inline] extern "rust-call"fn call_once(self , (c, ): (char, )) -> char::EscapeDebug {
|
||||
#[inline] extern "rust-call" fn call_once(self , (c, ): (char, )) -> char::EscapeDebug {
|
||||
Fn::call(&self , (c, ))
|
||||
}
|
||||
}
|
||||
#[derive(Clone)] struct CharEscapeUnicode;
|
||||
impl Fn<(char, )> for CharEscapeUnicode {
|
||||
#[inline] extern "rust-call"fn call(&self , (c, ): (char, )) -> char::EscapeUnicode { {
|
||||
#[inline] extern "rust-call" fn call(&self , (c, ): (char, )) -> char::EscapeUnicode { {
|
||||
c.escape_unicode()
|
||||
}
|
||||
}
|
||||
}
|
||||
impl FnMut<(char, )> for CharEscapeUnicode {
|
||||
#[inline] extern "rust-call"fn call_mut(&mut self , (c, ): (char, )) -> char::EscapeUnicode {
|
||||
#[inline] extern "rust-call" fn call_mut(&mut self , (c, ): (char, )) -> char::EscapeUnicode {
|
||||
Fn::call(&*self , (c, ))
|
||||
}
|
||||
}
|
||||
impl FnOnce<(char, )> for CharEscapeUnicode {
|
||||
type Output = char::EscapeUnicode;
|
||||
#[inline] extern "rust-call"fn call_once(self , (c, ): (char, )) -> char::EscapeUnicode {
|
||||
#[inline] extern "rust-call" fn call_once(self , (c, ): (char, )) -> char::EscapeUnicode {
|
||||
Fn::call(&self , (c, ))
|
||||
}
|
||||
}
|
||||
#[derive(Clone)] struct CharEscapeDefault;
|
||||
impl Fn<(char, )> for CharEscapeDefault {
|
||||
#[inline] extern "rust-call"fn call(&self , (c, ): (char, )) -> char::EscapeDefault { {
|
||||
#[inline] extern "rust-call" fn call(&self , (c, ): (char, )) -> char::EscapeDefault { {
|
||||
c.escape_default()
|
||||
}
|
||||
}
|
||||
}
|
||||
impl FnMut<(char, )> for CharEscapeDefault {
|
||||
#[inline] extern "rust-call"fn call_mut(&mut self , (c, ): (char, )) -> char::EscapeDefault {
|
||||
#[inline] extern "rust-call" fn call_mut(&mut self , (c, ): (char, )) -> char::EscapeDefault {
|
||||
Fn::call(&*self , (c, ))
|
||||
}
|
||||
}
|
||||
impl FnOnce<(char, )> for CharEscapeDefault {
|
||||
type Output = char::EscapeDefault;
|
||||
#[inline] extern "rust-call"fn call_once(self , (c, ): (char, )) -> char::EscapeDefault {
|
||||
#[inline] extern "rust-call" fn call_once(self , (c, ): (char, )) -> char::EscapeDefault {
|
||||
Fn::call(&self , (c, ))
|
||||
}
|
||||
}
|
||||
@ -833,7 +833,7 @@ macro_rules! rgb_color {
|
||||
/* parse error: expected SEMICOLON */
|
||||
/* parse error: expected expression, item or let statement */
|
||||
pub fn new() {
|
||||
let _ = 0as u32<<(8+8);
|
||||
let _ = 0 as u32<<(8+8);
|
||||
}
|
||||
// MACRO_ITEMS@0..31
|
||||
// FN@0..31
|
||||
|
@ -33,8 +33,13 @@ use syntax::{
|
||||
use tt::token_id::{Subtree, TokenId};
|
||||
|
||||
use crate::{
|
||||
db::DefDatabase, macro_id_to_def_id, nameres::ModuleSource, resolver::HasResolver,
|
||||
src::HasSource, test_db::TestDB, AdtId, AsMacroCall, Lookup, ModuleDefId,
|
||||
db::DefDatabase,
|
||||
macro_id_to_def_id,
|
||||
nameres::{MacroSubNs, ModuleSource},
|
||||
resolver::HasResolver,
|
||||
src::HasSource,
|
||||
test_db::TestDB,
|
||||
AdtId, AsMacroCall, Lookup, ModuleDefId,
|
||||
};
|
||||
|
||||
#[track_caller]
|
||||
@ -127,7 +132,9 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
|
||||
let macro_call = InFile::new(source.file_id, ¯o_call);
|
||||
let res = macro_call
|
||||
.as_call_id_with_errors(&db, krate, |path| {
|
||||
resolver.resolve_path_as_macro(&db, &path).map(|it| macro_id_to_def_id(&db, it))
|
||||
resolver
|
||||
.resolve_path_as_macro(&db, &path, Some(MacroSubNs::Bang))
|
||||
.map(|it| macro_id_to_def_id(&db, it))
|
||||
})
|
||||
.unwrap();
|
||||
let macro_call_id = res.value.unwrap();
|
||||
@ -280,6 +287,7 @@ fn pretty_print_macro_expansion(expn: SyntaxNode, map: Option<&TokenMap>) -> Str
|
||||
let curr_kind = token.kind();
|
||||
let space = match (prev_kind, curr_kind) {
|
||||
_ if prev_kind.is_trivia() || curr_kind.is_trivia() => "",
|
||||
_ if prev_kind.is_literal() && !curr_kind.is_punct() => " ",
|
||||
(T!['{'], T!['}']) => "",
|
||||
(T![=], _) | (_, T![=]) => " ",
|
||||
(_, T!['{']) => " ",
|
||||
|
@ -59,7 +59,7 @@ mod tests;
|
||||
|
||||
use std::{cmp::Ord, ops::Deref};
|
||||
|
||||
use base_db::{CrateId, Edition, FileId};
|
||||
use base_db::{CrateId, Edition, FileId, ProcMacroKind};
|
||||
use hir_expand::{name::Name, InFile, MacroCallId, MacroDefId};
|
||||
use itertools::Itertools;
|
||||
use la_arena::Arena;
|
||||
@ -77,7 +77,8 @@ use crate::{
|
||||
path::ModPath,
|
||||
per_ns::PerNs,
|
||||
visibility::Visibility,
|
||||
AstId, BlockId, BlockLoc, FunctionId, LocalModuleId, MacroId, ModuleId, ProcMacroId,
|
||||
AstId, BlockId, BlockLoc, FunctionId, LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId,
|
||||
ProcMacroId,
|
||||
};
|
||||
|
||||
/// Contains the results of (early) name resolution.
|
||||
@ -105,6 +106,9 @@ pub struct DefMap {
|
||||
prelude: Option<ModuleId>,
|
||||
/// The extern prelude is only populated for non-block DefMaps
|
||||
extern_prelude: FxHashMap<Name, ModuleId>,
|
||||
/// `macro_use` prelude that contains macros from `#[macro_use]`'d external crates. Note that
|
||||
/// this contains all kinds of macro, not just `macro_rules!` macro.
|
||||
macro_use_prelude: FxHashMap<Name, MacroId>,
|
||||
|
||||
/// Side table for resolving derive helpers.
|
||||
exported_derives: FxHashMap<MacroDefId, Box<[Name]>>,
|
||||
@ -277,6 +281,7 @@ impl DefMap {
|
||||
edition,
|
||||
recursion_limit: None,
|
||||
extern_prelude: FxHashMap::default(),
|
||||
macro_use_prelude: FxHashMap::default(),
|
||||
exported_derives: FxHashMap::default(),
|
||||
fn_proc_macro_mapping: FxHashMap::default(),
|
||||
proc_macro_loading_error: None,
|
||||
@ -376,9 +381,16 @@ impl DefMap {
|
||||
original_module: LocalModuleId,
|
||||
path: &ModPath,
|
||||
shadow: BuiltinShadowMode,
|
||||
expected_macro_subns: Option<MacroSubNs>,
|
||||
) -> (PerNs, Option<usize>) {
|
||||
let res =
|
||||
self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path, shadow);
|
||||
let res = self.resolve_path_fp_with_macro(
|
||||
db,
|
||||
ResolveMode::Other,
|
||||
original_module,
|
||||
path,
|
||||
shadow,
|
||||
expected_macro_subns,
|
||||
);
|
||||
(res.resolved_def, res.segment_index)
|
||||
}
|
||||
|
||||
@ -395,6 +407,7 @@ impl DefMap {
|
||||
original_module,
|
||||
path,
|
||||
shadow,
|
||||
None, // Currently this function isn't used for macro resolution.
|
||||
);
|
||||
(res.resolved_def, res.segment_index)
|
||||
}
|
||||
@ -489,6 +502,7 @@ impl DefMap {
|
||||
_c: _,
|
||||
exported_derives,
|
||||
extern_prelude,
|
||||
macro_use_prelude,
|
||||
diagnostics,
|
||||
modules,
|
||||
registered_attrs,
|
||||
@ -507,6 +521,7 @@ impl DefMap {
|
||||
} = self;
|
||||
|
||||
extern_prelude.shrink_to_fit();
|
||||
macro_use_prelude.shrink_to_fit();
|
||||
exported_derives.shrink_to_fit();
|
||||
diagnostics.shrink_to_fit();
|
||||
modules.shrink_to_fit();
|
||||
@ -562,3 +577,48 @@ pub enum ModuleSource {
|
||||
Module(ast::Module),
|
||||
BlockExpr(ast::BlockExpr),
|
||||
}
|
||||
|
||||
/// See `sub_namespace_match()`.
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub enum MacroSubNs {
|
||||
/// Function-like macros, suffixed with `!`.
|
||||
Bang,
|
||||
/// Macros inside attributes, i.e. attribute macros and derive macros.
|
||||
Attr,
|
||||
}
|
||||
|
||||
impl MacroSubNs {
|
||||
fn from_id(db: &dyn DefDatabase, macro_id: MacroId) -> Self {
|
||||
let expander = match macro_id {
|
||||
MacroId::Macro2Id(it) => it.lookup(db).expander,
|
||||
MacroId::MacroRulesId(it) => it.lookup(db).expander,
|
||||
MacroId::ProcMacroId(it) => {
|
||||
return match it.lookup(db).kind {
|
||||
ProcMacroKind::CustomDerive | ProcMacroKind::Attr => Self::Attr,
|
||||
ProcMacroKind::FuncLike => Self::Bang,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// Eager macros aren't *guaranteed* to be bang macros, but they *are* all bang macros currently.
|
||||
match expander {
|
||||
MacroExpander::Declarative
|
||||
| MacroExpander::BuiltIn(_)
|
||||
| MacroExpander::BuiltInEager(_) => Self::Bang,
|
||||
MacroExpander::BuiltInAttr(_) | MacroExpander::BuiltInDerive(_) => Self::Attr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Quoted from [rustc]:
|
||||
/// 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.
|
||||
///
|
||||
/// [rustc]: https://github.com/rust-lang/rust/blob/1.69.0/compiler/rustc_resolve/src/macros.rs#L75
|
||||
fn sub_namespace_match(candidate: Option<MacroSubNs>, expected: Option<MacroSubNs>) -> bool {
|
||||
match (candidate, expected) {
|
||||
(Some(candidate), Some(expected)) => candidate == expected,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ use crate::{
|
||||
AstIdWithPath, LocalModuleId, UnresolvedMacro,
|
||||
};
|
||||
|
||||
use super::DefMap;
|
||||
use super::{DefMap, MacroSubNs};
|
||||
|
||||
pub enum ResolvedAttr {
|
||||
/// Attribute resolved to an attribute macro.
|
||||
@ -43,9 +43,12 @@ impl DefMap {
|
||||
original_module,
|
||||
&ast_id.path,
|
||||
BuiltinShadowMode::Module,
|
||||
Some(MacroSubNs::Attr),
|
||||
);
|
||||
let def = match resolved_res.resolved_def.take_macros() {
|
||||
Some(def) => {
|
||||
// `MacroSubNs` is just a hint, so the path may still resolve to a custom derive
|
||||
// macro, or even function-like macro when the path is qualified.
|
||||
if def.is_attribute(db) {
|
||||
def
|
||||
} else {
|
||||
|
@ -44,7 +44,7 @@ use crate::{
|
||||
mod_resolution::ModDir,
|
||||
path_resolution::ReachedFixedPoint,
|
||||
proc_macro::{parse_macro_name_and_helper_attrs, ProcMacroDef, ProcMacroKind},
|
||||
BuiltinShadowMode, DefMap, ModuleData, ModuleOrigin, ResolveMode,
|
||||
BuiltinShadowMode, DefMap, MacroSubNs, ModuleData, ModuleOrigin, ResolveMode,
|
||||
},
|
||||
path::{ImportAlias, ModPath, PathKind},
|
||||
per_ns::PerNs,
|
||||
@ -289,80 +289,84 @@ impl DefCollector<'_> {
|
||||
let module_id = self.def_map.root;
|
||||
|
||||
let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate);
|
||||
if attrs.cfg().map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false)) {
|
||||
self.inject_prelude(&attrs);
|
||||
|
||||
// Process other crate-level attributes.
|
||||
for attr in &*attrs {
|
||||
let attr_name = match attr.path.as_ident() {
|
||||
Some(name) => name,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
if *attr_name == hir_expand::name![recursion_limit] {
|
||||
if let Some(limit) = attr.string_value() {
|
||||
if let Ok(limit) = limit.parse() {
|
||||
self.def_map.recursion_limit = Some(limit);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if *attr_name == hir_expand::name![crate_type] {
|
||||
if let Some("proc-macro") = attr.string_value().map(SmolStr::as_str) {
|
||||
self.is_proc_macro = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if attr_name.as_text().as_deref() == Some("rustc_coherence_is_core") {
|
||||
self.def_map.rustc_coherence_is_core = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if *attr_name == hir_expand::name![feature] {
|
||||
let hygiene = &Hygiene::new_unhygienic();
|
||||
let features = attr
|
||||
.parse_path_comma_token_tree(self.db.upcast(), hygiene)
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.filter_map(|feat| match feat.segments() {
|
||||
[name] => Some(name.to_smol_str()),
|
||||
_ => None,
|
||||
});
|
||||
self.def_map.unstable_features.extend(features);
|
||||
}
|
||||
|
||||
let attr_is_register_like = *attr_name == hir_expand::name![register_attr]
|
||||
|| *attr_name == hir_expand::name![register_tool];
|
||||
if !attr_is_register_like {
|
||||
continue;
|
||||
}
|
||||
|
||||
let registered_name = match attr.single_ident_value() {
|
||||
Some(ident) => ident.as_name(),
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
if *attr_name == hir_expand::name![register_attr] {
|
||||
self.def_map.registered_attrs.push(registered_name.to_smol_str());
|
||||
cov_mark::hit!(register_attr);
|
||||
} else {
|
||||
self.def_map.registered_tools.push(registered_name.to_smol_str());
|
||||
cov_mark::hit!(register_tool);
|
||||
}
|
||||
if let Some(cfg) = attrs.cfg() {
|
||||
if self.cfg_options.check(&cfg) == Some(false) {
|
||||
return;
|
||||
}
|
||||
|
||||
ModCollector {
|
||||
def_collector: self,
|
||||
macro_depth: 0,
|
||||
module_id,
|
||||
tree_id: TreeId::new(file_id.into(), None),
|
||||
item_tree: &item_tree,
|
||||
mod_dir: ModDir::root(),
|
||||
}
|
||||
.collect_in_top_module(item_tree.top_level_items());
|
||||
}
|
||||
|
||||
self.inject_prelude(&attrs);
|
||||
|
||||
// Process other crate-level attributes.
|
||||
for attr in &*attrs {
|
||||
let attr_name = match attr.path.as_ident() {
|
||||
Some(name) => name,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
if *attr_name == hir_expand::name![recursion_limit] {
|
||||
if let Some(limit) = attr.string_value() {
|
||||
if let Ok(limit) = limit.parse() {
|
||||
self.def_map.recursion_limit = Some(limit);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if *attr_name == hir_expand::name![crate_type] {
|
||||
if let Some("proc-macro") = attr.string_value().map(SmolStr::as_str) {
|
||||
self.is_proc_macro = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if attr_name.as_text().as_deref() == Some("rustc_coherence_is_core") {
|
||||
self.def_map.rustc_coherence_is_core = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if *attr_name == hir_expand::name![feature] {
|
||||
let hygiene = &Hygiene::new_unhygienic();
|
||||
let features = attr
|
||||
.parse_path_comma_token_tree(self.db.upcast(), hygiene)
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.filter_map(|feat| match feat.segments() {
|
||||
[name] => Some(name.to_smol_str()),
|
||||
_ => None,
|
||||
});
|
||||
self.def_map.unstable_features.extend(features);
|
||||
}
|
||||
|
||||
let attr_is_register_like = *attr_name == hir_expand::name![register_attr]
|
||||
|| *attr_name == hir_expand::name![register_tool];
|
||||
if !attr_is_register_like {
|
||||
continue;
|
||||
}
|
||||
|
||||
let registered_name = match attr.single_ident_value() {
|
||||
Some(ident) => ident.as_name(),
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
if *attr_name == hir_expand::name![register_attr] {
|
||||
self.def_map.registered_attrs.push(registered_name.to_smol_str());
|
||||
cov_mark::hit!(register_attr);
|
||||
} else {
|
||||
self.def_map.registered_tools.push(registered_name.to_smol_str());
|
||||
cov_mark::hit!(register_tool);
|
||||
}
|
||||
}
|
||||
|
||||
ModCollector {
|
||||
def_collector: self,
|
||||
macro_depth: 0,
|
||||
module_id,
|
||||
tree_id: TreeId::new(file_id.into(), None),
|
||||
item_tree: &item_tree,
|
||||
mod_dir: ModDir::root(),
|
||||
}
|
||||
.collect_in_top_module(item_tree.top_level_items());
|
||||
}
|
||||
|
||||
fn seed_with_inner(&mut self, tree_id: TreeId) {
|
||||
@ -543,33 +547,26 @@ impl DefCollector<'_> {
|
||||
Edition::Edition2015 => PathKind::Plain,
|
||||
_ => PathKind::Abs,
|
||||
};
|
||||
let path =
|
||||
ModPath::from_segments(path_kind, [krate.clone(), name![prelude], edition].into_iter());
|
||||
// Fall back to the older `std::prelude::v1` for compatibility with Rust <1.52.0
|
||||
// FIXME remove this fallback
|
||||
let fallback_path =
|
||||
ModPath::from_segments(path_kind, [krate, name![prelude], name![v1]].into_iter());
|
||||
let path = ModPath::from_segments(path_kind, [krate, name![prelude], edition]);
|
||||
|
||||
for path in &[path, fallback_path] {
|
||||
let (per_ns, _) = self.def_map.resolve_path(
|
||||
self.db,
|
||||
self.def_map.root,
|
||||
path,
|
||||
BuiltinShadowMode::Other,
|
||||
);
|
||||
let (per_ns, _) = self.def_map.resolve_path(
|
||||
self.db,
|
||||
self.def_map.root,
|
||||
&path,
|
||||
BuiltinShadowMode::Other,
|
||||
None,
|
||||
);
|
||||
|
||||
match per_ns.types {
|
||||
Some((ModuleDefId::ModuleId(m), _)) => {
|
||||
self.def_map.prelude = Some(m);
|
||||
break;
|
||||
}
|
||||
types => {
|
||||
tracing::debug!(
|
||||
"could not resolve prelude path `{}` to module (resolved to {:?})",
|
||||
path,
|
||||
types
|
||||
);
|
||||
}
|
||||
match per_ns.types {
|
||||
Some((ModuleDefId::ModuleId(m), _)) => {
|
||||
self.def_map.prelude = Some(m);
|
||||
}
|
||||
types => {
|
||||
tracing::debug!(
|
||||
"could not resolve prelude path `{}` to module (resolved to {:?})",
|
||||
path,
|
||||
types
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -715,6 +712,7 @@ impl DefCollector<'_> {
|
||||
}
|
||||
|
||||
/// Import macros from `#[macro_use] extern crate`.
|
||||
// FIXME: Support `#[macro_rules(macro_name, ...)]`.
|
||||
fn import_macros_from_extern_crate(
|
||||
&mut self,
|
||||
current_module_id: LocalModuleId,
|
||||
@ -733,7 +731,7 @@ impl DefCollector<'_> {
|
||||
}
|
||||
|
||||
cov_mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use);
|
||||
self.import_all_macros_exported(current_module_id, m.krate);
|
||||
self.import_all_macros_exported(m.krate);
|
||||
}
|
||||
}
|
||||
|
||||
@ -742,11 +740,12 @@ impl DefCollector<'_> {
|
||||
/// Exported macros are just all macros in the root module scope.
|
||||
/// Note that it contains not only all `#[macro_export]` macros, but also all aliases
|
||||
/// created by `use` in the root module, ignoring the visibility of `use`.
|
||||
fn import_all_macros_exported(&mut self, current_module_id: LocalModuleId, krate: CrateId) {
|
||||
fn import_all_macros_exported(&mut self, krate: CrateId) {
|
||||
let def_map = self.db.crate_def_map(krate);
|
||||
for (name, def) in def_map[def_map.root].scope.macros() {
|
||||
// `#[macro_use]` brings macros into legacy scope. Yes, even non-`macro_rules!` macros.
|
||||
self.define_legacy_macro(current_module_id, name.clone(), def);
|
||||
// `#[macro_use]` brings macros into macro_use prelude. Yes, even non-`macro_rules!`
|
||||
// macros.
|
||||
self.def_map.macro_use_prelude.insert(name.clone(), def);
|
||||
}
|
||||
}
|
||||
|
||||
@ -802,6 +801,7 @@ impl DefCollector<'_> {
|
||||
module_id,
|
||||
&import.path,
|
||||
BuiltinShadowMode::Module,
|
||||
None, // An import may resolve to any kind of macro.
|
||||
);
|
||||
|
||||
let def = res.resolved_def;
|
||||
@ -1099,7 +1099,14 @@ impl DefCollector<'_> {
|
||||
resolved.push((directive.module_id, directive.depth, directive.container, call_id));
|
||||
};
|
||||
let mut res = ReachedFixedPoint::Yes;
|
||||
// Retain unresolved macros after this round of resolution.
|
||||
macros.retain(|directive| {
|
||||
let subns = match &directive.kind {
|
||||
MacroDirectiveKind::FnLike { .. } => MacroSubNs::Bang,
|
||||
MacroDirectiveKind::Attr { .. } | MacroDirectiveKind::Derive { .. } => {
|
||||
MacroSubNs::Attr
|
||||
}
|
||||
};
|
||||
let resolver = |path| {
|
||||
let resolved_res = self.def_map.resolve_path_fp_with_macro(
|
||||
self.db,
|
||||
@ -1107,6 +1114,7 @@ impl DefCollector<'_> {
|
||||
directive.module_id,
|
||||
&path,
|
||||
BuiltinShadowMode::Module,
|
||||
Some(subns),
|
||||
);
|
||||
resolved_res
|
||||
.resolved_def
|
||||
@ -1425,6 +1433,7 @@ impl DefCollector<'_> {
|
||||
directive.module_id,
|
||||
&path,
|
||||
BuiltinShadowMode::Module,
|
||||
Some(MacroSubNs::Bang),
|
||||
);
|
||||
resolved_res
|
||||
.resolved_def
|
||||
@ -1517,6 +1526,7 @@ impl ModCollector<'_, '_> {
|
||||
|
||||
fn collect(&mut self, items: &[ModItem], container: ItemContainerId) {
|
||||
let krate = self.def_collector.def_map.krate;
|
||||
let is_crate_root = self.module_id == self.def_collector.def_map.root;
|
||||
|
||||
// Note: don't assert that inserted value is fresh: it's simply not true
|
||||
// for macros.
|
||||
@ -1524,19 +1534,24 @@ impl ModCollector<'_, '_> {
|
||||
|
||||
// Prelude module is always considered to be `#[macro_use]`.
|
||||
if let Some(prelude_module) = self.def_collector.def_map.prelude {
|
||||
if prelude_module.krate != krate {
|
||||
if prelude_module.krate != krate && is_crate_root {
|
||||
cov_mark::hit!(prelude_is_macro_use);
|
||||
self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate);
|
||||
self.def_collector.import_all_macros_exported(prelude_module.krate);
|
||||
}
|
||||
}
|
||||
|
||||
// This should be processed eagerly instead of deferred to resolving.
|
||||
// `#[macro_use] extern crate` is hoisted to imports macros before collecting
|
||||
// any other items.
|
||||
for &item in items {
|
||||
let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into());
|
||||
if attrs.cfg().map_or(true, |cfg| self.is_cfg_enabled(&cfg)) {
|
||||
if let ModItem::ExternCrate(id) = item {
|
||||
//
|
||||
// If we're not at the crate root, `macro_use`d extern crates are an error so let's just
|
||||
// ignore them.
|
||||
// FIXME: Support `#[macro_rules(macro_name, ...)]`.
|
||||
if is_crate_root {
|
||||
for &item in items {
|
||||
let ModItem::ExternCrate(id) = item else { continue; };
|
||||
let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into());
|
||||
if attrs.cfg().map_or(true, |cfg| self.is_cfg_enabled(&cfg)) {
|
||||
let import = &self.item_tree[id];
|
||||
let attrs = self.item_tree.attrs(
|
||||
self.def_collector.db,
|
||||
|
@ -16,7 +16,7 @@ use hir_expand::name::Name;
|
||||
use crate::{
|
||||
db::DefDatabase,
|
||||
item_scope::BUILTIN_SCOPE,
|
||||
nameres::{BuiltinShadowMode, DefMap},
|
||||
nameres::{sub_namespace_match, BuiltinShadowMode, DefMap, MacroSubNs},
|
||||
path::{ModPath, PathKind},
|
||||
per_ns::PerNs,
|
||||
visibility::{RawVisibility, Visibility},
|
||||
@ -58,6 +58,17 @@ impl ResolvePathResult {
|
||||
}
|
||||
}
|
||||
|
||||
impl PerNs {
|
||||
fn filter_macro(mut self, db: &dyn DefDatabase, expected: Option<MacroSubNs>) -> Self {
|
||||
self.macros = self.macros.filter(|&(id, _)| {
|
||||
let this = MacroSubNs::from_id(db, id);
|
||||
sub_namespace_match(Some(this), expected)
|
||||
});
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl DefMap {
|
||||
pub(super) fn resolve_name_in_extern_prelude(
|
||||
&self,
|
||||
@ -83,7 +94,7 @@ impl DefMap {
|
||||
let mut vis = match visibility {
|
||||
RawVisibility::Module(path) => {
|
||||
let (result, remaining) =
|
||||
self.resolve_path(db, original_module, path, BuiltinShadowMode::Module);
|
||||
self.resolve_path(db, original_module, path, BuiltinShadowMode::Module, None);
|
||||
if remaining.is_some() {
|
||||
return None;
|
||||
}
|
||||
@ -124,6 +135,9 @@ impl DefMap {
|
||||
mut original_module: LocalModuleId,
|
||||
path: &ModPath,
|
||||
shadow: BuiltinShadowMode,
|
||||
// Pass `MacroSubNs` if we know we're resolving macro names and which kind of macro we're
|
||||
// resolving them to. Pass `None` otherwise, e.g. when we're resolving import paths.
|
||||
expected_macro_subns: Option<MacroSubNs>,
|
||||
) -> ResolvePathResult {
|
||||
let mut result = ResolvePathResult::empty(ReachedFixedPoint::No);
|
||||
|
||||
@ -136,6 +150,7 @@ impl DefMap {
|
||||
original_module,
|
||||
path,
|
||||
shadow,
|
||||
expected_macro_subns,
|
||||
);
|
||||
|
||||
// Merge `new` into `result`.
|
||||
@ -169,6 +184,7 @@ impl DefMap {
|
||||
original_module: LocalModuleId,
|
||||
path: &ModPath,
|
||||
shadow: BuiltinShadowMode,
|
||||
expected_macro_subns: Option<MacroSubNs>,
|
||||
) -> ResolvePathResult {
|
||||
let graph = db.crate_graph();
|
||||
let _cx = stdx::panic_context::enter(format!(
|
||||
@ -220,7 +236,13 @@ impl DefMap {
|
||||
if path.segments().len() == 1 { shadow } else { BuiltinShadowMode::Module };
|
||||
|
||||
tracing::debug!("resolving {:?} in module", segment);
|
||||
self.resolve_name_in_module(db, original_module, segment, prefer_module)
|
||||
self.resolve_name_in_module(
|
||||
db,
|
||||
original_module,
|
||||
segment,
|
||||
prefer_module,
|
||||
expected_macro_subns,
|
||||
)
|
||||
}
|
||||
PathKind::Super(lvl) => {
|
||||
let mut module = original_module;
|
||||
@ -245,6 +267,7 @@ impl DefMap {
|
||||
block.parent.local_id,
|
||||
&new_path,
|
||||
shadow,
|
||||
expected_macro_subns,
|
||||
);
|
||||
}
|
||||
None => {
|
||||
@ -303,7 +326,12 @@ impl DefMap {
|
||||
);
|
||||
tracing::debug!("resolving {:?} in other crate", path);
|
||||
let defp_map = module.def_map(db);
|
||||
let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow);
|
||||
// Macro sub-namespaces only matter when resolving single-segment paths
|
||||
// because `macro_use` and other preludes should be taken into account. At
|
||||
// this point, we know we're resolving a multi-segment path so macro kind
|
||||
// expectation is discarded.
|
||||
let (def, s) =
|
||||
defp_map.resolve_path(db, module.local_id, &path, shadow, None);
|
||||
return ResolvePathResult::with(
|
||||
def,
|
||||
ReachedFixedPoint::Yes,
|
||||
@ -381,19 +409,24 @@ impl DefMap {
|
||||
module: LocalModuleId,
|
||||
name: &Name,
|
||||
shadow: BuiltinShadowMode,
|
||||
expected_macro_subns: Option<MacroSubNs>,
|
||||
) -> PerNs {
|
||||
// Resolve in:
|
||||
// - legacy scope of macro
|
||||
// - current module / scope
|
||||
// - extern prelude
|
||||
// - extern prelude / macro_use prelude
|
||||
// - std prelude
|
||||
let from_legacy_macro = self[module]
|
||||
.scope
|
||||
.get_legacy_macro(name)
|
||||
// FIXME: shadowing
|
||||
.and_then(|it| it.last())
|
||||
.map_or_else(PerNs::none, |&m| PerNs::macros(m, Visibility::Public));
|
||||
let from_scope = self[module].scope.get(name);
|
||||
.copied()
|
||||
.filter(|&id| {
|
||||
sub_namespace_match(Some(MacroSubNs::from_id(db, id)), expected_macro_subns)
|
||||
})
|
||||
.map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public));
|
||||
let from_scope = self[module].scope.get(name).filter_macro(db, expected_macro_subns);
|
||||
let from_builtin = match self.block {
|
||||
Some(_) => {
|
||||
// Only resolve to builtins in the root `DefMap`.
|
||||
@ -414,9 +447,18 @@ impl DefMap {
|
||||
.get(name)
|
||||
.map_or(PerNs::none(), |&it| PerNs::types(it.into(), Visibility::Public))
|
||||
};
|
||||
let macro_use_prelude = || {
|
||||
self.macro_use_prelude
|
||||
.get(name)
|
||||
.map_or(PerNs::none(), |&it| PerNs::macros(it.into(), Visibility::Public))
|
||||
};
|
||||
let prelude = || self.resolve_in_prelude(db, name);
|
||||
|
||||
from_legacy_macro.or(from_scope_or_builtin).or_else(extern_prelude).or_else(prelude)
|
||||
from_legacy_macro
|
||||
.or(from_scope_or_builtin)
|
||||
.or_else(extern_prelude)
|
||||
.or_else(macro_use_prelude)
|
||||
.or_else(prelude)
|
||||
}
|
||||
|
||||
fn resolve_name_in_crate_root_or_extern_prelude(
|
||||
|
@ -1216,17 +1216,112 @@ fn proc_attr(a: TokenStream, b: TokenStream) -> TokenStream { a }
|
||||
"#,
|
||||
);
|
||||
|
||||
let root = &def_map[def_map.root()].scope;
|
||||
let actual = root
|
||||
.legacy_macros()
|
||||
.sorted_by(|a, b| std::cmp::Ord::cmp(&a.0, &b.0))
|
||||
.map(|(name, _)| format!("{name}\n"))
|
||||
.collect::<String>();
|
||||
let root_module = &def_map[def_map.root()].scope;
|
||||
assert!(
|
||||
root_module.legacy_macros().count() == 0,
|
||||
"`#[macro_use]` shouldn't bring macros into textual macro scope",
|
||||
);
|
||||
|
||||
let actual = def_map.macro_use_prelude.iter().map(|(name, _)| name).sorted().join("\n");
|
||||
|
||||
expect![[r#"
|
||||
legacy
|
||||
macro20
|
||||
proc_attr
|
||||
"#]]
|
||||
proc_attr"#]]
|
||||
.assert_eq(&actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn non_prelude_macros_take_precedence_over_macro_use_prelude() {
|
||||
check(
|
||||
r#"
|
||||
//- /lib.rs edition:2021 crate:lib deps:dep,core
|
||||
#[macro_use]
|
||||
extern crate dep;
|
||||
|
||||
macro foo() { struct Ok; }
|
||||
macro bar() { fn ok() {} }
|
||||
|
||||
foo!();
|
||||
bar!();
|
||||
|
||||
//- /dep.rs crate:dep
|
||||
#[macro_export]
|
||||
macro_rules! foo {
|
||||
() => { struct NotOk; }
|
||||
}
|
||||
|
||||
//- /core.rs crate:core
|
||||
pub mod prelude {
|
||||
pub mod rust_2021 {
|
||||
#[macro_export]
|
||||
macro_rules! bar {
|
||||
() => { fn not_ok() {} }
|
||||
}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
crate
|
||||
Ok: t v
|
||||
bar: m
|
||||
dep: t
|
||||
foo: m
|
||||
ok: v
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn macro_sub_namespace() {
|
||||
let map = compute_crate_def_map(
|
||||
r#"
|
||||
//- minicore: derive, clone
|
||||
macro_rules! Clone { () => {} }
|
||||
macro_rules! derive { () => {} }
|
||||
|
||||
#[derive(Clone)]
|
||||
struct S;
|
||||
"#,
|
||||
);
|
||||
assert_eq!(map.modules[map.root].scope.impls().len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn macro_sub_namespace2() {
|
||||
check(
|
||||
r#"
|
||||
//- /main.rs edition:2021 crate:main deps:proc,core
|
||||
use proc::{foo, bar};
|
||||
|
||||
foo!();
|
||||
bar!();
|
||||
|
||||
//- /proc.rs crate:proc
|
||||
#![crate_type="proc-macro"]
|
||||
#[proc_macro_derive(foo)]
|
||||
pub fn foo() {}
|
||||
#[proc_macro_attribute]
|
||||
pub fn bar() {}
|
||||
|
||||
//- /core.rs crate:core
|
||||
pub mod prelude {
|
||||
pub mod rust_2021 {
|
||||
pub macro foo() {
|
||||
struct Ok;
|
||||
}
|
||||
pub macro bar() {
|
||||
fn ok() {}
|
||||
}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
crate
|
||||
Ok: t v
|
||||
bar: m
|
||||
foo: m
|
||||
ok: v
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ use crate::{
|
||||
hir::{BindingId, ExprId, LabelId},
|
||||
item_scope::{BuiltinShadowMode, BUILTIN_SCOPE},
|
||||
lang_item::LangItemTarget,
|
||||
nameres::DefMap,
|
||||
nameres::{DefMap, MacroSubNs},
|
||||
path::{ModPath, Path, PathKind},
|
||||
per_ns::PerNs,
|
||||
visibility::{RawVisibility, Visibility},
|
||||
@ -155,7 +155,8 @@ impl Resolver {
|
||||
path: &ModPath,
|
||||
) -> Option<PerNs> {
|
||||
let (item_map, module) = self.item_scope();
|
||||
let (module_res, idx) = item_map.resolve_path(db, module, path, BuiltinShadowMode::Module);
|
||||
let (module_res, idx) =
|
||||
item_map.resolve_path(db, module, path, BuiltinShadowMode::Module, None);
|
||||
match module_res.take_types()? {
|
||||
ModuleDefId::TraitId(it) => {
|
||||
let idx = idx?;
|
||||
@ -385,9 +386,17 @@ impl Resolver {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroId> {
|
||||
pub fn resolve_path_as_macro(
|
||||
&self,
|
||||
db: &dyn DefDatabase,
|
||||
path: &ModPath,
|
||||
expected_macro_kind: Option<MacroSubNs>,
|
||||
) -> Option<MacroId> {
|
||||
let (item_map, module) = self.item_scope();
|
||||
item_map.resolve_path(db, module, path, BuiltinShadowMode::Other).0.take_macros()
|
||||
item_map
|
||||
.resolve_path(db, module, path, BuiltinShadowMode::Other, expected_macro_kind)
|
||||
.0
|
||||
.take_macros()
|
||||
}
|
||||
|
||||
/// Returns a set of names available in the current scope.
|
||||
@ -626,7 +635,8 @@ impl Resolver {
|
||||
shadow: BuiltinShadowMode,
|
||||
) -> PerNs {
|
||||
let (item_map, module) = self.item_scope();
|
||||
let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow);
|
||||
// This method resolves `path` just like import paths, so no expected macro subns is given.
|
||||
let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow, None);
|
||||
if segment_index.is_some() {
|
||||
return PerNs::none();
|
||||
}
|
||||
|
@ -135,9 +135,8 @@ fn line_expand(
|
||||
_tt: &tt::Subtree,
|
||||
) -> ExpandResult<tt::Subtree> {
|
||||
// dummy implementation for type-checking purposes
|
||||
let line_num = 0;
|
||||
let expanded = quote! {
|
||||
#line_num
|
||||
0 as u32
|
||||
};
|
||||
|
||||
ExpandResult::ok(expanded)
|
||||
@ -179,9 +178,8 @@ fn column_expand(
|
||||
_tt: &tt::Subtree,
|
||||
) -> ExpandResult<tt::Subtree> {
|
||||
// dummy implementation for type-checking purposes
|
||||
let col_num = 0;
|
||||
let expanded = quote! {
|
||||
#col_num
|
||||
0 as u32
|
||||
};
|
||||
|
||||
ExpandResult::ok(expanded)
|
||||
|
@ -24,6 +24,7 @@ use hir_def::{
|
||||
TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
|
||||
},
|
||||
lang_item::{lang_attr, LangItem},
|
||||
nameres::MacroSubNs,
|
||||
path::{GenericArg, GenericArgs, ModPath, Path, PathKind, PathSegment, PathSegments},
|
||||
resolver::{HasResolver, Resolver, TypeNs},
|
||||
type_ref::{ConstRefOrPath, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef},
|
||||
@ -378,9 +379,15 @@ impl<'a> TyLoweringContext<'a> {
|
||||
};
|
||||
let ty = {
|
||||
let macro_call = macro_call.to_node(self.db.upcast());
|
||||
match expander.enter_expand::<ast::Type>(self.db.upcast(), macro_call, |path| {
|
||||
self.resolver.resolve_path_as_macro(self.db.upcast(), &path)
|
||||
}) {
|
||||
let resolver = |path| {
|
||||
self.resolver.resolve_path_as_macro(
|
||||
self.db.upcast(),
|
||||
&path,
|
||||
Some(MacroSubNs::Bang),
|
||||
)
|
||||
};
|
||||
match expander.enter_expand::<ast::Type>(self.db.upcast(), macro_call, resolver)
|
||||
{
|
||||
Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
|
||||
let ctx = expander.ctx(self.db.upcast());
|
||||
// FIXME: Report syntax errors in expansion here
|
||||
|
@ -661,8 +661,9 @@ fn infer_builtin_macros_line() {
|
||||
"#,
|
||||
expect![[r#"
|
||||
!0..1 '0': i32
|
||||
!0..6 '0asu32': u32
|
||||
63..87 '{ ...!(); }': ()
|
||||
73..74 'x': i32
|
||||
73..74 'x': u32
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -699,8 +700,9 @@ fn infer_builtin_macros_column() {
|
||||
"#,
|
||||
expect![[r#"
|
||||
!0..1 '0': i32
|
||||
!0..6 '0asu32': u32
|
||||
65..91 '{ ...!(); }': ()
|
||||
75..76 'x': i32
|
||||
75..76 'x': u32
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ use hir_def::{
|
||||
attr::{AttrsWithOwner, Documentation},
|
||||
item_scope::ItemInNs,
|
||||
path::ModPath,
|
||||
per_ns::PerNs,
|
||||
resolver::HasResolver,
|
||||
AttrDefId, GenericParamId, ModuleDefId,
|
||||
};
|
||||
@ -121,6 +120,7 @@ impl HasAttrs for AssocItem {
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolves the item `link` points to in the scope of `def`.
|
||||
fn resolve_doc_path(
|
||||
db: &dyn HirDatabase,
|
||||
def: AttrDefId,
|
||||
@ -155,14 +155,14 @@ fn resolve_doc_path(
|
||||
.syntax_node()
|
||||
.descendants()
|
||||
.find_map(ast::Path::cast)?;
|
||||
if ast_path.to_string() != link {
|
||||
if ast_path.syntax().text() != link {
|
||||
return None;
|
||||
}
|
||||
ModPath::from_src(db.upcast(), ast_path, &Hygiene::new_unhygienic())?
|
||||
};
|
||||
|
||||
let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath);
|
||||
let resolved = if resolved == PerNs::none() {
|
||||
let resolved = if resolved.is_none() {
|
||||
resolver.resolve_module_path_in_trait_assoc_items(db.upcast(), &modpath)?
|
||||
} else {
|
||||
resolved
|
||||
|
@ -10,6 +10,7 @@ use hir_def::{
|
||||
hir::Expr,
|
||||
lower::LowerCtx,
|
||||
macro_id_to_def_id,
|
||||
nameres::MacroSubNs,
|
||||
resolver::{self, HasResolver, Resolver, TypeNs},
|
||||
type_ref::Mutability,
|
||||
AsMacroCall, DefWithBodyId, FieldId, FunctionId, MacroId, TraitId, VariantId,
|
||||
@ -616,7 +617,7 @@ impl<'db> SemanticsImpl<'db> {
|
||||
let krate = resolver.krate();
|
||||
let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| {
|
||||
resolver
|
||||
.resolve_path_as_macro(self.db.upcast(), &path)
|
||||
.resolve_path_as_macro(self.db.upcast(), &path, Some(MacroSubNs::Bang))
|
||||
.map(|it| macro_id_to_def_id(self.db.upcast(), it))
|
||||
})?;
|
||||
hir_expand::db::expand_speculative(
|
||||
|
@ -17,6 +17,7 @@ use hir_def::{
|
||||
lang_item::LangItem,
|
||||
lower::LowerCtx,
|
||||
macro_id_to_def_id,
|
||||
nameres::MacroSubNs,
|
||||
path::{ModPath, Path, PathKind},
|
||||
resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
|
||||
type_ref::Mutability,
|
||||
@ -484,7 +485,9 @@ impl SourceAnalyzer {
|
||||
) -> Option<Macro> {
|
||||
let ctx = LowerCtx::with_file_id(db.upcast(), macro_call.file_id);
|
||||
let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &ctx))?;
|
||||
self.resolver.resolve_path_as_macro(db.upcast(), path.mod_path()?).map(|it| it.into())
|
||||
self.resolver
|
||||
.resolve_path_as_macro(db.upcast(), path.mod_path()?, Some(MacroSubNs::Bang))
|
||||
.map(|it| it.into())
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_bind_pat_to_const(
|
||||
@ -678,7 +681,7 @@ impl SourceAnalyzer {
|
||||
}
|
||||
}
|
||||
}
|
||||
return match resolve_hir_path_as_macro(db, &self.resolver, &hir_path) {
|
||||
return match resolve_hir_path_as_attr_macro(db, &self.resolver, &hir_path) {
|
||||
Some(m) => Some(PathResolution::Def(ModuleDef::Macro(m))),
|
||||
// this labels any path that starts with a tool module as the tool itself, this is technically wrong
|
||||
// but there is no benefit in differentiating these two cases for the time being
|
||||
@ -756,7 +759,7 @@ impl SourceAnalyzer {
|
||||
let krate = self.resolver.krate();
|
||||
let macro_call_id = macro_call.as_call_id(db.upcast(), krate, |path| {
|
||||
self.resolver
|
||||
.resolve_path_as_macro(db.upcast(), &path)
|
||||
.resolve_path_as_macro(db.upcast(), &path, Some(MacroSubNs::Bang))
|
||||
.map(|it| macro_id_to_def_id(db.upcast(), it))
|
||||
})?;
|
||||
Some(macro_call_id.as_file()).filter(|it| it.expansion_level(db.upcast()) < 64)
|
||||
@ -956,12 +959,14 @@ pub(crate) fn resolve_hir_path(
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn resolve_hir_path_as_macro(
|
||||
pub(crate) fn resolve_hir_path_as_attr_macro(
|
||||
db: &dyn HirDatabase,
|
||||
resolver: &Resolver,
|
||||
path: &Path,
|
||||
) -> Option<Macro> {
|
||||
resolver.resolve_path_as_macro(db.upcast(), path.mod_path()?).map(Into::into)
|
||||
resolver
|
||||
.resolve_path_as_macro(db.upcast(), path.mod_path()?, Some(MacroSubNs::Attr))
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
fn resolve_hir_path_(
|
||||
@ -1060,7 +1065,7 @@ fn resolve_hir_path_(
|
||||
|
||||
let macros = || {
|
||||
resolver
|
||||
.resolve_path_as_macro(db.upcast(), path.mod_path()?)
|
||||
.resolve_path_as_macro(db.upcast(), path.mod_path()?, None)
|
||||
.map(|def| PathResolution::Def(ModuleDef::Macro(def.into())))
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user