summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/hir-def
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rust-analyzer/crates/hir-def')
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/adt.rs113
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/attr.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data.rs49
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/find_path.rs93
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/generics.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/import_map.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/layout.rs96
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lib.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs45
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs49
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs40
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs78
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs22
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs37
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/pretty.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs7
32 files changed, 590 insertions, 166 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
index 22f98ea7c..698be7665 100644
--- a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
@@ -33,6 +33,8 @@ base-db = { path = "../base-db", version = "0.0.0" }
syntax = { path = "../syntax", version = "0.0.0" }
profile = { path = "../profile", version = "0.0.0" }
hir-expand = { path = "../hir-expand", version = "0.0.0" }
+rustc_abi = { version = "0.0.20221221", package = "hkalbasi-rustc-ap-rustc_abi", default-features = false }
+rustc_index = { version = "0.0.20221221", package = "hkalbasi-rustc-ap-rustc_index", default-features = false }
mbe = { path = "../mbe", version = "0.0.0" }
cfg = { path = "../cfg", version = "0.0.0" }
tt = { path = "../tt", version = "0.0.0" }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/adt.rs
index 938db032f..db3b41948 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/adt.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/adt.rs
@@ -1,6 +1,6 @@
//! Defines hir-level representation of structs, enums and unions
-use std::{num::NonZeroU32, sync::Arc};
+use std::sync::Arc;
use base_db::CrateId;
use either::Either;
@@ -9,6 +9,7 @@ use hir_expand::{
HirFileId, InFile,
};
use la_arena::{Arena, ArenaMap};
+use rustc_abi::{Integer, IntegerType};
use syntax::ast::{self, HasName, HasVisibility};
use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree};
@@ -18,6 +19,7 @@ use crate::{
db::DefDatabase,
intern::Interned,
item_tree::{AttrOwner, Field, FieldAstId, Fields, ItemTree, ModItem, RawVisibilityId},
+ layout::{Align, ReprFlags, ReprOptions},
nameres::diagnostics::DefDiagnostic,
src::HasChildSource,
src::HasSource,
@@ -34,16 +36,18 @@ use cfg::CfgOptions;
pub struct StructData {
pub name: Name,
pub variant_data: Arc<VariantData>,
- pub repr: Option<ReprData>,
+ pub repr: Option<ReprOptions>,
pub visibility: RawVisibility,
+ pub rustc_has_incoherent_inherent_impls: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EnumData {
pub name: Name,
pub variants: Arena<EnumVariantData>,
- pub repr: Option<ReprData>,
+ pub repr: Option<ReprOptions>,
pub visibility: RawVisibility,
+ pub rustc_has_incoherent_inherent_impls: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -67,80 +71,91 @@ pub struct FieldData {
pub visibility: RawVisibility,
}
-#[derive(Copy, Debug, Clone, PartialEq, Eq)]
-pub enum ReprKind {
- C,
- BuiltinInt { builtin: Either<BuiltinInt, BuiltinUint>, is_c: bool },
- Transparent,
- Default,
-}
-
-#[derive(Copy, Debug, Clone, PartialEq, Eq)]
-pub struct ReprData {
- pub kind: ReprKind,
- pub packed: bool,
- pub align: Option<NonZeroU32>,
-}
-
fn repr_from_value(
db: &dyn DefDatabase,
krate: CrateId,
item_tree: &ItemTree,
of: AttrOwner,
-) -> Option<ReprData> {
+) -> Option<ReprOptions> {
item_tree.attrs(db, krate, of).by_key("repr").tt_values().find_map(parse_repr_tt)
}
-fn parse_repr_tt(tt: &Subtree) -> Option<ReprData> {
+fn parse_repr_tt(tt: &Subtree) -> Option<ReprOptions> {
match tt.delimiter {
Some(Delimiter { kind: DelimiterKind::Parenthesis, .. }) => {}
_ => return None,
}
- let mut data = ReprData { kind: ReprKind::Default, packed: false, align: None };
+ let mut flags = ReprFlags::empty();
+ let mut int = None;
+ let mut max_align: Option<Align> = None;
+ let mut min_pack: Option<Align> = None;
let mut tts = tt.token_trees.iter().peekable();
while let Some(tt) = tts.next() {
if let TokenTree::Leaf(Leaf::Ident(ident)) = tt {
- match &*ident.text {
+ flags.insert(match &*ident.text {
"packed" => {
- data.packed = true;
- if let Some(TokenTree::Subtree(_)) = tts.peek() {
+ let pack = if let Some(TokenTree::Subtree(tt)) = tts.peek() {
tts.next();
- }
+ if let Some(TokenTree::Leaf(Leaf::Literal(lit))) = tt.token_trees.first() {
+ lit.text.parse().unwrap_or_default()
+ } else {
+ 0
+ }
+ } else {
+ 0
+ };
+ let pack = Align::from_bytes(pack).unwrap();
+ min_pack =
+ Some(if let Some(min_pack) = min_pack { min_pack.min(pack) } else { pack });
+ ReprFlags::empty()
}
"align" => {
if let Some(TokenTree::Subtree(tt)) = tts.peek() {
tts.next();
if let Some(TokenTree::Leaf(Leaf::Literal(lit))) = tt.token_trees.first() {
if let Ok(align) = lit.text.parse() {
- data.align = Some(align);
+ let align = Align::from_bytes(align).ok();
+ max_align = max_align.max(align);
}
}
}
+ ReprFlags::empty()
}
- "C" => {
- if let ReprKind::BuiltinInt { is_c, .. } = &mut data.kind {
- *is_c = true;
- } else {
- data.kind = ReprKind::C;
- }
- }
- "transparent" => data.kind = ReprKind::Transparent,
+ "C" => ReprFlags::IS_C,
+ "transparent" => ReprFlags::IS_TRANSPARENT,
repr => {
- let is_c = matches!(data.kind, ReprKind::C);
if let Some(builtin) = BuiltinInt::from_suffix(repr)
.map(Either::Left)
.or_else(|| BuiltinUint::from_suffix(repr).map(Either::Right))
{
- data.kind = ReprKind::BuiltinInt { builtin, is_c };
+ int = Some(match builtin {
+ Either::Left(bi) => match bi {
+ BuiltinInt::Isize => IntegerType::Pointer(true),
+ BuiltinInt::I8 => IntegerType::Fixed(Integer::I8, true),
+ BuiltinInt::I16 => IntegerType::Fixed(Integer::I16, true),
+ BuiltinInt::I32 => IntegerType::Fixed(Integer::I32, true),
+ BuiltinInt::I64 => IntegerType::Fixed(Integer::I64, true),
+ BuiltinInt::I128 => IntegerType::Fixed(Integer::I128, true),
+ },
+ Either::Right(bu) => match bu {
+ BuiltinUint::Usize => IntegerType::Pointer(false),
+ BuiltinUint::U8 => IntegerType::Fixed(Integer::I8, false),
+ BuiltinUint::U16 => IntegerType::Fixed(Integer::I16, false),
+ BuiltinUint::U32 => IntegerType::Fixed(Integer::I32, false),
+ BuiltinUint::U64 => IntegerType::Fixed(Integer::I64, false),
+ BuiltinUint::U128 => IntegerType::Fixed(Integer::I128, false),
+ },
+ });
}
+ ReprFlags::empty()
}
- }
+ })
}
}
- Some(data)
+ Some(ReprOptions { int, align: max_align, pack: min_pack, flags, field_shuffle_seed: 0 })
}
impl StructData {
@@ -157,6 +172,10 @@ impl StructData {
let item_tree = loc.id.item_tree(db);
let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone();
+ let rustc_has_incoherent_inherent_impls = item_tree
+ .attrs(db, loc.container.krate, ModItem::from(loc.id.value).into())
+ .by_key("rustc_has_incoherent_inherent_impls")
+ .exists();
let strukt = &item_tree[loc.id.value];
let (variant_data, diagnostics) = lower_fields(
@@ -175,6 +194,7 @@ impl StructData {
variant_data: Arc::new(variant_data),
repr,
visibility: item_tree[strukt.visibility].clone(),
+ rustc_has_incoherent_inherent_impls,
}),
diagnostics.into(),
)
@@ -194,6 +214,11 @@ impl StructData {
let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone();
+ let rustc_has_incoherent_inherent_impls = item_tree
+ .attrs(db, loc.container.krate, ModItem::from(loc.id.value).into())
+ .by_key("rustc_has_incoherent_inherent_impls")
+ .exists();
+
let union = &item_tree[loc.id.value];
let (variant_data, diagnostics) = lower_fields(
db,
@@ -211,6 +236,7 @@ impl StructData {
variant_data: Arc::new(variant_data),
repr,
visibility: item_tree[union.visibility].clone(),
+ rustc_has_incoherent_inherent_impls,
}),
diagnostics.into(),
)
@@ -231,6 +257,10 @@ impl EnumData {
let item_tree = loc.id.item_tree(db);
let cfg_options = db.crate_graph()[krate].cfg_options.clone();
let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
+ let rustc_has_incoherent_inherent_impls = item_tree
+ .attrs(db, loc.container.krate, ModItem::from(loc.id.value).into())
+ .by_key("rustc_has_incoherent_inherent_impls")
+ .exists();
let enum_ = &item_tree[loc.id.value];
let mut variants = Arena::new();
@@ -271,6 +301,7 @@ impl EnumData {
variants,
repr,
visibility: item_tree[enum_.visibility].clone(),
+ rustc_has_incoherent_inherent_impls,
}),
diagnostics.into(),
)
@@ -281,10 +312,10 @@ impl EnumData {
Some(id)
}
- pub fn variant_body_type(&self) -> Either<BuiltinInt, BuiltinUint> {
+ pub fn variant_body_type(&self) -> IntegerType {
match self.repr {
- Some(ReprData { kind: ReprKind::BuiltinInt { builtin, .. }, .. }) => builtin,
- _ => Either::Left(BuiltinInt::Isize),
+ Some(ReprOptions { int: Some(builtin), .. }) => builtin,
+ _ => IntegerType::Pointer(true),
}
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
index 2b39c6f8d..ab5d180e1 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
@@ -712,7 +712,7 @@ impl AttrSourceMap {
self.source
.get(ast_idx)
.map(|it| InFile::new(file_id, it))
- .unwrap_or_else(|| panic!("cannot find attr at index {:?}", id))
+ .unwrap_or_else(|| panic!("cannot find attr at index {id:?}"))
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
index 759f3b8c0..78fbaa9d7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
@@ -372,7 +372,7 @@ impl Body {
/// Retrieves all ident patterns this pattern shares the ident with.
pub fn ident_patterns_for<'slf>(&'slf self, pat: &'slf PatId) -> &'slf [PatId] {
match self.or_pats.get(pat) {
- Some(pats) => &**pats,
+ Some(pats) => pats,
None => std::slice::from_ref(pat),
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
index ccc01c3ef..e8da24e3a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
@@ -371,6 +371,10 @@ impl ExprCollector<'_> {
let expr = e.expr().map(|e| self.collect_expr(e));
self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
}
+ ast::Expr::YeetExpr(e) => {
+ let expr = e.expr().map(|e| self.collect_expr(e));
+ self.alloc_expr(Expr::Yeet { expr }, syntax_ptr)
+ }
ast::Expr::RecordExpr(e) => {
let path =
e.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
index 162d173d5..10b9b26bb 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
@@ -32,7 +32,7 @@ pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBo
Some(name) => name.to_string(),
None => "_".to_string(),
};
- format!("const {} = ", name)
+ format!("const {name} = ")
}
DefWithBodyId::VariantId(it) => {
needs_semi = false;
@@ -42,7 +42,7 @@ pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBo
Some(name) => name.to_string(),
None => "_".to_string(),
};
- format!("{}", name)
+ format!("{name}")
}
};
@@ -247,6 +247,15 @@ impl<'a> Printer<'a> {
self.print_expr(*expr);
}
}
+ Expr::Yeet { expr } => {
+ w!(self, "do");
+ self.whitespace();
+ w!(self, "yeet");
+ if let Some(expr) = expr {
+ self.whitespace();
+ self.print_expr(*expr);
+ }
+ }
Expr::RecordLit { path, fields, spread, ellipsis, is_assignee_expr: _ } => {
match path {
Some(path) => self.print_path(path),
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
index 45f64ebb0..2617d4288 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
@@ -47,7 +47,7 @@ pub struct ScopeData {
impl ExprScopes {
pub(crate) fn expr_scopes_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<ExprScopes> {
let body = db.body(def);
- let mut scopes = ExprScopes::new(&*body);
+ let mut scopes = ExprScopes::new(&body);
scopes.shrink_to_fit();
Arc::new(scopes)
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs
index 39581b33a..f7c1e683d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs
@@ -350,6 +350,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
),
ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
+ ungated!(rustc_safe_intrinsic, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
gated!(
allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), DuplicatesOk,
"allow_internal_unstable side-steps feature gating and stability checks",
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
index 9c7696908..e6b05f27a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
@@ -13,7 +13,9 @@ use crate::{
intern::Interned,
item_tree::{self, AssocItem, FnFlags, ItemTree, ItemTreeId, ModItem, Param, TreeId},
nameres::{
- attr_resolution::ResolvedAttr, diagnostics::DefDiagnostic, proc_macro::ProcMacroKind,
+ attr_resolution::ResolvedAttr,
+ diagnostics::DefDiagnostic,
+ proc_macro::{parse_macro_name_and_helper_attrs, ProcMacroKind},
DefMap,
},
type_ref::{TraitRef, TypeBound, TypeRef},
@@ -168,6 +170,7 @@ pub struct TypeAliasData {
pub type_ref: Option<Interned<TypeRef>>,
pub visibility: RawVisibility,
pub is_extern: bool,
+ pub rustc_has_incoherent_inherent_impls: bool,
/// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl).
pub bounds: Vec<Interned<TypeBound>>,
}
@@ -186,11 +189,17 @@ impl TypeAliasData {
item_tree[typ.visibility].clone()
};
+ let rustc_has_incoherent_inherent_impls = item_tree
+ .attrs(db, loc.container.module(db).krate(), ModItem::from(loc.id.value).into())
+ .by_key("rustc_has_incoherent_inherent_impls")
+ .exists();
+
Arc::new(TypeAliasData {
name: typ.name.clone(),
type_ref: typ.type_ref.clone(),
visibility,
is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
+ rustc_has_incoherent_inherent_impls,
bounds: typ.bounds.to_vec(),
})
}
@@ -202,6 +211,7 @@ pub struct TraitData {
pub items: Vec<(Name, AssocItemId)>,
pub is_auto: bool,
pub is_unsafe: bool,
+ pub rustc_has_incoherent_inherent_impls: bool,
pub visibility: RawVisibility,
/// Whether the trait has `#[rust_skip_array_during_method_dispatch]`. `hir_ty` will ignore
/// method calls to this trait's methods when the receiver is an array and the crate edition is
@@ -224,18 +234,17 @@ impl TraitData {
let item_tree = tree_id.item_tree(db);
let tr_def = &item_tree[tree_id.value];
let _cx = stdx::panic_context::enter(format!(
- "trait_data_query({:?} -> {:?} -> {:?})",
- tr, tr_loc, tr_def
+ "trait_data_query({tr:?} -> {tr_loc:?} -> {tr_def:?})"
));
let name = tr_def.name.clone();
let is_auto = tr_def.is_auto;
let is_unsafe = tr_def.is_unsafe;
let visibility = item_tree[tr_def.visibility].clone();
- let skip_array_during_method_dispatch = item_tree
- .attrs(db, module_id.krate(), ModItem::from(tree_id.value).into())
- .by_key("rustc_skip_array_during_method_dispatch")
- .exists();
-
+ let attrs = item_tree.attrs(db, module_id.krate(), ModItem::from(tree_id.value).into());
+ let skip_array_during_method_dispatch =
+ attrs.by_key("rustc_skip_array_during_method_dispatch").exists();
+ let rustc_has_incoherent_inherent_impls =
+ attrs.by_key("rustc_has_incoherent_inherent_impls").exists();
let (items, attribute_calls, diagnostics) = match &tr_def.items {
Some(items) => {
let mut collector = AssocItemCollector::new(
@@ -258,6 +267,7 @@ impl TraitData {
is_unsafe,
visibility,
skip_array_during_method_dispatch,
+ rustc_has_incoherent_inherent_impls,
}),
diagnostics.into(),
)
@@ -339,6 +349,10 @@ impl ImplData {
pub struct Macro2Data {
pub name: Name,
pub visibility: RawVisibility,
+ // It's a bit wasteful as currently this is only for builtin `Default` derive macro, but macro2
+ // are rarely used in practice so I think it's okay for now.
+ /// Derive helpers, if this is a derive rustc_builtin_macro
+ pub helpers: Option<Box<[Name]>>,
}
impl Macro2Data {
@@ -347,9 +361,18 @@ impl Macro2Data {
let item_tree = loc.id.item_tree(db);
let makro = &item_tree[loc.id.value];
+ let helpers = item_tree
+ .attrs(db, loc.container.krate(), ModItem::from(loc.id.value).into())
+ .by_key("rustc_builtin_macro")
+ .tt_values()
+ .next()
+ .and_then(|attr| parse_macro_name_and_helper_attrs(&attr.token_trees))
+ .map(|(_, helpers)| helpers);
+
Arc::new(Macro2Data {
name: makro.name.clone(),
visibility: item_tree[makro.visibility].clone(),
+ helpers,
})
}
}
@@ -519,7 +542,7 @@ impl<'a> AssocItemCollector<'a> {
if !attrs.is_cfg_enabled(self.expander.cfg_options()) {
self.inactive_diagnostics.push(DefDiagnostic::unconfigured_code(
self.module_id.local_id,
- InFile::new(self.expander.current_file_id(), item.ast_id(&item_tree).upcast()),
+ InFile::new(self.expander.current_file_id(), item.ast_id(item_tree).upcast()),
attrs.cfg().unwrap(),
self.expander.cfg_options().clone(),
));
@@ -528,7 +551,7 @@ impl<'a> AssocItemCollector<'a> {
'attrs: for attr in &*attrs {
let ast_id =
- AstId::new(self.expander.current_file_id(), item.ast_id(&item_tree).upcast());
+ AstId::new(self.expander.current_file_id(), item.ast_id(item_tree).upcast());
let ast_id_with_path = AstIdWithPath { path: (*attr.path).clone(), ast_id };
if let Ok(ResolvedAttr::Macro(call_id)) = self.def_map.resolve_attr_macro(
@@ -595,10 +618,8 @@ impl<'a> AssocItemCollector<'a> {
let ast_id_map = self.db.ast_id_map(self.expander.current_file_id());
let call = ast_id_map.get(call.ast_id).to_node(&root);
- let _cx = stdx::panic_context::enter(format!(
- "collect_items MacroCall: {}",
- call
- ));
+ let _cx =
+ stdx::panic_context::enter(format!("collect_items MacroCall: {call}"));
let res = self.expander.enter_expand::<ast::MacroItems>(self.db, call);
if let Ok(ExpandResult { value: Some((mark, _)), .. }) = res {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr.rs
index 162646550..7b6569421 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr.rs
@@ -36,6 +36,13 @@ pub(crate) fn dummy_expr_id() -> ExprId {
pub type PatId = Idx<Pat>;
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub enum ExprOrPatId {
+ ExprId(ExprId),
+ PatId(PatId),
+}
+stdx::impl_from!(ExprId, PatId for ExprOrPatId);
+
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Label {
pub name: Name,
@@ -137,6 +144,9 @@ pub enum Expr {
Yield {
expr: Option<ExprId>,
},
+ Yeet {
+ expr: Option<ExprId>,
+ },
RecordLit {
path: Option<Box<Path>>,
fields: Box<[RecordLitField]>,
@@ -313,7 +323,10 @@ impl Expr {
arms.iter().map(|arm| arm.expr).for_each(f);
}
Expr::Continue { .. } => {}
- Expr::Break { expr, .. } | Expr::Return { expr } | Expr::Yield { expr } => {
+ Expr::Break { expr, .. }
+ | Expr::Return { expr }
+ | Expr::Yield { expr }
+ | Expr::Yeet { expr } => {
if let &Some(expr) = expr {
f(expr);
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
index c70e6fdcc..ddd7ad99e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
@@ -107,7 +107,7 @@ fn find_path_inner(
}
// - if the item is in the prelude, return the name from there
- if let Some(value) = find_in_prelude(db, &crate_root.def_map(db), item, from) {
+ if let value @ Some(_) = find_in_prelude(db, &crate_root.def_map(db), &def_map, item, from) {
return value;
}
@@ -176,7 +176,7 @@ fn find_path_for_module(
// - if relative paths are fine, check if we are searching for a parent
if prefixed.filter(PrefixKind::is_absolute).is_none() {
- if let modpath @ Some(_) = find_self_super(&def_map, module_id, from) {
+ if let modpath @ Some(_) = find_self_super(def_map, module_id, from) {
return modpath;
}
}
@@ -205,7 +205,8 @@ fn find_path_for_module(
}
}
- if let Some(value) = find_in_prelude(db, &root_def_map, ItemInNs::Types(module_id.into()), from)
+ if let value @ Some(_) =
+ find_in_prelude(db, &root_def_map, &def_map, ItemInNs::Types(module_id.into()), from)
{
return value;
}
@@ -234,23 +235,41 @@ fn find_in_scope(
})
}
+/// Returns single-segment path (i.e. without any prefix) if `item` is found in prelude and its
+/// name doesn't clash in current scope.
fn find_in_prelude(
db: &dyn DefDatabase,
root_def_map: &DefMap,
+ local_def_map: &DefMap,
item: ItemInNs,
from: ModuleId,
-) -> Option<Option<ModPath>> {
- if let Some(prelude_module) = root_def_map.prelude() {
- // Preludes in block DefMaps are ignored, only the crate DefMap is searched
- let prelude_def_map = prelude_module.def_map(db);
- let prelude_scope = &prelude_def_map[prelude_module.local_id].scope;
- if let Some((name, vis)) = prelude_scope.name_of(item) {
- if vis.is_visible_from(db, from) {
- return Some(Some(ModPath::from_segments(PathKind::Plain, Some(name.clone()))));
- }
- }
+) -> Option<ModPath> {
+ let prelude_module = root_def_map.prelude()?;
+ // Preludes in block DefMaps are ignored, only the crate DefMap is searched
+ let prelude_def_map = prelude_module.def_map(db);
+ let prelude_scope = &prelude_def_map[prelude_module.local_id].scope;
+ let (name, vis) = prelude_scope.name_of(item)?;
+ if !vis.is_visible_from(db, from) {
+ return None;
+ }
+
+ // Check if the name is in current scope and it points to the same def.
+ let found_and_same_def =
+ local_def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
+ let per_ns = def_map[local_id].scope.get(name);
+ let same_def = match item {
+ ItemInNs::Types(it) => per_ns.take_types()? == it,
+ ItemInNs::Values(it) => per_ns.take_values()? == it,
+ ItemInNs::Macros(it) => per_ns.take_macros()? == it,
+ };
+ Some(same_def)
+ });
+
+ if found_and_same_def.unwrap_or(true) {
+ Some(ModPath::from_segments(PathKind::Plain, Some(name.clone())))
+ } else {
+ None
}
- None
}
fn find_self_super(def_map: &DefMap, item: ModuleId, from: ModuleId) -> Option<ModPath> {
@@ -512,7 +531,7 @@ mod tests {
fn check_found_path_(ra_fixture: &str, path: &str, prefix_kind: Option<PrefixKind>) {
let (db, pos) = TestDB::with_position(ra_fixture);
let module = db.module_at_position(pos);
- let parsed_path_file = syntax::SourceFile::parse(&format!("use {};", path));
+ let parsed_path_file = syntax::SourceFile::parse(&format!("use {path};"));
let ast_path =
parsed_path_file.syntax_node().descendants().find_map(syntax::ast::Path::cast).unwrap();
let mod_path = ModPath::from_src(&db, ast_path, &Hygiene::new_unhygienic()).unwrap();
@@ -531,7 +550,7 @@ mod tests {
let found_path =
find_path_inner(&db, ItemInNs::Types(resolved), module, prefix_kind, false);
- assert_eq!(found_path, Some(mod_path), "{:?}", prefix_kind);
+ assert_eq!(found_path, Some(mod_path), "{prefix_kind:?}");
}
fn check_found_path(
@@ -809,6 +828,48 @@ pub mod prelude {
}
#[test]
+ fn shadowed_prelude() {
+ check_found_path(
+ r#"
+//- /main.rs crate:main deps:std
+struct S;
+$0
+//- /std.rs crate:std
+pub mod prelude {
+ pub mod rust_2018 {
+ pub struct S;
+ }
+}
+"#,
+ "std::prelude::rust_2018::S",
+ "std::prelude::rust_2018::S",
+ "std::prelude::rust_2018::S",
+ "std::prelude::rust_2018::S",
+ );
+ }
+
+ #[test]
+ fn imported_prelude() {
+ check_found_path(
+ r#"
+//- /main.rs crate:main deps:std
+use S;
+$0
+//- /std.rs crate:std
+pub mod prelude {
+ pub mod rust_2018 {
+ pub struct S;
+ }
+}
+"#,
+ "S",
+ "S",
+ "S",
+ "S",
+ );
+ }
+
+ #[test]
fn enum_variant_from_prelude() {
let code = r#"
//- /main.rs crate:main deps:std
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
index 469b28c2d..f74559f5d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
@@ -142,8 +142,8 @@ pub enum WherePredicateTypeTarget {
impl GenericParams {
/// Iterator of type_or_consts field
- pub fn iter<'a>(
- &'a self,
+ pub fn iter(
+ &self,
) -> impl DoubleEndedIterator<Item = (Idx<TypeOrConstParamData>, &TypeOrConstParamData)> {
self.type_or_consts.iter()
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
index 688055e43..1ce191942 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
@@ -239,7 +239,7 @@ impl fmt::Debug for ImportMap {
ItemInNs::Values(_) => "v",
ItemInNs::Macros(_) => "m",
};
- format!("- {} ({})", info.path, ns)
+ format!("- {} ({ns})", info.path)
})
.collect();
@@ -389,12 +389,12 @@ impl Query {
/// Searches dependencies of `krate` for an importable path matching `query`.
///
/// This returns a list of items that could be imported from dependencies of `krate`.
-pub fn search_dependencies<'a>(
- db: &'a dyn DefDatabase,
+pub fn search_dependencies(
+ db: &dyn DefDatabase,
krate: CrateId,
query: Query,
) -> FxHashSet<ItemInNs> {
- let _p = profile::span("search_dependencies").detail(|| format!("{:?}", query));
+ let _p = profile::span("search_dependencies").detail(|| format!("{query:?}"));
let graph = db.crate_graph();
let import_maps: Vec<_> =
@@ -545,7 +545,7 @@ mod tests {
None
}
})?;
- return Some(format!("{}::{}", dependency_imports.path_of(trait_)?, assoc_item_name));
+ return Some(format!("{}::{assoc_item_name}", dependency_imports.path_of(trait_)?));
}
None
}
@@ -585,7 +585,7 @@ mod tests {
let map = db.import_map(krate);
- Some(format!("{}:\n{:?}\n", name, map))
+ Some(format!("{name}:\n{map:?}\n"))
})
.sorted()
.collect::<String>();
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
index 7721221c4..c7b213b7e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
@@ -96,7 +96,7 @@ pub(crate) enum BuiltinShadowMode {
/// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
/// Other methods will only resolve values, types and module scoped macros only.
impl ItemScope {
- pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
+ pub fn entries(&self) -> impl Iterator<Item = (&Name, PerNs)> + '_ {
// FIXME: shadowing
self.types
.keys()
@@ -159,18 +159,17 @@ impl ItemScope {
pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> {
let (def, mut iter) = match item {
ItemInNs::Macros(def) => {
- return self
- .macros
- .iter()
- .find_map(|(name, &(other_def, vis))| (other_def == def).then(|| (name, vis)));
+ return self.macros.iter().find_map(|(name, &(other_def, vis))| {
+ (other_def == def).then_some((name, vis))
+ });
}
ItemInNs::Types(def) => (def, self.types.iter()),
ItemInNs::Values(def) => (def, self.values.iter()),
};
- iter.find_map(|(name, &(other_def, vis))| (other_def == def).then(|| (name, vis)))
+ iter.find_map(|(name, &(other_def, vis))| (other_def == def).then_some((name, vis)))
}
- pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
+ pub(crate) fn traits(&self) -> impl Iterator<Item = TraitId> + '_ {
self.types
.values()
.filter_map(|&(def, _)| match def {
@@ -327,7 +326,7 @@ impl ItemScope {
changed
}
- pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Option<Name>, PerNs)> + 'a {
+ pub(crate) fn resolutions(&self) -> impl Iterator<Item = (Option<Name>, PerNs)> + '_ {
self.entries().map(|(name, res)| (Some(name.clone()), res)).chain(
self.unnamed_trait_imports
.iter()
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
index 0aa531eff..80297f8ad 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
@@ -105,7 +105,7 @@ pub struct ItemTree {
impl ItemTree {
pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
- let _p = profile::span("file_item_tree_query").detail(|| format!("{:?}", file_id));
+ let _p = profile::span("file_item_tree_query").detail(|| format!("{file_id:?}"));
let syntax = match db.parse_or_expand(file_id) {
Some(node) => node,
None => return Default::default(),
@@ -132,7 +132,7 @@ impl ItemTree {
ctx.lower_macro_stmts(stmts)
},
_ => {
- panic!("cannot create item tree from {:?} {}", syntax, syntax);
+ panic!("cannot create item tree from {syntax:?} {syntax}");
},
}
};
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/layout.rs b/src/tools/rust-analyzer/crates/hir-def/src/layout.rs
new file mode 100644
index 000000000..6bb4cd94f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/hir-def/src/layout.rs
@@ -0,0 +1,96 @@
+//! Definitions needed for computing data layout of types.
+
+use std::cmp;
+
+use la_arena::{Idx, RawIdx};
+pub use rustc_abi::{
+ Abi, AbiAndPrefAlign, AddressSpace, Align, Endian, FieldsShape, Integer, IntegerType,
+ LayoutCalculator, Niche, Primitive, ReprFlags, ReprOptions, Scalar, Size, StructKind,
+ TargetDataLayout, TargetDataLayoutErrors, WrappingRange,
+};
+
+use crate::LocalEnumVariantId;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct RustcEnumVariantIdx(pub LocalEnumVariantId);
+
+impl rustc_index::vec::Idx for RustcEnumVariantIdx {
+ fn new(idx: usize) -> Self {
+ RustcEnumVariantIdx(Idx::from_raw(RawIdx::from(idx as u32)))
+ }
+
+ fn index(self) -> usize {
+ u32::from(self.0.into_raw()) as usize
+ }
+}
+
+pub type Layout = rustc_abi::LayoutS<RustcEnumVariantIdx>;
+pub type TagEncoding = rustc_abi::TagEncoding<RustcEnumVariantIdx>;
+pub type Variants = rustc_abi::Variants<RustcEnumVariantIdx>;
+
+pub trait IntegerExt {
+ fn repr_discr(
+ dl: &TargetDataLayout,
+ repr: &ReprOptions,
+ min: i128,
+ max: i128,
+ ) -> Result<(Integer, bool), LayoutError>;
+}
+
+impl IntegerExt for Integer {
+ /// Finds the appropriate Integer type and signedness for the given
+ /// signed discriminant range and `#[repr]` attribute.
+ /// N.B.: `u128` values above `i128::MAX` will be treated as signed, but
+ /// that shouldn't affect anything, other than maybe debuginfo.
+ fn repr_discr(
+ dl: &TargetDataLayout,
+ repr: &ReprOptions,
+ min: i128,
+ max: i128,
+ ) -> Result<(Integer, bool), LayoutError> {
+ // Theoretically, negative values could be larger in unsigned representation
+ // than the unsigned representation of the signed minimum. However, if there
+ // are any negative values, the only valid unsigned representation is u128
+ // which can fit all i128 values, so the result remains unaffected.
+ let unsigned_fit = Integer::fit_unsigned(cmp::max(min as u128, max as u128));
+ let signed_fit = cmp::max(Integer::fit_signed(min), Integer::fit_signed(max));
+
+ if let Some(ity) = repr.int {
+ let discr = Integer::from_attr(dl, ity);
+ let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
+ if discr < fit {
+ return Err(LayoutError::UserError(
+ "Integer::repr_discr: `#[repr]` hint too small for \
+ discriminant range of enum "
+ .to_string(),
+ ));
+ }
+ return Ok((discr, ity.is_signed()));
+ }
+
+ let at_least = if repr.c() {
+ // This is usually I32, however it can be different on some platforms,
+ // notably hexagon and arm-none/thumb-none
+ dl.c_enum_min_size
+ } else {
+ // repr(Rust) enums try to be as small as possible
+ Integer::I8
+ };
+
+ // If there are no negative values, we can use the unsigned fit.
+ Ok(if min >= 0 {
+ (cmp::max(unsigned_fit, at_least), false)
+ } else {
+ (cmp::max(signed_fit, at_least), true)
+ })
+ }
+}
+
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub enum LayoutError {
+ UserError(String),
+ SizeOverflow,
+ HasPlaceholder,
+ NotImplemented,
+ Unknown,
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
index 5c7aa7234..8267ef09c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -34,6 +34,7 @@ pub mod adt;
pub mod data;
pub mod generics;
pub mod lang_item;
+pub mod layout;
pub mod expr;
pub mod body;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests.rs
index 81b9c5c4b..79c85d118 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests.rs
@@ -170,7 +170,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
}
let pp = pretty_print_macro_expansion(
parse.syntax_node(),
- show_token_ids.then(|| &*token_map),
+ show_token_ids.then_some(&*token_map),
);
let indent = IndentLevel::from_node(call.syntax());
let pp = reindent(indent, pp);
@@ -179,7 +179,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
if tree {
let tree = format!("{:#?}", parse.syntax_node())
.split_inclusive('\n')
- .map(|line| format!("// {}", line))
+ .map(|line| format!("// {line}"))
.collect::<String>();
format_to!(expn_text, "\n{}", tree)
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
index c04cd1651..bb4526672 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
@@ -163,7 +163,8 @@ macro_rules! compile_error {
}
// This expands to nothing (since it's in item position), but emits an error.
-compile_error!("error!");
+compile_error!("error, with an escaped quote: \"");
+compile_error!(r"this is a raw string");
"#,
expect![[r##"
#[rustc_builtin_macro]
@@ -172,7 +173,8 @@ macro_rules! compile_error {
($msg:expr,) => ({ /* compiler built-in */ })
}
-/* error: error! */
+/* error: error, with an escaped quote: " */
+/* error: this is a raw string */
"##]],
);
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
index 457e43925..2d5f2a692 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
@@ -1630,3 +1630,48 @@ const _: i32 = -0--1--2;
"#]],
);
}
+
+#[test]
+fn test_punct_without_space() {
+ // Puncts are "glued" greedily.
+ check(
+ r#"
+macro_rules! foo {
+ (: : :) => { "1 1 1" };
+ (: ::) => { "1 2" };
+ (:: :) => { "2 1" };
+
+ (: : : :) => { "1 1 1 1" };
+ (:: : :) => { "2 1 1" };
+ (: :: :) => { "1 2 1" };
+ (: : ::) => { "1 1 2" };
+ (:: ::) => { "2 2" };
+}
+
+fn test() {
+ foo!(:::);
+ foo!(: :::);
+ foo!(::::);
+}
+"#,
+ expect![[r#"
+macro_rules! foo {
+ (: : :) => { "1 1 1" };
+ (: ::) => { "1 2" };
+ (:: :) => { "2 1" };
+
+ (: : : :) => { "1 1 1 1" };
+ (:: : :) => { "2 1 1" };
+ (: :: :) => { "1 2 1" };
+ (: : ::) => { "1 1 2" };
+ (:: ::) => { "2 2" };
+}
+
+fn test() {
+ "2 1";
+ "1 2 1";
+ "2 2";
+}
+"#]],
+ );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs
index fc90c6e9f..26f16542c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs
@@ -136,3 +136,52 @@ macro_rules! m { ($($i:ident)? $vis:vis) => () }
"#]],
)
}
+
+// For this test and the one below, see rust-lang/rust#86730.
+#[test]
+fn expr_dont_match_let_expr() {
+ check(
+ r#"
+macro_rules! foo {
+ ($e:expr) => { $e }
+}
+
+fn test() {
+ foo!(let a = 3);
+}
+"#,
+ expect![[r#"
+macro_rules! foo {
+ ($e:expr) => { $e }
+}
+
+fn test() {
+ /* error: no rule matches input tokens */missing;
+}
+"#]],
+ );
+}
+
+#[test]
+fn expr_dont_match_inline_const() {
+ check(
+ r#"
+macro_rules! foo {
+ ($e:expr) => { $e }
+}
+
+fn test() {
+ foo!(const { 3 });
+}
+"#,
+ expect![[r#"
+macro_rules! foo {
+ ($e:expr) => { $e }
+}
+
+fn test() {
+ /* error: no rule matches input tokens */missing;
+}
+"#]],
+ );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs
index 8aff78408..7e7b40044 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs
@@ -94,7 +94,7 @@ macro_rules! m2 { () => ( ${invalid()} ) }
#[test]
fn test_rustc_issue_57597() {
- // <https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-57597.rs>
+ // <https://github.com/rust-lang/rust/blob/master/tests/ui/issues/issue-57597.rs>
check(
r#"
macro_rules! m0 { ($($($i:ident)?)+) => {}; }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
index 9b4ce9f97..f42b0079d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
@@ -457,7 +457,7 @@ impl DefMap {
for (name, child) in
map.modules[module].children.iter().sorted_by(|a, b| Ord::cmp(&a.0, &b.0))
{
- let path = format!("{}::{}", path, name);
+ let path = format!("{path}::{name}");
buf.push('\n');
go(buf, map, &path, *child);
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
index b0dd01f9d..160203b77 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
@@ -40,7 +40,7 @@ use crate::{
diagnostics::DefDiagnostic,
mod_resolution::ModDir,
path_resolution::ReachedFixedPoint,
- proc_macro::{ProcMacroDef, ProcMacroKind},
+ proc_macro::{parse_macro_name_and_helper_attrs, ProcMacroDef, ProcMacroKind},
BuiltinShadowMode, DefMap, ModuleData, ModuleOrigin, ResolveMode,
},
path::{ImportAlias, ModPath, PathKind},
@@ -67,7 +67,7 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: T
let dep_def_map = db.crate_def_map(dep.crate_id);
let dep_root = dep_def_map.module_id(dep_def_map.root);
- deps.insert(dep.as_name(), dep_root.into());
+ deps.insert(dep.as_name(), dep_root);
if dep.is_prelude() && !tree_id.is_block() {
def_map.extern_prelude.insert(dep.as_name(), dep_root);
@@ -1017,7 +1017,7 @@ impl DefCollector<'_> {
None => true,
Some(old_vis) => {
let max_vis = old_vis.max(vis, &self.def_map).unwrap_or_else(|| {
- panic!("`Tr as _` imports with unrelated visibilities {:?} and {:?} (trait {:?})", old_vis, vis, tr);
+ panic!("`Tr as _` imports with unrelated visibilities {old_vis:?} and {vis:?} (trait {tr:?})");
});
if max_vis == old_vis {
@@ -1094,7 +1094,7 @@ impl DefCollector<'_> {
ast_id,
*expand_to,
self.def_map.krate,
- &resolver_def_id,
+ resolver_def_id,
&mut |_err| (),
);
if let Ok(Ok(call_id)) = call_id {
@@ -1110,7 +1110,7 @@ impl DefCollector<'_> {
*derive_attr,
*derive_pos as u32,
self.def_map.krate,
- &resolver,
+ resolver,
);
if let Ok((macro_id, def_id, call_id)) = id {
@@ -1345,7 +1345,7 @@ impl DefCollector<'_> {
// Missing proc macros are non-fatal, so they are handled specially.
DefDiagnostic::unresolved_proc_macro(module_id, loc.kind.clone(), loc.def.krate)
}
- _ => DefDiagnostic::macro_error(module_id, loc.kind.clone(), err.to_string()),
+ _ => DefDiagnostic::macro_error(module_id, loc.kind, err.to_string()),
};
self.def_map.diagnostics.push(diag);
@@ -2005,6 +2005,7 @@ impl ModCollector<'_, '_> {
let ast_id = InFile::new(self.file_id(), mac.ast_id.upcast());
// Case 1: builtin macros
+ let mut helpers_opt = None;
let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into());
let expander = if attrs.by_key("rustc_builtin_macro").exists() {
if let Some(expander) = find_builtin_macro(&mac.name) {
@@ -2013,6 +2014,25 @@ impl ModCollector<'_, '_> {
Either::Right(it) => MacroExpander::BuiltInEager(it),
}
} else if let Some(expander) = find_builtin_derive(&mac.name) {
+ if let Some(attr) = attrs.by_key("rustc_builtin_macro").tt_values().next() {
+ // NOTE: The item *may* have both `#[rustc_builtin_macro]` and `#[proc_macro_derive]`,
+ // in which case rustc ignores the helper attributes from the latter, but it
+ // "doesn't make sense in practice" (see rust-lang/rust#87027).
+ if let Some((name, helpers)) =
+ parse_macro_name_and_helper_attrs(&attr.token_trees)
+ {
+ // NOTE: rustc overrides the name if the macro name if it's different from the
+ // macro name, but we assume it isn't as there's no such case yet. FIXME if
+ // the following assertion fails.
+ stdx::always!(
+ name == mac.name,
+ "built-in macro {} has #[rustc_builtin_macro] which declares different name {}",
+ mac.name,
+ name
+ );
+ helpers_opt = Some(helpers);
+ }
+ }
MacroExpander::BuiltInDerive(expander)
} else if let Some(expander) = find_builtin_attr(&mac.name) {
MacroExpander::BuiltInAttr(expander)
@@ -2037,6 +2057,12 @@ impl ModCollector<'_, '_> {
macro_id,
&self.item_tree[mac.visibility],
);
+ if let Some(helpers) = helpers_opt {
+ self.def_collector
+ .def_map
+ .exported_derives
+ .insert(macro_id_to_def_id(self.def_collector.db, macro_id.into()), helpers);
+ }
}
fn collect_macro_call(&mut self, mac: &MacroCall, container: ItemContainerId) {
@@ -2059,7 +2085,7 @@ impl ModCollector<'_, '_> {
.scope
.get_legacy_macro(name)
.and_then(|it| it.last())
- .map(|&it| macro_id_to_def_id(self.def_collector.db, it.into()))
+ .map(|&it| macro_id_to_def_id(self.def_collector.db, it))
},
)
})
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs
index ca7bcc814..4c263846d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs
@@ -34,7 +34,7 @@ impl ModDir {
let path = match attr_path.map(SmolStr::as_str) {
None => {
let mut path = self.dir_path.clone();
- path.push(&name.to_smol_str());
+ path.push(&name.unescaped().to_smol_str());
path
}
Some(attr_path) => {
@@ -74,12 +74,12 @@ impl ModDir {
candidate_files.push(self.dir_path.join_attr(attr_path, self.root_non_dir_owner))
}
None if file_id.is_include_macro(db.upcast()) => {
- candidate_files.push(format!("{}.rs", name));
- candidate_files.push(format!("{}/mod.rs", name));
+ candidate_files.push(format!("{name}.rs"));
+ candidate_files.push(format!("{name}/mod.rs"));
}
None => {
- candidate_files.push(format!("{}{}.rs", self.dir_path.0, name));
- candidate_files.push(format!("{}{}/mod.rs", self.dir_path.0, name));
+ candidate_files.push(format!("{}{name}.rs", self.dir_path.0));
+ candidate_files.push(format!("{}{name}/mod.rs", self.dir_path.0));
}
};
@@ -91,7 +91,7 @@ impl ModDir {
let (dir_path, root_non_dir_owner) = if is_mod_rs || attr_path.is_some() {
(DirPath::empty(), false)
} else {
- (DirPath::new(format!("{}/", name)), true)
+ (DirPath::new(format!("{name}/")), true)
};
if let Some(mod_dir) = self.child(dir_path, root_non_dir_owner) {
return Ok((file_id, is_mod_rs, mod_dir));
@@ -156,7 +156,7 @@ impl DirPath {
} else {
attr
};
- let res = format!("{}{}", base, attr);
+ let res = format!("{base}{attr}");
res
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
index 20d39ec6c..1d9d5cccd 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
@@ -170,8 +170,8 @@ impl DefMap {
) -> ResolvePathResult {
let graph = db.crate_graph();
let _cx = stdx::panic_context::enter(format!(
- "DefMap {:?} crate_name={:?} block={:?} path={}",
- self.krate, graph[self.krate].display_name, self.block, path
+ "DefMap {:?} crate_name={:?} block={:?} path={path}",
+ self.krate, graph[self.krate].display_name, self.block
));
let mut segments = path.segments().iter().enumerate();
@@ -390,7 +390,7 @@ impl DefMap {
.get_legacy_macro(name)
// FIXME: shadowing
.and_then(|it| it.last())
- .map_or_else(PerNs::none, |&m| PerNs::macros(m.into(), Visibility::Public));
+ .map_or_else(PerNs::none, |&m| PerNs::macros(m, Visibility::Public));
let from_scope = self[module].scope.get(name);
let from_builtin = match self.block {
Some(_) => {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs
index 52b79cd0f..06b23392c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs
@@ -37,45 +37,53 @@ impl Attrs {
Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::Attr })
} else if self.by_key("proc_macro_derive").exists() {
let derive = self.by_key("proc_macro_derive").tt_values().next()?;
+ let def = parse_macro_name_and_helper_attrs(&derive.token_trees)
+ .map(|(name, helpers)| ProcMacroDef { name, kind: ProcMacroKind::CustomDerive { helpers } });
- match &*derive.token_trees {
- // `#[proc_macro_derive(Trait)]`
- [TokenTree::Leaf(Leaf::Ident(trait_name))] => Some(ProcMacroDef {
- name: trait_name.as_name(),
- kind: ProcMacroKind::CustomDerive { helpers: Box::new([]) },
- }),
-
- // `#[proc_macro_derive(Trait, attributes(helper1, helper2, ...))]`
- [
- TokenTree::Leaf(Leaf::Ident(trait_name)),
- TokenTree::Leaf(Leaf::Punct(comma)),
- TokenTree::Leaf(Leaf::Ident(attributes)),
- TokenTree::Subtree(helpers)
- ] if comma.char == ',' && attributes.text == "attributes" =>
- {
- let helpers = helpers.token_trees.iter()
- .filter(|tt| !matches!(tt, TokenTree::Leaf(Leaf::Punct(comma)) if comma.char == ','))
- .map(|tt| {
- match tt {
- TokenTree::Leaf(Leaf::Ident(helper)) => Some(helper.as_name()),
- _ => None
- }
- })
- .collect::<Option<Box<[_]>>>()?;
-
- Some(ProcMacroDef {
- name: trait_name.as_name(),
- kind: ProcMacroKind::CustomDerive { helpers },
- })
- }
-
- _ => {
- tracing::trace!("malformed `#[proc_macro_derive]`: {}", derive);
- None
- }
+ if def.is_none() {
+ tracing::trace!("malformed `#[proc_macro_derive]`: {}", derive);
}
+
+ def
} else {
None
}
}
}
+
+// This fn is intended for `#[proc_macro_derive(..)]` and `#[rustc_builtin_macro(..)]`, which have
+// the same strucuture.
+#[rustfmt::skip]
+pub(crate) fn parse_macro_name_and_helper_attrs(tt: &[TokenTree]) -> Option<(Name, Box<[Name]>)> {
+ match tt {
+ // `#[proc_macro_derive(Trait)]`
+ // `#[rustc_builtin_macro(Trait)]`
+ [TokenTree::Leaf(Leaf::Ident(trait_name))] => Some((trait_name.as_name(), Box::new([]))),
+
+ // `#[proc_macro_derive(Trait, attributes(helper1, helper2, ...))]`
+ // `#[rustc_builtin_macro(Trait, attributes(helper1, helper2, ...))]`
+ [
+ TokenTree::Leaf(Leaf::Ident(trait_name)),
+ TokenTree::Leaf(Leaf::Punct(comma)),
+ TokenTree::Leaf(Leaf::Ident(attributes)),
+ TokenTree::Subtree(helpers)
+ ] if comma.char == ',' && attributes.text == "attributes" =>
+ {
+ let helpers = helpers
+ .token_trees
+ .iter()
+ .filter(
+ |tt| !matches!(tt, TokenTree::Leaf(Leaf::Punct(comma)) if comma.char == ','),
+ )
+ .map(|tt| match tt {
+ TokenTree::Leaf(Leaf::Ident(helper)) => Some(helper.as_name()),
+ _ => None,
+ })
+ .collect::<Option<Box<[_]>>>()?;
+
+ Some((trait_name.as_name(), helpers))
+ }
+
+ _ => None,
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
index 2e8cb3621..f5190b76d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
@@ -13,7 +13,7 @@ fn check_def_map_is_not_recomputed(ra_fixture_initial: &str, ra_fixture_change:
let events = db.log_executed(|| {
db.crate_def_map(krate);
});
- assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
+ assert!(format!("{events:?}").contains("crate_def_map"), "{events:#?}")
}
db.set_file_text(pos.file_id, Arc::new(ra_fixture_change.to_string()));
@@ -21,7 +21,7 @@ fn check_def_map_is_not_recomputed(ra_fixture_initial: &str, ra_fixture_change:
let events = db.log_executed(|| {
db.crate_def_map(krate);
});
- assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
+ assert!(!format!("{events:?}").contains("crate_def_map"), "{events:#?}")
}
}
@@ -94,7 +94,7 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() {
let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
assert_eq!(module_data.scope.resolutions().count(), 1);
});
- assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
+ assert!(format!("{events:?}").contains("crate_def_map"), "{events:#?}")
}
db.set_file_text(pos.file_id, Arc::new("m!(Y);".to_string()));
@@ -104,7 +104,7 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() {
let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
assert_eq!(module_data.scope.resolutions().count(), 1);
});
- assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
+ assert!(!format!("{events:?}").contains("crate_def_map"), "{events:#?}")
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
index 3ece1379a..fe0ad4f38 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
@@ -823,6 +823,28 @@ fn derive() {}
}
#[test]
+fn resolves_derive_helper_rustc_builtin_macro() {
+ cov_mark::check!(resolved_derive_helper);
+ // This is NOT the correct usage of `default` helper attribute, but we don't resolve helper
+ // attributes on non mod items in hir nameres.
+ check(
+ r#"
+//- minicore: derive, default
+#[derive(Default)]
+#[default]
+enum E {
+ A,
+ B,
+}
+"#,
+ expect![[r#"
+ crate
+ E: t
+ "#]],
+ );
+}
+
+#[test]
fn unresolved_attr_with_cfg_attr_hang() {
// Another regression test for https://github.com/rust-lang/rust-analyzer/issues/8905
check(
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs
index c575bf7ca..a01931288 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs
@@ -157,6 +157,43 @@ pub struct Baz;
}
#[test]
+fn module_resolution_works_for_inline_raw_modules() {
+ check(
+ r#"
+//- /lib.rs
+mod r#async {
+ pub mod a;
+ pub mod r#async;
+}
+use self::r#async::a::Foo;
+use self::r#async::r#async::Bar;
+
+//- /async/a.rs
+pub struct Foo;
+
+//- /async/async.rs
+pub struct Bar;
+"#,
+ expect![[r#"
+ crate
+ Bar: t v
+ Foo: t v
+ r#async: t
+
+ crate::r#async
+ a: t
+ r#async: t
+
+ crate::r#async::a
+ Foo: t v
+
+ crate::r#async::r#async
+ Bar: t v
+ "#]],
+ );
+}
+
+#[test]
fn module_resolution_decl_path() {
check(
r#"
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
index 933970d10..befd0c5ff 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
@@ -92,7 +92,7 @@ pub(crate) fn print_generic_args(generics: &GenericArgs, buf: &mut dyn Write) ->
pub(crate) fn print_generic_arg(arg: &GenericArg, buf: &mut dyn Write) -> fmt::Result {
match arg {
GenericArg::Type(ty) => print_type_ref(ty, buf),
- GenericArg::Const(c) => write!(buf, "{}", c),
+ GenericArg::Const(c) => write!(buf, "{c}"),
GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name),
}
}
@@ -118,7 +118,7 @@ pub(crate) fn print_type_ref(type_ref: &TypeRef, buf: &mut dyn Write) -> fmt::Re
Mutability::Shared => "*const",
Mutability::Mut => "*mut",
};
- write!(buf, "{} ", mtbl)?;
+ write!(buf, "{mtbl} ")?;
print_type_ref(pointee, buf)?;
}
TypeRef::Reference(pointee, lt, mtbl) => {
@@ -130,13 +130,13 @@ pub(crate) fn print_type_ref(type_ref: &TypeRef, buf: &mut dyn Write) -> fmt::Re
if let Some(lt) = lt {
write!(buf, "{} ", lt.name)?;
}
- write!(buf, "{}", mtbl)?;
+ write!(buf, "{mtbl}")?;
print_type_ref(pointee, buf)?;
}
TypeRef::Array(elem, len) => {
write!(buf, "[")?;
print_type_ref(elem, buf)?;
- write!(buf, "; {}]", len)?;
+ write!(buf, "; {len}]")?;
}
TypeRef::Slice(elem) => {
write!(buf, "[")?;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
index 070f68371..1ef7f9577 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -381,7 +381,7 @@ impl Resolver {
});
def_map[module_id].scope.legacy_macros().for_each(|(name, macs)| {
macs.iter().for_each(|&mac| {
- res.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(MacroId::from(mac))));
+ res.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(mac)));
})
});
def_map.extern_prelude().for_each(|(name, &def)| {
@@ -517,10 +517,7 @@ impl Scope {
});
m.def_map[m.module_id].scope.legacy_macros().for_each(|(name, macs)| {
macs.iter().for_each(|&mac| {
- acc.add(
- name,
- ScopeDef::ModuleDef(ModuleDefId::MacroId(MacroId::from(mac))),
- );
+ acc.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(mac)));
})
});
}