mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-30 02:33:55 +00:00
Auto merge of #15350 - max-heller:issue-11756, r=Veykril
Handle `#[cfg]`s on generic parameters Records attributes on generic parameters in the item tree and filters out generic parameters disabled by `#[cfg]`s in `generic_params_query`. Closes #11756
This commit is contained in:
commit
f98d654ddf
@ -21,6 +21,7 @@ use crate::{
|
||||
db::DefDatabase,
|
||||
dyn_map::{keys, DynMap},
|
||||
expander::Expander,
|
||||
item_tree::{AttrOwner, ItemTree},
|
||||
lower::LowerCtx,
|
||||
nameres::{DefMap, MacroSubNs},
|
||||
src::{HasChildSource, HasSource},
|
||||
@ -154,12 +155,58 @@ impl GenericParams {
|
||||
def: GenericDefId,
|
||||
) -> Interned<GenericParams> {
|
||||
let _p = profile::span("generic_params_query");
|
||||
|
||||
let krate = def.module(db).krate;
|
||||
let cfg_options = db.crate_graph();
|
||||
let cfg_options = &cfg_options[krate].cfg_options;
|
||||
|
||||
// Returns the generic parameters that are enabled under the current `#[cfg]` options
|
||||
let enabled_params = |params: &Interned<GenericParams>, item_tree: &ItemTree| {
|
||||
let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options);
|
||||
|
||||
// In the common case, no parameters will by disabled by `#[cfg]` attributes.
|
||||
// Therefore, make a first pass to check if all parameters are enabled and, if so,
|
||||
// clone the `Interned<GenericParams>` instead of recreating an identical copy.
|
||||
let all_type_or_consts_enabled =
|
||||
params.type_or_consts.iter().all(|(idx, _)| enabled(idx.into()));
|
||||
let all_lifetimes_enabled = params.lifetimes.iter().all(|(idx, _)| enabled(idx.into()));
|
||||
|
||||
if all_type_or_consts_enabled && all_lifetimes_enabled {
|
||||
params.clone()
|
||||
} else {
|
||||
Interned::new(GenericParams {
|
||||
type_or_consts: all_type_or_consts_enabled
|
||||
.then(|| params.type_or_consts.clone())
|
||||
.unwrap_or_else(|| {
|
||||
params
|
||||
.type_or_consts
|
||||
.iter()
|
||||
.filter_map(|(idx, param)| {
|
||||
enabled(idx.into()).then(|| param.clone())
|
||||
})
|
||||
.collect()
|
||||
}),
|
||||
lifetimes: all_lifetimes_enabled
|
||||
.then(|| params.lifetimes.clone())
|
||||
.unwrap_or_else(|| {
|
||||
params
|
||||
.lifetimes
|
||||
.iter()
|
||||
.filter_map(|(idx, param)| {
|
||||
enabled(idx.into()).then(|| param.clone())
|
||||
})
|
||||
.collect()
|
||||
}),
|
||||
where_predicates: params.where_predicates.clone(),
|
||||
})
|
||||
}
|
||||
};
|
||||
macro_rules! id_to_generics {
|
||||
($id:ident) => {{
|
||||
let id = $id.lookup(db).id;
|
||||
let tree = id.item_tree(db);
|
||||
let item = &tree[id.value];
|
||||
item.generic_params.clone()
|
||||
enabled_params(&item.generic_params, &tree)
|
||||
}};
|
||||
}
|
||||
|
||||
@ -169,7 +216,8 @@ impl GenericParams {
|
||||
let tree = loc.id.item_tree(db);
|
||||
let item = &tree[loc.id.value];
|
||||
|
||||
let mut generic_params = GenericParams::clone(&item.explicit_generic_params);
|
||||
let enabled_params = enabled_params(&item.explicit_generic_params, &tree);
|
||||
let mut generic_params = GenericParams::clone(&enabled_params);
|
||||
|
||||
let module = loc.container.module(db);
|
||||
let func_data = db.function_data(id);
|
||||
@ -198,9 +246,14 @@ impl GenericParams {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn fill(&mut self, lower_ctx: &LowerCtx<'_>, node: &dyn HasGenericParams) {
|
||||
pub(crate) fn fill(
|
||||
&mut self,
|
||||
lower_ctx: &LowerCtx<'_>,
|
||||
node: &dyn HasGenericParams,
|
||||
add_param_attrs: impl FnMut(AttrOwner, ast::GenericParam),
|
||||
) {
|
||||
if let Some(params) = node.generic_param_list() {
|
||||
self.fill_params(lower_ctx, params)
|
||||
self.fill_params(lower_ctx, params, add_param_attrs)
|
||||
}
|
||||
if let Some(where_clause) = node.where_clause() {
|
||||
self.fill_where_predicates(lower_ctx, where_clause);
|
||||
@ -218,7 +271,12 @@ impl GenericParams {
|
||||
}
|
||||
}
|
||||
|
||||
fn fill_params(&mut self, lower_ctx: &LowerCtx<'_>, params: ast::GenericParamList) {
|
||||
fn fill_params(
|
||||
&mut self,
|
||||
lower_ctx: &LowerCtx<'_>,
|
||||
params: ast::GenericParamList,
|
||||
mut add_param_attrs: impl FnMut(AttrOwner, ast::GenericParam),
|
||||
) {
|
||||
for type_or_const_param in params.type_or_const_params() {
|
||||
match type_or_const_param {
|
||||
ast::TypeOrConstParam::Type(type_param) => {
|
||||
@ -232,13 +290,14 @@ impl GenericParams {
|
||||
default,
|
||||
provenance: TypeParamProvenance::TypeParamList,
|
||||
};
|
||||
self.type_or_consts.alloc(param.into());
|
||||
let idx = self.type_or_consts.alloc(param.into());
|
||||
let type_ref = TypeRef::Path(name.into());
|
||||
self.fill_bounds(
|
||||
lower_ctx,
|
||||
type_param.type_bound_list(),
|
||||
Either::Left(type_ref),
|
||||
);
|
||||
add_param_attrs(idx.into(), ast::GenericParam::TypeParam(type_param));
|
||||
}
|
||||
ast::TypeOrConstParam::Const(const_param) => {
|
||||
let name = const_param.name().map_or_else(Name::missing, |it| it.as_name());
|
||||
@ -250,7 +309,8 @@ impl GenericParams {
|
||||
ty: Interned::new(ty),
|
||||
has_default: const_param.default_val().is_some(),
|
||||
};
|
||||
self.type_or_consts.alloc(param.into());
|
||||
let idx = self.type_or_consts.alloc(param.into());
|
||||
add_param_attrs(idx.into(), ast::GenericParam::ConstParam(const_param));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -258,13 +318,14 @@ impl GenericParams {
|
||||
let name =
|
||||
lifetime_param.lifetime().map_or_else(Name::missing, |lt| Name::new_lifetime(<));
|
||||
let param = LifetimeParamData { name: name.clone() };
|
||||
self.lifetimes.alloc(param);
|
||||
let idx = self.lifetimes.alloc(param);
|
||||
let lifetime_ref = LifetimeRef::new_name(name);
|
||||
self.fill_bounds(
|
||||
lower_ctx,
|
||||
lifetime_param.type_bound_list(),
|
||||
Either::Right(lifetime_ref),
|
||||
);
|
||||
add_param_attrs(idx.into(), ast::GenericParam::LifetimeParam(lifetime_param));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,7 +64,7 @@ use triomphe::Arc;
|
||||
use crate::{
|
||||
attr::Attrs,
|
||||
db::DefDatabase,
|
||||
generics::GenericParams,
|
||||
generics::{GenericParams, LifetimeParamData, TypeOrConstParamData},
|
||||
path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind},
|
||||
type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
|
||||
visibility::RawVisibility,
|
||||
@ -296,10 +296,12 @@ pub enum AttrOwner {
|
||||
Variant(Idx<Variant>),
|
||||
Field(Idx<Field>),
|
||||
Param(Idx<Param>),
|
||||
TypeOrConstParamData(Idx<TypeOrConstParamData>),
|
||||
LifetimeParamData(Idx<LifetimeParamData>),
|
||||
}
|
||||
|
||||
macro_rules! from_attrs {
|
||||
( $( $var:ident($t:ty) ),+ ) => {
|
||||
( $( $var:ident($t:ty) ),+ $(,)? ) => {
|
||||
$(
|
||||
impl From<$t> for AttrOwner {
|
||||
fn from(t: $t) -> AttrOwner {
|
||||
@ -310,7 +312,14 @@ macro_rules! from_attrs {
|
||||
};
|
||||
}
|
||||
|
||||
from_attrs!(ModItem(ModItem), Variant(Idx<Variant>), Field(Idx<Field>), Param(Idx<Param>));
|
||||
from_attrs!(
|
||||
ModItem(ModItem),
|
||||
Variant(Idx<Variant>),
|
||||
Field(Idx<Field>),
|
||||
Param(Idx<Param>),
|
||||
TypeOrConstParamData(Idx<TypeOrConstParamData>),
|
||||
LifetimeParamData(Idx<LifetimeParamData>),
|
||||
);
|
||||
|
||||
/// Trait implemented by all item nodes in the item tree.
|
||||
pub trait ItemTreeNode: Clone {
|
||||
|
@ -602,7 +602,21 @@ impl<'a> Ctx<'a> {
|
||||
generics.fill_bounds(&self.body_ctx, bounds, Either::Left(self_param));
|
||||
}
|
||||
|
||||
generics.fill(&self.body_ctx, node);
|
||||
let add_param_attrs = |item, param| {
|
||||
let attrs = RawAttrs::new(self.db.upcast(), ¶m, self.body_ctx.hygiene());
|
||||
// This is identical to the body of `Ctx::add_attrs()` but we can't call that here
|
||||
// because it requires `&mut self` and the call to `generics.fill()` below also
|
||||
// references `self`.
|
||||
match self.tree.attrs.entry(item) {
|
||||
Entry::Occupied(mut entry) => {
|
||||
*entry.get_mut() = entry.get().merge(attrs);
|
||||
}
|
||||
Entry::Vacant(entry) => {
|
||||
entry.insert(attrs);
|
||||
}
|
||||
}
|
||||
};
|
||||
generics.fill(&self.body_ctx, node, add_param_attrs);
|
||||
|
||||
generics.shrink_to_fit();
|
||||
Interned::new(generics)
|
||||
|
@ -16,7 +16,7 @@ pub(super) fn print_item_tree(db: &dyn ExpandDatabase, tree: &ItemTree) -> Strin
|
||||
let mut p = Printer { db, tree, buf: String::new(), indent_level: 0, needs_indent: true };
|
||||
|
||||
if let Some(attrs) = tree.attrs.get(&AttrOwner::TopLevel) {
|
||||
p.print_attrs(attrs, true);
|
||||
p.print_attrs(attrs, true, "\n");
|
||||
}
|
||||
p.blank();
|
||||
|
||||
@ -84,22 +84,23 @@ impl Printer<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
fn print_attrs(&mut self, attrs: &RawAttrs, inner: bool) {
|
||||
fn print_attrs(&mut self, attrs: &RawAttrs, inner: bool, separated_by: &str) {
|
||||
let inner = if inner { "!" } else { "" };
|
||||
for attr in &**attrs {
|
||||
wln!(
|
||||
w!(
|
||||
self,
|
||||
"#{}[{}{}]",
|
||||
"#{}[{}{}]{}",
|
||||
inner,
|
||||
attr.path.display(self.db),
|
||||
attr.input.as_ref().map(|it| it.to_string()).unwrap_or_default(),
|
||||
separated_by,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn print_attrs_of(&mut self, of: impl Into<AttrOwner>) {
|
||||
fn print_attrs_of(&mut self, of: impl Into<AttrOwner>, separated_by: &str) {
|
||||
if let Some(attrs) = self.tree.attrs.get(&of.into()) {
|
||||
self.print_attrs(attrs, false);
|
||||
self.print_attrs(attrs, false, separated_by);
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,7 +119,7 @@ impl Printer<'_> {
|
||||
self.indented(|this| {
|
||||
for field in fields.clone() {
|
||||
let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field];
|
||||
this.print_attrs_of(field);
|
||||
this.print_attrs_of(field, "\n");
|
||||
this.print_visibility(*visibility);
|
||||
w!(this, "{}: ", name.display(self.db));
|
||||
this.print_type_ref(type_ref);
|
||||
@ -132,7 +133,7 @@ impl Printer<'_> {
|
||||
self.indented(|this| {
|
||||
for field in fields.clone() {
|
||||
let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field];
|
||||
this.print_attrs_of(field);
|
||||
this.print_attrs_of(field, "\n");
|
||||
this.print_visibility(*visibility);
|
||||
w!(this, "{}: ", name.display(self.db));
|
||||
this.print_type_ref(type_ref);
|
||||
@ -195,7 +196,7 @@ impl Printer<'_> {
|
||||
}
|
||||
|
||||
fn print_mod_item(&mut self, item: ModItem) {
|
||||
self.print_attrs_of(item);
|
||||
self.print_attrs_of(item, "\n");
|
||||
|
||||
match item {
|
||||
ModItem::Use(it) => {
|
||||
@ -261,7 +262,7 @@ impl Printer<'_> {
|
||||
if !params.is_empty() {
|
||||
self.indented(|this| {
|
||||
for param in params.clone() {
|
||||
this.print_attrs_of(param);
|
||||
this.print_attrs_of(param, "\n");
|
||||
match &this.tree[param] {
|
||||
Param::Normal(ty) => {
|
||||
if flags.contains(FnFlags::HAS_SELF_PARAM) {
|
||||
@ -319,7 +320,7 @@ impl Printer<'_> {
|
||||
self.indented(|this| {
|
||||
for variant in variants.clone() {
|
||||
let Variant { name, fields, ast_id: _ } = &this.tree[variant];
|
||||
this.print_attrs_of(variant);
|
||||
this.print_attrs_of(variant, "\n");
|
||||
w!(this, "{}", name.display(self.db));
|
||||
this.print_fields(fields);
|
||||
wln!(this, ",");
|
||||
@ -484,11 +485,12 @@ impl Printer<'_> {
|
||||
|
||||
w!(self, "<");
|
||||
let mut first = true;
|
||||
for (_, lt) in params.lifetimes.iter() {
|
||||
for (idx, lt) in params.lifetimes.iter() {
|
||||
if !first {
|
||||
w!(self, ", ");
|
||||
}
|
||||
first = false;
|
||||
self.print_attrs_of(idx, " ");
|
||||
w!(self, "{}", lt.name.display(self.db));
|
||||
}
|
||||
for (idx, x) in params.type_or_consts.iter() {
|
||||
@ -496,6 +498,7 @@ impl Printer<'_> {
|
||||
w!(self, ", ");
|
||||
}
|
||||
first = false;
|
||||
self.print_attrs_of(idx, " ");
|
||||
match x {
|
||||
TypeOrConstParamData::TypeParamData(ty) => match &ty.name {
|
||||
Some(name) => w!(self, "{}", name.display(self.db)),
|
||||
|
@ -358,3 +358,15 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {}
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generics_with_attributes() {
|
||||
check(
|
||||
r#"
|
||||
struct S<#[cfg(never)] T>;
|
||||
"#,
|
||||
expect![[r#"
|
||||
pub(self) struct S<#[cfg(never)] T>;
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
@ -6469,3 +6469,22 @@ fn test() {
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generic_params_disabled_by_cfg() {
|
||||
check(
|
||||
r#"
|
||||
struct S<#[cfg(never)] T>;
|
||||
fn test() {
|
||||
let s$0: S = S;
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
*s*
|
||||
|
||||
```rust
|
||||
let s: S // size = 0, align = 1
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user