Skip to content

Commit

Permalink
feat: method resolution (#561)
Browse files Browse the repository at this point in the history
  • Loading branch information
baszalmstra authored Apr 15, 2024
1 parent fb97219 commit 45b92db
Show file tree
Hide file tree
Showing 8 changed files with 488 additions and 12 deletions.
2 changes: 1 addition & 1 deletion crates/mun_hir/src/code_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub use self::{
function::{Function, FunctionData},
module::{Module, ModuleDef},
package::Package,
r#impl::ImplData,
r#impl::{AssocItem, Impl, ImplData},
r#struct::{Field, Struct, StructData, StructKind, StructMemoryKind},
src::HasSource,
type_alias::{TypeAlias, TypeAliasData},
Expand Down
27 changes: 23 additions & 4 deletions crates/mun_hir/src/code_model/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::{
type_ref::{LocalTypeRefId, TypeRefMap, TypeRefSourceMap},
visibility::RawVisibility,
Body, DefDatabase, DiagnosticSink, FileId, HasSource, HasVisibility, HirDatabase, InFile,
InferenceResult, Name, Ty, Visibility,
InferenceResult, Name, Pat, Ty, Visibility,
};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
Expand Down Expand Up @@ -96,6 +96,11 @@ impl FunctionData {
pub fn type_ref_map(&self) -> &TypeRefMap {
&self.type_ref_map
}

/// Returns true if this function is an extern function.
pub fn is_extern(&self) -> bool {
self.is_extern
}
}

impl Function {
Expand Down Expand Up @@ -214,12 +219,26 @@ impl Param {
.nth(self.idx)
.map(|value| InFile { file_id, value })
}

/// Returns the name of the parameter.
///
/// Only if the parameter is a named binding will this function return a
/// name. If the function parameter is a wildcard for instance then this
/// function will return `None`.
pub fn name(&self, db: &dyn HirDatabase) -> Option<Name> {
let body = self.func.body(db);
let pat_id = body.params().get(self.idx)?.0;
let pat = &body[pat_id];
if let Pat::Bind { name, .. } = pat {
Some(name.clone())
} else {
None
}
}
}

impl HasVisibility for Function {
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
self.data(db.upcast())
.visibility
.resolve(db.upcast(), &self.id.resolver(db.upcast()))
db.function_visibility(self.id)
}
}
6 changes: 5 additions & 1 deletion crates/mun_hir/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ use crate::{
name_resolution::Namespace,
package_defs::PackageDefs,
ty::{lower::LowerTyMap, CallableDef, FnSig, InferenceResult, Ty, TypableDef},
AstIdMap, Body, ExprScopes, FileId, PackageId, PackageSet, Struct, TypeAlias,
visibility, AstIdMap, Body, ExprScopes, FileId, PackageId, PackageSet, Struct, TypeAlias,
Visibility,
};

// TODO(bas): In the future maybe move this to a seperate crate (mun_db?)
Expand Down Expand Up @@ -104,6 +105,9 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
#[salsa::invoke(crate::FunctionData::fn_data_query)]
fn fn_data(&self, func: FunctionId) -> Arc<FunctionData>;

#[salsa::invoke(visibility::function_visibility_query)]
fn function_visibility(&self, def: FunctionId) -> Visibility;

/// Returns the `PackageDefs` for the specified `PackageId`. The
/// `PackageDefs` contains all resolved items defined for every module
/// in the package.
Expand Down
106 changes: 105 additions & 1 deletion crates/mun_hir/src/display.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
use std::fmt;

use crate::db::HirDatabase;
use crate::{
code_model::AssocItem,
db::HirDatabase,
type_ref::{LocalTypeRefId, TypeRef, TypeRefMap},
Function, HasVisibility, ModuleId, Visibility,
};

pub struct HirFormatter<'a, 'b> {
pub db: &'a dyn HirDatabase,
Expand Down Expand Up @@ -50,3 +55,102 @@ where
self.1.hir_fmt(&mut HirFormatter { db: self.0, fmt: f })
}
}

impl HirDisplay for AssocItem {
fn hir_fmt(&self, f: &mut HirFormatter<'_, '_>) -> fmt::Result {
match self {
AssocItem::Function(fun) => fun.hir_fmt(f),
}
}
}

impl HirDisplay for Function {
fn hir_fmt(&self, f: &mut HirFormatter<'_, '_>) -> fmt::Result {
let db = f.db;
let data = db.fn_data(self.id);
let module = self.module(db);
write_visiblity(module.id, self.visibility(db), f)?;
if data.is_extern() {
write!(f, "extern ")?;
}
write!(f, "fn {}(", self.name(db))?;

let type_map = data.type_ref_map();
for (idx, (&type_ref_id, param)) in data.params().iter().zip(self.params(db)).enumerate() {
let name = param.name(db);
if idx != 0 {
write!(f, ", ")?;
}
match name {
Some(name) => write!(f, "{name}: ")?,
None => write!(f, "_: ")?,
}
write_type_ref(type_ref_id, type_map, f)?;
}

write!(f, ")")?;

let ret_type_id = *data.ret_type();
match &type_map[ret_type_id] {
TypeRef::Tuple(elems) if elems.is_empty() => {}
_ => {
write!(f, " -> ")?;
write_type_ref(ret_type_id, type_map, f)?;
}
}

Ok(())
}
}

fn write_type_ref(
type_ref_id: LocalTypeRefId,
container: &TypeRefMap,
f: &mut HirFormatter<'_, '_>,
) -> fmt::Result {
let type_ref = &container[type_ref_id];
match type_ref {
TypeRef::Path(path) => write!(f, "{path}"),
TypeRef::Array(element_ty) => {
write!(f, "[")?;
write_type_ref(*element_ty, container, f)?;
write!(f, "]")
}
TypeRef::Never => write!(f, "!"),
TypeRef::Tuple(elems) => {
write!(f, "(")?;
for (idx, elem) in elems.iter().enumerate() {
if idx != 0 {
write!(f, ", ")?;
}
write_type_ref(*elem, container, f)?;
}
write!(f, ")")
}
TypeRef::Error => write!(f, "{{error}}"),
}
}

/// Writes the visibility of an item to the formatter.
fn write_visiblity(
module_id: ModuleId,
vis: Visibility,
f: &mut HirFormatter<'_, '_>,
) -> fmt::Result {
match vis {
Visibility::Public => write!(f, "pub "),
Visibility::Module(vis_id) => {
let module_tree = f.db.module_tree(module_id.package);
if module_id == vis_id {
// Only visible to self
Ok(())
} else if vis_id.local_id == module_tree.root {
write!(f, "pub(package) ")
} else if module_tree[module_id.local_id].parent == Some(vis_id.local_id) {
write!(f, "pub(super) ")
} else {
write!(f, "pub(in ...) ")
}
}
}
}
Loading

0 comments on commit 45b92db

Please sign in to comment.