Skip to content

Commit

Permalink
Auto merge of rust-lang#14185 - anergictcell:fix_14142, r=HKalbasi
Browse files Browse the repository at this point in the history
Fix: Run doctests for structs with lifetime parameters from IDE

Fixes rust-lang#14142: Doctests can't be triggered for structs with lifetimes

This MR adds lifetime parameters to the structs path for runnables so that they can be triggered from an IDE as well.

This is my first MR for rust-analyzer, please let me know if I should change something, either in code or the description here.
  • Loading branch information
bors committed Feb 28, 2023
2 parents a0be16b + af79491 commit c386316
Show file tree
Hide file tree
Showing 3 changed files with 370 additions and 10 deletions.
7 changes: 7 additions & 0 deletions crates/hir-def/src/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,13 @@ impl Resolver {
})
}

pub fn generic_params(&self) -> Option<&Interned<GenericParams>> {
self.scopes().find_map(|scope| match scope {
Scope::GenericParams { params, .. } => Some(params),
_ => None,
})
}

pub fn body_owner(&self) -> Option<DefWithBodyId> {
self.scopes().find_map(|scope| match scope {
Scope::ExprScope(it) => Some(it.owner),
Expand Down
91 changes: 90 additions & 1 deletion crates/hir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ use hir_def::{
adt::VariantData,
body::{BodyDiagnostic, SyntheticSyntax},
expr::{BindingAnnotation, ExprOrPatId, LabelId, Pat, PatId},
generics::{TypeOrConstParamData, TypeParamProvenance},
generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance},
item_tree::ItemTreeNode,
lang_item::{LangItem, LangItemTarget},
layout::{Layout, LayoutError, ReprOptions},
Expand Down Expand Up @@ -1170,6 +1170,25 @@ impl Adt {
}
}

/// Returns the lifetime of the DataType
pub fn lifetime(&self, db: &dyn HirDatabase) -> Option<LifetimeParamData> {
let resolver = match self {
Adt::Struct(s) => s.id.resolver(db.upcast()),
Adt::Union(u) => u.id.resolver(db.upcast()),
Adt::Enum(e) => e.id.resolver(db.upcast()),
};
resolver
.generic_params()
.and_then(|gp| {
(&gp.lifetimes)
.iter()
// there should only be a single lifetime
// but `Arena` requires to use an iterator
.nth(0)
})
.map(|arena| arena.1.clone())
}

pub fn as_enum(&self) -> Option<Enum> {
if let Self::Enum(v) = self {
Some(*v)
Expand Down Expand Up @@ -3332,6 +3351,24 @@ impl Type {
}
}

/// Iterates its type arguments
///
/// It iterates the actual type arguments when concrete types are used
/// and otherwise the generic names.
/// It does not include `const` arguments.
///
/// For code, such as:
/// ```text
/// struct Foo<T, U>
///
/// impl<U> Foo<String, U>
/// ```
///
/// It iterates:
/// ```text
/// - "String"
/// - "U"
/// ```
pub fn type_arguments(&self) -> impl Iterator<Item = Type> + '_ {
self.ty
.strip_references()
Expand All @@ -3342,6 +3379,58 @@ impl Type {
.map(move |ty| self.derived(ty))
}

/// Iterates its type and const arguments
///
/// It iterates the actual type and const arguments when concrete types
/// are used and otherwise the generic names.
///
/// For code, such as:
/// ```text
/// struct Foo<T, const U: usize, const X: usize>
///
/// impl<U> Foo<String, U, 12>
/// ```
///
/// It iterates:
/// ```text
/// - "String"
/// - "U"
/// - "12"
/// ```
pub fn type_and_const_arguments<'a>(
&'a self,
db: &'a dyn HirDatabase,
) -> impl Iterator<Item = SmolStr> + 'a {
self.ty
.strip_references()
.as_adt()
.into_iter()
.flat_map(|(_, substs)| substs.iter(Interner))
.filter_map(|arg| {
// arg can be either a `Ty` or `constant`
if let Some(ty) = arg.ty(Interner) {
Some(SmolStr::new(ty.display(db).to_string()))
} else if let Some(const_) = arg.constant(Interner) {
Some(SmolStr::new_inline(&const_.display(db).to_string()))
} else {
None
}
})
}

/// Combines lifetime indicators, type and constant parameters into a single `Iterator`
pub fn generic_parameters<'a>(
&'a self,
db: &'a dyn HirDatabase,
) -> impl Iterator<Item = SmolStr> + 'a {
// iterate the lifetime
self.as_adt()
.and_then(|a| a.lifetime(db).and_then(|lt| Some((&lt.name).to_smol_str())))
.into_iter()
// add the type and const paramaters
.chain(self.type_and_const_arguments(db))
}

pub fn iterate_method_candidates_with_traits<T>(
&self,
db: &dyn HirDatabase,
Expand Down
Loading

0 comments on commit c386316

Please sign in to comment.