Skip to content

Commit c648884

Browse files
committed
Differentiate method/tymethod by determining 'defaultness'
Currently a method only has defaultness if it is a provided trait method, but this will change when specialisation is available and may need to become a concept known to hir. I opted to go for a 'fewest changes' approach given specialisation is still under development.
1 parent 62b76e7 commit c648884

File tree

7 files changed

+31
-9
lines changed

7 files changed

+31
-9
lines changed

crates/hir/src/code_model.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -772,7 +772,14 @@ impl Function {
772772
hir_ty::diagnostics::validate_body(db, self.id.into(), sink)
773773
}
774774

775-
pub fn parent_def(self, db: &dyn HirDatabase) -> Option<MethodOwner> {
775+
/// Whether this function declaration has a definition.
776+
///
777+
/// This is false in the case of required (not provided) trait methods.
778+
pub fn has_body(self, db: &dyn HirDatabase) -> bool {
779+
db.function_data(self.id).has_body
780+
}
781+
782+
pub fn method_owner(self, db: &dyn HirDatabase) -> Option<MethodOwner> {
776783
match self.as_assoc_item(db).map(|assoc| assoc.container(db)) {
777784
Some(AssocItemContainer::Trait(t)) => Some(t.into()),
778785
Some(AssocItemContainer::ImplDef(imp)) => {

crates/hir/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ pub use crate::{
3535
code_model::{
3636
Access, Adt, AsAssocItem, AssocItem, AssocItemContainer, Callable, CallableKind, Const,
3737
Crate, CrateDependency, DefWithBody, Enum, EnumVariant, Field, FieldSource, Function,
38-
GenericDef, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, ScopeDef, Static,
39-
Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility,
38+
GenericDef, HasVisibility, ImplDef, Local, MacroDef, MethodOwner, Module, ModuleDef,
39+
ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility,
4040
},
4141
has_source::HasSource,
4242
semantics::{original_range, PathResolution, Semantics, SemanticsScope},

crates/hir_def/src/data.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub struct FunctionData {
2525
/// True if the first param is `self`. This is relevant to decide whether this
2626
/// can be called as a method.
2727
pub has_self_param: bool,
28+
pub has_body: bool,
2829
pub is_unsafe: bool,
2930
pub is_varargs: bool,
3031
pub visibility: RawVisibility,
@@ -42,6 +43,7 @@ impl FunctionData {
4243
ret_type: func.ret_type.clone(),
4344
attrs: item_tree.attrs(ModItem::from(loc.id.value).into()).clone(),
4445
has_self_param: func.has_self_param,
46+
has_body: func.has_body,
4547
is_unsafe: func.is_unsafe,
4648
is_varargs: func.is_varargs,
4749
visibility: item_tree[func.visibility].clone(),

crates/hir_def/src/item_tree.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,7 @@ pub struct Function {
505505
pub visibility: RawVisibilityId,
506506
pub generic_params: GenericParamsId,
507507
pub has_self_param: bool,
508+
pub has_body: bool,
508509
pub is_unsafe: bool,
509510
pub params: Box<[TypeRef]>,
510511
pub is_varargs: bool,

crates/hir_def/src/item_tree/lower.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,12 +330,15 @@ impl Ctx {
330330
ret_type
331331
};
332332

333+
let has_body = func.body().is_some();
334+
333335
let ast_id = self.source_ast_id_map.ast_id(func);
334336
let mut res = Function {
335337
name,
336338
visibility,
337339
generic_params: GenericParamsId::EMPTY,
338340
has_self_param,
341+
has_body,
339342
is_unsafe: func.unsafe_token().is_some(),
340343
params: params.into_boxed_slice(),
341344
is_varargs,

crates/ide/src/doc_links.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use ide_db::{defs::Definition, RootDatabase};
1313

1414
use hir::{
1515
db::{DefDatabase, HirDatabase},
16-
Adt, AsName, AssocItem, Crate, Field, HasAttrs, ItemInNs, ModuleDef,
16+
Adt, AsName, AssocItem, Crate, Field, HasAttrs, ItemInNs, MethodOwner, ModuleDef,
1717
};
1818
use ide_db::{
1919
defs::{classify_name, classify_name_ref, Definition},
@@ -117,7 +117,7 @@ fn get_doc_link(db: &RootDatabase, definition: Definition) -> Option<String> {
117117
let target_def: ModuleDef = match definition {
118118
Definition::ModuleDef(moddef) => match moddef {
119119
ModuleDef::Function(f) => {
120-
f.parent_def(db).map(|mowner| mowner.into()).unwrap_or_else(|| f.clone().into())
120+
f.method_owner(db).map(|mowner| mowner.into()).unwrap_or_else(|| f.clone().into())
121121
}
122122
moddef => moddef,
123123
},
@@ -401,9 +401,18 @@ fn get_symbol_fragment(db: &dyn HirDatabase, field_or_assoc: &FieldOrAssocItem)
401401
Some(match field_or_assoc {
402402
FieldOrAssocItem::Field(field) => format!("#structfield.{}", field.name(db)),
403403
FieldOrAssocItem::AssocItem(assoc) => match assoc {
404-
// TODO: Rustdoc sometimes uses tymethod instead of method. This case needs to be investigated.
405-
AssocItem::Function(function) => format!("#method.{}", function.name(db)),
406-
// TODO: This might be the old method for documenting associated constants, i32::MAX uses a separate page...
404+
AssocItem::Function(function) => {
405+
let is_trait_method =
406+
matches!(function.method_owner(db), Some(MethodOwner::Trait(..)));
407+
// This distinction may get more complicated when specialisation is available.
408+
// In particular this decision is made based on whether a method 'has defaultness'.
409+
// Currently this is only the case for provided trait methods.
410+
if is_trait_method && !function.has_body(db) {
411+
format!("#tymethod.{}", function.name(db))
412+
} else {
413+
format!("#method.{}", function.name(db))
414+
}
415+
}
407416
AssocItem::Const(constant) => format!("#associatedconstant.{}", constant.name(db)?),
408417
AssocItem::TypeAlias(ty) => format!("#associatedtype.{}", ty.name(db)),
409418
},

editors/code/src/commands.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ export function openDocs(ctx: Ctx): Cmd {
425425
const client = ctx.client;
426426
const editor = vscode.window.activeTextEditor;
427427
if (!editor || !client) {
428-
return
428+
return;
429429
};
430430

431431
const position = editor.selection.active;

0 commit comments

Comments
 (0)