From cb4ca89d0a10b535c30570c06e9fe5863270aced Mon Sep 17 00:00:00 2001 From: Wodann Date: Tue, 30 Apr 2024 23:33:39 +0000 Subject: [PATCH 1/5] WIP: feat: infer self & Self HIR types --- crates/mun_codegen/src/ir/body.rs | 2 + crates/mun_hir/Cargo.toml | 1 + crates/mun_hir/src/code_model.rs | 2 +- crates/mun_hir/src/code_model/function.rs | 9 +- crates/mun_hir/src/code_model/module.rs | 10 +- crates/mun_hir/src/db.rs | 3 + crates/mun_hir/src/expr.rs | 38 ++++++- crates/mun_hir/src/expr/scope.rs | 3 + crates/mun_hir/src/item_tree.rs | 30 +++++- crates/mun_hir/src/item_tree/lower.rs | 36 +++++-- crates/mun_hir/src/item_tree/pretty.rs | 14 ++- crates/mun_hir/src/name.rs | 16 ++- crates/mun_hir/src/path.rs | 10 ++ crates/mun_hir/src/resolve.rs | 98 +++++++++++++++---- crates/mun_hir/src/semantics.rs | 19 +++- crates/mun_hir/src/source_id.rs | 2 +- crates/mun_hir/src/ty.rs | 4 +- crates/mun_hir/src/ty/infer.rs | 23 ++++- crates/mun_hir/src/ty/infer/place_expr.rs | 2 +- crates/mun_hir/src/ty/lower.rs | 27 +++-- crates/mun_hir/src/ty/tests.rs | 37 ++++++- crates/mun_hir/src/type_ref.rs | 8 +- .../src/completion/item.rs | 2 + .../src/completion/render.rs | 1 + crates/mun_language_server/src/symbol_kind.rs | 2 + crates/mun_language_server/src/to_lsp.rs | 6 +- crates/mun_syntax/Cargo.toml | 2 +- crates/mun_syntax/src/ast/generated.rs | 4 + crates/mun_syntax/src/grammar.ron | 1 + 29 files changed, 342 insertions(+), 70 deletions(-) diff --git a/crates/mun_codegen/src/ir/body.rs b/crates/mun_codegen/src/ir/body.rs index ff4572af6..04c063e37 100644 --- a/crates/mun_codegen/src/ir/body.rs +++ b/crates/mun_codegen/src/ir/body.rs @@ -574,6 +574,7 @@ impl<'db, 'ink, 't> BodyIrGenerator<'db, 'ink, 't> { .expect("unknown path") .0 { + ValueNs::ImplSelf(_) => unimplemented!("no support for self types"), ValueNs::LocalBinding(pat) => { if let Some(param) = self.pat_to_param.get(&pat) { *param @@ -618,6 +619,7 @@ impl<'db, 'ink, 't> BodyIrGenerator<'db, 'ink, 't> { .expect("unknown path") .0 { + ValueNs::ImplSelf(_) => unimplemented!("no support for self types"), ValueNs::LocalBinding(pat) => *self .pat_to_local .get(&pat) diff --git a/crates/mun_hir/Cargo.toml b/crates/mun_hir/Cargo.toml index 74e4239ea..1209a5d8c 100644 --- a/crates/mun_hir/Cargo.toml +++ b/crates/mun_hir/Cargo.toml @@ -25,6 +25,7 @@ once_cell = { version = "1.19.0", default-features = false } rustc-hash = { version = "1.1", default-features = false } salsa = { version = "0.16.1", default-features = false } smallvec = { version = "1.11.2", features = ["union"], default-features = false } +bitflags = { version = "2.5.0", default-features = false } [dev-dependencies] mun_test = { path = "../mun_test" } diff --git a/crates/mun_hir/src/code_model.rs b/crates/mun_hir/src/code_model.rs index 1fdd2e794..455cc7979 100644 --- a/crates/mun_hir/src/code_model.rs +++ b/crates/mun_hir/src/code_model.rs @@ -12,7 +12,7 @@ pub use self::{ function::{Function, FunctionData}, module::{Module, ModuleDef}, package::Package, - r#impl::{AssocItem, Impl, ImplData}, + r#impl::{AssocItem, ImplData}, r#struct::{Field, Struct, StructData, StructKind, StructMemoryKind}, src::HasSource, type_alias::{TypeAlias, TypeAliasData}, diff --git a/crates/mun_hir/src/code_model/function.rs b/crates/mun_hir/src/code_model/function.rs index d9bc8a63e..f58dd223f 100644 --- a/crates/mun_hir/src/code_model/function.rs +++ b/crates/mun_hir/src/code_model/function.rs @@ -7,6 +7,7 @@ use crate::{ expr::{validator::ExprValidator, BodySourceMap}, has_module::HasModule, ids::{FunctionId, Lookup}, + item_tree::FunctionFlags, name_resolution::Namespace, resolve::HasResolver, type_ref::{LocalTypeRefId, TypeRefMap, TypeRefSourceMap}, @@ -34,7 +35,7 @@ pub struct FunctionData { ret_type: LocalTypeRefId, type_ref_map: TypeRefMap, type_ref_source_map: TypeRefSourceMap, - is_extern: bool, + flags: FunctionFlags, } impl FunctionData { @@ -68,7 +69,7 @@ impl FunctionData { ret_type, type_ref_map, type_ref_source_map, - is_extern: func.is_extern, + flags: func.flags, visibility: item_tree[func.visibility].clone(), }) } @@ -99,7 +100,7 @@ impl FunctionData { /// Returns true if this function is an extern function. pub fn is_extern(&self) -> bool { - self.is_extern + self.flags.is_extern() } } @@ -168,7 +169,7 @@ impl Function { } pub fn is_extern(self, db: &dyn HirDatabase) -> bool { - db.fn_data(self.id).is_extern + db.fn_data(self.id).flags.is_extern() } pub(crate) fn body_source_map(self, db: &dyn HirDatabase) -> Arc { diff --git a/crates/mun_hir/src/code_model/module.rs b/crates/mun_hir/src/code_model/module.rs index 95455fd3f..195c2a573 100644 --- a/crates/mun_hir/src/code_model/module.rs +++ b/crates/mun_hir/src/code_model/module.rs @@ -1,4 +1,4 @@ -use super::{Function, Package, Struct, TypeAlias}; +use super::{r#impl::Impl, Function, Package, Struct, TypeAlias}; use crate::{ ids::{ItemDefinitionId, ModuleId}, primitive_type::PrimitiveType, @@ -141,6 +141,14 @@ impl Module { ) .collect() } + + pub fn impls(self, db: &dyn HirDatabase) -> Vec { + let package_defs = db.package_defs(self.id.package); + package_defs.modules[self.id.local_id] + .impls() + .map(Impl::from) + .collect() + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] diff --git a/crates/mun_hir/src/db.rs b/crates/mun_hir/src/db.rs index 247ceddd1..e0866180c 100644 --- a/crates/mun_hir/src/db.rs +++ b/crates/mun_hir/src/db.rs @@ -155,6 +155,9 @@ pub trait HirDatabase: DefDatabase + Upcast { #[salsa::invoke(crate::ty::type_for_def)] fn type_for_def(&self, def: TypableDef, ns: Namespace) -> Ty; + #[salsa::invoke(crate::ty::type_for_impl_self)] + fn type_for_impl_self(&self, def: ImplId) -> Ty; + #[salsa::invoke(InherentImpls::inherent_impls_in_package_query)] fn inherent_impls_in_package(&self, package: PackageId) -> Arc; } diff --git a/crates/mun_hir/src/expr.rs b/crates/mun_hir/src/expr.rs index a788c7234..08840bd50 100644 --- a/crates/mun_hir/src/expr.rs +++ b/crates/mun_hir/src/expr.rs @@ -16,7 +16,7 @@ use crate::{ diagnostics::DiagnosticSink, ids::{DefWithBodyId, Lookup}, in_file::InFile, - name::AsName, + name::{name, AsName}, primitive_type::{PrimitiveFloat, PrimitiveInt}, type_ref::{LocalTypeRefId, TypeRef, TypeRefMap, TypeRefMapBuilder, TypeRefSourceMap}, DefDatabase, FileId, HirDatabase, Name, Path, @@ -46,6 +46,7 @@ pub struct Body { /// /// If this `Body` is for the body of a constant, this will just be empty. params: Vec<(PatId, LocalTypeRefId)>, + self_param: Option<(PatId, LocalTypeRefId)>, /// The `ExprId` of the actual body expression. body_expr: ExprId, ret_type: LocalTypeRefId, @@ -82,6 +83,10 @@ impl Body { &self.params } + pub fn self_param(&self) -> Option<&(PatId, LocalTypeRefId)> { + self.self_param.as_ref() + } + pub fn body_expr(&self) -> ExprId { self.body_expr } @@ -147,7 +152,7 @@ impl Index for Body { type ExprPtr = Either, AstPtr>; type ExprSource = InFile; -type PatPtr = AstPtr; //Either, AstPtr>; +type PatPtr = Either, AstPtr>; type PatSource = InFile; type RecordPtr = AstPtr; @@ -189,7 +194,7 @@ impl BodySourceMap { } pub(crate) fn node_pat(&self, node: &ast::Pat) -> Option { - self.pat_map.get(&AstPtr::new(node)).cloned() + self.pat_map.get(&Either::Left(AstPtr::new(node))).cloned() } pub fn type_refs(&self) -> &TypeRefSourceMap { @@ -466,6 +471,7 @@ pub(crate) struct ExprCollector<'a> { pats: Arena, source_map: BodySourceMap, params: Vec<(PatId, LocalTypeRefId)>, + self_param: Option<(PatId, LocalTypeRefId)>, body_expr: Option, ret_type: Option, type_ref_builder: TypeRefMapBuilder, @@ -482,6 +488,7 @@ impl<'a> ExprCollector<'a> { pats: Arena::default(), source_map: BodySourceMap::default(), params: Vec::new(), + self_param: None, body_expr: None, ret_type: None, type_ref_builder: TypeRefMap::builder(), @@ -525,6 +532,28 @@ impl<'a> ExprCollector<'a> { fn collect_fn_body(&mut self, node: &ast::FunctionDef) { if let Some(param_list) = node.param_list() { + if let Some(self_param) = param_list.self_param() { + let self_pat = self.alloc_pat( + Pat::Bind { name: name![self] }, + Either::Right(AstPtr::new(&self_param)), + ); + let self_type = self + .type_ref_builder + .alloc_from_node_opt(self_param.ascribed_type().as_ref()); + + self.self_param = Some((self_pat, self_type)); + + // let is_mutable = + // self_param.mut_token().is_some() && + // self_param.amp_token().is_none(); + // let binding_id: la_arena::Idx = + // self.alloc_binding(name![self], + // BindingAnnotation::new(is_mutable, false)); + // self.body.self_param = Some(binding_id); + // self.source_map.self_param = + // Some(self.expander.in_file(AstPtr::new(&self_param))); + } + for param in param_list.params() { let pat = if let Some(pat) = param.pat() { pat @@ -895,7 +924,7 @@ impl<'a> ExprCollector<'a> { ast::PatKind::PlaceholderPat(_) => Pat::Wild, }; let ptr = AstPtr::new(&pat); - self.alloc_pat(pattern, ptr) + self.alloc_pat(pattern, Either::Left(ptr)) } fn collect_return(&mut self, expr: ast::ReturnExpr) -> ExprId { @@ -930,6 +959,7 @@ impl<'a> ExprCollector<'a> { exprs: self.exprs, pats: self.pats, params: self.params, + self_param: self.self_param, body_expr: self.body_expr.expect("A body should have been collected"), type_refs, ret_type: self diff --git a/crates/mun_hir/src/expr/scope.rs b/crates/mun_hir/src/expr/scope.rs index cbb6996b9..2440abc82 100644 --- a/crates/mun_hir/src/expr/scope.rs +++ b/crates/mun_hir/src/expr/scope.rs @@ -52,6 +52,9 @@ impl ExprScopes { scope_by_expr: FxHashMap::default(), }; let root = scopes.root_scope(); + if let Some(self_param) = body.self_param { + scopes.add_bindings(body, root, self_param.0); + } scopes.add_params_bindings(body, root, body.params().iter().map(|p| &p.0)); compute_expr_scopes(body.body_expr(), body, &mut scopes, root); scopes diff --git a/crates/mun_hir/src/item_tree.rs b/crates/mun_hir/src/item_tree.rs index 0a9222d4d..072882f63 100644 --- a/crates/mun_hir/src/item_tree.rs +++ b/crates/mun_hir/src/item_tree.rs @@ -301,11 +301,38 @@ pub struct Import { pub struct Function { pub name: Name, pub visibility: RawVisibilityId, - pub is_extern: bool, pub types: TypeRefMap, pub params: IdRange, pub ret_type: LocalTypeRefId, pub ast_id: FileAstId, + pub(crate) flags: FunctionFlags, +} + +bitflags::bitflags! { + #[doc = "Flags that are used to store additional information about a function"] + #[derive(Debug, Clone, Copy, Eq, PartialEq, Default)] + pub(crate) struct FunctionFlags: u8 { + const HAS_SELF_PARAM = 1 << 0; + const HAS_BODY = 1 << 1; + const IS_EXTERN = 1 << 2; + } +} + +impl FunctionFlags { + /// Whether the function has a self parameter. + pub fn has_self_param(self) -> bool { + self.contains(Self::HAS_SELF_PARAM) + } + + /// Whether the function has a body. + pub fn has_body(self) -> bool { + self.contains(Self::HAS_BODY) + } + + /// Whether the function is extern. + pub fn is_extern(self) -> bool { + self.contains(Self::IS_EXTERN) + } } #[derive(Debug, Clone, Eq, PartialEq)] @@ -317,6 +344,7 @@ pub struct Param { #[derive(Debug, Clone, Eq, PartialEq)] pub enum ParamAstId { Param(FileAstId), + SelfParam(FileAstId), } #[derive(Debug, Clone, Eq, PartialEq)] diff --git a/crates/mun_hir/src/item_tree/lower.rs b/crates/mun_hir/src/item_tree/lower.rs index 698e00192..7f88008b5 100644 --- a/crates/mun_hir/src/item_tree/lower.rs +++ b/crates/mun_hir/src/item_tree/lower.rs @@ -9,9 +9,9 @@ use mun_syntax::ast::{ use smallvec::SmallVec; use super::{ - diagnostics, AssociatedItem, Field, Fields, Function, IdRange, Impl, ItemTree, ItemTreeData, - ItemTreeNode, ItemVisibilities, LocalItemTreeId, ModItem, Param, ParamAstId, RawVisibilityId, - Struct, TypeAlias, + diagnostics, AssociatedItem, Field, Fields, Function, FunctionFlags, IdRange, Impl, ItemTree, + ItemTreeData, ItemTreeNode, ItemVisibilities, LocalItemTreeId, ModItem, Param, ParamAstId, + RawVisibilityId, Struct, TypeAlias, }; use crate::{ item_tree::Import, @@ -158,7 +158,21 @@ impl Context { // Lower all the params let start_param_idx = self.next_param_idx(); + let mut has_self_param = false; if let Some(param_list) = func.param_list() { + if let Some(self_param) = param_list.self_param() { + let ast_id = self.source_ast_id_map.ast_id(&self_param); + let type_ref = match self_param.ascribed_type().as_ref() { + Some(type_ref) => types.alloc_from_node(type_ref), + None => types.alloc_self(), + }; + self.data.params.alloc(Param { + type_ref, + ast_id: ParamAstId::SelfParam(ast_id), + }); + has_self_param = true; + } + for param in param_list.params() { let ast_id = self.source_ast_id_map.ast_id(¶m); let type_ref = types.alloc_from_node_opt(param.ascribed_type().as_ref()); @@ -177,18 +191,28 @@ impl Context { Some(ty) => types.alloc_from_node(&ty), }; - let is_extern = func.is_extern(); - let (types, _types_source_map) = types.finish(); let ast_id = self.source_ast_id_map.ast_id(func); + + let mut flags = FunctionFlags::default(); + if func.is_extern() { + flags |= FunctionFlags::IS_EXTERN; + } + if func.body().is_some() { + flags |= FunctionFlags::HAS_BODY; + } + if has_self_param { + flags |= FunctionFlags::HAS_SELF_PARAM; + } + let res = Function { name, visibility, - is_extern, types, params, ret_type, ast_id, + flags, }; Some(self.data.functions.alloc(res).into()) diff --git a/crates/mun_hir/src/item_tree/pretty.rs b/crates/mun_hir/src/item_tree/pretty.rs index 08b44221a..cee4c716c 100644 --- a/crates/mun_hir/src/item_tree/pretty.rs +++ b/crates/mun_hir/src/item_tree/pretty.rs @@ -167,21 +167,29 @@ impl Printer<'_> { let Function { name, visibility, - is_extern, types, params, ret_type, ast_id: _, + flags, } = &self.tree[it]; self.print_visibility(*visibility)?; - if *is_extern { + if flags.is_extern() { write!(self, "extern ")?; } write!(self, "fn {name}")?; write!(self, "(")?; if !params.is_empty() { self.indented(|this| { - for param in params.clone() { + let mut params = params.clone(); + if flags.has_self_param() { + // Skip self parameter + params.next(); + + write!(this, "self")?; + } + + for param in params { let Param { type_ref, ast_id: _, diff --git a/crates/mun_hir/src/name.rs b/crates/mun_hir/src/name.rs index f6ee3a32d..040733117 100644 --- a/crates/mun_hir/src/name.rs +++ b/crates/mun_hir/src/name.rs @@ -35,8 +35,8 @@ impl Name { } /// Shortcut to create inline plain text name - const fn new_inline(text: &str) -> Name { - Name::new_text(SmolStr::new_inline(text)) + const fn new_static(text: &'static str) -> Name { + Name::new_text(SmolStr::new_static(text)) } /// Resolve a name from the text of token. @@ -105,7 +105,7 @@ pub mod known { $( #[allow(bad_style)] pub const $ident: super::Name = - super::Name::new_inline(stringify!($ident)); + super::Name::new_static(stringify!($ident)); )* }; } @@ -116,8 +116,18 @@ pub mod known { bool, ); + // self/Self cannot be used as an identifier + pub const SELF_PARAM: super::Name = super::Name::new_static("self"); + pub const SELF_TYPE: super::Name = super::Name::new_static("Self"); + #[macro_export] macro_rules! name { + (self) => { + $crate::name::known::SELF_PARAM + }; + (Self) => { + $crate::name::known::SELF_TYPE + }; ($ident:ident) => { $crate::name::known::$ident }; diff --git a/crates/mun_hir/src/path.rs b/crates/mun_hir/src/path.rs index b3a7d6f88..05e9511d2 100644 --- a/crates/mun_hir/src/path.rs +++ b/crates/mun_hir/src/path.rs @@ -84,6 +84,11 @@ impl Path { self.kind == PathKind::Plain && self.segments.len() == 1 } + /// Whether the path is `self`. + pub fn is_self(&self) -> bool { + self.kind == PathKind::Super(0) && self.segments.is_empty() + } + /// If this path represents a single identifier, like `foo`, return its /// name. pub fn as_ident(&self) -> Option<&Name> { @@ -115,6 +120,11 @@ impl Path { } } + /// Returns the first segment of the path, if any. + pub fn first_segment(&self) -> Option<&Name> { + self.segments.first() + } + /// Returns the last segment of the path, if any. pub fn last_segment(&self) -> Option<&Name> { self.segments.last() diff --git a/crates/mun_hir/src/resolve.rs b/crates/mun_hir/src/resolve.rs index f83341fe4..bc9f311ff 100644 --- a/crates/mun_hir/src/resolve.rs +++ b/crates/mun_hir/src/resolve.rs @@ -9,6 +9,7 @@ use crate::{ }, item_scope::BUILTIN_SCOPE, module_tree::LocalModuleId, + name, package_defs::PackageDefs, primitive_type::PrimitiveType, visibility::RawVisibility, @@ -23,10 +24,11 @@ pub struct Resolver { #[derive(Debug, Clone)] pub(crate) enum Scope { /// All the items and imported names of a module - ModuleScope(ModuleItemMap), - + Module(ModuleItemMap), + /// Brings `Self` in `impl` block into scope + Impl(ImplId), /// Local bindings - ExprScope(ExprScope), + Expr(ExprScope), } #[derive(Debug, Clone)] @@ -50,6 +52,7 @@ pub enum ResolveValueResult { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum ValueNs { + ImplSelf(ImplId), LocalBinding(PatId), FunctionId(FunctionId), StructId(StructId), @@ -57,6 +60,7 @@ pub enum ValueNs { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum TypeNs { + SelfType(ImplId), StructId(StructId), TypeAliasId(TypeAliasId), PrimitiveType(PrimitiveType), @@ -64,6 +68,7 @@ pub enum TypeNs { /// An item definition visible from a certain scope. pub enum ScopeDef { + ImplSelfType(ImplId), PerNs(PerNs<(ItemDefinitionId, Visibility)>), Local(PatId), } @@ -75,13 +80,19 @@ impl Resolver { self } + /// Adds an `impl` block scope to the resolver from which it can resolve + /// names + fn push_impl_scope(self, impl_id: ImplId) -> Resolver { + self.push_scope(Scope::Impl(impl_id)) + } + /// Adds a module scope to the resolver from which it can resolve names pub(crate) fn push_module_scope( self, package_defs: Arc, module_id: LocalModuleId, ) -> Resolver { - self.push_scope(Scope::ModuleScope(ModuleItemMap { + self.push_scope(Scope::Module(ModuleItemMap { package_defs, module_id, })) @@ -94,7 +105,7 @@ impl Resolver { expr_scopes: Arc, scope_id: LocalScopeId, ) -> Resolver { - self.push_scope(Scope::ExprScope(ExprScope { + self.push_scope(Scope::Expr(ExprScope { owner, expr_scopes, scope_id, @@ -128,9 +139,12 @@ impl Resolver { /// Returns the `Module` scope of the resolver fn module_scope(&self) -> Option<(&PackageDefs, LocalModuleId)> { - self.scopes.iter().rev().find_map(|scope| match scope { - Scope::ModuleScope(m) => Some((&*m.package_defs, m.module_id)), - Scope::ExprScope(_) => None, + self.scopes.iter().rev().find_map(|scope| { + if let Scope::Module(m) = scope { + Some((&*m.package_defs, m.module_id)) + } else { + None + } }) } @@ -170,11 +184,20 @@ impl Resolver { Some((res, vis)) } - let segments_count = path.segments.len(); - let first_name = path.segments.first()?; + let num_segments = path.segments.len(); + println!("num_segments: {num_segments}"); + + let tmp = name![self]; + let first_name = if path.is_self() { + &tmp + } else { + path.segments.first()? + }; + + println!("first_name: {first_name:?}"); for scope in self.scopes.iter().rev() { match scope { - Scope::ExprScope(scope) if segments_count <= 1 => { + Scope::Expr(scope) if num_segments <= 1 => { let entry = scope .expr_scopes .entries(scope.scope_id) @@ -182,15 +205,26 @@ impl Resolver { .find(|entry| entry.name() == first_name); if let Some(e) = entry { + println!("found: {:?}", e); return Some(ResolveValueResult::ValueNs( ValueNs::LocalBinding(e.pat()), Visibility::Public, )); } } - Scope::ExprScope(_) => continue, + Scope::Expr(_) => continue, + + Scope::Impl(i) => { + if first_name == &name![Self] { + return Some(if num_segments <= 1 { + ResolveValueResult::ValueNs(ValueNs::ImplSelf(*i), Visibility::Public) + } else { + ResolveValueResult::Partial(TypeNs::SelfType(*i), 1) + }); + } + } - Scope::ModuleScope(m) => { + Scope::Module(m) => { let (module_def, idx) = m.package_defs.resolve_path_in_module(db, m.module_id, path); return match idx { @@ -254,12 +288,28 @@ impl Resolver { Some((res, vis)) } + let first_name = path.first_segment()?; + + let remaining_idx = || { + if path.segments.len() == 1 { + None + } else { + Some(1) + } + }; + for scope in self.scopes.iter().rev() { match scope { - Scope::ExprScope(_) => continue, - Scope::ModuleScope(m) => { + Scope::Expr(_) => continue, + Scope::Impl(i) => { + if first_name == &name![Self] { + return Some((TypeNs::SelfType(*i), Visibility::Public, remaining_idx())); + } + } + Scope::Module(m) => { let (module_def, idx) = m.package_defs.resolve_path_in_module(db, m.module_id, path); + let (res, vis) = to_type_ns(module_def)?; return Some((res, vis, idx)); } @@ -294,9 +344,12 @@ impl Resolver { /// If the resolver holds a scope from a body, returns that body. pub fn body_owner(&self) -> Option { - self.scopes.iter().rev().find_map(|scope| match scope { - Scope::ExprScope(it) => Some(it.owner), - Scope::ModuleScope(_) => None, + self.scopes.iter().rev().find_map(|scope| { + if let Scope::Expr(it) = scope { + Some(it.owner) + } else { + None + } }) } @@ -312,7 +365,7 @@ impl Scope { /// Calls the `visitor` for each entry in scope. fn visit_names(&self, _db: &dyn DefDatabase, visitor: &mut dyn FnMut(Name, ScopeDef)) { match self { - Scope::ModuleScope(m) => { + Scope::Module(m) => { m.package_defs[m.module_id] .entries() .for_each(|(name, def)| visitor(name.clone(), ScopeDef::PerNs(def))); @@ -320,7 +373,10 @@ impl Scope { visitor(name.clone(), ScopeDef::PerNs(def)); }); } - Scope::ExprScope(scope) => scope + Scope::Impl(i) => { + visitor(name![Self], ScopeDef::ImplSelfType(*i)); + } + Scope::Expr(scope) => scope .expr_scopes .entries(scope.scope_id) .iter() @@ -400,6 +456,6 @@ impl HasResolver for ItemContainerId { impl HasResolver for ImplId { fn resolver(self, db: &dyn DefDatabase) -> Resolver { - self.module(db).resolver(db) + self.lookup(db).module.resolver(db).push_impl_scope(self) } } diff --git a/crates/mun_hir/src/semantics.rs b/crates/mun_hir/src/semantics.rs index cbbaf3ba1..b253f30d2 100644 --- a/crates/mun_hir/src/semantics.rs +++ b/crates/mun_hir/src/semantics.rs @@ -19,9 +19,8 @@ use rustc_hash::FxHashMap; use smallvec::SmallVec; use crate::{ - ids::{DefWithBodyId, ItemDefinitionId}, - resolve, - resolve::HasResolver, + ids::{DefWithBodyId, ImplId, ItemDefinitionId}, + resolve::{self, HasResolver}, semantics::source_to_def::{SourceToDefCache, SourceToDefContainer, SourceToDefContext}, source_analyzer::SourceAnalyzer, FileId, HirDatabase, InFile, ModuleDef, Name, PatId, PerNs, Resolver, Ty, Visibility, @@ -165,6 +164,7 @@ pub struct SemanticsScope<'a> { /// Represents an element in a scope pub enum ScopeDef { ModuleDef(ModuleDef), + ImplSelfType(Impl), Local(Local), Unknown, } @@ -194,6 +194,18 @@ impl ScopeDef { } } +/// An `impl` block +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Impl { + pub(crate) id: ImplId, +} + +impl Impl { + pub fn self_ty(self, db: &dyn HirDatabase) -> Ty { + db.type_for_impl_self(self.id) + } +} + /// A local variable in a body #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct Local { @@ -216,6 +228,7 @@ impl<'a> SemanticsScope<'a> { resolver.visit_all_names(self.db.upcast(), &mut |name, def| { let def = match def { + resolve::ScopeDef::ImplSelfType(id) => ScopeDef::ImplSelfType(Impl { id }), resolve::ScopeDef::PerNs(it) => { let items = ScopeDef::all_items(it); for item in items { diff --git a/crates/mun_hir/src/source_id.rs b/crates/mun_hir/src/source_id.rs index b35d42f4d..0ddbb2bfb 100644 --- a/crates/mun_hir/src/source_id.rs +++ b/crates/mun_hir/src/source_id.rs @@ -70,7 +70,7 @@ register_ast_id_node! { StructDef, Impl, TypeAliasDef, - Param + Param, SelfParam } /// Maps items' `SyntaxNode`s to `ErasedFileAstId`s and back. diff --git a/crates/mun_hir/src/ty.rs b/crates/mun_hir/src/ty.rs index 55dd45504..925c50dad 100644 --- a/crates/mun_hir/src/ty.rs +++ b/crates/mun_hir/src/ty.rs @@ -8,7 +8,9 @@ use std::{fmt, iter::FromIterator, mem, ops::Deref, sync::Arc}; pub(crate) use infer::infer_query; pub use infer::InferenceResult; -pub(crate) use lower::{callable_item_sig, fn_sig_for_fn, type_for_def, CallableDef, TypableDef}; +pub(crate) use lower::{ + callable_item_sig, fn_sig_for_fn, type_for_def, type_for_impl_self, CallableDef, TypableDef, +}; pub use primitives::{FloatTy, IntTy}; pub use resolve::ResolveBitness; use smallvec::SmallVec; diff --git a/crates/mun_hir/src/ty/infer.rs b/crates/mun_hir/src/ty/infer.rs index 5ffc4d7cd..b8a64d7bb 100644 --- a/crates/mun_hir/src/ty/infer.rs +++ b/crates/mun_hir/src/ty/infer.rs @@ -227,6 +227,12 @@ impl<'a> InferenceResultBuilder<'a> { /// method the `return_ty` will have a valid value, also all parameters /// are added inferred. fn infer_signature(&mut self) { + if let Some((self_pat, self_type_ref)) = self.body.self_param() { + println!("self param: {:?} -> {:?}", self_pat, self_type_ref); + let ty = self.resolve_type(*self_type_ref); + self.infer_pat(*self_pat, ty); + } + // Iterate over all the parameters and associated types of the body and infer // the types of the parameters. for (pat, type_ref) in self.body.params().iter() { @@ -242,7 +248,8 @@ impl<'a> InferenceResultBuilder<'a> { fn infer_pat(&mut self, pat: PatId, ty: Ty) { #[allow(clippy::single_match)] match &self.body[pat] { - Pat::Bind { .. } => { + Pat::Bind { name } => { + println!("infer pat: {} -> {:?}", name, ty); self.set_pat_type(pat, ty); } _ => {} @@ -524,6 +531,7 @@ impl<'a> InferenceResultBuilder<'a> { }; let ty = self.resolve_ty_as_far_as_possible(ty); + println!("ty: {ty:?}"); self.set_expr_type(tgt_expr, ty.clone()); ty } @@ -732,8 +740,14 @@ impl<'a> InferenceResultBuilder<'a> { .push(diagnostics::InferenceDiagnostic::PathIsPrivate { id }); } + println!("type of pat: {:?}", self.type_of_pat); + // Match based on what type of value we found match value { + ValueNs::ImplSelf(i) => { + let ty = self.db.type_for_impl_self(i); + Some(ty) + } ValueNs::LocalBinding(pat) => Some(self.type_of_pat.get(pat)?.clone()), ValueNs::FunctionId(f) => { let ty = self @@ -1171,9 +1185,10 @@ mod diagnostics { ptr.value .either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()) }), - ExprOrPatId::PatId(id) => { - body.pat_syntax(*id).map(|ptr| ptr.value.syntax_node_ptr()) - } + ExprOrPatId::PatId(id) => body.pat_syntax(*id).map(|ptr| { + ptr.value + .either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()) + }), } .unwrap(); diff --git a/crates/mun_hir/src/ty/infer/place_expr.rs b/crates/mun_hir/src/ty/infer/place_expr.rs index 7432002f6..7c6ff5976 100644 --- a/crates/mun_hir/src/ty/infer/place_expr.rs +++ b/crates/mun_hir/src/ty/infer/place_expr.rs @@ -15,7 +15,7 @@ impl<'a> InferenceResultBuilder<'a> { /// Checks if the specified path references a memory location. fn check_place_path(&mut self, resolver: &Resolver, path: &Path) -> bool { match resolver.resolve_path_as_value_fully(self.db.upcast(), path) { - Some((ValueNs::LocalBinding(_), _)) => true, + Some((ValueNs::ImplSelf(_) | ValueNs::LocalBinding(_), _)) => true, Some((ValueNs::FunctionId(_) | ValueNs::StructId(_), _)) | None => false, } } diff --git a/crates/mun_hir/src/ty/lower.rs b/crates/mun_hir/src/ty/lower.rs index cccf21918..5a978c2d7 100644 --- a/crates/mun_hir/src/ty/lower.rs +++ b/crates/mun_hir/src/ty/lower.rs @@ -84,6 +84,7 @@ impl Ty { diagnostics: &mut Vec, type_ref: LocalTypeRefId, ) -> Ty { + println!("ty3: {:?}", type_ref_map[type_ref]); let res = match &type_ref_map[type_ref] { TypeRef::Path(path) => Ty::from_path(db, resolver, type_ref, path, diagnostics), TypeRef::Error => Some(TyKind::Unknown.intern()), @@ -121,15 +122,8 @@ impl Ty { path: &Path, diagnostics: &mut Vec, ) -> Option { - // Find the type - let (ty, vis) = resolver.resolve_path_as_type_fully(db.upcast(), path)?; - - // Get the definition and visibility - let def = match ty { - TypeNs::StructId(id) => TypableDef::Struct(id.into()), - TypeNs::TypeAliasId(id) => TypableDef::TypeAlias(id.into()), - TypeNs::PrimitiveType(id) => TypableDef::PrimitiveType(id), - }; + // Find the type namespace and visibility + let (type_ns, vis) = resolver.resolve_path_as_type_fully(db.upcast(), path)?; // Get the current module and see if the type is visible from here if let Some(module) = resolver.module() { @@ -138,7 +132,14 @@ impl Ty { } } - Some(db.type_for_def(def, Namespace::Types)) + let type_for_def_fn = |def| Some(db.type_for_def(def, Namespace::Types)); + + match type_ns { + TypeNs::SelfType(id) => Some(db.type_for_impl_self(id)), + TypeNs::StructId(id) => type_for_def_fn(TypableDef::Struct(id.into())), + TypeNs::TypeAliasId(id) => type_for_def_fn(TypableDef::TypeAlias(id.into())), + TypeNs::PrimitiveType(id) => type_for_def_fn(TypableDef::PrimitiveType(id)), + } } } @@ -252,6 +253,12 @@ pub(crate) fn type_for_def(db: &dyn HirDatabase, def: TypableDef, ns: Namespace) } } +pub(crate) fn type_for_impl_self(db: &dyn HirDatabase, i: ImplId) -> Ty { + let impl_data = db.impl_data(i); + let resolver = i.resolver(db.upcast()); + Ty::from_hir(db, &resolver, &impl_data.type_ref_map, impl_data.self_ty).0 +} + /// Build the declared type of a static. fn type_for_primitive(def: PrimitiveType) -> Ty { match def { diff --git a/crates/mun_hir/src/ty/tests.rs b/crates/mun_hir/src/ty/tests.rs index fe3d07e6f..4d0cba0cd 100644 --- a/crates/mun_hir/src/ty/tests.rs +++ b/crates/mun_hir/src/ty/tests.rs @@ -1,7 +1,7 @@ use std::{fmt::Write, sync::Arc}; use crate::{ - diagnostics::DiagnosticSink, expr::BodySourceMap, mock::MockDatabase, + code_model::AssocItem, diagnostics::DiagnosticSink, expr::BodySourceMap, mock::MockDatabase, with_fixture::WithFixture, HirDisplay, InferenceResult, ModuleDef, Package, }; @@ -656,6 +656,23 @@ fn infer_return() { "###); } +#[test] +fn infer_self_param() { + insta::assert_snapshot!(infer( + r#" + struct Foo { + a: i32 + } + + impl Foo { + fn with_self(self) -> Self { + self + } + } + "# + )); +} + #[test] fn infer_basics() { insta::assert_snapshot!(infer( @@ -1320,7 +1337,9 @@ fn infer(content: &str) -> String { for (pat, ty) in infer_result.type_of_pat.iter() { let syntax_ptr = match body_source_map.pat_syntax(pat) { - Some(sp) => sp.map(|ast| ast.syntax_node_ptr()), + Some(sp) => { + sp.map(|ast| ast.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr())) + } None => continue, }; types.push((syntax_ptr, ty)); @@ -1382,6 +1401,20 @@ fn infer(content: &str) -> String { } } + for item in Package::all(&db) + .iter() + .flat_map(|pkg| pkg.modules(&db)) + .flat_map(|module| module.impls(&db)) + { + for associated_item in item.items(&db) { + let AssocItem::Function(fun) = associated_item; + + let source_map = fun.body_source_map(&db); + let infer_result = fun.infer(&db); + infer_def(infer_result, source_map); + } + } + drop(diag_sink); acc.truncate(acc.trim_end().len()); diff --git a/crates/mun_hir/src/type_ref.rs b/crates/mun_hir/src/type_ref.rs index 8d1c5f70b..23d38a320 100644 --- a/crates/mun_hir/src/type_ref.rs +++ b/crates/mun_hir/src/type_ref.rs @@ -7,7 +7,7 @@ use la_arena::{Arena, ArenaMap, Idx}; use mun_syntax::{ast, AstPtr}; use rustc_hash::FxHashMap; -use crate::Path; +use crate::{name, Path}; /// The ID of a `TypeRef` in a `TypeRefMap` pub type LocalTypeRefId = Idx; @@ -116,6 +116,12 @@ impl TypeRefMapBuilder { self.alloc_type_ref(type_ref, ptr) } + /// Constructs a new instance for a `Self` type. Returns the Id of the newly + /// created `TypeRef`. + pub fn alloc_self(&mut self) -> LocalTypeRefId { + self.map.type_refs.alloc(TypeRef::Path(name![Self].into())) + } + /// Constructs a new `TypeRef` for the empty tuple type. Returns the Id of /// the newly create `TypeRef`. pub fn unit(&mut self) -> LocalTypeRefId { diff --git a/crates/mun_language_server/src/completion/item.rs b/crates/mun_language_server/src/completion/item.rs index 8112a8960..dfde6450d 100644 --- a/crates/mun_language_server/src/completion/item.rs +++ b/crates/mun_language_server/src/completion/item.rs @@ -50,6 +50,8 @@ impl CompletionItemKind { SymbolKind::Function => "fn", SymbolKind::Local => "lc", SymbolKind::Module => "md", + SymbolKind::SelfParam => "sp", + SymbolKind::SelfType => "st", SymbolKind::Struct => "st", SymbolKind::TypeAlias => "ta", }, diff --git a/crates/mun_language_server/src/completion/render.rs b/crates/mun_language_server/src/completion/render.rs index 735571e70..b726c5033 100644 --- a/crates/mun_language_server/src/completion/render.rs +++ b/crates/mun_language_server/src/completion/render.rs @@ -74,6 +74,7 @@ impl<'a> Render<'a> { ScopeDef::ModuleDef(TypeAlias(_)) => { CompletionItemKind::SymbolKind(SymbolKind::TypeAlias) } + ScopeDef::ImplSelfType(_) => CompletionItemKind::SymbolKind(SymbolKind::SelfParam), ScopeDef::Local(_) => CompletionItemKind::SymbolKind(SymbolKind::Local), ScopeDef::Unknown => { let item = CompletionItem::builder(CompletionKind::Reference, local_name) diff --git a/crates/mun_language_server/src/symbol_kind.rs b/crates/mun_language_server/src/symbol_kind.rs index 4285f5747..1206d7939 100644 --- a/crates/mun_language_server/src/symbol_kind.rs +++ b/crates/mun_language_server/src/symbol_kind.rs @@ -5,6 +5,8 @@ pub enum SymbolKind { Function, Local, Module, + SelfParam, + SelfType, Struct, TypeAlias, } diff --git a/crates/mun_language_server/src/to_lsp.rs b/crates/mun_language_server/src/to_lsp.rs index c68cbdc32..1e88cbe6f 100644 --- a/crates/mun_language_server/src/to_lsp.rs +++ b/crates/mun_language_server/src/to_lsp.rs @@ -80,9 +80,9 @@ pub(crate) fn symbol_kind(symbol_kind: SymbolKind) -> lsp_types::SymbolKind { match symbol_kind { SymbolKind::Function => lsp_types::SymbolKind::FUNCTION, SymbolKind::Struct => lsp_types::SymbolKind::STRUCT, - SymbolKind::TypeAlias => lsp_types::SymbolKind::TYPE_PARAMETER, + SymbolKind::TypeAlias | SymbolKind::SelfType => lsp_types::SymbolKind::TYPE_PARAMETER, SymbolKind::Field => lsp_types::SymbolKind::FIELD, - SymbolKind::Local => lsp_types::SymbolKind::VARIABLE, + SymbolKind::Local | SymbolKind::SelfParam => lsp_types::SymbolKind::VARIABLE, SymbolKind::Module => lsp_types::SymbolKind::MODULE, } } @@ -123,6 +123,8 @@ pub(crate) fn completion_item_kind( SymbolKind::Function => lsp_types::CompletionItemKind::FUNCTION, SymbolKind::Local => lsp_types::CompletionItemKind::VARIABLE, SymbolKind::Module => lsp_types::CompletionItemKind::MODULE, + SymbolKind::SelfParam => lsp_types::CompletionItemKind::VALUE, + SymbolKind::SelfType => lsp_types::CompletionItemKind::TYPE_PARAMETER, SymbolKind::Struct | SymbolKind::TypeAlias => lsp_types::CompletionItemKind::STRUCT, }, CompletionItemKind::Attribute => lsp_types::CompletionItemKind::ENUM_MEMBER, diff --git a/crates/mun_syntax/Cargo.toml b/crates/mun_syntax/Cargo.toml index a07e82026..3368707a7 100644 --- a/crates/mun_syntax/Cargo.toml +++ b/crates/mun_syntax/Cargo.toml @@ -18,7 +18,7 @@ drop_bomb = { version = "0.1.5", default-features = false } itertools = { version = "0.12.0", default-features = false } ra_ap_text_edit = { version = "0.0.190", default-features = false } rowan = { version = "0.15.15", default-features = false } -smol_str = { version = "0.2.0", default-features = false, features = ["serde", "std"] } +smol_str = { version = "0.2.1", default-features = false, features = ["serde", "std"] } text-size = { version = "1.1.1", default-features = false, features = ["serde"] } unicode-xid = { version = "0.2.4", default-features = false } diff --git a/crates/mun_syntax/src/ast/generated.rs b/crates/mun_syntax/src/ast/generated.rs index 74ec0e484..0bb9f676f 100644 --- a/crates/mun_syntax/src/ast/generated.rs +++ b/crates/mun_syntax/src/ast/generated.rs @@ -1010,6 +1010,10 @@ impl ParamList { pub fn params(&self) -> impl Iterator { super::children(self) } + + pub fn self_param(&self) -> Option { + super::child_opt(self) + } } // ParenExpr diff --git a/crates/mun_syntax/src/grammar.ron b/crates/mun_syntax/src/grammar.ron index a7806cd21..4e5fa2c53 100644 --- a/crates/mun_syntax/src/grammar.ron +++ b/crates/mun_syntax/src/grammar.ron @@ -206,6 +206,7 @@ Grammar( ), "RetType": (options: ["TypeRef"]), "ParamList": ( + options: [ "SelfParam" ], collections: [ ["params", "Param"] ] From 7654e6c4303dc0ac2cf364c9209c578ae92e1db5 Mon Sep 17 00:00:00 2001 From: Wodann Date: Sat, 1 Jun 2024 22:53:33 +0000 Subject: [PATCH 2/5] WIP --- crates/mun_hir/src/expr.rs | 14 +------------- crates/mun_hir/src/line_index.rs | 5 ++++- crates/mun_hir/src/method_resolution.rs | 6 +++--- crates/mun_hir/src/resolve.rs | 3 --- crates/mun_hir/src/ty/infer.rs | 7 +------ crates/mun_hir/src/ty/lower.rs | 1 - .../mun_hir__ty__tests__infer_self_param.snap | 7 +++++++ crates/mun_language_server/src/completion/item.rs | 2 +- crates/mun_runtime/tests/memory.rs | 1 - 9 files changed, 17 insertions(+), 29 deletions(-) create mode 100644 crates/mun_hir/src/ty/snapshots/mun_hir__ty__tests__infer_self_param.snap diff --git a/crates/mun_hir/src/expr.rs b/crates/mun_hir/src/expr.rs index 08840bd50..3304cbbd3 100644 --- a/crates/mun_hir/src/expr.rs +++ b/crates/mun_hir/src/expr.rs @@ -537,21 +537,9 @@ impl<'a> ExprCollector<'a> { Pat::Bind { name: name![self] }, Either::Right(AstPtr::new(&self_param)), ); - let self_type = self - .type_ref_builder - .alloc_from_node_opt(self_param.ascribed_type().as_ref()); + let self_type = self.type_ref_builder.alloc_self(); self.self_param = Some((self_pat, self_type)); - - // let is_mutable = - // self_param.mut_token().is_some() && - // self_param.amp_token().is_none(); - // let binding_id: la_arena::Idx = - // self.alloc_binding(name![self], - // BindingAnnotation::new(is_mutable, false)); - // self.body.self_param = Some(binding_id); - // self.source_map.self_param = - // Some(self.expander.in_file(AstPtr::new(&self_param))); } for param in param_list.params() { diff --git a/crates/mun_hir/src/line_index.rs b/crates/mun_hir/src/line_index.rs index 8c9d66bc0..621b8b4e0 100644 --- a/crates/mun_hir/src/line_index.rs +++ b/crates/mun_hir/src/line_index.rs @@ -249,7 +249,10 @@ mod tests { line: 1, col_utf16: 1, }); - assert_eq!(index.text_part(1, 1, text, (end - start).into()), Some("❤️")); + assert_eq!( + index.text_part(1, 1, text, (end - start).into()), + Some("❤️") + ); } #[test] diff --git a/crates/mun_hir/src/method_resolution.rs b/crates/mun_hir/src/method_resolution.rs index faba98d98..39b6e05a4 100644 --- a/crates/mun_hir/src/method_resolution.rs +++ b/crates/mun_hir/src/method_resolution.rs @@ -561,7 +561,7 @@ mod tests { fixture.root_module.id, &Name::new("bar"), ) - .is_ok()) + .is_ok()); } #[test] @@ -574,7 +574,7 @@ mod tests { &Name::new("not_found"), ) .unwrap_err() - .is_none()) + .is_none()); } #[test] @@ -587,7 +587,7 @@ mod tests { &Name::new("baz"), ) .unwrap_err() - .is_some()) + .is_some()); } fn display_method_resolution(ctx: MethodResolutionCtx<'_>) -> String { diff --git a/crates/mun_hir/src/resolve.rs b/crates/mun_hir/src/resolve.rs index bc9f311ff..29b6d19c3 100644 --- a/crates/mun_hir/src/resolve.rs +++ b/crates/mun_hir/src/resolve.rs @@ -185,7 +185,6 @@ impl Resolver { } let num_segments = path.segments.len(); - println!("num_segments: {num_segments}"); let tmp = name![self]; let first_name = if path.is_self() { @@ -194,7 +193,6 @@ impl Resolver { path.segments.first()? }; - println!("first_name: {first_name:?}"); for scope in self.scopes.iter().rev() { match scope { Scope::Expr(scope) if num_segments <= 1 => { @@ -205,7 +203,6 @@ impl Resolver { .find(|entry| entry.name() == first_name); if let Some(e) = entry { - println!("found: {:?}", e); return Some(ResolveValueResult::ValueNs( ValueNs::LocalBinding(e.pat()), Visibility::Public, diff --git a/crates/mun_hir/src/ty/infer.rs b/crates/mun_hir/src/ty/infer.rs index b8a64d7bb..d66730661 100644 --- a/crates/mun_hir/src/ty/infer.rs +++ b/crates/mun_hir/src/ty/infer.rs @@ -228,7 +228,6 @@ impl<'a> InferenceResultBuilder<'a> { /// are added inferred. fn infer_signature(&mut self) { if let Some((self_pat, self_type_ref)) = self.body.self_param() { - println!("self param: {:?} -> {:?}", self_pat, self_type_ref); let ty = self.resolve_type(*self_type_ref); self.infer_pat(*self_pat, ty); } @@ -248,8 +247,7 @@ impl<'a> InferenceResultBuilder<'a> { fn infer_pat(&mut self, pat: PatId, ty: Ty) { #[allow(clippy::single_match)] match &self.body[pat] { - Pat::Bind { name } => { - println!("infer pat: {} -> {:?}", name, ty); + Pat::Bind { name: _name } => { self.set_pat_type(pat, ty); } _ => {} @@ -531,7 +529,6 @@ impl<'a> InferenceResultBuilder<'a> { }; let ty = self.resolve_ty_as_far_as_possible(ty); - println!("ty: {ty:?}"); self.set_expr_type(tgt_expr, ty.clone()); ty } @@ -740,8 +737,6 @@ impl<'a> InferenceResultBuilder<'a> { .push(diagnostics::InferenceDiagnostic::PathIsPrivate { id }); } - println!("type of pat: {:?}", self.type_of_pat); - // Match based on what type of value we found match value { ValueNs::ImplSelf(i) => { diff --git a/crates/mun_hir/src/ty/lower.rs b/crates/mun_hir/src/ty/lower.rs index 5a978c2d7..89f6d3d44 100644 --- a/crates/mun_hir/src/ty/lower.rs +++ b/crates/mun_hir/src/ty/lower.rs @@ -84,7 +84,6 @@ impl Ty { diagnostics: &mut Vec, type_ref: LocalTypeRefId, ) -> Ty { - println!("ty3: {:?}", type_ref_map[type_ref]); let res = match &type_ref_map[type_ref] { TypeRef::Path(path) => Ty::from_path(db, resolver, type_ref, path, diagnostics), TypeRef::Error => Some(TyKind::Unknown.intern()), diff --git a/crates/mun_hir/src/ty/snapshots/mun_hir__ty__tests__infer_self_param.snap b/crates/mun_hir/src/ty/snapshots/mun_hir__ty__tests__infer_self_param.snap new file mode 100644 index 000000000..b2efbf602 --- /dev/null +++ b/crates/mun_hir/src/ty/snapshots/mun_hir__ty__tests__infer_self_param.snap @@ -0,0 +1,7 @@ +--- +source: crates/mun_hir/src/ty/tests.rs +expression: "infer(r#\"\n struct Foo {\n a: i32\n }\n\n impl Foo {\n fn with_self(self) -> Self {\n self\n }\n }\n \"#)" +--- +55..59 'self': Foo +69..89 '{ ... }': Foo +79..83 'self': Foo diff --git a/crates/mun_language_server/src/completion/item.rs b/crates/mun_language_server/src/completion/item.rs index dfde6450d..1e887011a 100644 --- a/crates/mun_language_server/src/completion/item.rs +++ b/crates/mun_language_server/src/completion/item.rs @@ -51,7 +51,7 @@ impl CompletionItemKind { SymbolKind::Local => "lc", SymbolKind::Module => "md", SymbolKind::SelfParam => "sp", - SymbolKind::SelfType => "st", + SymbolKind::SelfType => "sy", SymbolKind::Struct => "st", SymbolKind::TypeAlias => "ta", }, diff --git a/crates/mun_runtime/tests/memory.rs b/crates/mun_runtime/tests/memory.rs index b11951fe3..50d4c37b1 100644 --- a/crates/mun_runtime/tests/memory.rs +++ b/crates/mun_runtime/tests/memory.rs @@ -1370,7 +1370,6 @@ fn map_array_to_array_different_struct_to_struct() { .iter() .zip([b, a, b].into_iter()) .for_each(|(lhs, rhs)| { - // println!("struct type: {:?}", lhs.type_info()); assert_eq!(lhs.get::("0").unwrap(), i64::from(rhs)); }); } From 57750b605154fbebf9833e8dd986d6e7a1a004e9 Mon Sep 17 00:00:00 2001 From: Wodann Date: Sun, 2 Jun 2024 04:39:38 +0000 Subject: [PATCH 3/5] test: add test for self field access --- crates/mun_hir/src/code_model/module.rs | 13 +++++++++++-- crates/mun_hir/src/ty/tests.rs | 21 +++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/crates/mun_hir/src/code_model/module.rs b/crates/mun_hir/src/code_model/module.rs index 195c2a573..f2f31e91e 100644 --- a/crates/mun_hir/src/code_model/module.rs +++ b/crates/mun_hir/src/code_model/module.rs @@ -1,4 +1,4 @@ -use super::{r#impl::Impl, Function, Package, Struct, TypeAlias}; +use super::{r#impl::Impl, AssocItem, Function, Package, Struct, TypeAlias}; use crate::{ ids::{ItemDefinitionId, ModuleId}, primitive_type::PrimitiveType, @@ -81,7 +81,7 @@ 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 + // Add diagnostics from inherent impls let inherent_impls = db.inherent_impls_in_package(self.id.package); inherent_impls.add_module_diagnostics(db, self.id.local_id, sink); @@ -102,6 +102,15 @@ impl Module { _ => (), } } + + // Add diagnostics from impls + for item in self.impls(db) { + for associated_item in item.items(db) { + let AssocItem::Function(fun) = associated_item; + + fun.diagnostics(db, sink); + } + } } /// Returns all the child modules of this module diff --git a/crates/mun_hir/src/ty/tests.rs b/crates/mun_hir/src/ty/tests.rs index 4d0cba0cd..5b123b9fb 100644 --- a/crates/mun_hir/src/ty/tests.rs +++ b/crates/mun_hir/src/ty/tests.rs @@ -673,6 +673,27 @@ fn infer_self_param() { )); } +#[test] +fn infer_self_field() { + insta::assert_snapshot!(infer( + r#" + struct Foo { + a: i32 + } + + impl Foo { + fn self_a(self) -> i32 { + self.a + } + + fn self_b(self) -> i32 { + self.b // error: attempted to access a non-existent field in a struct. + } + } + "# + )); +} + #[test] fn infer_basics() { insta::assert_snapshot!(infer( From ef825d58eb64a33d40dfe801ec71d4e475a4ffc6 Mon Sep 17 00:00:00 2001 From: Wodann Date: Sun, 2 Jun 2024 05:46:13 +0000 Subject: [PATCH 4/5] test: self field access --- .../src/expr/validator/uninitialized_access.rs | 4 ++++ .../mun_hir__ty__tests__infer_self_field.snap | 13 +++++++++++++ .../mun_hir__ty__tests__infer_self_members.snap | 12 ++++++++++++ 3 files changed, 29 insertions(+) create mode 100644 crates/mun_hir/src/ty/snapshots/mun_hir__ty__tests__infer_self_field.snap create mode 100644 crates/mun_hir/src/ty/snapshots/mun_hir__ty__tests__infer_self_members.snap diff --git a/crates/mun_hir/src/expr/validator/uninitialized_access.rs b/crates/mun_hir/src/expr/validator/uninitialized_access.rs index fdaff8517..adf94bb7a 100644 --- a/crates/mun_hir/src/expr/validator/uninitialized_access.rs +++ b/crates/mun_hir/src/expr/validator/uninitialized_access.rs @@ -21,6 +21,10 @@ impl<'d> ExprValidator<'d> { // Add all parameter patterns to the set of initialized patterns (they must have // been initialized) + if let Some((pat, _)) = self.body.self_param { + initialized_patterns.insert(pat); + } + for (pat, _) in self.body.params.iter() { initialized_patterns.insert(*pat); } diff --git a/crates/mun_hir/src/ty/snapshots/mun_hir__ty__tests__infer_self_field.snap b/crates/mun_hir/src/ty/snapshots/mun_hir__ty__tests__infer_self_field.snap new file mode 100644 index 000000000..ff7c48aae --- /dev/null +++ b/crates/mun_hir/src/ty/snapshots/mun_hir__ty__tests__infer_self_field.snap @@ -0,0 +1,13 @@ +--- +source: crates/mun_hir/src/ty/tests.rs +expression: "infer(r#\"\n struct Foo {\n a: i32\n }\n\n impl Foo {\n fn self_a(self) -> i32 {\n self.a\n }\n\n fn self_b(self) -> i32 {\n self.b // error: attempted to access a non-existent field in a struct.\n }\n }\n \"#)" +--- +126..132: attempted to access a non-existent field in a struct. +52..56 'self': Foo +65..87 '{ ... }': i32 +75..79 'self': Foo +75..81 'self.a': i32 +103..107 'self': Foo +116..203 '{ ... }': i32 +126..130 'self': Foo +126..132 'self.b': {unknown} diff --git a/crates/mun_hir/src/ty/snapshots/mun_hir__ty__tests__infer_self_members.snap b/crates/mun_hir/src/ty/snapshots/mun_hir__ty__tests__infer_self_members.snap new file mode 100644 index 000000000..a25b253fc --- /dev/null +++ b/crates/mun_hir/src/ty/snapshots/mun_hir__ty__tests__infer_self_members.snap @@ -0,0 +1,12 @@ +--- +source: crates/mun_hir/src/ty/tests.rs +expression: "infer(r#\"\n struct Foo {\n a: i32\n }\n\n impl Foo {\n fn self_a(self) -> i32 {\n self.a\n }\n\n fn self_b(self) -> i32 {\n self.b\n }\n }\n \"#)" +--- +52..56 'self': Foo +65..87 '{ ... }': i32 +75..79 'self': Foo +75..81 'self.a': i32 +103..107 'self': Foo +116..138 '{ ... }': i32 +126..130 'self': Foo +126..132 'self.b': {unknown} From 015414812cc48678f5a0297e6da81888a646ed12 Mon Sep 17 00:00:00 2001 From: Wodann Date: Tue, 4 Jun 2024 22:59:04 -0500 Subject: [PATCH 5/5] fix: windows build --- crates/mun_compiler_daemon/Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/mun_compiler_daemon/Cargo.toml b/crates/mun_compiler_daemon/Cargo.toml index 1166b32c8..fd2b9ec60 100644 --- a/crates/mun_compiler_daemon/Cargo.toml +++ b/crates/mun_compiler_daemon/Cargo.toml @@ -21,3 +21,7 @@ mun_compiler = { version = "0.6.0-dev", path = "../mun_compiler" } mun_project = { version = "0.6.0-dev", path = "../mun_project" } mun_hir = { version = "0.6.0-dev", path = "../mun_hir" } notify = { version = "4.0", default-features = false } + +# Enable std feature for winapi through feature unification to ensure notify uses the correct `c_void` type +[target.'cfg(windows)'.dependencies] +winapi = { version = "0.3.8", features = ["std"] }