Merge commit 'ac998a74b3' into sync-from-ra

This commit is contained in:
Laurențiu Nicola 2024-02-18 09:41:20 +02:00
parent d33d8675d0
commit 6b17dba68c
178 changed files with 7101 additions and 1965 deletions

View file

@ -377,27 +377,39 @@ impl AttrsWithOwner {
AttrDefId::GenericParamId(it) => match it {
GenericParamId::ConstParamId(it) => {
let src = it.parent().child_source(db);
RawAttrs::from_attrs_owner(
db.upcast(),
src.with_value(&src.value[it.local_id()]),
db.span_map(src.file_id).as_ref(),
)
// FIXME: We should be never getting `None` here.
match src.value.get(it.local_id()) {
Some(val) => RawAttrs::from_attrs_owner(
db.upcast(),
src.with_value(val),
db.span_map(src.file_id).as_ref(),
),
None => RawAttrs::EMPTY,
}
}
GenericParamId::TypeParamId(it) => {
let src = it.parent().child_source(db);
RawAttrs::from_attrs_owner(
db.upcast(),
src.with_value(&src.value[it.local_id()]),
db.span_map(src.file_id).as_ref(),
)
// FIXME: We should be never getting `None` here.
match src.value.get(it.local_id()) {
Some(val) => RawAttrs::from_attrs_owner(
db.upcast(),
src.with_value(val),
db.span_map(src.file_id).as_ref(),
),
None => RawAttrs::EMPTY,
}
}
GenericParamId::LifetimeParamId(it) => {
let src = it.parent.child_source(db);
RawAttrs::from_attrs_owner(
db.upcast(),
src.with_value(&src.value[it.local_id]),
db.span_map(src.file_id).as_ref(),
)
// FIXME: We should be never getting `None` here.
match src.value.get(it.local_id) {
Some(val) => RawAttrs::from_attrs_owner(
db.upcast(),
src.with_value(val),
db.span_map(src.file_id).as_ref(),
),
None => RawAttrs::EMPTY,
}
}
},
AttrDefId::ExternBlockId(it) => attrs_from_item_tree_loc(db, it),

View file

@ -416,6 +416,11 @@ impl ExprCollector<'_> {
let expr = e.expr().map(|e| self.collect_expr(e));
self.alloc_expr(Expr::Return { expr }, syntax_ptr)
}
ast::Expr::BecomeExpr(e) => {
let expr =
e.expr().map(|e| self.collect_expr(e)).unwrap_or_else(|| self.missing_expr());
self.alloc_expr(Expr::Become { expr }, syntax_ptr)
}
ast::Expr::YieldExpr(e) => {
self.is_lowering_coroutine = true;
let expr = e.expr().map(|e| self.collect_expr(e));
@ -1000,10 +1005,6 @@ impl ExprCollector<'_> {
krate: *krate,
});
}
Some(ExpandError::RecursionOverflowPoisoned) => {
// Recursion limit has been reached in the macro expansion tree, but not in
// this very macro call. Don't add diagnostics to avoid duplication.
}
Some(err) => {
self.source_map.diagnostics.push(BodyDiagnostic::MacroError {
node: InFile::new(outer_file, syntax_ptr),
@ -1112,7 +1113,7 @@ impl ExprCollector<'_> {
statements.push(Statement::Expr { expr, has_semi });
}
}
ast::Stmt::Item(_item) => (),
ast::Stmt::Item(_item) => statements.push(Statement::Item),
}
}

View file

@ -261,6 +261,11 @@ impl Printer<'_> {
self.print_expr(*expr);
}
}
Expr::Become { expr } => {
w!(self, "become");
self.whitespace();
self.print_expr(*expr);
}
Expr::Yield { expr } => {
w!(self, "yield");
if let Some(expr) = expr {
@ -623,6 +628,7 @@ impl Printer<'_> {
}
wln!(self);
}
Statement::Item => (),
}
}

View file

@ -197,6 +197,7 @@ fn compute_block_scopes(
Statement::Expr { expr, .. } => {
compute_expr_scopes(*expr, body, scopes, scope);
}
Statement::Item => (),
}
}
if let Some(expr) = tail {

View file

@ -634,7 +634,6 @@ impl<'a> AssocItemCollector<'a> {
attr,
) {
Ok(ResolvedAttr::Macro(call_id)) => {
self.attr_calls.push((ast_id, call_id));
// If proc attribute macro expansion is disabled, skip expanding it here
if !self.db.expand_proc_attr_macros() {
continue 'attrs;
@ -647,10 +646,21 @@ impl<'a> AssocItemCollector<'a> {
// disabled. This is analogous to the handling in
// `DefCollector::collect_macros`.
if exp.is_dummy() {
self.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
self.module_id.local_id,
loc.kind,
loc.def.krate,
));
continue 'attrs;
}
if exp.is_disabled() {
continue 'attrs;
}
}
self.attr_calls.push((ast_id, call_id));
let res =
self.expander.enter_expand_id::<ast::MacroItems>(self.db, call_id);
self.collect_macro_items(res, &|| loc.kind.clone());

View file

@ -140,13 +140,11 @@ impl Expander {
// The overflow error should have been reported when it occurred (see the next branch),
// so don't return overflow error here to avoid diagnostics duplication.
cov_mark::hit!(overflow_but_not_me);
return ExpandResult::only_err(ExpandError::RecursionOverflowPoisoned);
return ExpandResult::ok(None);
} else if self.recursion_limit.check(self.recursion_depth as usize + 1).is_err() {
self.recursion_depth = u32::MAX;
cov_mark::hit!(your_stack_belongs_to_me);
return ExpandResult::only_err(ExpandError::other(
"reached recursion limit during macro expansion",
));
return ExpandResult::only_err(ExpandError::RecursionOverflow);
}
let ExpandResult { value, err } = op(self);

View file

@ -447,18 +447,25 @@ fn select_best_path(
}
const STD_CRATES: [Name; 3] = [known::std, known::core, known::alloc];
let choose = |new_path: (ModPath, _), old_path: (ModPath, _)| {
let new_has_prelude = new_path.0.segments().iter().any(|seg| seg == &known::prelude);
let old_has_prelude = old_path.0.segments().iter().any(|seg| seg == &known::prelude);
let choose = |new: (ModPath, _), old: (ModPath, _)| {
let (new_path, _) = &new;
let (old_path, _) = &old;
let new_has_prelude = new_path.segments().iter().any(|seg| seg == &known::prelude);
let old_has_prelude = old_path.segments().iter().any(|seg| seg == &known::prelude);
match (new_has_prelude, old_has_prelude, prefer_prelude) {
(true, false, true) | (false, true, false) => new_path,
(true, false, false) | (false, true, true) => old_path,
// no prelude difference in the paths, so pick the smaller one
(true, false, true) | (false, true, false) => new,
(true, false, false) | (false, true, true) => old,
// no prelude difference in the paths, so pick the shorter one
(true, true, _) | (false, false, _) => {
if new_path.0.len() < old_path.0.len() {
new_path
let new_path_is_shorter = new_path
.len()
.cmp(&old_path.len())
.then_with(|| new_path.textual_len().cmp(&old_path.textual_len()))
.is_lt();
if new_path_is_shorter {
new
} else {
old_path
old
}
}
}
@ -469,8 +476,8 @@ fn select_best_path(
let rank = match prefer_no_std {
false => |name: &Name| match name {
name if name == &known::core => 0,
name if name == &known::alloc => 0,
name if name == &known::std => 1,
name if name == &known::alloc => 1,
name if name == &known::std => 2,
_ => unreachable!(),
},
true => |name: &Name| match name {
@ -1539,4 +1546,38 @@ pub mod foo {
"krate::prelude::Foo",
);
}
#[test]
fn respect_segment_length() {
check_found_path(
r#"
//- /main.rs crate:main deps:petgraph
$0
//- /petgraph.rs crate:petgraph
pub mod graph {
pub use crate::graph_impl::{
NodeIndex
};
}
mod graph_impl {
pub struct NodeIndex<Ix>(Ix);
}
pub mod stable_graph {
#[doc(no_inline)]
pub use crate::graph::{NodeIndex};
}
pub mod prelude {
#[doc(no_inline)]
pub use crate::graph::{NodeIndex};
}
"#,
"petgraph::graph::NodeIndex",
"petgraph::graph::NodeIndex",
"petgraph::graph::NodeIndex",
"petgraph::graph::NodeIndex",
);
}
}

View file

@ -182,6 +182,7 @@ pub enum Expr {
tail: Option<ExprId>,
},
Const(ConstBlockId),
// FIXME: Fold this into Block with an unsafe flag?
Unsafe {
id: Option<BlockId>,
statements: Box<[Statement]>,
@ -216,6 +217,9 @@ pub enum Expr {
Return {
expr: Option<ExprId>,
},
Become {
expr: ExprId,
},
Yield {
expr: Option<ExprId>,
},
@ -349,6 +353,9 @@ pub enum Statement {
expr: ExprId,
has_semi: bool,
},
// At the moment, we only use this to figure out if a return expression
// is really the last statement of a block. See #16566
Item,
}
impl Expr {
@ -382,6 +389,7 @@ impl Expr {
}
}
Statement::Expr { expr: expression, .. } => f(*expression),
Statement::Item => (),
}
}
if let &Some(expr) = tail {
@ -410,6 +418,7 @@ impl Expr {
f(expr);
}
}
Expr::Become { expr } => f(*expr),
Expr::RecordLit { fields, spread, .. } => {
for field in fields.iter() {
f(field.expr);

View file

@ -33,7 +33,7 @@ m!(&k");
"#,
expect![[r#"
macro_rules! m { ($i:literal) => {}; }
/* error: invalid token tree */"#]],
/* error: mismatched delimiters */"#]],
);
}

View file

@ -68,26 +68,26 @@ m2!();
"#,
expect![[r#"
macro_rules! i1 { invalid }
/* error: invalid macro definition: expected subtree */
/* error: macro definition has parse errors */
macro_rules! e1 { $i:ident => () }
/* error: invalid macro definition: expected subtree */
/* error: macro definition has parse errors */
macro_rules! e2 { ($i:ident) () }
/* error: invalid macro definition: expected `=` */
/* error: macro definition has parse errors */
macro_rules! e3 { ($(i:ident)_) => () }
/* error: invalid macro definition: invalid repeat */
/* error: macro definition has parse errors */
macro_rules! f1 { ($i) => ($i) }
/* error: invalid macro definition: missing fragment specifier */
/* error: macro definition has parse errors */
macro_rules! f2 { ($i:) => ($i) }
/* error: invalid macro definition: missing fragment specifier */
/* error: macro definition has parse errors */
macro_rules! f3 { ($i:_) => () }
/* error: invalid macro definition: missing fragment specifier */
/* error: macro definition has parse errors */
macro_rules! m1 { ($$i) => () }
/* error: invalid macro definition: `$$` is not allowed on the pattern side */
/* error: macro definition has parse errors */
macro_rules! m2 { () => ( ${invalid()} ) }
/* error: invalid macro definition: invalid metavariable expression */
/* error: macro definition has parse errors */
"#]],
)
}
@ -137,18 +137,18 @@ macro_rules! m9 { ($($($($i:ident)?)*)+) => {}; }
macro_rules! mA { ($($($($i:ident)+)?)*) => {}; }
macro_rules! mB { ($($($($i:ident)+)*)?) => {}; }
/* error: invalid macro definition: empty token tree in repetition */
/* error: invalid macro definition: empty token tree in repetition */
/* error: invalid macro definition: empty token tree in repetition */
/* error: invalid macro definition: empty token tree in repetition */
/* error: invalid macro definition: empty token tree in repetition */
/* error: invalid macro definition: empty token tree in repetition */
/* error: invalid macro definition: empty token tree in repetition */
/* error: invalid macro definition: empty token tree in repetition */
/* error: invalid macro definition: empty token tree in repetition */
/* error: invalid macro definition: empty token tree in repetition */
/* error: invalid macro definition: empty token tree in repetition */
/* error: invalid macro definition: empty token tree in repetition */
/* error: macro definition has parse errors */
/* error: macro definition has parse errors */
/* error: macro definition has parse errors */
/* error: macro definition has parse errors */
/* error: macro definition has parse errors */
/* error: macro definition has parse errors */
/* error: macro definition has parse errors */
/* error: macro definition has parse errors */
/* error: macro definition has parse errors */
/* error: macro definition has parse errors */
/* error: macro definition has parse errors */
/* error: macro definition has parse errors */
"#]],
);
}

View file

@ -275,9 +275,9 @@ macro_rules! depth_too_large {
}
fn test() {
/* error: invalid macro definition: invalid metavariable expression */;
/* error: invalid macro definition: invalid metavariable expression */;
/* error: invalid macro definition: invalid metavariable expression */;
/* error: macro definition has parse errors */;
/* error: macro definition has parse errors */;
/* error: macro definition has parse errors */;
}
"#]],
);

View file

@ -1090,3 +1090,57 @@ fn main() {
"#]],
);
}
#[test]
fn regression_16529() {
check(
r#"
mod any {
#[macro_export]
macro_rules! nameable {
{
struct $name:ident[$a:lifetime]
} => {
$crate::any::nameable! {
struct $name[$a]
a
}
};
{
struct $name:ident[$a:lifetime]
a
} => {};
}
pub use nameable;
nameable! {
Name['a]
}
}
"#,
expect![[r#"
mod any {
#[macro_export]
macro_rules! nameable {
{
struct $name:ident[$a:lifetime]
} => {
$crate::any::nameable! {
struct $name[$a]
a
}
};
{
struct $name:ident[$a:lifetime]
a
} => {};
}
pub use nameable;
/* error: unexpected token in input */$crate::any::nameable! {
struct $name[$a]a
}
}
"#]],
);
}

View file

@ -97,8 +97,8 @@ m2!(x
macro_rules! m1 { ($x:ident) => { ($x } }
macro_rules! m2 { ($x:ident) => {} }
/* error: invalid macro definition: expected subtree */
/* error: invalid token tree */
/* error: macro definition has parse errors */
/* error: mismatched delimiters */
"#]],
)
}

View file

@ -58,6 +58,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
name: "identity_when_valid".into(),
kind: ProcMacroKind::Attr,
expander: sync::Arc::new(IdentityWhenValidProcMacroExpander),
disabled: false,
},
)];
let db = TestDB::with_files_extra_proc_macros(ra_fixture, extra_proc_macros);

View file

@ -11,7 +11,7 @@ use either::Either;
use hir_expand::{
ast_id_map::FileAstId,
attrs::{Attr, AttrId},
builtin_attr_macro::find_builtin_attr,
builtin_attr_macro::{find_builtin_attr, BuiltinAttrExpander},
builtin_derive_macro::find_builtin_derive,
builtin_fn_macro::find_builtin_macro,
name::{name, AsName, Name},
@ -98,9 +98,13 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI
};
(
name.as_name(),
CustomProcMacroExpander::new(hir_expand::proc_macro::ProcMacroId(
idx as u32,
)),
if it.disabled {
CustomProcMacroExpander::disabled()
} else {
CustomProcMacroExpander::new(
hir_expand::proc_macro::ProcMacroId::new(idx as u32),
)
},
)
})
.collect())
@ -604,9 +608,6 @@ impl DefCollector<'_> {
id: ItemTreeId<item_tree::Function>,
fn_id: FunctionId,
) {
if self.def_map.block.is_some() {
return;
}
let kind = def.kind.to_basedb_kind();
let (expander, kind) =
match self.proc_macros.as_ref().map(|it| it.iter().find(|(n, _)| n == &def.name)) {
@ -1120,9 +1121,16 @@ impl DefCollector<'_> {
let mut push_resolved = |directive: &MacroDirective, call_id| {
resolved.push((directive.module_id, directive.depth, directive.container, call_id));
};
#[derive(PartialEq, Eq)]
enum Resolved {
Yes,
No,
}
let mut res = ReachedFixedPoint::Yes;
// Retain unresolved macros after this round of resolution.
macros.retain(|directive| {
let mut retain = |directive: &MacroDirective| {
let subns = match &directive.kind {
MacroDirectiveKind::FnLike { .. } => MacroSubNs::Bang,
MacroDirectiveKind::Attr { .. } | MacroDirectiveKind::Derive { .. } => {
@ -1156,10 +1164,11 @@ impl DefCollector<'_> {
self.def_map.modules[directive.module_id]
.scope
.add_macro_invoc(ast_id.ast_id, call_id);
push_resolved(directive, call_id);
res = ReachedFixedPoint::No;
return false;
return Resolved::Yes;
}
}
MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos, call_site } => {
@ -1198,7 +1207,7 @@ impl DefCollector<'_> {
push_resolved(directive, call_id);
res = ReachedFixedPoint::No;
return false;
return Resolved::Yes;
}
}
MacroDirectiveKind::Attr { ast_id: file_ast_id, mod_item, attr, tree } => {
@ -1221,7 +1230,7 @@ impl DefCollector<'_> {
}
.collect(&[*mod_item], directive.container);
res = ReachedFixedPoint::No;
false
Resolved::Yes
};
if let Some(ident) = path.as_ident() {
@ -1237,13 +1246,18 @@ impl DefCollector<'_> {
let def = match resolver_def_id(path.clone()) {
Some(def) if def.is_attribute() => def,
_ => return true,
_ => return Resolved::No,
};
if matches!(
def,
MacroDefId { kind: MacroDefKind::BuiltInAttr(expander, _),.. }
if expander.is_derive()
) {
if let MacroDefId {
kind:
MacroDefKind::BuiltInAttr(
BuiltinAttrExpander::Derive | BuiltinAttrExpander::DeriveConst,
_,
),
..
} = def
{
// Resolved to `#[derive]`, we don't actually expand this attribute like
// normal (as that would just be an identity expansion with extra output)
// Instead we treat derive attributes special and apply them separately.
@ -1316,16 +1330,6 @@ impl DefCollector<'_> {
let call_id =
attr_macro_as_call_id(self.db, file_ast_id, attr, self.def_map.krate, def);
// If proc attribute macro expansion is disabled, skip expanding it here
if !self.db.expand_proc_attr_macros() {
self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
directive.module_id,
self.db.lookup_intern_macro_call(call_id).kind,
def.krate,
));
return recollect_without(self);
}
// Skip #[test]/#[bench] expansion, which would merely result in more memory usage
// due to duplicating functions into macro expansions
if matches!(
@ -1337,17 +1341,29 @@ impl DefCollector<'_> {
}
if let MacroDefKind::ProcMacro(exp, ..) = def.kind {
if exp.is_dummy() {
// If there's no expander for the proc macro (e.g.
// because proc macros are disabled, or building the
// proc macro crate failed), report this and skip
// expansion like we would if it was disabled
// If proc attribute macro expansion is disabled, skip expanding it here
if !self.db.expand_proc_attr_macros() {
self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
directive.module_id,
self.db.lookup_intern_macro_call(call_id).kind,
def.krate,
));
return recollect_without(self);
}
// If there's no expander for the proc macro (e.g.
// because proc macros are disabled, or building the
// proc macro crate failed), report this and skip
// expansion like we would if it was disabled
if exp.is_dummy() {
self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
directive.module_id,
self.db.lookup_intern_macro_call(call_id).kind,
def.krate,
));
return recollect_without(self);
}
if exp.is_disabled() {
return recollect_without(self);
}
}
@ -1358,12 +1374,13 @@ impl DefCollector<'_> {
push_resolved(directive, call_id);
res = ReachedFixedPoint::No;
return false;
return Resolved::Yes;
}
}
true
});
Resolved::No
};
macros.retain(|it| retain(it) == Resolved::No);
// Attribute resolution can add unresolved macro invocations, so concatenate the lists.
macros.extend(mem::take(&mut self.unresolved_macros));
self.unresolved_macros = macros;
@ -1673,7 +1690,11 @@ impl ModCollector<'_, '_> {
FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db);
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
if self.def_collector.is_proc_macro && self.module_id == DefMap::ROOT {
if self.def_collector.def_map.block.is_none()
&& self.def_collector.is_proc_macro
&& self.module_id == DefMap::ROOT
{
if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) {
self.def_collector.export_proc_macro(
proc_macro,
@ -2333,7 +2354,7 @@ impl ModCollector<'_, '_> {
resolved_res.resolved_def.take_macros().map(|it| db.macro_def(it))
},
) {
// FIXME: if there were errors, this mightve been in the eager expansion from an
// FIXME: if there were errors, this might've been in the eager expansion from an
// unresolved macro, so we need to push this into late macro resolution. see fixme above
if res.err.is_none() {
// Legacy macros need to be expanded immediately, so that any macros they produce

View file

@ -103,6 +103,9 @@ impl DefDiagnostic {
}
// FIXME: Whats the difference between this and unresolved_macro_call
// FIXME: This is used for a lot of things, unresolved proc macros, disabled proc macros, etc
// yet the diagnostic handler in ide-diagnostics has to figure out what happened because this
// struct loses all that information!
pub(crate) fn unresolved_proc_macro(
container: LocalModuleId,
ast: MacroCallKind,