Skip to content

Commit

Permalink
feat: assoc method completion
Browse files Browse the repository at this point in the history
  • Loading branch information
baszalmstra committed Jan 7, 2025
1 parent 3d70e0e commit c7c9f39
Show file tree
Hide file tree
Showing 29 changed files with 695 additions and 331 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions crates/mun_hir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub use crate::{
ArithOp, BinaryOp, Body, CmpOp, Expr, ExprId, ExprScopes, Literal, LogicOp, Ordering, Pat,
PatId, RecordLitField, Statement, UnaryOp,
},
ids::ItemLoc,
ids::{AssocItemId, ItemLoc},
in_file::InFile,
name::Name,
name_resolution::PerNs,
Expand Down Expand Up @@ -62,7 +62,7 @@ mod utils;

mod has_module;
mod item_scope;
mod method_resolution;
pub mod method_resolution;
#[cfg(test)]
mod mock;
mod package_defs;
Expand Down
20 changes: 20 additions & 0 deletions crates/mun_hir/src/semantics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ use crate::{
HirDatabase, InFile, ModuleDef, Name, PatId, PerNs, Resolver, Ty, Visibility,
};

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum PathResolution {
/// An item
Def(ModuleDef),
/// A local binding (only value namespace)
Local(Local),
SelfType(Impl),
}

/// The primary API to get semantic information, like types, from syntax trees.
/// Exposes the database it was created with through the `db` field.
pub struct Semantics<'db> {
Expand Down Expand Up @@ -147,6 +156,11 @@ impl<'db> Semantics<'db> {
});
InFile::new(file_id, node)
}

/// Resolves the specified `ast::Path`
pub fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> {
self.analyze(path.syntax()).resolve_path(self.db, path)
}
}

/// Returns the root node of the specified node.
Expand Down Expand Up @@ -201,6 +215,12 @@ pub struct Impl {
pub(crate) id: ImplId,
}

impl From<ImplId> for Impl {
fn from(id: ImplId) -> Self {
Impl { id }
}

Check warning on line 221 in crates/mun_hir/src/semantics.rs

View check run for this annotation

Codecov / codecov/patch

crates/mun_hir/src/semantics.rs#L219-L221

Added lines #L219 - L221 were not covered by tests
}

impl Impl {
pub fn self_ty(self, db: &dyn HirDatabase) -> Ty {
db.type_for_impl_self(self.id)
Expand Down
50 changes: 48 additions & 2 deletions crates/mun_hir/src/source_analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ use mun_syntax::{ast, AstNode, SyntaxNode, TextRange, TextSize};
use crate::{
expr::{scope::LocalScopeId, BodySourceMap},
ids::DefWithBodyId,
resolver_for_scope, Body, ExprId, ExprScopes, HirDatabase, InFile, InferenceResult, Resolver,
Ty,
resolver_for_scope,
semantics::PathResolution,
Body, ExprId, ExprScopes, HirDatabase, InFile, InferenceResult, Path, Resolver, Struct, Ty,
TypeAlias, TypeNs,
};

/// A `SourceAnalyzer` is a wrapper which exposes the HIR API in terms of the
Expand Down Expand Up @@ -79,6 +81,22 @@ impl SourceAnalyzer {
let sm = self.body_source_map.as_ref()?;
sm.node_expr(expr)
}

pub(crate) fn resolve_path(
&self,
db: &dyn HirDatabase,
path: &ast::Path,
) -> Option<PathResolution> {
let hir_path = Path::from_ast(path.clone())?;

// Case where path is a qualifier of another path, e.g. foo::bar::Baz where we
// are trying to resolve foo::bar.
if path.parent_path().is_some() {
return resolve_hir_path_qualifier(db, &self.resolver, &hir_path);
}

None

Check warning on line 98 in crates/mun_hir/src/source_analyzer.rs

View check run for this annotation

Codecov / codecov/patch

crates/mun_hir/src/source_analyzer.rs#L96-L98

Added lines #L96 - L98 were not covered by tests
}
}

/// Returns the id of the scope that is active at the location of `node`.
Expand Down Expand Up @@ -173,3 +191,31 @@ fn adjust(
})
.map(|(_ptr, scope)| *scope)
}

/// Resolves a path where we know it is a qualifier of another path.
fn resolve_hir_path_qualifier(
db: &dyn HirDatabase,
resolver: &Resolver,
path: &Path,
) -> Option<PathResolution> {
let (ty, _, remaining_idx) = resolver.resolve_path_as_type(db.upcast(), path)?;
let (ty, _unresolved) = match remaining_idx {
Some(remaining_idx) => {
if remaining_idx + 1 == path.segments.len() {
Some((ty, path.segments.last()))

Check warning on line 205 in crates/mun_hir/src/source_analyzer.rs

View check run for this annotation

Codecov / codecov/patch

crates/mun_hir/src/source_analyzer.rs#L203-L205

Added lines #L203 - L205 were not covered by tests
} else {
None

Check warning on line 207 in crates/mun_hir/src/source_analyzer.rs

View check run for this annotation

Codecov / codecov/patch

crates/mun_hir/src/source_analyzer.rs#L207

Added line #L207 was not covered by tests
}
}
None => Some((ty, None)),
}?;

Check warning on line 211 in crates/mun_hir/src/source_analyzer.rs

View check run for this annotation

Codecov / codecov/patch

crates/mun_hir/src/source_analyzer.rs#L211

Added line #L211 was not covered by tests

let res = match ty {
TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),

Check warning on line 214 in crates/mun_hir/src/source_analyzer.rs

View check run for this annotation

Codecov / codecov/patch

crates/mun_hir/src/source_analyzer.rs#L214

Added line #L214 was not covered by tests
TypeNs::StructId(it) => PathResolution::Def(Struct::from(it).into()),
TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
TypeNs::PrimitiveType(it) => PathResolution::Def(it.into()),

Check warning on line 217 in crates/mun_hir/src/source_analyzer.rs

View check run for this annotation

Codecov / codecov/patch

crates/mun_hir/src/source_analyzer.rs#L216-L217

Added lines #L216 - L217 were not covered by tests
};

Some(res)
}
2 changes: 1 addition & 1 deletion crates/mun_hir/src/ty/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ pub mod diagnostics {
};

#[derive(Debug, PartialEq, Eq, Clone)]
pub(crate) enum LowerDiagnostic {
pub enum LowerDiagnostic {
UnresolvedType { id: LocalTypeRefId },
TypeIsPrivate { id: LocalTypeRefId },
}
Expand Down
1 change: 1 addition & 0 deletions crates/mun_language_server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@ mun_test = { path = "../mun_test"}
insta = { workspace = true }
itertools = { workspace = true }
tempdir = { workspace = true }
text_trees = { workspace = true }
38 changes: 31 additions & 7 deletions crates/mun_language_server/src/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,26 @@
//! completions.
mod context;
mod dot;
// mod dot;
mod item;
mod render;
mod unqualified_path;
// mod unqualified_path;

mod dot;
mod expr;
mod name_ref;
#[cfg(test)]
mod test_utils;

use context::CompletionContext;
use context::{
CompletionAnalysis, CompletionContext, DotAccess, NameRefContext, NameRefKind,
PathCompletionContext, PathExprContext, PathKind, Qualified,
};
pub use item::{CompletionItem, CompletionItemKind, CompletionKind};
use mun_hir::semantics::ScopeDef;

use crate::{
completion::render::{render_field, render_resolution, RenderContext},
completion::render::{render_field, render_fn, render_resolution, RenderContext},
db::AnalysisDatabase,
FilePosition,
};
Expand All @@ -36,11 +42,18 @@ use crate::{
/// complete the fields of `foo` and don't want the local variables of
/// the active scope.
pub(crate) fn completions(db: &AnalysisDatabase, position: FilePosition) -> Option<Completions> {
let context = CompletionContext::new(db, position)?;
let (context, analysis) = CompletionContext::new(db, position)?;

let mut result = Completions::default();
unqualified_path::complete_unqualified_path(&mut result, &context);
dot::complete_dot(&mut result, &context);

match analysis {
CompletionAnalysis::NameRef(name_ref_ctx) => {
name_ref::complete_name_ref(&mut result, &context, &name_ref_ctx);
}
}

// unqualified_path::complete_unqualified_path(&mut result, &context);
// dot::complete_dot(&mut result, &context);
Some(result)
}

Expand Down Expand Up @@ -80,4 +93,15 @@ impl Completions {
let item = render_field(RenderContext::new(ctx), field);
self.add(item);
}

fn add_function(
&mut self,
ctx: &CompletionContext<'_>,
func: mun_hir::Function,
local_name: Option<String>,
) {
if let Some(item) = render_fn(RenderContext::new(ctx), local_name, func) {
self.add(item);
}
}
}
146 changes: 0 additions & 146 deletions crates/mun_language_server/src/completion/context.rs

This file was deleted.

Loading

0 comments on commit c7c9f39

Please sign in to comment.