Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: parsing & hir of impl blocks #551

Merged
merged 4 commits into from
Jan 7, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions crates/mun_diagnostics/src/hir/duplicate_definition_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,10 @@ pub struct DuplicateDefinition<'db, 'diag, DB: mun_hir::HirDatabase> {

impl<'db, 'diag, DB: mun_hir::HirDatabase> Diagnostic for DuplicateDefinition<'db, 'diag, DB> {
fn range(&self) -> TextRange {
syntax_node_identifier_range(&self.diag.definition, &self.db.parse(self.diag.file))
syntax_node_identifier_range(
&self.diag.definition.value,
&self.db.parse(self.diag.definition.file_id),
)
}

fn title(&self) -> String {
Expand All @@ -99,8 +102,8 @@ impl<'db, 'diag, DB: mun_hir::HirDatabase> Diagnostic for DuplicateDefinition<'d
fn primary_annotation(&self) -> Option<SourceAnnotation> {
Some(SourceAnnotation {
range: syntax_node_signature_range(
&self.diag.definition,
&self.db.parse(self.diag.file),
&self.diag.definition.value,
&self.db.parse(self.diag.definition.file_id),
),
message: format!("`{}` redefined here", self.diag.name),
})
Expand All @@ -109,10 +112,10 @@ impl<'db, 'diag, DB: mun_hir::HirDatabase> Diagnostic for DuplicateDefinition<'d
fn secondary_annotations(&self) -> Vec<SecondaryAnnotation> {
vec![SecondaryAnnotation {
range: InFile::new(
self.diag.file,
self.diag.first_definition.file_id,
syntax_node_signature_range(
&self.diag.first_definition,
&self.db.parse(self.diag.file),
&self.diag.first_definition.value,
&self.db.parse(self.diag.first_definition.file_id),
),
),
message: format!(
Expand All @@ -135,7 +138,7 @@ impl<'db, 'diag, DB: mun_hir::HirDatabase> Diagnostic for DuplicateDefinition<'d
impl<'db, 'diag, DB: mun_hir::HirDatabase> DuplicateDefinition<'db, 'diag, DB> {
/// Returns either `type` or `value` definition on the type of definition.
fn value_or_type_string(&self) -> &'static str {
if self.diag.definition.kind() == SyntaxKind::STRUCT_DEF {
if self.diag.definition.value.kind() == SyntaxKind::STRUCT_DEF {
"type"
} else {
"value"
Expand Down
2 changes: 2 additions & 0 deletions crates/mun_hir/src/code_model.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod function;
mod r#impl;
mod module;
mod package;
pub(crate) mod src;
Expand All @@ -12,6 +13,7 @@ pub use self::{
function::Function,
module::{Module, ModuleDef},
package::Package,
r#impl::{Impl, ImplData},
r#struct::{Field, LocalFieldId, Struct, StructKind, StructMemoryKind},
src::HasSource,
type_alias::TypeAlias,
Expand Down
5 changes: 2 additions & 3 deletions crates/mun_hir/src/code_model/function.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::Module;
use crate::expr::validator::ExprValidator;
use crate::expr::BodySourceMap;
use crate::has_module::HasModule;
use crate::ids::{FunctionId, Lookup};
use crate::name_resolution::Namespace;
use crate::resolve::HasResolver;
Expand Down Expand Up @@ -99,9 +100,7 @@ impl FunctionData {

impl Function {
pub fn module(self, db: &dyn HirDatabase) -> Module {
Module {
id: self.id.lookup(db.upcast()).module,
}
self.id.module(db.upcast()).into()
}

/// Returns the full name of the function including all module specifiers (e.g: `foo::bar`).
Expand Down
118 changes: 118 additions & 0 deletions crates/mun_hir/src/code_model/impl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
use crate::has_module::HasModule;
use crate::ids::{AssocItemId, FunctionLoc, ImplId, Intern, ItemContainerId, Lookup};
use crate::item_tree::{AssociatedItem, ItemTreeId};
use crate::type_ref::{LocalTypeRefId, TypeRefMap, TypeRefMapBuilder, TypeRefSourceMap};
use crate::{DefDatabase, FileId, Function, HirDatabase, ItemLoc, Module, Package, Ty};
use std::sync::Arc;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]

Check warning on line 8 in crates/mun_hir/src/code_model/impl.rs

View check run for this annotation

Codecov / codecov/patch

crates/mun_hir/src/code_model/impl.rs#L8

Added line #L8 was not covered by tests
pub struct Impl {
pub(crate) id: ImplId,
}

impl Impl {
/// Returns all the implementations defined in the specified `package`.
pub fn all_in_package(db: &dyn HirDatabase, package: Package) -> Vec<Impl> {
let inherent_impls = db.inherent_impls_in_package(package.id);
inherent_impls.all_impls().map(Self::from).collect()
}

Check warning on line 18 in crates/mun_hir/src/code_model/impl.rs

View check run for this annotation

Codecov / codecov/patch

crates/mun_hir/src/code_model/impl.rs#L15-L18

Added lines #L15 - L18 were not covered by tests

/// The module in which the `impl` was defined.
///
/// Note that this is not necessarily the module in which the self type was defined. `impl`s
/// can be defined in any module from where the self type is visibile.
pub fn module(self, db: &dyn HirDatabase) -> Module {
self.id.module(db.upcast()).into()
}

Check warning on line 26 in crates/mun_hir/src/code_model/impl.rs

View check run for this annotation

Codecov / codecov/patch

crates/mun_hir/src/code_model/impl.rs#L24-L26

Added lines #L24 - L26 were not covered by tests

/// Returns the file in which the implementation was defined
pub fn file_id(self, db: &dyn HirDatabase) -> FileId {
self.id.lookup(db.upcast()).id.file_id
}

Check warning on line 31 in crates/mun_hir/src/code_model/impl.rs

View check run for this annotation

Codecov / codecov/patch

crates/mun_hir/src/code_model/impl.rs#L29-L31

Added lines #L29 - L31 were not covered by tests

/// Returns the type for which this is an implementation
pub fn self_ty(self, db: &dyn HirDatabase) -> Ty {
let data = db.impl_data(self.id);
let lowered = db.lower_impl(self.id);
lowered[data.self_ty].clone()
}

Check warning on line 38 in crates/mun_hir/src/code_model/impl.rs

View check run for this annotation

Codecov / codecov/patch

crates/mun_hir/src/code_model/impl.rs#L34-L38

Added lines #L34 - L38 were not covered by tests

/// Returns all the items in the implementation
pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
db.impl_data(self.id)
.items
.iter()
.copied()
.map(Into::into)
.collect()
}

Check warning on line 48 in crates/mun_hir/src/code_model/impl.rs

View check run for this annotation

Codecov / codecov/patch

crates/mun_hir/src/code_model/impl.rs#L41-L48

Added lines #L41 - L48 were not covered by tests
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]

Check warning on line 51 in crates/mun_hir/src/code_model/impl.rs

View check run for this annotation

Codecov / codecov/patch

crates/mun_hir/src/code_model/impl.rs#L51

Added line #L51 was not covered by tests
pub enum AssocItem {
Function(Function),
}

impl From<AssocItemId> for AssocItem {
fn from(value: AssocItemId) -> Self {
match value {
AssocItemId::FunctionId(it) => AssocItem::Function(it.into()),
}
}

Check warning on line 61 in crates/mun_hir/src/code_model/impl.rs

View check run for this annotation

Codecov / codecov/patch

crates/mun_hir/src/code_model/impl.rs#L57-L61

Added lines #L57 - L61 were not covered by tests
}

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

Check warning on line 67 in crates/mun_hir/src/code_model/impl.rs

View check run for this annotation

Codecov / codecov/patch

crates/mun_hir/src/code_model/impl.rs#L65-L67

Added lines #L65 - L67 were not covered by tests
}

#[derive(Debug, PartialEq, Eq)]

Check warning on line 70 in crates/mun_hir/src/code_model/impl.rs

View check run for this annotation

Codecov / codecov/patch

crates/mun_hir/src/code_model/impl.rs#L70

Added line #L70 was not covered by tests
pub struct ImplData {
pub items: Vec<AssocItemId>,
pub self_ty: LocalTypeRefId,
pub type_ref_map: TypeRefMap,
pub type_ref_source_map: TypeRefSourceMap,
}

impl ImplData {
pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData> {
let ItemLoc {
module: _,
id: tree_id,
} = id.lookup(db);

let item_tree = db.item_tree(tree_id.file_id);
let impl_def = &item_tree[tree_id.value];
let src = item_tree.source(db, tree_id.value);

// Associate the self type
let mut type_builder = TypeRefMapBuilder::default();
let self_ty = type_builder.alloc_from_node_opt(src.type_ref().as_ref());
let (type_ref_map, type_ref_source_map) = type_builder.finish();

// Add all the associated items
let container = ItemContainerId::ImplId(id);
let items = impl_def
.items
.iter()
.map(|it| match it {
AssociatedItem::Function(id) => {
let loc = FunctionLoc {
container,
id: ItemTreeId::new(tree_id.file_id, *id),
};
let func_id = loc.intern(db);
AssocItemId::FunctionId(func_id)
}
})
.collect();

Arc::new(ImplData {
items,
self_ty,
type_ref_map,
type_ref_source_map,
})
}
}
11 changes: 11 additions & 0 deletions crates/mun_hir/src/code_model/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ impl From<ModuleId> for Module {
}

impl Module {
/// Returns the package associated with this module
pub fn package(self) -> Package {
Package {
id: self.id.package,
}
}

/// Returns the module that corresponds to the given file
pub fn from_file(db: &dyn HirDatabase, file: FileId) -> Option<Module> {
Package::all(db)
Expand Down Expand Up @@ -71,6 +78,10 @@ impl Module {
let package_defs = db.package_defs(self.id.package);
package_defs.add_diagnostics(db.upcast(), self.id.local_id, sink);

// Add diagnostics from impls
let inherent_impls = db.inherent_impls_in_package(self.id.package);
inherent_impls.add_module_diagnostics(db, self.id.local_id, sink);

// Add diagnostics from the item tree
if let Some(file_id) = self.file_id(db) {
let item_tree = db.item_tree(file_id);
Expand Down
5 changes: 2 additions & 3 deletions crates/mun_hir/src/code_model/struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use mun_syntax::{
};
use std::{fmt, sync::Arc};

use crate::has_module::HasModule;
use crate::resolve::HasResolver;
use crate::visibility::RawVisibility;
pub use ast::StructMemoryKind;
Expand Down Expand Up @@ -66,9 +67,7 @@ impl Field {

impl Struct {
pub fn module(self, db: &dyn HirDatabase) -> Module {
Module {
id: self.id.lookup(db.upcast()).module,
}
self.id.module(db.upcast()).into()
}

pub fn file_id(self, db: &dyn HirDatabase) -> FileId {
Expand Down
6 changes: 3 additions & 3 deletions crates/mun_hir/src/code_model/struct/validator/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::utils::tests::*;
fn test_private_leak_struct_fields() {
insta::assert_snapshot!(diagnostics(
r#"

struct Foo(usize);
pub struct Bar(usize);

Expand All @@ -27,7 +27,7 @@ fn test_private_leak_struct_fields() {
pub bar: Bar,
}

pub(crate) struct BarBaz;
pub(package) struct BarBaz;

// invalid, exporting pub(crate) to pub
pub struct FooBarBaz {
Expand All @@ -37,6 +37,6 @@ fn test_private_leak_struct_fields() {
"#),
@r###"
180..183: can't leak private type
392..395: can't leak private type
394..397: can't leak private type
"###);
}
5 changes: 2 additions & 3 deletions crates/mun_hir/src/code_model/type_alias.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

use super::Module;
use crate::expr::validator::TypeAliasValidator;
use crate::has_module::HasModule;
use crate::resolve::HasResolver;
use crate::ty::lower::LowerTyMap;

Expand All @@ -26,9 +27,7 @@

impl TypeAlias {
pub fn module(self, db: &dyn HirDatabase) -> Module {
Module {
id: self.id.lookup(db.upcast()).module,
}
self.id.module(db.upcast()).into()

Check warning on line 30 in crates/mun_hir/src/code_model/type_alias.rs

View check run for this annotation

Codecov / codecov/patch

crates/mun_hir/src/code_model/type_alias.rs#L30

Added line #L30 was not covered by tests
}

pub fn file_id(self, db: &dyn HirDatabase) -> FileId {
Expand Down
15 changes: 14 additions & 1 deletion crates/mun_hir/src/db.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#![allow(clippy::type_repetition_in_bounds)]

use crate::code_model::ImplData;
use crate::expr::BodySourceMap;
use crate::ids::{DefWithBodyId, FunctionId};
use crate::ids::{DefWithBodyId, FunctionId, ImplId};
use crate::input::{SourceRoot, SourceRootId};
use crate::item_tree::{self, ItemTree};
use crate::method_resolution::InherentImpls;
use crate::module_tree::ModuleTree;
use crate::name_resolution::Namespace;
use crate::package_defs::PackageDefs;
Expand Down Expand Up @@ -82,6 +84,8 @@ pub trait InternDatabase: SourceDatabase {
fn intern_struct(&self, loc: ids::StructLoc) -> ids::StructId;
#[salsa::interned]
fn intern_type_alias(&self, loc: ids::TypeAliasLoc) -> ids::TypeAliasId;
#[salsa::interned]
fn intern_impl(self, loc: ids::ImplLoc) -> ids::ImplId;
}

#[salsa::query_group(DefDatabaseStorage)]
Expand Down Expand Up @@ -113,6 +117,9 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {

#[salsa::invoke(ExprScopes::expr_scopes_query)]
fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>;

#[salsa::invoke(ImplData::impl_data_query)]
fn impl_data(&self, def: ImplId) -> Arc<ImplData>;
}

#[salsa::query_group(HirDatabaseStorage)]
Expand All @@ -137,8 +144,14 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[salsa::invoke(crate::ty::callable_item_sig)]
fn callable_sig(&self, def: CallableDef) -> FnSig;

#[salsa::invoke(crate::ty::lower::lower_impl_query)]
fn lower_impl(&self, def: ImplId) -> Arc<LowerTyMap>;

#[salsa::invoke(crate::ty::type_for_def)]
fn type_for_def(&self, def: TypableDef, ns: Namespace) -> Ty;

#[salsa::invoke(InherentImpls::inherent_impls_in_package_query)]
fn inherent_impls_in_package(&self, package: PackageId) -> Arc<InherentImpls>;
}

fn parse_query(db: &dyn AstDatabase, file_id: FileId) -> Parse<SourceFile> {
Expand Down
45 changes: 41 additions & 4 deletions crates/mun_hir/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,10 +359,9 @@

#[derive(Debug)]
pub struct DuplicateDefinition {
pub file: FileId,
pub name: String,
pub first_definition: SyntaxNodePtr,
pub definition: SyntaxNodePtr,
pub first_definition: InFile<SyntaxNodePtr>,
pub definition: InFile<SyntaxNodePtr>,
}

impl Diagnostic for DuplicateDefinition {
Expand All @@ -371,7 +370,7 @@
}

fn source(&self) -> InFile<SyntaxNodePtr> {
InFile::new(self.file, self.definition.clone())
self.definition.clone()
}

fn as_any(&self) -> &(dyn Any + Send + 'static) {
Expand Down Expand Up @@ -825,3 +824,41 @@
self
}
}

#[derive(Debug)]

Check warning on line 828 in crates/mun_hir/src/diagnostics.rs

View check run for this annotation

Codecov / codecov/patch

crates/mun_hir/src/diagnostics.rs#L828

Added line #L828 was not covered by tests
pub struct IncoherentImpl {
Wodann marked this conversation as resolved.
Show resolved Hide resolved
pub impl_: InFile<AstPtr<ast::Impl>>,
}

impl Diagnostic for IncoherentImpl {
fn message(&self) -> String {
String::from("cannot define inherent `impl` for foreign type")
}

Check warning on line 836 in crates/mun_hir/src/diagnostics.rs

View check run for this annotation

Codecov / codecov/patch

crates/mun_hir/src/diagnostics.rs#L834-L836

Added lines #L834 - L836 were not covered by tests

fn source(&self) -> InFile<SyntaxNodePtr> {
self.impl_.clone().map(Into::into)
}

Check warning on line 840 in crates/mun_hir/src/diagnostics.rs

View check run for this annotation

Codecov / codecov/patch

crates/mun_hir/src/diagnostics.rs#L838-L840

Added lines #L838 - L840 were not covered by tests

fn as_any(&self) -> &(dyn Any + Send + 'static) {
self
}

Check warning on line 844 in crates/mun_hir/src/diagnostics.rs

View check run for this annotation

Codecov / codecov/patch

crates/mun_hir/src/diagnostics.rs#L842-L844

Added lines #L842 - L844 were not covered by tests
}

#[derive(Debug)]

Check warning on line 847 in crates/mun_hir/src/diagnostics.rs

View check run for this annotation

Codecov / codecov/patch

crates/mun_hir/src/diagnostics.rs#L847

Added line #L847 was not covered by tests
pub struct InvalidSelfTyImpl {
pub impl_: InFile<AstPtr<ast::Impl>>,
}

impl Diagnostic for InvalidSelfTyImpl {
fn message(&self) -> String {
String::from("inherent `impl` blocks can only be added for structs")
}

fn source(&self) -> InFile<SyntaxNodePtr> {
self.impl_.clone().map(Into::into)
}

fn as_any(&self) -> &(dyn Any + Send + 'static) {
self
}

Check warning on line 863 in crates/mun_hir/src/diagnostics.rs

View check run for this annotation

Codecov / codecov/patch

crates/mun_hir/src/diagnostics.rs#L861-L863

Added lines #L861 - L863 were not covered by tests
}
Loading
Loading