diff options
Diffstat (limited to 'src/tools/rust-analyzer/crates/hir')
11 files changed, 657 insertions, 162 deletions
diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs index 54425d69b..db0b84ef0 100644 --- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs @@ -14,7 +14,8 @@ use syntax::{ast, AstNode}; use crate::{ Adt, AssocItem, Const, ConstParam, Enum, Field, Function, GenericParam, Impl, LifetimeParam, - Macro, Module, ModuleDef, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant, + Macro, Module, ModuleDef, Static, Struct, Trait, TraitAlias, TypeAlias, TypeParam, Union, + Variant, }; pub trait HasAttrs { @@ -60,6 +61,7 @@ impl_has_attrs![ (Static, StaticId), (Const, ConstId), (Trait, TraitId), + (TraitAlias, TraitAliasId), (TypeAlias, TypeAliasId), (Macro, MacroId), (Function, FunctionId), @@ -134,6 +136,7 @@ fn resolve_doc_path( AttrDefId::StaticId(it) => it.resolver(db.upcast()), AttrDefId::ConstId(it) => it.resolver(db.upcast()), AttrDefId::TraitId(it) => it.resolver(db.upcast()), + AttrDefId::TraitAliasId(it) => it.resolver(db.upcast()), AttrDefId::TypeAliasId(it) => it.resolver(db.upcast()), AttrDefId::ImplId(it) => it.resolver(db.upcast()), AttrDefId::ExternBlockId(it) => it.resolver(db.upcast()), diff --git a/src/tools/rust-analyzer/crates/hir/src/db.rs b/src/tools/rust-analyzer/crates/hir/src/db.rs index e25d86784..0935b5ea5 100644 --- a/src/tools/rust-analyzer/crates/hir/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir/src/db.rs @@ -5,8 +5,9 @@ //! But we need this for at least LRU caching at the query level. pub use hir_def::db::*; pub use hir_expand::db::{ - AstDatabase, AstDatabaseStorage, AstIdMapQuery, HygieneFrameQuery, InternMacroCallQuery, - MacroArgTextQuery, MacroDefQuery, MacroExpandQuery, ParseMacroExpansionQuery, + AstIdMapQuery, ExpandDatabase, ExpandDatabaseStorage, ExpandProcMacroQuery, HygieneFrameQuery, + InternMacroCallQuery, MacroArgTextQuery, MacroDefQuery, MacroExpandErrorQuery, + MacroExpandQuery, ParseMacroExpansionQuery, }; pub use hir_ty::db::*; diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index 54d43fa8d..253d62daf 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -3,6 +3,8 @@ //! //! This probably isn't the best way to do this -- ideally, diagnostics should //! be expressed in terms of hir types themselves. +pub use hir_ty::diagnostics::{IncoherentImpl, IncorrectCase}; + use base_db::CrateId; use cfg::{CfgExpr, CfgOptions}; use either::Either; @@ -10,7 +12,7 @@ use hir_def::path::ModPath; use hir_expand::{name::Name, HirFileId, InFile}; use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; -use crate::{AssocItem, Field, MacroKind, Type}; +use crate::{AssocItem, Field, Local, MacroKind, Type}; macro_rules! diagnostics { ($($diag:ident,)*) => { @@ -31,15 +33,18 @@ macro_rules! diagnostics { diagnostics![ BreakOutsideOfLoop, + ExpectedFunction, InactiveCode, IncorrectCase, InvalidDeriveTarget, + IncoherentImpl, MacroError, MalformedDerive, MismatchedArgCount, MissingFields, MissingMatchArms, MissingUnsafe, + NeedMut, NoSuchField, PrivateAssocItem, PrivateField, @@ -47,10 +52,13 @@ diagnostics![ TypeMismatch, UnimplementedBuiltinMacro, UnresolvedExternCrate, + UnresolvedField, UnresolvedImport, UnresolvedMacroCall, + UnresolvedMethodCall, UnresolvedModule, UnresolvedProcMacro, + UnusedMut, ]; #[derive(Debug)] @@ -131,6 +139,28 @@ pub struct PrivateAssocItem { } #[derive(Debug)] +pub struct ExpectedFunction { + pub call: InFile<AstPtr<ast::Expr>>, + pub found: Type, +} + +#[derive(Debug)] +pub struct UnresolvedField { + pub expr: InFile<AstPtr<ast::Expr>>, + pub receiver: Type, + pub name: Name, + pub method_with_same_name_exists: bool, +} + +#[derive(Debug)] +pub struct UnresolvedMethodCall { + pub expr: InFile<AstPtr<ast::Expr>>, + pub receiver: Type, + pub name: Name, + pub field_with_same_name: Option<Type>, +} + +#[derive(Debug)] pub struct PrivateField { pub expr: InFile<AstPtr<ast::Expr>>, pub field: Field, @@ -140,6 +170,7 @@ pub struct PrivateField { pub struct BreakOutsideOfLoop { pub expr: InFile<AstPtr<ast::Expr>>, pub is_break: bool, + pub bad_value_break: bool, } #[derive(Debug)] @@ -171,17 +202,24 @@ pub struct MismatchedArgCount { #[derive(Debug)] pub struct MissingMatchArms { - pub file: HirFileId, - pub match_expr: AstPtr<ast::Expr>, + pub scrutinee_expr: InFile<AstPtr<ast::Expr>>, pub uncovered_patterns: String, } #[derive(Debug)] pub struct TypeMismatch { - // FIXME: add mismatches in patterns as well - pub expr: InFile<AstPtr<ast::Expr>>, + pub expr_or_pat: Either<InFile<AstPtr<ast::Expr>>, InFile<AstPtr<ast::Pat>>>, pub expected: Type, pub actual: Type, } -pub use hir_ty::diagnostics::IncorrectCase; +#[derive(Debug)] +pub struct NeedMut { + pub local: Local, + pub span: InFile<SyntaxNodePtr>, +} + +#[derive(Debug)] +pub struct UnusedMut { + pub local: Local, +} diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 0d1942012..5aae92efd 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -17,15 +17,23 @@ use hir_ty::{ }; use crate::{ - Adt, Const, ConstParam, Enum, Field, Function, GenericParam, HasCrate, HasVisibility, - LifetimeParam, Macro, Module, Static, Struct, Trait, TyBuilder, Type, TypeAlias, - TypeOrConstParam, TypeParam, Union, Variant, + Adt, AsAssocItem, AssocItemContainer, Const, ConstParam, Enum, Field, Function, GenericParam, + HasCrate, HasVisibility, LifetimeParam, Macro, Module, Static, Struct, Trait, TraitAlias, + TyBuilder, Type, TypeAlias, TypeOrConstParam, TypeParam, Union, Variant, }; impl HirDisplay for Function { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - let data = f.db.function_data(self.id); - write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; + let db = f.db; + let data = db.function_data(self.id); + let container = self.as_assoc_item(db).map(|it| it.container(db)); + let mut module = self.module(db); + if let Some(AssocItemContainer::Impl(_)) = container { + // Block-local impls are "hoisted" to the nearest (non-block) module. + module = module.nearest_non_block_module(db); + } + let module_id = module.id; + write_visibility(module_id, self.visibility(db), f)?; if data.has_default_kw() { f.write_str("default ")?; } @@ -35,7 +43,7 @@ impl HirDisplay for Function { if data.has_async_kw() { f.write_str("async ")?; } - if self.is_unsafe_to_call(f.db) { + if self.is_unsafe_to_call(db) { f.write_str("unsafe ")?; } if let Some(abi) = &data.abi { @@ -50,7 +58,7 @@ impl HirDisplay for Function { let write_self_param = |ty: &TypeRef, f: &mut HirFormatter<'_>| match ty { TypeRef::Path(p) if p.is_self_type() => f.write_str("self"), - TypeRef::Reference(inner, lifetime, mut_) if matches!(&**inner,TypeRef::Path(p) if p.is_self_type()) => + TypeRef::Reference(inner, lifetime, mut_) if matches!(&**inner, TypeRef::Path(p) if p.is_self_type()) => { f.write_char('&')?; if let Some(lifetime) = lifetime { @@ -442,8 +450,15 @@ fn write_where_clause(def: GenericDefId, f: &mut HirFormatter<'_>) -> Result<(), impl HirDisplay for Const { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; - let data = f.db.const_data(self.id); + let db = f.db; + let container = self.as_assoc_item(db).map(|it| it.container(db)); + let mut module = self.module(db); + if let Some(AssocItemContainer::Impl(_)) = container { + // Block-local impls are "hoisted" to the nearest (non-block) module. + module = module.nearest_non_block_module(db); + } + write_visibility(module.id, self.visibility(db), f)?; + let data = db.const_data(self.id); f.write_str("const ")?; match &data.name { Some(name) => write!(f, "{name}: ")?, @@ -486,6 +501,22 @@ impl HirDisplay for Trait { } } +impl HirDisplay for TraitAlias { + fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { + write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; + let data = f.db.trait_alias_data(self.id); + write!(f, "trait {}", data.name)?; + let def_id = GenericDefId::TraitAliasId(self.id); + write_generic_params(def_id, f)?; + f.write_str(" = ")?; + // FIXME: Currently we lower every bounds in a trait alias as a trait bound on `Self` i.e. + // `trait Foo = Bar` is stored and displayed as `trait Foo = where Self: Bar`, which might + // be less readable. + write_where_clause(def_id, f)?; + Ok(()) + } +} + impl HirDisplay for TypeAlias { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; diff --git a/src/tools/rust-analyzer/crates/hir/src/from_id.rs b/src/tools/rust-analyzer/crates/hir/src/from_id.rs index f825a72c0..aaaa7abf3 100644 --- a/src/tools/rust-analyzer/crates/hir/src/from_id.rs +++ b/src/tools/rust-analyzer/crates/hir/src/from_id.rs @@ -4,7 +4,7 @@ //! are splitting the hir. use hir_def::{ - expr::{LabelId, PatId}, + expr::{BindingId, LabelId}, AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, GenericDefId, GenericParamId, ModuleDefId, VariantId, }; @@ -37,6 +37,7 @@ from_id![ (hir_def::EnumId, crate::Enum), (hir_def::TypeAliasId, crate::TypeAlias), (hir_def::TraitId, crate::Trait), + (hir_def::TraitAliasId, crate::TraitAlias), (hir_def::StaticId, crate::Static), (hir_def::ConstId, crate::Const), (hir_def::FunctionId, crate::Function), @@ -110,6 +111,7 @@ impl From<ModuleDefId> for ModuleDef { ModuleDefId::ConstId(it) => ModuleDef::Const(it.into()), ModuleDefId::StaticId(it) => ModuleDef::Static(it.into()), ModuleDefId::TraitId(it) => ModuleDef::Trait(it.into()), + ModuleDefId::TraitAliasId(it) => ModuleDef::TraitAlias(it.into()), ModuleDefId::TypeAliasId(it) => ModuleDef::TypeAlias(it.into()), ModuleDefId::BuiltinType(it) => ModuleDef::BuiltinType(it.into()), ModuleDefId::MacroId(it) => ModuleDef::Macro(it.into()), @@ -127,6 +129,7 @@ impl From<ModuleDef> for ModuleDefId { ModuleDef::Const(it) => ModuleDefId::ConstId(it.into()), ModuleDef::Static(it) => ModuleDefId::StaticId(it.into()), ModuleDef::Trait(it) => ModuleDefId::TraitId(it.into()), + ModuleDef::TraitAlias(it) => ModuleDefId::TraitAliasId(it.into()), ModuleDef::TypeAlias(it) => ModuleDefId::TypeAliasId(it.into()), ModuleDef::BuiltinType(it) => ModuleDefId::BuiltinType(it.into()), ModuleDef::Macro(it) => ModuleDefId::MacroId(it.into()), @@ -172,6 +175,7 @@ impl From<GenericDef> for GenericDefId { GenericDef::Function(it) => GenericDefId::FunctionId(it.id), GenericDef::Adt(it) => GenericDefId::AdtId(it.into()), GenericDef::Trait(it) => GenericDefId::TraitId(it.id), + GenericDef::TraitAlias(it) => GenericDefId::TraitAliasId(it.id), GenericDef::TypeAlias(it) => GenericDefId::TypeAliasId(it.id), GenericDef::Impl(it) => GenericDefId::ImplId(it.id), GenericDef::Variant(it) => GenericDefId::EnumVariantId(it.into()), @@ -186,6 +190,7 @@ impl From<GenericDefId> for GenericDef { GenericDefId::FunctionId(it) => GenericDef::Function(it.into()), GenericDefId::AdtId(it) => GenericDef::Adt(it.into()), GenericDefId::TraitId(it) => GenericDef::Trait(it.into()), + GenericDefId::TraitAliasId(it) => GenericDef::TraitAlias(it.into()), GenericDefId::TypeAliasId(it) => GenericDef::TypeAlias(it.into()), GenericDefId::ImplId(it) => GenericDef::Impl(it.into()), GenericDefId::EnumVariantId(it) => GenericDef::Variant(it.into()), @@ -246,9 +251,9 @@ impl From<AssocItem> for GenericDefId { } } -impl From<(DefWithBodyId, PatId)> for Local { - fn from((parent, pat_id): (DefWithBodyId, PatId)) -> Self { - Local { parent, pat_id } +impl From<(DefWithBodyId, BindingId)> for Local { + fn from((parent, binding_id): (DefWithBodyId, BindingId)) -> Self { + Local { parent, binding_id } } } diff --git a/src/tools/rust-analyzer/crates/hir/src/has_source.rs b/src/tools/rust-analyzer/crates/hir/src/has_source.rs index f8b01db3e..9f6b5c0a9 100644 --- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/has_source.rs @@ -10,8 +10,9 @@ use hir_expand::InFile; use syntax::ast; use crate::{ - db::HirDatabase, Adt, Const, Enum, Field, FieldSource, Function, Impl, LifetimeParam, Macro, - Module, Static, Struct, Trait, TypeAlias, TypeOrConstParam, Union, Variant, + db::HirDatabase, Adt, Const, Enum, Field, FieldSource, Function, Impl, LifetimeParam, + LocalSource, Macro, Module, Static, Struct, Trait, TraitAlias, TypeAlias, TypeOrConstParam, + Union, Variant, }; pub trait HasSource { @@ -122,6 +123,12 @@ impl HasSource for Trait { Some(self.id.lookup(db.upcast()).source(db.upcast())) } } +impl HasSource for TraitAlias { + type Ast = ast::TraitAlias; + fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { + Some(self.id.lookup(db.upcast()).source(db.upcast())) + } +} impl HasSource for TypeAlias { type Ast = ast::TypeAlias; fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { @@ -158,7 +165,7 @@ impl HasSource for Impl { } impl HasSource for TypeOrConstParam { - type Ast = Either<ast::TypeOrConstParam, ast::Trait>; + type Ast = Either<ast::TypeOrConstParam, ast::TraitOrAlias>; fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { let child_source = self.id.parent.child_source(db.upcast()); Some(child_source.map(|it| it[self.id.local_id].clone())) @@ -172,3 +179,11 @@ impl HasSource for LifetimeParam { Some(child_source.map(|it| it[self.id.local_id].clone())) } } + +impl HasSource for LocalSource { + type Ast = Either<ast::IdentPat, ast::SelfParam>; + + fn source(self, _: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { + Some(self.source) + } +} diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 2cb4ed2c3..35424feec 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -41,34 +41,34 @@ use either::Either; use hir_def::{ adt::VariantData, body::{BodyDiagnostic, SyntheticSyntax}, - expr::{BindingAnnotation, ExprOrPatId, LabelId, Pat, PatId}, - generics::{TypeOrConstParamData, TypeParamProvenance}, + expr::{BindingAnnotation, BindingId, ExprOrPatId, LabelId, Pat}, + generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance}, item_tree::ItemTreeNode, lang_item::{LangItem, LangItemTarget}, layout::{Layout, LayoutError, ReprOptions}, - nameres::{self, diagnostics::DefDiagnostic}, + nameres::{self, diagnostics::DefDiagnostic, ModuleOrigin}, per_ns::PerNs, resolver::{HasResolver, Resolver}, src::HasSource as _, - type_ref::ConstScalar, AdtId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalEnumVariantId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId, - TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, + TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, }; use hir_expand::{name::name, MacroCallKind}; use hir_ty::{ all_super_traits, autoderef, - consteval::{unknown_const_as_generic, ComputedExpr, ConstEvalError, ConstExt}, + consteval::{try_const_usize, unknown_const_as_generic, ConstEvalError, ConstExt}, diagnostics::BodyValidationDiagnostic, + display::HexifiedConst, layout::layout_of_ty, method_resolution::{self, TyFingerprint}, + mir::{self, interpret_mir}, primitive::UintTy, traits::FnTrait, AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, - ConcreteConst, ConstValue, GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, - Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, - WhereClause, + GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution, + TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, WhereClause, }; use itertools::Itertools; use nameres::diagnostics::DefDiagnosticKind; @@ -77,7 +77,7 @@ use rustc_hash::FxHashSet; use stdx::{impl_from, never}; use syntax::{ ast::{self, HasAttrs as _, HasDocComments, HasName}, - AstNode, AstPtr, SmolStr, SyntaxNodePtr, TextRange, T, + AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, TextRange, T, }; use crate::db::{DefDatabase, HirDatabase}; @@ -85,12 +85,12 @@ use crate::db::{DefDatabase, HirDatabase}; pub use crate::{ attrs::{HasAttrs, Namespace}, diagnostics::{ - AnyDiagnostic, BreakOutsideOfLoop, InactiveCode, IncorrectCase, InvalidDeriveTarget, - MacroError, MalformedDerive, MismatchedArgCount, MissingFields, MissingMatchArms, - MissingUnsafe, NoSuchField, PrivateAssocItem, PrivateField, - ReplaceFilterMapNextWithFindMap, TypeMismatch, UnimplementedBuiltinMacro, - UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall, UnresolvedModule, - UnresolvedProcMacro, + AnyDiagnostic, BreakOutsideOfLoop, ExpectedFunction, InactiveCode, IncoherentImpl, + IncorrectCase, InvalidDeriveTarget, MacroError, MalformedDerive, MismatchedArgCount, + MissingFields, MissingMatchArms, MissingUnsafe, NeedMut, NoSuchField, PrivateAssocItem, + PrivateField, ReplaceFilterMapNextWithFindMap, TypeMismatch, UnimplementedBuiltinMacro, + UnresolvedExternCrate, UnresolvedField, UnresolvedImport, UnresolvedMacroCall, + UnresolvedMethodCall, UnresolvedModule, UnresolvedProcMacro, UnusedMut, }, has_source::HasSource, semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits}, @@ -130,6 +130,7 @@ pub use { }, hir_ty::{ display::{HirDisplay, HirDisplayError, HirWrite}, + mir::MirEvalError, PointerCast, Safety, }, }; @@ -272,6 +273,7 @@ pub enum ModuleDef { Const(Const), Static(Static), Trait(Trait), + TraitAlias(TraitAlias), TypeAlias(TypeAlias), BuiltinType(BuiltinType), Macro(Macro), @@ -284,6 +286,7 @@ impl_from!( Const, Static, Trait, + TraitAlias, TypeAlias, BuiltinType, Macro @@ -310,6 +313,7 @@ impl ModuleDef { ModuleDef::Const(it) => Some(it.module(db)), ModuleDef::Static(it) => Some(it.module(db)), ModuleDef::Trait(it) => Some(it.module(db)), + ModuleDef::TraitAlias(it) => Some(it.module(db)), ModuleDef::TypeAlias(it) => Some(it.module(db)), ModuleDef::Macro(it) => Some(it.module(db)), ModuleDef::BuiltinType(_) => None, @@ -338,6 +342,7 @@ impl ModuleDef { ModuleDef::Const(it) => it.name(db)?, ModuleDef::Adt(it) => it.name(db), ModuleDef::Trait(it) => it.name(db), + ModuleDef::TraitAlias(it) => it.name(db), ModuleDef::Function(it) => it.name(db), ModuleDef::Variant(it) => it.name(db), ModuleDef::TypeAlias(it) => it.name(db), @@ -356,6 +361,7 @@ impl ModuleDef { Adt::Union(it) => it.id.into(), }, ModuleDef::Trait(it) => it.id.into(), + ModuleDef::TraitAlias(it) => it.id.into(), ModuleDef::Function(it) => it.id.into(), ModuleDef::TypeAlias(it) => it.id.into(), ModuleDef::Module(it) => it.id.into(), @@ -398,6 +404,7 @@ impl ModuleDef { ModuleDef::Module(_) | ModuleDef::Adt(_) | ModuleDef::Trait(_) + | ModuleDef::TraitAlias(_) | ModuleDef::TypeAlias(_) | ModuleDef::Macro(_) | ModuleDef::BuiltinType(_) => None, @@ -413,6 +420,7 @@ impl ModuleDef { ModuleDef::Const(it) => it.attrs(db), ModuleDef::Static(it) => it.attrs(db), ModuleDef::Trait(it) => it.attrs(db), + ModuleDef::TraitAlias(it) => it.attrs(db), ModuleDef::TypeAlias(it) => it.attrs(db), ModuleDef::Macro(it) => it.attrs(db), ModuleDef::BuiltinType(_) => return None, @@ -429,6 +437,7 @@ impl HasVisibility for ModuleDef { ModuleDef::Const(it) => it.visibility(db), ModuleDef::Static(it) => it.visibility(db), ModuleDef::Trait(it) => it.visibility(db), + ModuleDef::TraitAlias(it) => it.visibility(db), ModuleDef::TypeAlias(it) => it.visibility(db), ModuleDef::Variant(it) => it.visibility(db), ModuleDef::Macro(it) => it.visibility(db), @@ -488,6 +497,20 @@ impl Module { Some(Module { id: def_map.module_id(parent_id) }) } + /// Finds nearest non-block ancestor `Module` (`self` included). + pub fn nearest_non_block_module(self, db: &dyn HirDatabase) -> Module { + let mut id = self.id; + loop { + let def_map = id.def_map(db.upcast()); + let origin = def_map[id.local_id].origin; + if matches!(origin, ModuleOrigin::BlockExpr { .. }) { + id = id.containing_module(db.upcast()).expect("block without parent module") + } else { + return Module { id }; + } + } + } + pub fn path_to_root(self, db: &dyn HirDatabase) -> Vec<Module> { let mut res = vec![self]; let mut curr = self; @@ -581,11 +604,23 @@ impl Module { } } + let inherent_impls = db.inherent_impls_in_crate(self.id.krate()); + for impl_def in self.impl_defs(db) { for diag in db.impl_data_with_diagnostics(impl_def.id).1.iter() { emit_def_diagnostic(db, acc, diag); } + if inherent_impls.invalid_impls().contains(&impl_def.id) { + let loc = impl_def.id.lookup(db.upcast()); + let tree = loc.id.item_tree(db.upcast()); + let node = &tree[loc.id.value]; + let file_id = loc.id.file_id(); + let ast_id_map = db.ast_id_map(file_id); + + acc.push(IncoherentImpl { impl_: ast_id_map.get(node.ast_id()), file_id }.into()) + } + for item in impl_def.items(db) { let def: DefWithBody = match item { AssocItem::Function(it) => it.into(), @@ -1092,8 +1127,8 @@ impl Variant { self.source(db)?.value.expr() } - pub fn eval(self, db: &dyn HirDatabase) -> Result<ComputedExpr, ConstEvalError> { - db.const_eval_variant(self.into()) + pub fn eval(self, db: &dyn HirDatabase) -> Result<i128, ConstEvalError> { + db.const_eval_discriminant(self.into()) } } @@ -1170,6 +1205,25 @@ impl Adt { } } + /// Returns the lifetime of the DataType + pub fn lifetime(&self, db: &dyn HirDatabase) -> Option<LifetimeParamData> { + let resolver = match self { + Adt::Struct(s) => s.id.resolver(db.upcast()), + Adt::Union(u) => u.id.resolver(db.upcast()), + Adt::Enum(e) => e.id.resolver(db.upcast()), + }; + resolver + .generic_params() + .and_then(|gp| { + (&gp.lifetimes) + .iter() + // there should only be a single lifetime + // but `Arena` requires to use an iterator + .nth(0) + }) + .map(|arena| arena.1.clone()) + } + pub fn as_enum(&self) -> Option<Enum> { if let Self::Enum(v) = self { Some(*v) @@ -1285,6 +1339,15 @@ impl DefWithBody { body.pretty_print(db.upcast(), self.id()) } + /// A textual representation of the MIR of this def's body for debugging purposes. + pub fn debug_mir(self, db: &dyn HirDatabase) -> String { + let body = db.mir_body(self.id()); + match body { + Ok(body) => body.pretty_print(db), + Err(e) => format!("error:\n{e:?}"), + } + } + pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) { let krate = self.module(db).id.krate(); @@ -1334,42 +1397,35 @@ impl DefWithBody { let infer = db.infer(self.into()); let source_map = Lazy::new(|| db.body_with_source_map(self.into()).1); + let expr_syntax = |expr| source_map.expr_syntax(expr).expect("unexpected synthetic"); for d in &infer.diagnostics { match d { - hir_ty::InferenceDiagnostic::NoSuchField { expr } => { - let field = source_map.field_syntax(*expr); + &hir_ty::InferenceDiagnostic::NoSuchField { expr } => { + let field = source_map.field_syntax(expr); acc.push(NoSuchField { field }.into()) } - &hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break } => { - let expr = source_map - .expr_syntax(expr) - .expect("break outside of loop in synthetic syntax"); - acc.push(BreakOutsideOfLoop { expr, is_break }.into()) + &hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { + expr, + is_break, + bad_value_break, + } => { + let expr = expr_syntax(expr); + acc.push(BreakOutsideOfLoop { expr, is_break, bad_value_break }.into()) } - hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => { - match source_map.expr_syntax(*call_expr) { - Ok(source_ptr) => acc.push( - MismatchedArgCount { - call_expr: source_ptr, - expected: *expected, - found: *found, - } + &hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => { + acc.push( + MismatchedArgCount { call_expr: expr_syntax(call_expr), expected, found } .into(), - ), - Err(SyntheticSyntax) => (), - } + ) } &hir_ty::InferenceDiagnostic::PrivateField { expr, field } => { - let expr = source_map.expr_syntax(expr).expect("unexpected synthetic"); + let expr = expr_syntax(expr); let field = field.into(); acc.push(PrivateField { expr, field }.into()) } &hir_ty::InferenceDiagnostic::PrivateAssocItem { id, item } => { let expr_or_pat = match id { - ExprOrPatId::ExprId(expr) => source_map - .expr_syntax(expr) - .expect("unexpected synthetic") - .map(Either::Left), + ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(Either::Left), ExprOrPatId::PatId(pat) => source_map .pat_syntax(pat) .expect("unexpected synthetic") @@ -1378,16 +1434,76 @@ impl DefWithBody { let item = item.into(); acc.push(PrivateAssocItem { expr_or_pat, item }.into()) } + hir_ty::InferenceDiagnostic::ExpectedFunction { call_expr, found } => { + let call_expr = expr_syntax(*call_expr); + + acc.push( + ExpectedFunction { + call: call_expr, + found: Type::new(db, DefWithBodyId::from(self), found.clone()), + } + .into(), + ) + } + hir_ty::InferenceDiagnostic::UnresolvedField { + expr, + receiver, + name, + method_with_same_name_exists, + } => { + let expr = expr_syntax(*expr); + + acc.push( + UnresolvedField { + expr, + name: name.clone(), + receiver: Type::new(db, DefWithBodyId::from(self), receiver.clone()), + method_with_same_name_exists: *method_with_same_name_exists, + } + .into(), + ) + } + hir_ty::InferenceDiagnostic::UnresolvedMethodCall { + expr, + receiver, + name, + field_with_same_name, + } => { + let expr = expr_syntax(*expr); + + acc.push( + UnresolvedMethodCall { + expr, + name: name.clone(), + receiver: Type::new(db, DefWithBodyId::from(self), receiver.clone()), + field_with_same_name: field_with_same_name + .clone() + .map(|ty| Type::new(db, DefWithBodyId::from(self), ty)), + } + .into(), + ) + } } } - for (expr, mismatch) in infer.expr_type_mismatches() { - let expr = match source_map.expr_syntax(expr) { - Ok(expr) => expr, - Err(SyntheticSyntax) => continue, + for (pat_or_expr, mismatch) in infer.type_mismatches() { + let expr_or_pat = match pat_or_expr { + ExprOrPatId::ExprId(expr) => source_map.expr_syntax(expr).map(Either::Left), + // FIXME: Re-enable these once we have less false positives + ExprOrPatId::PatId(_pat) => continue, + #[allow(unreachable_patterns)] + ExprOrPatId::PatId(pat) => source_map.pat_syntax(pat).map(Either::Right), + }; + let expr_or_pat = match expr_or_pat { + Ok(Either::Left(expr)) => Either::Left(expr), + Ok(Either::Right(InFile { file_id, value: Either::Left(pat) })) => { + Either::Right(InFile { file_id, value: pat }) + } + Ok(Either::Right(_)) | Err(SyntheticSyntax) => continue, }; + acc.push( TypeMismatch { - expr, + expr_or_pat, expected: Type::new(db, DefWithBodyId::from(self), mismatch.expected.clone()), actual: Type::new(db, DefWithBodyId::from(self), mismatch.actual.clone()), } @@ -1405,6 +1521,41 @@ impl DefWithBody { } } + let hir_body = db.body(self.into()); + + if let Ok(borrowck_result) = db.borrowck(self.into()) { + let mir_body = &borrowck_result.mir_body; + let mol = &borrowck_result.mutability_of_locals; + for (binding_id, _) in hir_body.bindings.iter() { + let need_mut = &mol[mir_body.binding_locals[binding_id]]; + let local = Local { parent: self.into(), binding_id }; + match (need_mut, local.is_mut(db)) { + (mir::MutabilityReason::Mut { .. }, true) + | (mir::MutabilityReason::Not, false) => (), + (mir::MutabilityReason::Mut { spans }, false) => { + for span in spans { + let span: InFile<SyntaxNodePtr> = match span { + mir::MirSpan::ExprId(e) => match source_map.expr_syntax(*e) { + Ok(s) => s.map(|x| x.into()), + Err(_) => continue, + }, + mir::MirSpan::PatId(p) => match source_map.pat_syntax(*p) { + Ok(s) => s.map(|x| match x { + Either::Left(e) => e.into(), + Either::Right(e) => e.into(), + }), + Err(_) => continue, + }, + mir::MirSpan::Unknown => continue, + }; + acc.push(NeedMut { local, span }.into()); + } + } + (mir::MutabilityReason::Not, true) => acc.push(UnusedMut { local }.into()), + } + } + } + for diagnostic in BodyValidationDiagnostic::collect(db, self.into()) { match diagnostic { BodyValidationDiagnostic::RecordMissingFields { @@ -1489,11 +1640,13 @@ impl DefWithBody { if let ast::Expr::MatchExpr(match_expr) = &source_ptr.value.to_node(&root) { - if let Some(match_expr) = match_expr.expr() { + if let Some(scrut_expr) = match_expr.expr() { acc.push( MissingMatchArms { - file: source_ptr.file_id, - match_expr: AstPtr::new(&match_expr), + scrutinee_expr: InFile::new( + source_ptr.file_id, + AstPtr::new(&scrut_expr), + ), uncovered_patterns, } .into(), @@ -1582,6 +1735,10 @@ impl Function { .collect() } + pub fn num_params(self, db: &dyn HirDatabase) -> usize { + db.function_data(self.id).params.len() + } + pub fn method_params(self, db: &dyn HirDatabase) -> Option<Vec<Param>> { if self.self_param(db).is_none() { return None; @@ -1639,6 +1796,14 @@ impl Function { let def_map = db.crate_def_map(loc.krate(db).into()); def_map.fn_as_proc_macro(self.id).map(|id| Macro { id: id.into() }) } + + pub fn eval(self, db: &dyn HirDatabase) -> Result<(), MirEvalError> { + let body = db + .mir_body(self.id.into()) + .map_err(|e| MirEvalError::MirLowerError(self.id.into(), e))?; + interpret_mir(db, &body, false)?; + Ok(()) + } } // Note: logically, this belongs to `hir_ty`, but we are not using it there yet. @@ -1679,8 +1844,8 @@ impl Param { let parent = DefWithBodyId::FunctionId(self.func.into()); let body = db.body(parent); let pat_id = body.params[self.idx]; - if let Pat::Bind { .. } = &body[pat_id] { - Some(Local { parent, pat_id: body.params[self.idx] }) + if let Pat::Bind { id, .. } = &body[pat_id] { + Some(Local { parent, binding_id: *id }) } else { None } @@ -1781,8 +1946,18 @@ impl Const { Type::new_with_resolver_inner(db, &resolver, ty) } - pub fn eval(self, db: &dyn HirDatabase) -> Result<ComputedExpr, ConstEvalError> { - db.const_eval(self.id) + pub fn render_eval(self, db: &dyn HirDatabase) -> Result<String, ConstEvalError> { + let c = db.const_eval(self.id)?; + let r = format!("{}", HexifiedConst(c).display(db)); + // We want to see things like `<utf8-error>` and `<layout-error>` as they are probably bug in our + // implementation, but there is no need to show things like `<enum-not-supported>` or `<ref-not-supported>` to + // the user. + if r.contains("not-supported>") { + return Err(ConstEvalError::MirEvalError(MirEvalError::NotSupported( + "rendering complex constants".to_string(), + ))); + } + return Ok(r); } } @@ -1894,6 +2069,27 @@ impl HasVisibility for Trait { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct TraitAlias { + pub(crate) id: TraitAliasId, +} + +impl TraitAlias { + pub fn module(self, db: &dyn HirDatabase) -> Module { + Module { id: self.id.lookup(db.upcast()).container } + } + + pub fn name(self, db: &dyn HirDatabase) -> Name { + db.trait_alias_data(self.id).name.clone() + } +} + +impl HasVisibility for TraitAlias { + fn visibility(&self, db: &dyn HirDatabase) -> Visibility { + db.trait_alias_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast())) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct TypeAlias { pub(crate) id: TypeAliasId, } @@ -2265,6 +2461,7 @@ pub enum GenericDef { Function(Function), Adt(Adt), Trait(Trait), + TraitAlias(TraitAlias), TypeAlias(TypeAlias), Impl(Impl), // enum variants cannot have generics themselves, but their parent enums @@ -2277,6 +2474,7 @@ impl_from!( Function, Adt(Struct, Enum, Union), Trait, + TraitAlias, TypeAlias, Impl, Variant, @@ -2317,20 +2515,53 @@ impl GenericDef { } /// A single local definition. -/// -/// If the definition of this is part of a "MultiLocal", that is a local that has multiple declarations due to or-patterns -/// then this only references a single one of those. -/// To retrieve the other locals you should use [`Local::associated_locals`] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct Local { pub(crate) parent: DefWithBodyId, - pub(crate) pat_id: PatId, + pub(crate) binding_id: BindingId, +} + +pub struct LocalSource { + pub local: Local, + pub source: InFile<Either<ast::IdentPat, ast::SelfParam>>, +} + +impl LocalSource { + pub fn as_ident_pat(&self) -> Option<&ast::IdentPat> { + match &self.source.value { + Either::Left(x) => Some(x), + Either::Right(_) => None, + } + } + + pub fn into_ident_pat(self) -> Option<ast::IdentPat> { + match self.source.value { + Either::Left(x) => Some(x), + Either::Right(_) => None, + } + } + + pub fn original_file(&self, db: &dyn HirDatabase) -> FileId { + self.source.file_id.original_file(db.upcast()) + } + + pub fn name(&self) -> Option<ast::Name> { + self.source.value.name() + } + + pub fn syntax(&self) -> &SyntaxNode { + self.source.value.syntax() + } + + pub fn syntax_ptr(self) -> InFile<SyntaxNodePtr> { + self.source.map(|x| SyntaxNodePtr::new(x.syntax())) + } } impl Local { pub fn is_param(self, db: &dyn HirDatabase) -> bool { - let src = self.source(db); - match src.value { + let src = self.primary_source(db); + match src.source.value { Either::Left(pat) => pat .syntax() .ancestors() @@ -2350,13 +2581,7 @@ impl Local { pub fn name(self, db: &dyn HirDatabase) -> Name { let body = db.body(self.parent); - match &body[self.pat_id] { - Pat::Bind { name, .. } => name.clone(), - _ => { - stdx::never!("hir::Local is missing a name!"); - Name::missing() - } - } + body[self.binding_id].name.clone() } pub fn is_self(self, db: &dyn HirDatabase) -> bool { @@ -2365,15 +2590,12 @@ impl Local { pub fn is_mut(self, db: &dyn HirDatabase) -> bool { let body = db.body(self.parent); - matches!(&body[self.pat_id], Pat::Bind { mode: BindingAnnotation::Mutable, .. }) + body[self.binding_id].mode == BindingAnnotation::Mutable } pub fn is_ref(self, db: &dyn HirDatabase) -> bool { let body = db.body(self.parent); - matches!( - &body[self.pat_id], - Pat::Bind { mode: BindingAnnotation::Ref | BindingAnnotation::RefMut, .. } - ) + matches!(body[self.binding_id].mode, BindingAnnotation::Ref | BindingAnnotation::RefMut) } pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody { @@ -2387,34 +2609,33 @@ impl Local { pub fn ty(self, db: &dyn HirDatabase) -> Type { let def = self.parent; let infer = db.infer(def); - let ty = infer[self.pat_id].clone(); + let ty = infer[self.binding_id].clone(); Type::new(db, def, ty) } - pub fn associated_locals(self, db: &dyn HirDatabase) -> Box<[Local]> { - let body = db.body(self.parent); - body.ident_patterns_for(&self.pat_id) + /// All definitions for this local. Example: `let (a$0, _) | (_, a$0) = x;` + pub fn sources(self, db: &dyn HirDatabase) -> Vec<LocalSource> { + let (body, source_map) = db.body_with_source_map(self.parent); + body[self.binding_id] + .definitions .iter() - .map(|&pat_id| Local { parent: self.parent, pat_id }) + .map(|&definition| { + let src = source_map.pat_syntax(definition).unwrap(); // Hmm... + let root = src.file_syntax(db.upcast()); + src.map(|ast| match ast { + // Suspicious unwrap + Either::Left(it) => Either::Left(it.cast().unwrap().to_node(&root)), + Either::Right(it) => Either::Right(it.to_node(&root)), + }) + }) + .map(|source| LocalSource { local: self, source }) .collect() } - /// If this local is part of a multi-local, retrieve the representative local. - /// That is the local that references are being resolved to. - pub fn representative(self, db: &dyn HirDatabase) -> Local { - let body = db.body(self.parent); - Local { pat_id: body.pattern_representative(self.pat_id), ..self } - } - - pub fn source(self, db: &dyn HirDatabase) -> InFile<Either<ast::IdentPat, ast::SelfParam>> { - let (_body, source_map) = db.body_with_source_map(self.parent); - let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm... - let root = src.file_syntax(db.upcast()); - src.map(|ast| match ast { - // Suspicious unwrap - Either::Left(it) => Either::Left(it.cast().unwrap().to_node(&root)), - Either::Right(it) => Either::Right(it.to_node(&root)), - }) + /// The leftmost definition for this local. Example: `let (a$0, _) | (_, a) = x;` + pub fn primary_source(self, db: &dyn HirDatabase) -> LocalSource { + let all_sources = self.sources(db); + all_sources.into_iter().next().unwrap() } } @@ -3001,6 +3222,14 @@ impl Type { matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Uint(UintTy::Usize))) } + pub fn is_float(&self) -> bool { + matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Float(_))) + } + + pub fn is_char(&self) -> bool { + matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Char)) + } + pub fn is_int_or_uint(&self) -> bool { match self.ty.kind(Interner) { TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)) => true, @@ -3015,6 +3244,13 @@ impl Type { } } + pub fn as_slice(&self) -> Option<Type> { + match &self.ty.kind(Interner) { + TyKind::Slice(ty) => Some(self.derived(ty.clone())), + _ => None, + } + } + pub fn strip_references(&self) -> Type { self.derived(self.ty.strip_references().clone()) } @@ -3190,6 +3426,14 @@ impl Type { matches!(self.ty.kind(Interner), TyKind::Raw(..)) } + pub fn remove_raw_ptr(&self) -> Option<Type> { + if let TyKind::Raw(_, ty) = self.ty.kind(Interner) { + Some(self.derived(ty.clone())) + } else { + None + } + } + pub fn contains_unknown(&self) -> bool { // FIXME: When we get rid of `ConstScalar::Unknown`, we can just look at precomputed // `TypeFlags` in `TyData`. @@ -3260,12 +3504,7 @@ impl Type { pub fn as_array(&self, _db: &dyn HirDatabase) -> Option<(Type, usize)> { if let TyKind::Array(ty, len) = &self.ty.kind(Interner) { - match len.data(Interner).value { - ConstValue::Concrete(ConcreteConst { interned: ConstScalar::UInt(len) }) => { - Some((self.derived(ty.clone()), len as usize)) - } - _ => None, - } + try_const_usize(len).map(|x| (self.derived(ty.clone()), x as usize)) } else { None } @@ -3321,6 +3560,24 @@ impl Type { } } + /// Iterates its type arguments + /// + /// It iterates the actual type arguments when concrete types are used + /// and otherwise the generic names. + /// It does not include `const` arguments. + /// + /// For code, such as: + /// ```text + /// struct Foo<T, U> + /// + /// impl<U> Foo<String, U> + /// ``` + /// + /// It iterates: + /// ```text + /// - "String" + /// - "U" + /// ``` pub fn type_arguments(&self) -> impl Iterator<Item = Type> + '_ { self.ty .strip_references() @@ -3331,12 +3588,62 @@ impl Type { .map(move |ty| self.derived(ty)) } - pub fn iterate_method_candidates<T>( + /// Iterates its type and const arguments + /// + /// It iterates the actual type and const arguments when concrete types + /// are used and otherwise the generic names. + /// + /// For code, such as: + /// ```text + /// struct Foo<T, const U: usize, const X: usize> + /// + /// impl<U> Foo<String, U, 12> + /// ``` + /// + /// It iterates: + /// ```text + /// - "String" + /// - "U" + /// - "12" + /// ``` + pub fn type_and_const_arguments<'a>( + &'a self, + db: &'a dyn HirDatabase, + ) -> impl Iterator<Item = SmolStr> + 'a { + self.ty + .strip_references() + .as_adt() + .into_iter() + .flat_map(|(_, substs)| substs.iter(Interner)) + .filter_map(|arg| { + // arg can be either a `Ty` or `constant` + if let Some(ty) = arg.ty(Interner) { + Some(SmolStr::new(ty.display(db).to_string())) + } else if let Some(const_) = arg.constant(Interner) { + Some(SmolStr::new_inline(&const_.display(db).to_string())) + } else { + None + } + }) + } + + /// Combines lifetime indicators, type and constant parameters into a single `Iterator` + pub fn generic_parameters<'a>( + &'a self, + db: &'a dyn HirDatabase, + ) -> impl Iterator<Item = SmolStr> + 'a { + // iterate the lifetime + self.as_adt() + .and_then(|a| a.lifetime(db).and_then(|lt| Some((<.name).to_smol_str()))) + .into_iter() + // add the type and const paramaters + .chain(self.type_and_const_arguments(db)) + } + + pub fn iterate_method_candidates_with_traits<T>( &self, db: &dyn HirDatabase, scope: &SemanticsScope<'_>, - // FIXME this can be retrieved from `scope`, except autoimport uses this - // to specify a different set, so the method needs to be split traits_in_scope: &FxHashSet<TraitId>, with_local_impls: Option<Module>, name: Option<&Name>, @@ -3364,6 +3671,24 @@ impl Type { slot } + pub fn iterate_method_candidates<T>( + &self, + db: &dyn HirDatabase, + scope: &SemanticsScope<'_>, + with_local_impls: Option<Module>, + name: Option<&Name>, + callback: impl FnMut(Function) -> Option<T>, + ) -> Option<T> { + self.iterate_method_candidates_with_traits( + db, + scope, + &scope.visible_traits().0, + with_local_impls, + name, + callback, + ) + } + fn iterate_method_candidates_dyn( &self, db: &dyn HirDatabase, @@ -3632,11 +3957,13 @@ impl Type { } } +// FIXME: Document this #[derive(Debug)] pub struct Callable { ty: Type, sig: CallableSig, callee: Callee, + /// Whether this is a method that was called with method call syntax. pub(crate) is_bound_method: bool, } @@ -3670,14 +3997,14 @@ impl Callable { Other => CallableKind::Other, } } - pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<ast::SelfParam> { + pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<(ast::SelfParam, Type)> { let func = match self.callee { Callee::Def(CallableDefId::FunctionId(it)) if self.is_bound_method => it, _ => return None, }; let src = func.lookup(db.upcast()).source(db.upcast()); let param_list = src.value.param_list()?; - param_list.self_param() + Some((param_list.self_param()?, self.ty.derived(self.sig.params()[0].clone()))) } pub fn n_params(&self) -> usize { self.sig.params().len() - if self.is_bound_method { 1 } else { 0 } @@ -3936,6 +4263,12 @@ impl HasCrate for Trait { } } +impl HasCrate for TraitAlias { + fn krate(&self, db: &dyn HirDatabase) -> Crate { + self.module(db).krate() + } +} + impl HasCrate for Static { fn krate(&self, db: &dyn HirDatabase) -> Crate { self.module(db).krate() diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 486b7ee62..407ba6f65 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -12,10 +12,10 @@ use hir_def::{ macro_id_to_def_id, resolver::{self, HasResolver, Resolver, TypeNs}, type_ref::Mutability, - AsMacroCall, DefWithBodyId, FunctionId, MacroId, TraitId, VariantId, + AsMacroCall, DefWithBodyId, FieldId, FunctionId, MacroId, TraitId, VariantId, }; use hir_expand::{ - db::AstDatabase, + db::ExpandDatabase, name::{known, AsName}, ExpansionInfo, MacroCallId, }; @@ -68,7 +68,8 @@ impl PathResolution { | ModuleDef::Function(_) | ModuleDef::Module(_) | ModuleDef::Static(_) - | ModuleDef::Trait(_), + | ModuleDef::Trait(_) + | ModuleDef::TraitAlias(_), ) => None, PathResolution::Def(ModuleDef::TypeAlias(alias)) => { Some(TypeNs::TypeAliasId((*alias).into())) @@ -365,6 +366,16 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.resolve_method_call(call).map(Function::from) } + /// Attempts to resolve this call expression as a method call falling back to resolving it as a field. + pub fn resolve_method_call_field_fallback( + &self, + call: &ast::MethodCallExpr, + ) -> Option<Either<Function, Field>> { + self.imp + .resolve_method_call_fallback(call) + .map(|it| it.map_left(Function::from).map_right(Field::from)) + } + pub fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<Function> { self.imp.resolve_await_to_poll(await_expr).map(Function::from) } @@ -400,7 +411,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.resolve_record_field(field) } - pub fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<Field> { + pub fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<(Field, Type)> { self.imp.resolve_record_pat_field(field) } @@ -527,8 +538,8 @@ impl<'db> SemanticsImpl<'db> { } fn expand_derive_as_pseudo_attr_macro(&self, attr: &ast::Attr) -> Option<SyntaxNode> { - let src = self.wrap_node_infile(attr.clone()); let adt = attr.syntax().parent().and_then(ast::Adt::cast)?; + let src = self.wrap_node_infile(attr.clone()); let call_id = self.with_ctx(|ctx| { ctx.attr_to_derive_macro_call(src.with_value(&adt), src).map(|(_, it, _)| it) })?; @@ -1092,7 +1103,10 @@ impl<'db> SemanticsImpl<'db> { let kind = match adjust.kind { hir_ty::Adjust::NeverToAny => Adjust::NeverToAny, hir_ty::Adjust::Deref(Some(hir_ty::OverloadedDeref(m))) => { - Adjust::Deref(Some(OverloadedDeref(mutability(m)))) + // FIXME: Should we handle unknown mutability better? + Adjust::Deref(Some(OverloadedDeref( + m.map(mutability).unwrap_or(Mutability::Shared), + ))) } hir_ty::Adjust::Deref(None) => Adjust::Deref(None), hir_ty::Adjust::Borrow(hir_ty::AutoBorrow::RawPtr(m)) => { @@ -1145,6 +1159,13 @@ impl<'db> SemanticsImpl<'db> { self.analyze(call.syntax())?.resolve_method_call(self.db, call) } + fn resolve_method_call_fallback( + &self, + call: &ast::MethodCallExpr, + ) -> Option<Either<FunctionId, FieldId>> { + self.analyze(call.syntax())?.resolve_method_call_fallback(self.db, call) + } + fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<FunctionId> { self.analyze(await_expr.syntax())?.resolve_await_to_poll(self.db, await_expr) } @@ -1180,7 +1201,7 @@ impl<'db> SemanticsImpl<'db> { self.analyze(field.syntax())?.resolve_record_field(self.db, field) } - fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<Field> { + fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<(Field, Type)> { self.analyze(field.syntax())?.resolve_record_pat_field(self.db, field) } @@ -1330,6 +1351,7 @@ impl<'db> SemanticsImpl<'db> { }) } ChildContainer::TraitId(it) => it.resolver(self.db.upcast()), + ChildContainer::TraitAliasId(it) => it.resolver(self.db.upcast()), ChildContainer::ImplId(it) => it.resolver(self.db.upcast()), ChildContainer::ModuleId(it) => it.resolver(self.db.upcast()), ChildContainer::EnumId(it) => it.resolver(self.db.upcast()), @@ -1514,7 +1536,7 @@ impl<'db> SemanticsImpl<'db> { fn macro_call_to_macro_id( ctx: &mut SourceToDefCtx<'_, '_>, - db: &dyn AstDatabase, + db: &dyn ExpandDatabase, macro_call_id: MacroCallId, ) -> Option<MacroId> { let loc = db.lookup_intern_macro_call(macro_call_id); @@ -1556,6 +1578,7 @@ to_def_impls![ (crate::Enum, ast::Enum, enum_to_def), (crate::Union, ast::Union, union_to_def), (crate::Trait, ast::Trait, trait_to_def), + (crate::TraitAlias, ast::TraitAlias, trait_alias_to_def), (crate::Impl, ast::Impl, impl_to_def), (crate::TypeAlias, ast::TypeAlias, type_alias_to_def), (crate::Const, ast::Const, const_to_def), @@ -1634,8 +1657,8 @@ impl<'a> SemanticsScope<'a> { resolver::ScopeDef::ImplSelfType(it) => ScopeDef::ImplSelfType(it.into()), resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()), resolver::ScopeDef::GenericParam(id) => ScopeDef::GenericParam(id.into()), - resolver::ScopeDef::Local(pat_id) => match self.resolver.body_owner() { - Some(parent) => ScopeDef::Local(Local { parent, pat_id }), + resolver::ScopeDef::Local(binding_id) => match self.resolver.body_owner() { + Some(parent) => ScopeDef::Local(Local { parent, binding_id }), None => continue, }, resolver::ScopeDef::Label(label_id) => match self.resolver.body_owner() { @@ -1673,6 +1696,7 @@ impl<'a> SemanticsScope<'a> { } } +#[derive(Debug)] pub struct VisibleTraits(pub FxHashSet<TraitId>); impl ops::Deref for VisibleTraits { diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs index 2b5bfda1d..f6f8c9a25 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs @@ -89,16 +89,16 @@ use base_db::FileId; use hir_def::{ child_by_source::ChildBySource, dyn_map::DynMap, - expr::{LabelId, PatId}, + expr::{BindingId, LabelId}, keys::{self, Key}, AdtId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FieldId, FunctionId, GenericDefId, GenericParamId, ImplId, LifetimeParamId, MacroId, ModuleId, StaticId, StructId, - TraitId, TypeAliasId, TypeParamId, UnionId, VariantId, + TraitAliasId, TraitId, TypeAliasId, TypeParamId, UnionId, VariantId, }; use hir_expand::{attrs::AttrId, name::AsName, HirFileId, MacroCallId}; use rustc_hash::FxHashMap; use smallvec::SmallVec; -use stdx::impl_from; +use stdx::{impl_from, never}; use syntax::{ ast::{self, HasName}, AstNode, SyntaxNode, @@ -159,6 +159,12 @@ impl SourceToDefCtx<'_, '_> { pub(super) fn trait_to_def(&mut self, src: InFile<ast::Trait>) -> Option<TraitId> { self.to_def(src, keys::TRAIT) } + pub(super) fn trait_alias_to_def( + &mut self, + src: InFile<ast::TraitAlias>, + ) -> Option<TraitAliasId> { + self.to_def(src, keys::TRAIT_ALIAS) + } pub(super) fn impl_to_def(&mut self, src: InFile<ast::Impl>) -> Option<ImplId> { self.to_def(src, keys::IMPL) } @@ -210,14 +216,14 @@ impl SourceToDefCtx<'_, '_> { pub(super) fn bind_pat_to_def( &mut self, src: InFile<ast::IdentPat>, - ) -> Option<(DefWithBodyId, PatId)> { + ) -> Option<(DefWithBodyId, BindingId)> { let container = self.find_pat_or_label_container(src.syntax())?; let (body, source_map) = self.db.body_with_source_map(container); let src = src.map(ast::Pat::from); let pat_id = source_map.node_pat(src.as_ref())?; // the pattern could resolve to a constant, verify that that is not the case - if let crate::Pat::Bind { .. } = body[pat_id] { - Some((container, pat_id)) + if let crate::Pat::Bind { id, .. } = body[pat_id] { + Some((container, id)) } else { None } @@ -225,11 +231,16 @@ impl SourceToDefCtx<'_, '_> { pub(super) fn self_param_to_def( &mut self, src: InFile<ast::SelfParam>, - ) -> Option<(DefWithBodyId, PatId)> { + ) -> Option<(DefWithBodyId, BindingId)> { let container = self.find_pat_or_label_container(src.syntax())?; - let (_body, source_map) = self.db.body_with_source_map(container); + let (body, source_map) = self.db.body_with_source_map(container); let pat_id = source_map.node_self_param(src.as_ref())?; - Some((container, pat_id)) + if let crate::Pat::Bind { id, .. } = body[pat_id] { + Some((container, id)) + } else { + never!(); + None + } } pub(super) fn label_to_def( &mut self, @@ -353,6 +364,9 @@ impl SourceToDefCtx<'_, '_> { match item { ast::Item::Module(it) => self.module_to_def(container.with_value(it))?.into(), ast::Item::Trait(it) => self.trait_to_def(container.with_value(it))?.into(), + ast::Item::TraitAlias(it) => { + self.trait_alias_to_def(container.with_value(it))?.into() + } ast::Item::Impl(it) => self.impl_to_def(container.with_value(it))?.into(), ast::Item::Enum(it) => self.enum_to_def(container.with_value(it))?.into(), ast::Item::TypeAlias(it) => { @@ -400,6 +414,9 @@ impl SourceToDefCtx<'_, '_> { ast::Item::Struct(it) => self.struct_to_def(InFile::new(file_id, it))?.into(), ast::Item::Enum(it) => self.enum_to_def(InFile::new(file_id, it))?.into(), ast::Item::Trait(it) => self.trait_to_def(InFile::new(file_id, it))?.into(), + ast::Item::TraitAlias(it) => { + self.trait_alias_to_def(InFile::new(file_id, it))?.into() + } ast::Item::TypeAlias(it) => { self.type_alias_to_def(InFile::new(file_id, it))?.into() } @@ -435,6 +452,7 @@ pub(crate) enum ChildContainer { DefWithBodyId(DefWithBodyId), ModuleId(ModuleId), TraitId(TraitId), + TraitAliasId(TraitAliasId), ImplId(ImplId), EnumId(EnumId), VariantId(VariantId), @@ -447,6 +465,7 @@ impl_from! { DefWithBodyId, ModuleId, TraitId, + TraitAliasId, ImplId, EnumId, VariantId, @@ -462,6 +481,7 @@ impl ChildContainer { ChildContainer::DefWithBodyId(it) => it.child_by_source(db, file_id), ChildContainer::ModuleId(it) => it.child_by_source(db, file_id), ChildContainer::TraitId(it) => it.child_by_source(db, file_id), + ChildContainer::TraitAliasId(_) => DynMap::default(), ChildContainer::ImplId(it) => it.child_by_source(db, file_id), ChildContainer::EnumId(it) => it.child_by_source(db, file_id), ChildContainer::VariantId(it) => it.child_by_source(db, file_id), diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 3b39e9fa9..c24d196e1 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -10,6 +10,7 @@ use std::{ sync::Arc, }; +use either::Either; use hir_def::{ body::{ self, @@ -51,7 +52,7 @@ use syntax::{ use crate::{ db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BindingMode, BuiltinAttr, BuiltinType, Callable, Const, DeriveHelper, Field, Function, Local, Macro, ModuleDef, Static, - Struct, ToolModule, Trait, Type, TypeAlias, Variant, + Struct, ToolModule, Trait, TraitAlias, Type, TypeAlias, Variant, }; /// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of @@ -266,6 +267,21 @@ impl SourceAnalyzer { Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs)) } + pub(crate) fn resolve_method_call_fallback( + &self, + db: &dyn HirDatabase, + call: &ast::MethodCallExpr, + ) -> Option<Either<FunctionId, FieldId>> { + let expr_id = self.expr_id(db, &call.clone().into())?; + let inference_result = self.infer.as_ref()?; + match inference_result.method_resolution(expr_id) { + Some((f_in_trait, substs)) => { + Some(Either::Left(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs))) + } + None => inference_result.field_resolution(expr_id).map(Either::Right), + } + } + pub(crate) fn resolve_await_to_poll( &self, db: &dyn HirDatabase, @@ -406,8 +422,8 @@ impl SourceAnalyzer { // Shorthand syntax, resolve to the local let path = ModPath::from_segments(PathKind::Plain, once(local_name.clone())); match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) { - Some(ValueNs::LocalBinding(pat_id)) => { - Some(Local { pat_id, parent: self.resolver.body_owner()? }) + Some(ValueNs::LocalBinding(binding_id)) => { + Some(Local { binding_id, parent: self.resolver.body_owner()? }) } _ => None, } @@ -425,14 +441,17 @@ impl SourceAnalyzer { &self, db: &dyn HirDatabase, field: &ast::RecordPatField, - ) -> Option<Field> { + ) -> Option<(Field, Type)> { let field_name = field.field_name()?.as_name(); let record_pat = ast::RecordPat::cast(field.syntax().parent().and_then(|p| p.parent())?)?; let pat_id = self.pat_id(&record_pat.into())?; let variant = self.infer.as_ref()?.variant_resolution_for_pat(pat_id)?; let variant_data = variant.variant_data(db.upcast()); let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? }; - Some(field.into()) + let (_, subst) = self.infer.as_ref()?.type_of_pat.get(pat_id)?.as_adt()?; + let field_ty = + db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, subst); + Some((field.into(), Type::new_with_resolver(db, &self.resolver, field_ty))) } pub(crate) fn resolve_macro_call( @@ -791,7 +810,7 @@ impl SourceAnalyzer { || Arc::new(hir_ty::TraitEnvironment::empty(krate)), |d| db.trait_environment(d), ); - method_resolution::lookup_impl_method(db, env, func, substs) + method_resolution::lookup_impl_method(db, env, func, substs).0 } fn resolve_impl_const_or_trait_def( @@ -809,7 +828,7 @@ impl SourceAnalyzer { || Arc::new(hir_ty::TraitEnvironment::empty(krate)), |d| db.trait_environment(d), ); - method_resolution::lookup_impl_const(db, env, const_id, subs) + method_resolution::lookup_impl_const(db, env, const_id, subs).0 } fn lang_trait_fn( @@ -943,17 +962,17 @@ fn resolve_hir_path_( res.map(|ty_ns| (ty_ns, path.segments().first())) } None => { - let (ty, remaining) = + let (ty, remaining_idx) = resolver.resolve_path_in_type_ns(db.upcast(), path.mod_path())?; - match remaining { - Some(remaining) if remaining > 1 => { - if remaining + 1 == path.segments().len() { + match remaining_idx { + Some(remaining_idx) => { + if remaining_idx + 1 == path.segments().len() { Some((ty, path.segments().last())) } else { None } } - _ => Some((ty, path.segments().get(1))), + None => Some((ty, None)), } } }?; @@ -978,6 +997,7 @@ fn resolve_hir_path_( TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()), TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()), TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()), + TypeNs::TraitAliasId(it) => PathResolution::Def(TraitAlias::from(it).into()), }; match unresolved { Some(unresolved) => resolver @@ -1001,8 +1021,8 @@ fn resolve_hir_path_( let values = || { resolver.resolve_path_in_value_ns_fully(db.upcast(), path.mod_path()).and_then(|val| { let res = match val { - ValueNs::LocalBinding(pat_id) => { - let var = Local { parent: body_owner?, pat_id }; + ValueNs::LocalBinding(binding_id) => { + let var = Local { parent: body_owner?, binding_id }; PathResolution::Local(var) } ValueNs::FunctionId(it) => PathResolution::Def(Function::from(it).into()), @@ -1065,6 +1085,7 @@ fn resolve_hir_path_qualifier( TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()), TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()), TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()), + TypeNs::TraitAliasId(it) => PathResolution::Def(TraitAlias::from(it).into()), }) .or_else(|| { resolver diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs index fd78decda..a9afa1c6f 100644 --- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs +++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs @@ -68,6 +68,7 @@ pub enum FileSymbolKind { Static, Struct, Trait, + TraitAlias, TypeAlias, Union, } @@ -153,6 +154,9 @@ impl<'a> SymbolCollector<'a> { self.push_decl(id, FileSymbolKind::Trait); self.collect_from_trait(id); } + ModuleDefId::TraitAliasId(id) => { + self.push_decl(id, FileSymbolKind::TraitAlias); + } ModuleDefId::TypeAliasId(id) => { self.push_decl_assoc(id, FileSymbolKind::TypeAlias); } |