diff options
Diffstat (limited to 'src/tools/rust-analyzer/crates/hir')
-rw-r--r-- | src/tools/rust-analyzer/crates/hir/Cargo.toml | 1 | ||||
-rw-r--r-- | src/tools/rust-analyzer/crates/hir/src/attrs.rs | 8 | ||||
-rw-r--r-- | src/tools/rust-analyzer/crates/hir/src/db.rs | 4 | ||||
-rw-r--r-- | src/tools/rust-analyzer/crates/hir/src/diagnostics.rs | 59 | ||||
-rw-r--r-- | src/tools/rust-analyzer/crates/hir/src/display.rs | 72 | ||||
-rw-r--r-- | src/tools/rust-analyzer/crates/hir/src/from_id.rs | 5 | ||||
-rw-r--r-- | src/tools/rust-analyzer/crates/hir/src/lib.rs | 796 | ||||
-rw-r--r-- | src/tools/rust-analyzer/crates/hir/src/semantics.rs | 66 | ||||
-rw-r--r-- | src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs | 10 | ||||
-rw-r--r-- | src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs | 94 | ||||
-rw-r--r-- | src/tools/rust-analyzer/crates/hir/src/symbols.rs | 297 |
11 files changed, 956 insertions, 456 deletions
diff --git a/src/tools/rust-analyzer/crates/hir/Cargo.toml b/src/tools/rust-analyzer/crates/hir/Cargo.toml index ef40a8902..a20aff93f 100644 --- a/src/tools/rust-analyzer/crates/hir/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir/Cargo.toml @@ -17,6 +17,7 @@ either = "1.7.0" arrayvec = "0.7.2" itertools = "0.10.5" smallvec.workspace = true +triomphe.workspace = true once_cell = "1.17.0" # local deps diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs index db0b84ef0..b81793729 100644 --- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs @@ -4,7 +4,6 @@ use hir_def::{ attr::{AttrsWithOwner, Documentation}, item_scope::ItemInNs, path::ModPath, - per_ns::PerNs, resolver::HasResolver, AttrDefId, GenericParamId, ModuleDefId, }; @@ -41,7 +40,7 @@ macro_rules! impl_has_attrs { impl HasAttrs for $def { fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner { let def = AttrDefId::$def_id(self.into()); - db.attrs(def) + db.attrs_with_owner(def) } fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> { let def = AttrDefId::$def_id(self.into()); @@ -121,6 +120,7 @@ impl HasAttrs for AssocItem { } } +/// Resolves the item `link` points to in the scope of `def`. fn resolve_doc_path( db: &dyn HirDatabase, def: AttrDefId, @@ -155,14 +155,14 @@ fn resolve_doc_path( .syntax_node() .descendants() .find_map(ast::Path::cast)?; - if ast_path.to_string() != link { + if ast_path.syntax().text() != link { return None; } ModPath::from_src(db.upcast(), ast_path, &Hygiene::new_unhygienic())? }; let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath); - let resolved = if resolved == PerNs::none() { + let resolved = if resolved.is_none() { resolver.resolve_module_path_in_trait_assoc_items(db.upcast(), &modpath)? } else { resolved diff --git a/src/tools/rust-analyzer/crates/hir/src/db.rs b/src/tools/rust-analyzer/crates/hir/src/db.rs index 0935b5ea5..e0cde689f 100644 --- a/src/tools/rust-analyzer/crates/hir/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir/src/db.rs @@ -6,8 +6,8 @@ pub use hir_def::db::*; pub use hir_expand::db::{ AstIdMapQuery, ExpandDatabase, ExpandDatabaseStorage, ExpandProcMacroQuery, HygieneFrameQuery, - InternMacroCallQuery, MacroArgTextQuery, MacroDefQuery, MacroExpandErrorQuery, - MacroExpandQuery, ParseMacroExpansionQuery, + InternMacroCallQuery, MacroArgTextQuery, MacroDefQuery, MacroExpandQuery, + ParseMacroExpansionErrorQuery, 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 253d62daf..b64d81490 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -10,7 +10,7 @@ use cfg::{CfgExpr, CfgOptions}; use either::Either; use hir_def::path::ModPath; use hir_expand::{name::Name, HirFileId, InFile}; -use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; +use syntax::{ast, AstPtr, SyntaxError, SyntaxNodePtr, TextRange}; use crate::{AssocItem, Field, Local, MacroKind, Type}; @@ -38,19 +38,25 @@ diagnostics![ IncorrectCase, InvalidDeriveTarget, IncoherentImpl, + MacroDefError, MacroError, + MacroExpansionParseError, MalformedDerive, MismatchedArgCount, MissingFields, MissingMatchArms, MissingUnsafe, + MovedOutOfRef, NeedMut, NoSuchField, PrivateAssocItem, PrivateField, ReplaceFilterMapNextWithFindMap, + TypedHole, TypeMismatch, + UndeclaredLabel, UnimplementedBuiltinMacro, + UnreachableLabel, UnresolvedExternCrate, UnresolvedField, UnresolvedImport, @@ -62,6 +68,19 @@ diagnostics![ ]; #[derive(Debug)] +pub struct BreakOutsideOfLoop { + pub expr: InFile<AstPtr<ast::Expr>>, + pub is_break: bool, + pub bad_value_break: bool, +} + +#[derive(Debug)] +pub struct TypedHole { + pub expr: InFile<AstPtr<ast::Expr>>, + pub expected: Type, +} + +#[derive(Debug)] pub struct UnresolvedModule { pub decl: InFile<AstPtr<ast::Module>>, pub candidates: Box<[String]>, @@ -84,6 +103,17 @@ pub struct UnresolvedMacroCall { pub path: ModPath, pub is_bang: bool, } +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct UnreachableLabel { + pub node: InFile<AstPtr<ast::Lifetime>>, + pub name: Name, +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct UndeclaredLabel { + pub node: InFile<AstPtr<ast::Lifetime>>, + pub name: Name, +} #[derive(Debug, Clone, Eq, PartialEq)] pub struct InactiveCode { @@ -111,6 +141,20 @@ pub struct MacroError { pub message: String, } +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct MacroExpansionParseError { + pub node: InFile<SyntaxNodePtr>, + pub precise_location: Option<TextRange>, + pub errors: Box<[SyntaxError]>, +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct MacroDefError { + pub node: InFile<AstPtr<ast::Macro>>, + pub message: String, + pub name: Option<TextRange>, +} + #[derive(Debug)] pub struct UnimplementedBuiltinMacro { pub node: InFile<SyntaxNodePtr>, @@ -167,13 +211,6 @@ pub struct PrivateField { } #[derive(Debug)] -pub struct BreakOutsideOfLoop { - pub expr: InFile<AstPtr<ast::Expr>>, - pub is_break: bool, - pub bad_value_break: bool, -} - -#[derive(Debug)] pub struct MissingUnsafe { pub expr: InFile<AstPtr<ast::Expr>>, } @@ -223,3 +260,9 @@ pub struct NeedMut { pub struct UnusedMut { pub local: Local, } + +#[derive(Debug)] +pub struct MovedOutOfRef { + pub ty: Type, + pub span: InFile<SyntaxNodePtr>, +} diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 5aae92efd..9a2090ab7 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -1,6 +1,6 @@ //! HirDisplay implementations for various hir types. use hir_def::{ - adt::VariantData, + data::adt::VariantData, generics::{ TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget, }, @@ -8,6 +8,7 @@ use hir_def::{ type_ref::{TypeBound, TypeRef}, AdtId, GenericDefId, }; +use hir_expand::name; use hir_ty::{ display::{ write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError, @@ -50,7 +51,7 @@ impl HirDisplay for Function { // FIXME: String escape? write!(f, "extern \"{}\" ", &**abi)?; } - write!(f, "fn {}", data.name)?; + write!(f, "fn {}", data.name.display(f.db.upcast()))?; write_generic_params(GenericDefId::FunctionId(self.id), f)?; @@ -62,7 +63,7 @@ impl HirDisplay for Function { { f.write_char('&')?; if let Some(lifetime) = lifetime { - write!(f, "{} ", lifetime.name)?; + write!(f, "{} ", lifetime.name.display(f.db.upcast()))?; } if let hir_def::type_ref::Mutability::Mut = mut_ { f.write_str("mut ")?; @@ -76,22 +77,22 @@ impl HirDisplay for Function { }; let mut first = true; - for (name, type_ref) in &data.params { + // FIXME: Use resolved `param.ty` once we no longer discard lifetimes + for (type_ref, param) in data.params.iter().zip(self.assoc_fn_params(db)) { + let local = param.as_local(db).map(|it| it.name(db)); if !first { f.write_str(", ")?; } else { first = false; - if data.has_self_param() { + if local == Some(name!(self)) { write_self_param(type_ref, f)?; continue; } } - match name { - Some(name) => write!(f, "{name}: ")?, + match local { + Some(name) => write!(f, "{}: ", name.display(f.db.upcast()))?, None => f.write_str("_: ")?, } - // FIXME: Use resolved `param.ty` or raw `type_ref`? - // The former will ignore lifetime arguments currently. type_ref.hir_fmt(f)?; } @@ -150,7 +151,7 @@ impl HirDisplay for Struct { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; f.write_str("struct ")?; - write!(f, "{}", self.name(f.db))?; + write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; let def_id = GenericDefId::AdtId(AdtId::StructId(self.id)); write_generic_params(def_id, f)?; write_where_clause(def_id, f)?; @@ -162,7 +163,7 @@ impl HirDisplay for Enum { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; f.write_str("enum ")?; - write!(f, "{}", self.name(f.db))?; + write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; let def_id = GenericDefId::AdtId(AdtId::EnumId(self.id)); write_generic_params(def_id, f)?; write_where_clause(def_id, f)?; @@ -174,7 +175,7 @@ impl HirDisplay for Union { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; f.write_str("union ")?; - write!(f, "{}", self.name(f.db))?; + write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; let def_id = GenericDefId::AdtId(AdtId::UnionId(self.id)); write_generic_params(def_id, f)?; write_where_clause(def_id, f)?; @@ -185,14 +186,14 @@ impl HirDisplay for Union { impl HirDisplay for Field { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { write_visibility(self.parent.module(f.db).id, self.visibility(f.db), f)?; - write!(f, "{}: ", self.name(f.db))?; + write!(f, "{}: ", self.name(f.db).display(f.db.upcast()))?; self.ty(f.db).hir_fmt(f) } } impl HirDisplay for Variant { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write!(f, "{}", self.name(f.db))?; + write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; let data = self.variant_data(f.db); match &*data { VariantData::Unit => {} @@ -221,7 +222,7 @@ impl HirDisplay for Variant { f.write_str(", ")?; } // Enum variant fields must be pub. - write!(f, "{}: ", field.name)?; + write!(f, "{}: ", field.name.display(f.db.upcast()))?; field.type_ref.hir_fmt(f)?; } f.write_str(" }")?; @@ -258,7 +259,7 @@ impl HirDisplay for TypeOrConstParam { impl HirDisplay for TypeParam { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write!(f, "{}", self.name(f.db))?; + write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; if f.omit_verbose_types() { return Ok(()); } @@ -285,13 +286,13 @@ impl HirDisplay for TypeParam { impl HirDisplay for LifetimeParam { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write!(f, "{}", self.name(f.db)) + write!(f, "{}", self.name(f.db).display(f.db.upcast())) } } impl HirDisplay for ConstParam { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write!(f, "const {}: ", self.name(f.db))?; + write!(f, "const {}: ", self.name(f.db).display(f.db.upcast()))?; self.ty(f.db).hir_fmt(f) } } @@ -324,7 +325,7 @@ fn write_generic_params( }; for (_, lifetime) in params.lifetimes.iter() { delim(f)?; - write!(f, "{}", lifetime.name)?; + write!(f, "{}", lifetime.name.display(f.db.upcast()))?; } for (_, ty) in params.type_or_consts.iter() { if let Some(name) = &ty.name() { @@ -334,7 +335,7 @@ fn write_generic_params( continue; } delim(f)?; - write!(f, "{name}")?; + write!(f, "{}", name.display(f.db.upcast()))?; if let Some(default) = &ty.default { f.write_str(" = ")?; default.hir_fmt(f)?; @@ -342,7 +343,7 @@ fn write_generic_params( } TypeOrConstParamData::ConstParamData(c) => { delim(f)?; - write!(f, "const {name}: ")?; + write!(f, "const {}: ", name.display(f.db.upcast()))?; c.ty.hir_fmt(f)?; } } @@ -379,7 +380,7 @@ fn write_where_clause(def: GenericDefId, f: &mut HirFormatter<'_>) -> Result<(), WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f), WherePredicateTypeTarget::TypeOrConstParam(id) => { match ¶ms.type_or_consts[*id].name() { - Some(name) => write!(f, "{name}"), + Some(name) => write!(f, "{}", name.display(f.db.upcast())), None => f.write_str("{unnamed}"), } } @@ -411,10 +412,15 @@ fn write_where_clause(def: GenericDefId, f: &mut HirFormatter<'_>) -> Result<(), WherePredicate::Lifetime { target, bound } => { if matches!(prev_pred, Some(WherePredicate::Lifetime { target: target_, .. }) if target_ == target) { - write!(f, " + {}", bound.name)?; + write!(f, " + {}", bound.name.display(f.db.upcast()))?; } else { new_predicate(f)?; - write!(f, "{}: {}", target.name, bound.name)?; + write!( + f, + "{}: {}", + target.name.display(f.db.upcast()), + bound.name.display(f.db.upcast()) + )?; } } WherePredicate::ForLifetime { lifetimes, target, bound } => { @@ -431,7 +437,7 @@ fn write_where_clause(def: GenericDefId, f: &mut HirFormatter<'_>) -> Result<(), if idx != 0 { f.write_str(", ")?; } - write!(f, "{lifetime}")?; + write!(f, "{}", lifetime.display(f.db.upcast()))?; } f.write_str("> ")?; write_target(target, f)?; @@ -461,7 +467,7 @@ impl HirDisplay for Const { let data = db.const_data(self.id); f.write_str("const ")?; match &data.name { - Some(name) => write!(f, "{name}: ")?, + Some(name) => write!(f, "{}: ", name.display(f.db.upcast()))?, None => f.write_str("_: ")?, } data.type_ref.hir_fmt(f)?; @@ -477,7 +483,7 @@ impl HirDisplay for Static { if data.mutable { f.write_str("mut ")?; } - write!(f, "{}: ", &data.name)?; + write!(f, "{}: ", data.name.display(f.db.upcast()))?; data.type_ref.hir_fmt(f)?; Ok(()) } @@ -493,7 +499,7 @@ impl HirDisplay for Trait { if data.is_auto { f.write_str("auto ")?; } - write!(f, "trait {}", data.name)?; + write!(f, "trait {}", data.name.display(f.db.upcast()))?; let def_id = GenericDefId::TraitId(self.id); write_generic_params(def_id, f)?; write_where_clause(def_id, f)?; @@ -505,7 +511,7 @@ 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)?; + write!(f, "trait {}", data.name.display(f.db.upcast()))?; let def_id = GenericDefId::TraitAliasId(self.id); write_generic_params(def_id, f)?; f.write_str(" = ")?; @@ -521,7 +527,7 @@ 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)?; let data = f.db.type_alias_data(self.id); - write!(f, "type {}", data.name)?; + write!(f, "type {}", data.name.display(f.db.upcast()))?; let def_id = GenericDefId::TypeAliasId(self.id); write_generic_params(def_id, f)?; write_where_clause(def_id, f)?; @@ -541,8 +547,8 @@ impl HirDisplay for Module { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { // FIXME: Module doesn't have visibility saved in data. match self.name(f.db) { - Some(name) => write!(f, "mod {name}"), - None if self.is_crate_root(f.db) => match self.krate(f.db).display_name(f.db) { + Some(name) => write!(f, "mod {}", name.display(f.db.upcast())), + None if self.is_crate_root() => match self.krate(f.db).display_name(f.db) { Some(name) => write!(f, "extern crate {name}"), None => f.write_str("extern crate {unknown}"), }, @@ -558,6 +564,6 @@ impl HirDisplay for Macro { hir_def::MacroId::MacroRulesId(_) => f.write_str("macro_rules!"), hir_def::MacroId::ProcMacroId(_) => f.write_str("proc_macro"), }?; - write!(f, " {}", self.name(f.db)) + write!(f, " {}", self.name(f.db).display(f.db.upcast())) } } 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 aaaa7abf3..de2390219 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::{BindingId, LabelId}, + hir::{BindingId, LabelId}, AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, GenericDefId, GenericParamId, ModuleDefId, VariantId, }; @@ -40,6 +40,7 @@ from_id![ (hir_def::TraitAliasId, crate::TraitAlias), (hir_def::StaticId, crate::Static), (hir_def::ConstId, crate::Const), + (hir_def::InTypeConstId, crate::InTypeConst), (hir_def::FunctionId, crate::Function), (hir_def::ImplId, crate::Impl), (hir_def::TypeOrConstParamId, crate::TypeOrConstParam), @@ -144,6 +145,7 @@ impl From<DefWithBody> for DefWithBodyId { DefWithBody::Static(it) => DefWithBodyId::StaticId(it.id), DefWithBody::Const(it) => DefWithBodyId::ConstId(it.id), DefWithBody::Variant(it) => DefWithBodyId::VariantId(it.into()), + DefWithBody::InTypeConst(it) => DefWithBodyId::InTypeConstId(it.id), } } } @@ -155,6 +157,7 @@ impl From<DefWithBodyId> for DefWithBody { DefWithBodyId::StaticId(it) => DefWithBody::Static(it.into()), DefWithBodyId::ConstId(it) => DefWithBody::Const(it.into()), DefWithBodyId::VariantId(it) => DefWithBody::Variant(it.into()), + DefWithBodyId::InTypeConstId(it) => DefWithBody::InTypeConst(it.into()), } } } diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 35424feec..6df625380 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -6,7 +6,7 @@ //! applied. So, the relation between syntax and HIR is many-to-one. //! //! HIR is the public API of the all of the compiler logic above syntax trees. -//! It is written in "OO" style. Each type is self contained (as in, it knows it's +//! It is written in "OO" style. Each type is self contained (as in, it knows its //! parents and full context). It should be "clean code". //! //! `hir_*` crates are the implementation of the compiler logic. @@ -33,27 +33,29 @@ pub mod symbols; mod display; -use std::{iter, ops::ControlFlow, sync::Arc}; +use std::{iter, ops::ControlFlow}; use arrayvec::ArrayVec; use base_db::{CrateDisplayName, CrateId, CrateOrigin, Edition, FileId, ProcMacroKind}; use either::Either; use hir_def::{ - adt::VariantData, body::{BodyDiagnostic, SyntheticSyntax}, - expr::{BindingAnnotation, BindingId, ExprOrPatId, LabelId, Pat}, + data::adt::VariantData, generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance}, + hir::{BindingAnnotation, BindingId, ExprOrPatId, LabelId, Pat}, item_tree::ItemTreeNode, - lang_item::{LangItem, LangItemTarget}, - layout::{Layout, LayoutError, ReprOptions}, + lang_item::LangItemTarget, + layout::{self, ReprOptions, TargetDataLayout}, + macro_id_to_def_id, nameres::{self, diagnostics::DefDiagnostic, ModuleOrigin}, per_ns::PerNs, resolver::{HasResolver, Resolver}, src::HasSource as _, - AdtId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, - EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId, - LocalEnumVariantId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId, - TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, + AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, + EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, InTypeConstId, ItemContainerId, + LifetimeParamId, LocalEnumVariantId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, + StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, + UnionId, }; use hir_expand::{name::name, MacroCallKind}; use hir_ty::{ @@ -61,14 +63,15 @@ use hir_ty::{ consteval::{try_const_usize, unknown_const_as_generic, ConstEvalError, ConstExt}, diagnostics::BodyValidationDiagnostic, display::HexifiedConst, - layout::layout_of_ty, + layout::{Layout as TyLayout, RustcEnumVariantIdx, TagEncoding}, method_resolution::{self, TyFingerprint}, mir::{self, interpret_mir}, primitive::UintTy, traits::FnTrait, AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution, - TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, WhereClause, + TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, ValueTyDefId, + WhereClause, }; use itertools::Itertools; use nameres::diagnostics::DefDiagnosticKind; @@ -79,6 +82,7 @@ use syntax::{ ast::{self, HasAttrs as _, HasDocComments, HasName}, AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, TextRange, T, }; +use triomphe::Arc; use crate::db::{DefDatabase, HirDatabase}; @@ -86,11 +90,13 @@ pub use crate::{ attrs::{HasAttrs, Namespace}, diagnostics::{ 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, + IncorrectCase, InvalidDeriveTarget, MacroDefError, MacroError, MacroExpansionParseError, + MalformedDerive, MismatchedArgCount, MissingFields, MissingMatchArms, MissingUnsafe, + MovedOutOfRef, NeedMut, NoSuchField, PrivateAssocItem, PrivateField, + ReplaceFilterMapNextWithFindMap, TypeMismatch, TypedHole, UndeclaredLabel, + UnimplementedBuiltinMacro, UnreachableLabel, UnresolvedExternCrate, UnresolvedField, + UnresolvedImport, UnresolvedMacroCall, UnresolvedMethodCall, UnresolvedModule, + UnresolvedProcMacro, UnusedMut, }, has_source::HasSource, semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits}, @@ -108,20 +114,18 @@ pub use crate::{ pub use { cfg::{CfgAtom, CfgExpr, CfgOptions}, hir_def::{ - adt::StructKind, - attr::{Attrs, AttrsWithOwner, Documentation}, - builtin_attr::AttributeTemplate, + attr::{builtin::AttributeTemplate, Attrs, AttrsWithOwner, Documentation}, + data::adt::StructKind, find_path::PrefixKind, import_map, - nameres::ModuleSource, + lang_item::LangItem, + nameres::{DefMap, ModuleSource}, path::{ModPath, PathKind}, type_ref::{Mutability, TypeRef}, visibility::Visibility, - // FIXME: This is here since it is input of a method in `HirWrite` - // and things outside of hir need to implement that trait. We probably - // should move whole `hir_ty::display` to this crate so we will become - // able to use `ModuleDef` or `Definition` instead of `ModuleDefId`. - ModuleDefId, + // FIXME: This is here since some queries take it as input that are used + // outside of hir. + {AdtId, ModuleDefId}, }, hir_expand::{ attrs::Attr, @@ -129,7 +133,8 @@ pub use { ExpandResult, HirFileId, InFile, MacroFile, Origin, }, hir_ty::{ - display::{HirDisplay, HirDisplayError, HirWrite}, + display::{ClosureStyle, HirDisplay, HirDisplayError, HirWrite}, + layout::LayoutError, mir::MirEvalError, PointerCast, Safety, }, @@ -198,7 +203,7 @@ impl Crate { pub fn root_module(self, db: &dyn HirDatabase) -> Module { let def_map = db.crate_def_map(self.id); - Module { id: def_map.module_id(def_map.root()) } + Module { id: def_map.crate_root().into() } } pub fn modules(self, db: &dyn HirDatabase) -> Vec<Module> { @@ -253,7 +258,8 @@ impl Crate { } pub fn potential_cfg(&self, db: &dyn HirDatabase) -> CfgOptions { - db.crate_graph()[self.id].potential_cfg_options.clone() + let data = &db.crate_graph()[self.id]; + data.potential_cfg_options.clone().unwrap_or_else(|| data.cfg_options.clone()) } } @@ -326,7 +332,7 @@ impl ModuleDef { segments.extend(m.name(db)) } segments.reverse(); - Some(segments.into_iter().join("::")) + Some(segments.iter().map(|it| it.display(db.upcast())).join("::")) } pub fn canonical_module_path( @@ -470,12 +476,11 @@ impl Module { /// in the module tree of any target in `Cargo.toml`. pub fn crate_root(self, db: &dyn HirDatabase) -> Module { let def_map = db.crate_def_map(self.id.krate()); - Module { id: def_map.module_id(def_map.root()) } + Module { id: def_map.crate_root().into() } } - pub fn is_crate_root(self, db: &dyn HirDatabase) -> bool { - let def_map = db.crate_def_map(self.id.krate()); - def_map.root() == self.id.local_id + pub fn is_crate_root(self) -> bool { + DefMap::ROOT == self.id.local_id } /// Iterates over all child modules. @@ -552,7 +557,11 @@ impl Module { /// Fills `acc` with the module's diagnostics. pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) { let _p = profile::span("Module::diagnostics").detail(|| { - format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) + format!( + "{:?}", + self.name(db) + .map_or("<unknown>".into(), |name| name.display(db.upcast()).to_string()) + ) }); let def_map = self.id.def_map(db.upcast()); for diag in def_map.diagnostics() { @@ -562,6 +571,7 @@ impl Module { } emit_def_diagnostic(db, acc, diag); } + for decl in self.declarations(db) { match decl { ModuleDef::Module(m) => { @@ -600,9 +610,11 @@ impl Module { } acc.extend(decl.diagnostics(db)) } + ModuleDef::Macro(m) => emit_macro_def_diagnostics(db, acc, m), _ => acc.extend(decl.diagnostics(db)), } } + self.legacy_macros(db).into_iter().for_each(|m| emit_macro_def_diagnostics(db, acc, m)); let inherent_impls = db.inherent_impls_in_crate(self.id.krate()); @@ -684,8 +696,31 @@ impl Module { } } +fn emit_macro_def_diagnostics(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, m: Macro) { + let id = macro_id_to_def_id(db.upcast(), m.id); + if let Err(e) = db.macro_def(id) { + let Some(ast) = id.ast_id().left() else { + never!("MacroDefError for proc-macro: {:?}", e); + return; + }; + emit_def_diagnostic_( + db, + acc, + &DefDiagnosticKind::MacroDefError { ast, message: e.to_string() }, + ); + } +} + fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag: &DefDiagnostic) { - match &diag.kind { + emit_def_diagnostic_(db, acc, &diag.kind) +} + +fn emit_def_diagnostic_( + db: &dyn HirDatabase, + acc: &mut Vec<AnyDiagnostic>, + diag: &DefDiagnosticKind, +) { + match diag { DefDiagnosticKind::UnresolvedModule { ast: declaration, candidates } => { let decl = declaration.to_node(db.upcast()); acc.push( @@ -725,7 +760,6 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag: .into(), ); } - DefDiagnosticKind::UnresolvedProcMacro { ast, krate } => { let (node, precise_location, macro_name, kind) = precise_macro_call_location(ast, db); acc.push( @@ -733,7 +767,6 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag: .into(), ); } - DefDiagnosticKind::UnresolvedMacroCall { ast, path } => { let (node, precise_location, _, _) = precise_macro_call_location(ast, db); acc.push( @@ -746,12 +779,16 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag: .into(), ); } - DefDiagnosticKind::MacroError { ast, message } => { let (node, precise_location, _, _) = precise_macro_call_location(ast, db); acc.push(MacroError { node, precise_location, message: message.clone() }.into()); } - + DefDiagnosticKind::MacroExpansionParseError { ast, errors } => { + let (node, precise_location, _, _) = precise_macro_call_location(ast, db); + acc.push( + MacroExpansionParseError { node, precise_location, errors: errors.clone() }.into(), + ); + } DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => { let node = ast.to_node(db.upcast()); // Must have a name, otherwise we wouldn't emit it. @@ -793,6 +830,17 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag: None => stdx::never!("derive diagnostic on item without derive attribute"), } } + DefDiagnosticKind::MacroDefError { ast, message } => { + let node = ast.to_node(db.upcast()); + acc.push( + MacroDefError { + node: InFile::new(ast.file_id, AstPtr::new(&node)), + name: node.name().map(|it| it.syntax().text_range()), + message: message.clone(), + } + .into(), + ); + } } } @@ -800,7 +848,7 @@ fn precise_macro_call_location( ast: &MacroCallKind, db: &dyn HirDatabase, ) -> (InFile<SyntaxNodePtr>, Option<TextRange>, Option<String>, MacroKind) { - // FIXME: maaybe we actually want slightly different ranges for the different macro diagnostics + // FIXME: maybe we actually want slightly different ranges for the different macro diagnostics // - e.g. the full attribute for macro errors, but only the name for name resolution match ast { MacroCallKind::FnLike { ast_id, .. } => { @@ -915,7 +963,8 @@ impl Field { } pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> { - layout_of_ty(db, &self.ty(db).ty, self.parent.module(db).krate().into()) + db.layout_of_ty(self.ty(db).ty.clone(), self.parent.module(db).krate().into()) + .map(|layout| Layout(layout, db.target_data_layout(self.krate(db).into()).unwrap())) } pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef { @@ -959,6 +1008,10 @@ impl Struct { Type::from_def(db, self.id) } + pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type { + Type::from_value_def(db, self.id) + } + pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprOptions> { db.struct_data(self.id).repr } @@ -996,6 +1049,10 @@ impl Union { Type::from_def(db, self.id) } + pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type { + Type::from_value_def(db, self.id) + } + pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> { db.union_data(self.id) .variant_data @@ -1034,6 +1091,10 @@ impl Enum { db.enum_data(self.id).variants.iter().map(|(id, _)| Variant { parent: self, id }).collect() } + pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprOptions> { + db.enum_data(self.id).repr + } + pub fn ty(self, db: &dyn HirDatabase) -> Type { Type::from_def(db, self.id) } @@ -1043,7 +1104,7 @@ impl Enum { Type::new_for_crate( self.id.lookup(db.upcast()).container.krate(), TyBuilder::builtin(match db.enum_data(self.id).variant_body_type() { - hir_def::layout::IntegerType::Pointer(sign) => match sign { + layout::IntegerType::Pointer(sign) => match sign { true => hir_def::builtin_type::BuiltinType::Int( hir_def::builtin_type::BuiltinInt::Isize, ), @@ -1051,29 +1112,34 @@ impl Enum { hir_def::builtin_type::BuiltinUint::Usize, ), }, - hir_def::layout::IntegerType::Fixed(i, sign) => match sign { + layout::IntegerType::Fixed(i, sign) => match sign { true => hir_def::builtin_type::BuiltinType::Int(match i { - hir_def::layout::Integer::I8 => hir_def::builtin_type::BuiltinInt::I8, - hir_def::layout::Integer::I16 => hir_def::builtin_type::BuiltinInt::I16, - hir_def::layout::Integer::I32 => hir_def::builtin_type::BuiltinInt::I32, - hir_def::layout::Integer::I64 => hir_def::builtin_type::BuiltinInt::I64, - hir_def::layout::Integer::I128 => hir_def::builtin_type::BuiltinInt::I128, + layout::Integer::I8 => hir_def::builtin_type::BuiltinInt::I8, + layout::Integer::I16 => hir_def::builtin_type::BuiltinInt::I16, + layout::Integer::I32 => hir_def::builtin_type::BuiltinInt::I32, + layout::Integer::I64 => hir_def::builtin_type::BuiltinInt::I64, + layout::Integer::I128 => hir_def::builtin_type::BuiltinInt::I128, }), false => hir_def::builtin_type::BuiltinType::Uint(match i { - hir_def::layout::Integer::I8 => hir_def::builtin_type::BuiltinUint::U8, - hir_def::layout::Integer::I16 => hir_def::builtin_type::BuiltinUint::U16, - hir_def::layout::Integer::I32 => hir_def::builtin_type::BuiltinUint::U32, - hir_def::layout::Integer::I64 => hir_def::builtin_type::BuiltinUint::U64, - hir_def::layout::Integer::I128 => hir_def::builtin_type::BuiltinUint::U128, + layout::Integer::I8 => hir_def::builtin_type::BuiltinUint::U8, + layout::Integer::I16 => hir_def::builtin_type::BuiltinUint::U16, + layout::Integer::I32 => hir_def::builtin_type::BuiltinUint::U32, + layout::Integer::I64 => hir_def::builtin_type::BuiltinUint::U64, + layout::Integer::I128 => hir_def::builtin_type::BuiltinUint::U128, }), }, }), ) } + /// Returns true if at least one variant of this enum is a non-unit variant. pub fn is_data_carrying(self, db: &dyn HirDatabase) -> bool { self.variants(db).iter().any(|v| !matches!(v.kind(db), StructKind::Unit)) } + + pub fn layout(self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> { + Adt::from(self).layout(db) + } } impl HasVisibility for Enum { @@ -1103,6 +1169,10 @@ impl Variant { self.parent } + pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type { + Type::from_value_def(db, EnumVariantId { parent: self.parent.id, local_id: self.id }) + } + pub fn name(self, db: &dyn HirDatabase) -> Name { db.enum_data(self.parent.id).variants[self.id].name.clone() } @@ -1130,6 +1200,18 @@ impl Variant { pub fn eval(self, db: &dyn HirDatabase) -> Result<i128, ConstEvalError> { db.const_eval_discriminant(self.into()) } + + pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> { + let parent_enum = self.parent_enum(db); + let parent_layout = parent_enum.layout(db)?; + Ok(match &parent_layout.0.variants { + layout::Variants::Multiple { variants, .. } => Layout( + Arc::new(variants[RustcEnumVariantIdx(self.id)].clone()), + db.target_data_layout(parent_enum.krate(db).into()).unwrap(), + ), + _ => parent_layout, + }) + } } /// Variants inherit visibility from the parent enum. @@ -1161,7 +1243,9 @@ impl Adt { if db.generic_params(self.into()).iter().count() != 0 { return Err(LayoutError::HasPlaceholder); } - db.layout_of_adt(self.into(), Substitution::empty(Interner)) + let krate = self.krate(db).id; + db.layout_of_adt(self.into(), Substitution::empty(Interner), krate) + .map(|layout| Layout(layout, db.target_data_layout(krate).unwrap())) } /// Turns this ADT into a type. Any type parameters of the ADT will be @@ -1292,8 +1376,9 @@ pub enum DefWithBody { Static(Static), Const(Const), Variant(Variant), + InTypeConst(InTypeConst), } -impl_from!(Function, Const, Static, Variant for DefWithBody); +impl_from!(Function, Const, Static, Variant, InTypeConst for DefWithBody); impl DefWithBody { pub fn module(self, db: &dyn HirDatabase) -> Module { @@ -1302,6 +1387,7 @@ impl DefWithBody { DefWithBody::Function(f) => f.module(db), DefWithBody::Static(s) => s.module(db), DefWithBody::Variant(v) => v.module(db), + DefWithBody::InTypeConst(c) => c.module(db), } } @@ -1311,6 +1397,7 @@ impl DefWithBody { DefWithBody::Static(s) => Some(s.name(db)), DefWithBody::Const(c) => c.name(db), DefWithBody::Variant(v) => Some(v.name(db)), + DefWithBody::InTypeConst(_) => None, } } @@ -1321,6 +1408,11 @@ impl DefWithBody { DefWithBody::Static(it) => it.ty(db), DefWithBody::Const(it) => it.ty(db), DefWithBody::Variant(it) => it.parent.variant_body_ty(db), + DefWithBody::InTypeConst(it) => Type::new_with_resolver_inner( + db, + &DefWithBodyId::from(it.id).resolver(db.upcast()), + TyKind::Error.intern(Interner), + ), } } @@ -1330,6 +1422,7 @@ impl DefWithBody { DefWithBody::Static(it) => it.id.into(), DefWithBody::Const(it) => it.id.into(), DefWithBody::Variant(it) => it.into(), + DefWithBody::InTypeConst(it) => it.id.into(), } } @@ -1392,6 +1485,12 @@ impl DefWithBody { } .into(), ), + BodyDiagnostic::UnreachableLabel { node, name } => { + acc.push(UnreachableLabel { node: node.clone(), name: name.clone() }.into()) + } + BodyDiagnostic::UndeclaredLabel { node, name } => { + acc.push(UndeclaredLabel { node: node.clone(), name: name.clone() }.into()) + } } } @@ -1404,14 +1503,6 @@ impl DefWithBody { let field = source_map.field_syntax(expr); acc.push(NoSuchField { field }.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 } => { acc.push( MismatchedArgCount { call_expr: expr_syntax(call_expr), expected, found } @@ -1483,14 +1574,29 @@ impl DefWithBody { .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::TypedHole { expr, expected } => { + let expr = expr_syntax(*expr); + acc.push( + TypedHole { + expr, + expected: Type::new(db, DefWithBodyId::from(self), expected.clone()), + } + .into(), + ) + } } } 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 { @@ -1515,7 +1621,7 @@ impl DefWithBody { match source_map.expr_syntax(expr) { Ok(expr) => acc.push(MissingUnsafe { expr }.into()), Err(SyntheticSyntax) => { - // FIXME: Here and eslwhere in this file, the `expr` was + // FIXME: Here and elsewhere in this file, the `expr` was // desugared, report or assert that this doesn't happen. } } @@ -1523,35 +1629,71 @@ 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()); + if let Ok(borrowck_results) = db.borrowck(self.into()) { + for borrowck_result in borrowck_results.iter() { + let mir_body = &borrowck_result.mir_body; + for moof in &borrowck_result.moved_out_of_ref { + let span: InFile<SyntaxNodePtr> = match moof.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( + MovedOutOfRef { ty: Type::new_for_crate(krate, moof.ty.clone()), span } + .into(), + ) + } + let mol = &borrowck_result.mutability_of_locals; + for (binding_id, binding_data) in hir_body.bindings.iter() { + if binding_data.problems.is_some() { + // We should report specific diagnostics for these problems, not `need-mut` and `unused-mut`. + continue; + } + let Some(&local) = mir_body.binding_locals.get(binding_id) else { + continue; + }; + let need_mut = &mol[local]; + 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) => { + if !infer.mutated_bindings_in_closure.contains(&binding_id) { + let should_ignore = matches!(body[binding_id].name.as_str(), Some(x) if x.starts_with("_")); + if !should_ignore { + acc.push(UnusedMut { local }.into()) + } + } } } - (mir::MutabilityReason::Not, true) => acc.push(UnusedMut { local }.into()), } } } @@ -1665,6 +1807,8 @@ impl DefWithBody { DefWithBody::Static(it) => it.into(), DefWithBody::Const(it) => it.into(), DefWithBody::Variant(it) => it.into(), + // FIXME: don't ignore diagnostics for in type const + DefWithBody::InTypeConst(_) => return, }; for diag in hir_ty::diagnostics::incorrect_case(db, krate, def.into()) { acc.push(diag.into()) @@ -1686,6 +1830,10 @@ impl Function { db.function_data(self.id).name.clone() } + pub fn ty(self, db: &dyn HirDatabase) -> Type { + Type::from_value_def(db, self.id) + } + /// Get this function's return type pub fn ret_type(self, db: &dyn HirDatabase) -> Type { let resolver = self.id.resolver(db.upcast()); @@ -1797,12 +1945,41 @@ impl Function { 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(()) + pub fn eval( + self, + db: &dyn HirDatabase, + span_formatter: impl Fn(FileId, TextRange) -> String, + ) -> String { + let body = match db.monomorphized_mir_body( + self.id.into(), + Substitution::empty(Interner), + db.trait_environment(self.id.into()), + ) { + Ok(body) => body, + Err(e) => { + let mut r = String::new(); + _ = e.pretty_print(&mut r, db, &span_formatter); + return r; + } + }; + let (result, stdout, stderr) = interpret_mir(db, &body, false); + let mut text = match result { + Ok(_) => "pass".to_string(), + Err(e) => { + let mut r = String::new(); + _ = e.pretty_print(&mut r, db, &span_formatter); + r + } + }; + if !stdout.is_empty() { + text += "\n--------- stdout ---------\n"; + text += &stdout; + } + if !stderr.is_empty() { + text += "\n--------- stderr ---------\n"; + text += &stderr; + } + text } } @@ -1837,7 +2014,7 @@ impl Param { } pub fn name(&self, db: &dyn HirDatabase) -> Option<Name> { - db.function_data(self.func.id).params[self.idx].0.clone() + Some(self.as_local(db)?.name(db)) } pub fn as_local(&self, db: &dyn HirDatabase) -> Option<Local> { @@ -1878,7 +2055,7 @@ impl SelfParam { func_data .params .first() - .map(|(_, param)| match &**param { + .map(|param| match &**param { TypeRef::Reference(.., mutability) => match mutability { hir_def::type_ref::Mutability::Shared => Access::Shared, hir_def::type_ref::Mutability::Mut => Access::Exclusive, @@ -1921,6 +2098,17 @@ impl HasVisibility for Function { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct InTypeConst { + pub(crate) id: InTypeConstId, +} + +impl InTypeConst { + pub fn module(self, db: &dyn HirDatabase) -> Module { + Module { id: self.id.lookup(db.upcast()).owner.module(db.upcast()) } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Const { pub(crate) id: ConstId, } @@ -1939,24 +2127,12 @@ impl Const { } pub fn ty(self, db: &dyn HirDatabase) -> Type { - let data = db.const_data(self.id); - let resolver = self.id.resolver(db.upcast()); - let ctx = hir_ty::TyLoweringContext::new(db, &resolver); - let ty = ctx.lower_ty(&data.type_ref); - Type::new_with_resolver_inner(db, &resolver, ty) + Type::from_value_def(db, self.id) } pub fn render_eval(self, db: &dyn HirDatabase) -> Result<String, ConstEvalError> { - let c = db.const_eval(self.id)?; + let c = db.const_eval(self.id.into(), Substitution::empty(Interner))?; 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); } } @@ -1990,11 +2166,7 @@ impl Static { } pub fn ty(self, db: &dyn HirDatabase) -> Type { - let data = db.static_data(self.id); - let resolver = self.id.resolver(db.upcast()); - let ctx = hir_ty::TyLoweringContext::new(db, &resolver); - let ty = ctx.lower_ty(&data.type_ref); - Type::new_with_resolver_inner(db, &resolver, ty) + Type::from_value_def(db, self.id) } } @@ -2366,7 +2538,7 @@ impl AsAssocItem for DefWithBody { match self { DefWithBody::Function(it) => it.as_assoc_item(db), DefWithBody::Const(it) => it.as_assoc_item(db), - DefWithBody::Static(_) | DefWithBody::Variant(_) => None, + DefWithBody::Static(_) | DefWithBody::Variant(_) | DefWithBody::InTypeConst(_) => None, } } } @@ -2492,14 +2664,22 @@ impl GenericDef { Either::Right(x) => GenericParam::TypeParam(x), } }); - let lt_params = generics + self.lifetime_params(db) + .into_iter() + .map(GenericParam::LifetimeParam) + .chain(ty_params) + .collect() + } + + pub fn lifetime_params(self, db: &dyn HirDatabase) -> Vec<LifetimeParam> { + let generics = db.generic_params(self.into()); + generics .lifetimes .iter() .map(|(local_id, _)| LifetimeParam { id: LifetimeParamId { parent: self.into(), local_id }, }) - .map(GenericParam::LifetimeParam); - lt_params.chain(ty_params).collect() + .collect() } pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeOrConstParam> { @@ -2545,8 +2725,12 @@ impl LocalSource { self.source.file_id.original_file(db.upcast()) } - pub fn name(&self) -> Option<ast::Name> { - self.source.value.name() + pub fn file(&self) -> HirFileId { + self.source.file_id + } + + pub fn name(&self) -> Option<InFile<ast::Name>> { + self.source.as_ref().map(|it| it.name()).transpose() } pub fn syntax(&self) -> &SyntaxNode { @@ -2616,6 +2800,22 @@ impl Local { /// 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); + self.sources_(db, &body, &source_map).collect() + } + + /// The leftmost definition for this local. Example: `let (a$0, _) | (_, a) = x;` + pub fn primary_source(self, db: &dyn HirDatabase) -> LocalSource { + let (body, source_map) = db.body_with_source_map(self.parent); + let src = self.sources_(db, &body, &source_map).next().unwrap(); + src + } + + fn sources_<'a>( + self, + db: &'a dyn HirDatabase, + body: &'a hir_def::body::Body, + source_map: &'a hir_def::body::BodySourceMap, + ) -> impl Iterator<Item = LocalSource> + 'a { body[self.binding_id] .definitions .iter() @@ -2628,14 +2828,7 @@ impl Local { Either::Right(it) => Either::Right(it.to_node(&root)), }) }) - .map(|source| LocalSource { local: self, source }) - .collect() - } - - /// 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() + .map(move |source| LocalSource { local: self, source }) } } @@ -2689,9 +2882,7 @@ impl BuiltinAttr { } fn builtin(name: &str) -> Option<Self> { - hir_def::builtin_attr::INERT_ATTRIBUTES - .iter() - .position(|tool| tool.name == name) + hir_def::attr::builtin::find_builtin_attr_idx(name) .map(|idx| BuiltinAttr { krate: None, idx: idx as u32 }) } @@ -2699,14 +2890,14 @@ impl BuiltinAttr { // FIXME: Return a `Name` here match self.krate { Some(krate) => db.crate_def_map(krate).registered_attrs()[self.idx as usize].clone(), - None => SmolStr::new(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx as usize].name), + None => SmolStr::new(hir_def::attr::builtin::INERT_ATTRIBUTES[self.idx as usize].name), } } pub fn template(&self, _: &dyn HirDatabase) -> Option<AttributeTemplate> { match self.krate { Some(_) => None, - None => Some(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx as usize].template), + None => Some(hir_def::attr::builtin::INERT_ATTRIBUTES[self.idx as usize].template), } } } @@ -2729,7 +2920,7 @@ impl ToolModule { } fn builtin(name: &str) -> Option<Self> { - hir_def::builtin_attr::TOOL_MODULES + hir_def::attr::builtin::TOOL_MODULES .iter() .position(|&tool| tool == name) .map(|idx| ToolModule { krate: None, idx: idx as u32 }) @@ -2739,7 +2930,7 @@ impl ToolModule { // FIXME: Return a `Name` here match self.krate { Some(krate) => db.crate_def_map(krate).registered_tools()[self.idx as usize].clone(), - None => SmolStr::new(hir_def::builtin_attr::TOOL_MODULES[self.idx as usize]), + None => SmolStr::new(hir_def::attr::builtin::TOOL_MODULES[self.idx as usize]), } } } @@ -3117,6 +3308,103 @@ impl TraitRef { } } +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct Closure { + id: ClosureId, + subst: Substitution, +} + +impl From<Closure> for ClosureId { + fn from(value: Closure) -> Self { + value.id + } +} + +impl Closure { + fn as_ty(self) -> Ty { + TyKind::Closure(self.id, self.subst).intern(Interner) + } + + pub fn display_with_id(&self, db: &dyn HirDatabase) -> String { + self.clone().as_ty().display(db).with_closure_style(ClosureStyle::ClosureWithId).to_string() + } + + pub fn display_with_impl(&self, db: &dyn HirDatabase) -> String { + self.clone().as_ty().display(db).with_closure_style(ClosureStyle::ImplFn).to_string() + } + + pub fn captured_items(&self, db: &dyn HirDatabase) -> Vec<ClosureCapture> { + let owner = db.lookup_intern_closure((self.id).into()).0; + let infer = &db.infer(owner); + let info = infer.closure_info(&self.id); + info.0 + .iter() + .cloned() + .map(|capture| ClosureCapture { owner, closure: self.id, capture }) + .collect() + } + + pub fn capture_types(&self, db: &dyn HirDatabase) -> Vec<Type> { + let owner = db.lookup_intern_closure((self.id).into()).0; + let infer = &db.infer(owner); + let (captures, _) = infer.closure_info(&self.id); + captures + .iter() + .cloned() + .map(|capture| Type { + env: db.trait_environment_for_body(owner), + ty: capture.ty(&self.subst), + }) + .collect() + } + + pub fn fn_trait(&self, db: &dyn HirDatabase) -> FnTrait { + let owner = db.lookup_intern_closure((self.id).into()).0; + let infer = &db.infer(owner); + let info = infer.closure_info(&self.id); + info.1 + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ClosureCapture { + owner: DefWithBodyId, + closure: ClosureId, + capture: hir_ty::CapturedItem, +} + +impl ClosureCapture { + pub fn local(&self) -> Local { + Local { parent: self.owner, binding_id: self.capture.local() } + } + + pub fn kind(&self) -> CaptureKind { + match self.capture.kind() { + hir_ty::CaptureKind::ByRef( + hir_ty::mir::BorrowKind::Shallow | hir_ty::mir::BorrowKind::Shared, + ) => CaptureKind::SharedRef, + hir_ty::CaptureKind::ByRef(hir_ty::mir::BorrowKind::Unique) => { + CaptureKind::UniqueSharedRef + } + hir_ty::CaptureKind::ByRef(hir_ty::mir::BorrowKind::Mut { .. }) => { + CaptureKind::MutableRef + } + hir_ty::CaptureKind::ByValue => CaptureKind::Move, + } + } + + pub fn display_place(&self, db: &dyn HirDatabase) -> String { + self.capture.display_place(self.owner, db) + } +} + +pub enum CaptureKind { + SharedRef, + UniqueSharedRef, + MutableRef, + Move, +} + #[derive(Clone, PartialEq, Eq, Debug)] pub struct Type { env: Arc<TraitEnvironment>, @@ -3164,24 +3452,33 @@ impl Type { Type { env: environment, ty } } - fn from_def(db: &dyn HirDatabase, def: impl HasResolver + Into<TyDefId>) -> Type { - let ty_def = def.into(); - let parent_subst = match ty_def { - TyDefId::TypeAliasId(id) => match id.lookup(db.upcast()).container { - ItemContainerId::TraitId(id) => { - let subst = TyBuilder::subst_for_def(db, id, None).fill_with_unknown().build(); - Some(subst) - } - ItemContainerId::ImplId(id) => { - let subst = TyBuilder::subst_for_def(db, id, None).fill_with_unknown().build(); - Some(subst) - } - _ => None, + fn from_def(db: &dyn HirDatabase, def: impl Into<TyDefId> + HasResolver) -> Type { + let ty = db.ty(def.into()); + let substs = TyBuilder::unknown_subst( + db, + match def.into() { + TyDefId::AdtId(it) => GenericDefId::AdtId(it), + TyDefId::TypeAliasId(it) => GenericDefId::TypeAliasId(it), + TyDefId::BuiltinType(_) => return Type::new(db, def, ty.skip_binders().clone()), }, - _ => None, - }; - let ty = TyBuilder::def_ty(db, ty_def, parent_subst).fill_with_unknown().build(); - Type::new(db, def, ty) + ); + Type::new(db, def, ty.substitute(Interner, &substs)) + } + + fn from_value_def(db: &dyn HirDatabase, def: impl Into<ValueTyDefId> + HasResolver) -> Type { + let ty = db.value_ty(def.into()); + let substs = TyBuilder::unknown_subst( + db, + match def.into() { + ValueTyDefId::ConstId(it) => GenericDefId::ConstId(it), + ValueTyDefId::FunctionId(it) => GenericDefId::FunctionId(it), + ValueTyDefId::StructId(it) => GenericDefId::AdtId(AdtId::StructId(it)), + ValueTyDefId::UnionId(it) => GenericDefId::AdtId(AdtId::UnionId(it)), + ValueTyDefId::EnumVariantId(it) => GenericDefId::EnumVariantId(it), + ValueTyDefId::StaticId(_) => return Type::new(db, def, ty.skip_binders().clone()), + }, + ); + Type::new(db, def, ty.substitute(Interner, &substs)) } pub fn new_slice(ty: Type) -> Type { @@ -3237,6 +3534,14 @@ impl Type { } } + pub fn is_scalar(&self) -> bool { + matches!(self.ty.kind(Interner), TyKind::Scalar(_)) + } + + pub fn is_tuple(&self) -> bool { + matches!(self.ty.kind(Interner), TyKind::Tuple(..)) + } + pub fn remove_ref(&self) -> Option<Type> { match &self.ty.kind(Interner) { TyKind::Ref(.., ty) => Some(self.derived(ty.clone())), @@ -3331,7 +3636,7 @@ impl Type { binders: CanonicalVarKinds::empty(Interner), }; - db.trait_solve(self.env.krate, goal).is_some() + db.trait_solve(self.env.krate, self.env.block, goal).is_some() } pub fn normalize_trait_assoc_type( @@ -3378,7 +3683,12 @@ impl Type { } pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> { + let mut the_ty = &self.ty; let callee = match self.ty.kind(Interner) { + TyKind::Ref(_, _, ty) if ty.as_closure().is_some() => { + the_ty = ty; + Callee::Closure(ty.as_closure().unwrap()) + } TyKind::Closure(id, _) => Callee::Closure(*id), TyKind::Function(_) => Callee::FnPtr, TyKind::FnDef(..) => Callee::Def(self.ty.callable_def(db)?), @@ -3393,7 +3703,7 @@ impl Type { } }; - let sig = self.ty.callable_sig(db)?; + let sig = the_ty.callable_sig(db)?; Some(Callable { ty: self.clone(), sig, callee, is_bound_method: false }) } @@ -3401,6 +3711,13 @@ impl Type { matches!(self.ty.kind(Interner), TyKind::Closure { .. }) } + pub fn as_closure(&self) -> Option<Closure> { + match self.ty.kind(Interner) { + TyKind::Closure(id, subst) => Some(Closure { id: *id, subst: subst.clone() }), + _ => None, + } + } + pub fn is_fn(&self) -> bool { matches!(self.ty.kind(Interner), TyKind::FnDef(..) | TyKind::Function { .. }) } @@ -3502,23 +3819,24 @@ impl Type { } } - pub fn as_array(&self, _db: &dyn HirDatabase) -> Option<(Type, usize)> { + pub fn as_array(&self, db: &dyn HirDatabase) -> Option<(Type, usize)> { if let TyKind::Array(ty, len) = &self.ty.kind(Interner) { - try_const_usize(len).map(|x| (self.derived(ty.clone()), x as usize)) + try_const_usize(db, len).map(|x| (self.derived(ty.clone()), x as usize)) } else { None } } - pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a { + /// Returns types that this type dereferences to (including this type itself). The returned + /// iterator won't yield the same type more than once even if the deref chain contains a cycle. + pub fn autoderef(&self, db: &dyn HirDatabase) -> impl Iterator<Item = Type> + '_ { self.autoderef_(db).map(move |ty| self.derived(ty)) } - fn autoderef_<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Ty> + 'a { + fn autoderef_(&self, db: &dyn HirDatabase) -> impl Iterator<Item = Ty> { // There should be no inference vars in types passed here let canonical = hir_ty::replace_errors_with_variables(&self.ty); - let environment = self.env.clone(); - autoderef(db, environment, canonical).map(|canonical| canonical.value) + autoderef(db, self.env.clone(), canonical) } // This would be nicer if it just returned an iterator, but that runs into @@ -3636,7 +3954,7 @@ impl Type { 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 + // add the type and const parameters .chain(self.type_and_const_arguments(db)) } @@ -3955,6 +4273,11 @@ impl Type { .map(|id| TypeOrConstParam { id }.split(db).either_into()) .collect() } + + pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> { + db.layout_of_ty(self.ty.clone(), self.env.krate) + .map(|layout| Layout(layout, db.target_data_layout(self.env.krate).unwrap())) + } } // FIXME: Document this @@ -4064,6 +4387,48 @@ fn closure_source(db: &dyn HirDatabase, closure: ClosureId) -> Option<ast::Closu } } +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Layout(Arc<TyLayout>, Arc<TargetDataLayout>); + +impl Layout { + pub fn size(&self) -> u64 { + self.0.size.bytes() + } + + pub fn align(&self) -> u64 { + self.0.align.abi.bytes() + } + + pub fn niches(&self) -> Option<u128> { + Some(self.0.largest_niche?.available(&*self.1)) + } + + pub fn field_offset(&self, idx: usize) -> Option<u64> { + match self.0.fields { + layout::FieldsShape::Primitive => None, + layout::FieldsShape::Union(_) => Some(0), + layout::FieldsShape::Array { stride, count } => { + let i = u64::try_from(idx).ok()?; + (i < count).then_some((stride * i).bytes()) + } + layout::FieldsShape::Arbitrary { ref offsets, .. } => Some(offsets.get(idx)?.bytes()), + } + } + + pub fn enum_tag_size(&self) -> Option<usize> { + let tag_size = + if let layout::Variants::Multiple { tag, tag_encoding, .. } = &self.0.variants { + match tag_encoding { + TagEncoding::Direct => tag.size(&*self.1).bytes_usize(), + TagEncoding::Niche { .. } => 0, + } + } else { + return None; + }; + Some(tag_size) + } +} + #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum BindingMode { Move, @@ -4215,6 +4580,12 @@ impl HasCrate for Union { } } +impl HasCrate for Enum { + fn krate(&self, db: &dyn HirDatabase) -> Crate { + self.module(db).krate() + } +} + impl HasCrate for Field { fn krate(&self, db: &dyn HirDatabase) -> Crate { self.parent_def(db).module(db).krate() @@ -4286,3 +4657,90 @@ impl HasCrate for Module { Module::krate(*self) } } + +pub trait HasContainer { + fn container(&self, db: &dyn HirDatabase) -> ItemContainer; +} + +impl HasContainer for Module { + fn container(&self, db: &dyn HirDatabase) -> ItemContainer { + // FIXME: handle block expressions as modules (their parent is in a different DefMap) + let def_map = self.id.def_map(db.upcast()); + match def_map[self.id.local_id].parent { + Some(parent_id) => ItemContainer::Module(Module { id: def_map.module_id(parent_id) }), + None => ItemContainer::Crate(def_map.krate()), + } + } +} + +impl HasContainer for Function { + fn container(&self, db: &dyn HirDatabase) -> ItemContainer { + container_id_to_hir(self.id.lookup(db.upcast()).container) + } +} + +impl HasContainer for Struct { + fn container(&self, db: &dyn HirDatabase) -> ItemContainer { + ItemContainer::Module(Module { id: self.id.lookup(db.upcast()).container }) + } +} + +impl HasContainer for Union { + fn container(&self, db: &dyn HirDatabase) -> ItemContainer { + ItemContainer::Module(Module { id: self.id.lookup(db.upcast()).container }) + } +} + +impl HasContainer for Enum { + fn container(&self, db: &dyn HirDatabase) -> ItemContainer { + ItemContainer::Module(Module { id: self.id.lookup(db.upcast()).container }) + } +} + +impl HasContainer for TypeAlias { + fn container(&self, db: &dyn HirDatabase) -> ItemContainer { + container_id_to_hir(self.id.lookup(db.upcast()).container) + } +} + +impl HasContainer for Const { + fn container(&self, db: &dyn HirDatabase) -> ItemContainer { + container_id_to_hir(self.id.lookup(db.upcast()).container) + } +} + +impl HasContainer for Static { + fn container(&self, db: &dyn HirDatabase) -> ItemContainer { + container_id_to_hir(self.id.lookup(db.upcast()).container) + } +} + +impl HasContainer for Trait { + fn container(&self, db: &dyn HirDatabase) -> ItemContainer { + ItemContainer::Module(Module { id: self.id.lookup(db.upcast()).container }) + } +} + +impl HasContainer for TraitAlias { + fn container(&self, db: &dyn HirDatabase) -> ItemContainer { + ItemContainer::Module(Module { id: self.id.lookup(db.upcast()).container }) + } +} + +fn container_id_to_hir(c: ItemContainerId) -> ItemContainer { + match c { + ItemContainerId::ExternBlockId(_id) => ItemContainer::ExternBlock(), + ItemContainerId::ModuleId(id) => ItemContainer::Module(Module { id }), + ItemContainerId::ImplId(id) => ItemContainer::Impl(Impl { id }), + ItemContainerId::TraitId(id) => ItemContainer::Trait(Trait { id }), + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ItemContainer { + Trait(Trait), + Impl(Impl), + Module(Module), + ExternBlock(), + Crate(CrateId), +} diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 407ba6f65..5a76a9185 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -7,9 +7,10 @@ use std::{cell::RefCell, fmt, iter, mem, ops}; use base_db::{FileId, FileRange}; use either::Either; use hir_def::{ - body, - expr::Expr, + hir::Expr, + lower::LowerCtx, macro_id_to_def_id, + nameres::MacroSubNs, resolver::{self, HasResolver, Resolver, TypeNs}, type_ref::Mutability, AsMacroCall, DefWithBodyId, FieldId, FunctionId, MacroId, TraitId, VariantId, @@ -140,7 +141,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.parse(file_id) } - pub fn parse_or_expand(&self, file_id: HirFileId) -> Option<SyntaxNode> { + pub fn parse_or_expand(&self, file_id: HirFileId) -> SyntaxNode { self.imp.parse_or_expand(file_id) } @@ -350,6 +351,13 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.type_of_pat(pat) } + /// It also includes the changes that binding mode makes in the type. For example in + /// `let ref x @ Some(_) = None` the result of `type_of_pat` is `Option<T>` but the result + /// of this function is `&mut Option<T>` + pub fn type_of_binding_in_pat(&self, pat: &ast::IdentPat) -> Option<Type> { + self.imp.type_of_binding_in_pat(pat) + } + pub fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> { self.imp.type_of_self(param) } @@ -475,10 +483,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.scope_at_offset(node, offset) } - pub fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> { - self.imp.scope_for_def(def) - } - pub fn assert_contains_node(&self, node: &SyntaxNode) { self.imp.assert_contains_node(node) } @@ -518,23 +522,23 @@ impl<'db> SemanticsImpl<'db> { tree } - fn parse_or_expand(&self, file_id: HirFileId) -> Option<SyntaxNode> { - let node = self.db.parse_or_expand(file_id)?; + fn parse_or_expand(&self, file_id: HirFileId) -> SyntaxNode { + let node = self.db.parse_or_expand(file_id); self.cache(node.clone(), file_id); - Some(node) + node } fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { let sa = self.analyze_no_infer(macro_call.syntax())?; let file_id = sa.expand(self.db, InFile::new(sa.file_id, macro_call))?; - let node = self.parse_or_expand(file_id)?; + let node = self.parse_or_expand(file_id); Some(node) } fn expand_attr_macro(&self, item: &ast::Item) -> Option<SyntaxNode> { let src = self.wrap_node_infile(item.clone()); let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(src))?; - self.parse_or_expand(macro_call_id.as_file()) + Some(self.parse_or_expand(macro_call_id.as_file())) } fn expand_derive_as_pseudo_attr_macro(&self, attr: &ast::Attr) -> Option<SyntaxNode> { @@ -543,7 +547,7 @@ impl<'db> SemanticsImpl<'db> { let call_id = self.with_ctx(|ctx| { ctx.attr_to_derive_macro_call(src.with_value(&adt), src).map(|(_, it, _)| it) })?; - self.parse_or_expand(call_id.as_file()) + Some(self.parse_or_expand(call_id.as_file())) } fn resolve_derive_macro(&self, attr: &ast::Attr) -> Option<Vec<Option<Macro>>> { @@ -566,7 +570,7 @@ impl<'db> SemanticsImpl<'db> { .into_iter() .flat_map(|call| { let file_id = call?.as_file(); - let node = self.db.parse_or_expand(file_id)?; + let node = self.db.parse_or_expand(file_id); self.cache(node.clone(), file_id); Some(node) }) @@ -609,7 +613,7 @@ impl<'db> SemanticsImpl<'db> { let krate = resolver.krate(); let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| { resolver - .resolve_path_as_macro(self.db.upcast(), &path) + .resolve_path_as_macro(self.db.upcast(), &path, Some(MacroSubNs::Bang)) .map(|it| macro_id_to_def_id(self.db.upcast(), it)) })?; hir_expand::db::expand_speculative( @@ -990,7 +994,7 @@ impl<'db> SemanticsImpl<'db> { } fn diagnostics_display_range(&self, src: InFile<SyntaxNodePtr>) -> FileRange { - let root = self.parse_or_expand(src.file_id).unwrap(); + let root = self.parse_or_expand(src.file_id); let node = src.map(|it| it.to_node(&root)); node.as_ref().original_file_range(self.db.upcast()) } @@ -1065,21 +1069,22 @@ impl<'db> SemanticsImpl<'db> { fn resolve_type(&self, ty: &ast::Type) -> Option<Type> { let analyze = self.analyze(ty.syntax())?; - let ctx = body::LowerCtx::new(self.db.upcast(), analyze.file_id); - let ty = hir_ty::TyLoweringContext::new(self.db, &analyze.resolver) - .lower_ty(&crate::TypeRef::from_ast(&ctx, ty.clone())); + let ctx = LowerCtx::with_file_id(self.db.upcast(), analyze.file_id); + let ty = hir_ty::TyLoweringContext::new( + self.db, + &analyze.resolver, + analyze.resolver.module().into(), + ) + .lower_ty(&crate::TypeRef::from_ast(&ctx, ty.clone())); Some(Type::new_with_resolver(self.db, &analyze.resolver, ty)) } fn resolve_trait(&self, path: &ast::Path) -> Option<Trait> { let analyze = self.analyze(path.syntax())?; let hygiene = hir_expand::hygiene::Hygiene::new(self.db.upcast(), analyze.file_id); - let ctx = body::LowerCtx::with_hygiene(self.db.upcast(), &hygiene); + let ctx = LowerCtx::with_hygiene(self.db.upcast(), &hygiene); let hir_path = Path::from_src(path.clone(), &ctx)?; - match analyze - .resolver - .resolve_path_in_type_ns_fully(self.db.upcast(), hir_path.mod_path())? - { + match analyze.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), &hir_path)? { TypeNs::TraitId(id) => Some(Trait { id }), _ => None, } @@ -1141,6 +1146,10 @@ impl<'db> SemanticsImpl<'db> { .map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced }) } + fn type_of_binding_in_pat(&self, pat: &ast::IdentPat) -> Option<Type> { + self.analyze(pat.syntax())?.type_of_binding_in_pat(self.db, pat) + } + fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> { self.analyze(param.syntax())?.type_of_self(self.db, param) } @@ -1298,12 +1307,6 @@ impl<'db> SemanticsImpl<'db> { ) } - fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> { - let file_id = self.db.lookup_intern_trait(def.id).id.file_id(); - let resolver = def.id.resolver(self.db.upcast()); - SemanticsScope { db: self.db, file_id, resolver } - } - fn source<Def: HasSource>(&self, def: Def) -> Option<InFile<Def::Ast>> where Def::Ast: AstNode, @@ -1647,6 +1650,7 @@ impl<'a> SemanticsScope<'a> { VisibleTraits(resolver.traits_in_scope(self.db.upcast())) } + /// Calls the passed closure `f` on all names in scope. pub fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) { let scope = self.resolver.names_in_scope(self.db.upcast()); for (name, entries) in scope { @@ -1674,7 +1678,7 @@ impl<'a> SemanticsScope<'a> { /// Resolve a path as-if it was written at the given scope. This is /// necessary a heuristic, as it doesn't take hygiene into account. pub fn speculative_resolve(&self, path: &ast::Path) -> Option<PathResolution> { - let ctx = body::LowerCtx::new(self.db.upcast(), self.file_id); + let ctx = LowerCtx::with_file_id(self.db.upcast(), self.file_id); let path = Path::from_src(path.clone(), &ctx)?; resolve_hir_path(self.db, &self.resolver, &path) } 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 f6f8c9a25..c50ffa4f8 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 @@ -14,7 +14,7 @@ //! expression, an item definition. //! //! Knowing only the syntax gives us relatively little info. For example, -//! looking at the syntax of the function we can realise that it is a part of an +//! looking at the syntax of the function we can realize that it is a part of an //! `impl` block, but we won't be able to tell what trait function the current //! function overrides, and whether it does that correctly. For that, we need to //! go from [`ast::Fn`] to [`crate::Function`], and that's exactly what this @@ -88,9 +88,11 @@ use base_db::FileId; use hir_def::{ child_by_source::ChildBySource, - dyn_map::DynMap, - expr::{BindingId, LabelId}, - keys::{self, Key}, + dyn_map::{ + keys::{self, Key}, + DynMap, + }, + hir::{BindingId, LabelId}, AdtId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FieldId, FunctionId, GenericDefId, GenericParamId, ImplId, LifetimeParamId, MacroId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeParamId, UnionId, VariantId, 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 c24d196e1..ecb1b306a 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -5,21 +5,19 @@ //! //! So, this modules should not be used during hir construction, it exists //! purely for "IDE needs". -use std::{ - iter::{self, once}, - sync::Arc, -}; +use std::iter::{self, once}; use either::Either; use hir_def::{ body::{ - self, scope::{ExprScopes, ScopeId}, Body, BodySourceMap, }, - expr::{ExprId, Pat, PatId}, + hir::{BindingId, ExprId, Pat, PatId}, lang_item::LangItem, + lower::LowerCtx, macro_id_to_def_id, + nameres::MacroSubNs, path::{ModPath, Path, PathKind}, resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs}, type_ref::Mutability, @@ -39,8 +37,9 @@ use hir_ty::{ record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions, UnsafeExpr, }, - method_resolution::{self, lang_items_for_bin_op}, - Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, TyLoweringContext, + lang_items::lang_items_for_bin_op, + method_resolution, Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, + TyLoweringContext, }; use itertools::Itertools; use smallvec::SmallVec; @@ -48,6 +47,7 @@ use syntax::{ ast::{self, AstNode}, SyntaxKind, SyntaxNode, TextRange, TextSize, }; +use triomphe::Arc; use crate::{ db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BindingMode, BuiltinAttr, @@ -134,13 +134,22 @@ impl SourceAnalyzer { self.body_source_map()?.node_pat(src) } + fn binding_id_of_pat(&self, pat: &ast::IdentPat) -> Option<BindingId> { + let pat_id = self.pat_id(&pat.clone().into())?; + if let Pat::Bind { id, .. } = self.body()?.pats[pat_id] { + Some(id) + } else { + None + } + } + fn expand_expr( &self, db: &dyn HirDatabase, expr: InFile<ast::MacroCall>, ) -> Option<InFile<ast::Expr>> { let macro_file = self.body_source_map()?.node_macro_file(expr.as_ref())?; - let expanded = db.parse_or_expand(macro_file)?; + let expanded = db.parse_or_expand(macro_file); let res = if let Some(stmts) = ast::MacroStmts::cast(expanded.clone()) { match stmts.expr()? { ast::Expr::MacroExpr(mac) => { @@ -199,6 +208,18 @@ impl SourceAnalyzer { Some((mk_ty(ty), coerced.map(mk_ty))) } + pub(crate) fn type_of_binding_in_pat( + &self, + db: &dyn HirDatabase, + pat: &ast::IdentPat, + ) -> Option<Type> { + let binding_id = self.binding_id_of_pat(pat)?; + let infer = self.infer.as_ref()?; + let ty = infer[binding_id].clone(); + let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty); + Some(mk_ty(ty)) + } + pub(crate) fn type_of_self( &self, db: &dyn HirDatabase, @@ -215,9 +236,9 @@ impl SourceAnalyzer { _db: &dyn HirDatabase, pat: &ast::IdentPat, ) -> Option<BindingMode> { - let pat_id = self.pat_id(&pat.clone().into())?; + let binding_id = self.binding_id_of_pat(pat)?; let infer = self.infer.as_ref()?; - infer.pat_binding_modes.get(&pat_id).map(|bm| match bm { + infer.binding_modes.get(binding_id).map(|bm| match bm { hir_ty::BindingMode::Move => BindingMode::Move, hir_ty::BindingMode::Ref(hir_ty::Mutability::Mut) => BindingMode::Ref(Mutability::Mut), hir_ty::BindingMode::Ref(hir_ty::Mutability::Not) => { @@ -420,7 +441,10 @@ impl SourceAnalyzer { None } else { // Shorthand syntax, resolve to the local - let path = ModPath::from_segments(PathKind::Plain, once(local_name.clone())); + let path = Path::from_known_path_with_no_generic(ModPath::from_segments( + PathKind::Plain, + once(local_name.clone()), + )); match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) { Some(ValueNs::LocalBinding(binding_id)) => { Some(Local { binding_id, parent: self.resolver.body_owner()? }) @@ -459,9 +483,11 @@ impl SourceAnalyzer { db: &dyn HirDatabase, macro_call: InFile<&ast::MacroCall>, ) -> Option<Macro> { - let ctx = body::LowerCtx::new(db.upcast(), macro_call.file_id); + let ctx = LowerCtx::with_file_id(db.upcast(), macro_call.file_id); let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &ctx))?; - self.resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(|it| it.into()) + self.resolver + .resolve_path_as_macro(db.upcast(), path.mod_path()?, Some(MacroSubNs::Bang)) + .map(|it| it.into()) } pub(crate) fn resolve_bind_pat_to_const( @@ -571,7 +597,7 @@ impl SourceAnalyzer { // This must be a normal source file rather than macro file. let hygiene = Hygiene::new(db.upcast(), self.file_id); - let ctx = body::LowerCtx::with_hygiene(db.upcast(), &hygiene); + let ctx = LowerCtx::with_hygiene(db.upcast(), &hygiene); let hir_path = Path::from_src(path.clone(), &ctx)?; // Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are @@ -655,7 +681,7 @@ impl SourceAnalyzer { } } } - return match resolve_hir_path_as_macro(db, &self.resolver, &hir_path) { + return match resolve_hir_path_as_attr_macro(db, &self.resolver, &hir_path) { Some(m) => Some(PathResolution::Def(ModuleDef::Macro(m))), // this labels any path that starts with a tool module as the tool itself, this is technically wrong // but there is no benefit in differentiating these two cases for the time being @@ -733,7 +759,7 @@ impl SourceAnalyzer { let krate = self.resolver.krate(); let macro_call_id = macro_call.as_call_id(db.upcast(), krate, |path| { self.resolver - .resolve_path_as_macro(db.upcast(), &path) + .resolve_path_as_macro(db.upcast(), &path, Some(MacroSubNs::Bang)) .map(|it| macro_id_to_def_id(db.upcast(), it)) })?; Some(macro_call_id.as_file()).filter(|it| it.expansion_level(db.upcast()) < 64) @@ -801,15 +827,11 @@ impl SourceAnalyzer { func: FunctionId, substs: Substitution, ) -> FunctionId { - let krate = self.resolver.krate(); let owner = match self.resolver.body_owner() { Some(it) => it, None => return func, }; - let env = owner.as_generic_def_id().map_or_else( - || Arc::new(hir_ty::TraitEnvironment::empty(krate)), - |d| db.trait_environment(d), - ); + let env = db.trait_environment_for_body(owner); method_resolution::lookup_impl_method(db, env, func, substs).0 } @@ -819,15 +841,11 @@ impl SourceAnalyzer { const_id: ConstId, subs: Substitution, ) -> ConstId { - let krate = self.resolver.krate(); let owner = match self.resolver.body_owner() { Some(it) => it, None => return const_id, }; - let env = owner.as_generic_def_id().map_or_else( - || Arc::new(hir_ty::TraitEnvironment::empty(krate)), - |d| db.trait_environment(d), - ); + let env = db.trait_environment_for_body(owner); method_resolution::lookup_impl_const(db, env, const_id, subs).0 } @@ -941,12 +959,14 @@ pub(crate) fn resolve_hir_path( } #[inline] -pub(crate) fn resolve_hir_path_as_macro( +pub(crate) fn resolve_hir_path_as_attr_macro( db: &dyn HirDatabase, resolver: &Resolver, path: &Path, ) -> Option<Macro> { - resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(Into::into) + resolver + .resolve_path_as_macro(db.upcast(), path.mod_path()?, Some(MacroSubNs::Attr)) + .map(Into::into) } fn resolve_hir_path_( @@ -958,12 +978,12 @@ fn resolve_hir_path_( let types = || { let (ty, unresolved) = match path.type_anchor() { Some(type_ref) => { - let (_, res) = TyLoweringContext::new(db, resolver).lower_ty_ext(type_ref); + let (_, res) = TyLoweringContext::new(db, resolver, resolver.module().into()) + .lower_ty_ext(type_ref); res.map(|ty_ns| (ty_ns, path.segments().first())) } None => { - let (ty, remaining_idx) = - resolver.resolve_path_in_type_ns(db.upcast(), path.mod_path())?; + let (ty, remaining_idx) = resolver.resolve_path_in_type_ns(db.upcast(), path)?; match remaining_idx { Some(remaining_idx) => { if remaining_idx + 1 == path.segments().len() { @@ -1019,7 +1039,7 @@ fn resolve_hir_path_( let body_owner = resolver.body_owner(); let values = || { - resolver.resolve_path_in_value_ns_fully(db.upcast(), path.mod_path()).and_then(|val| { + resolver.resolve_path_in_value_ns_fully(db.upcast(), path).and_then(|val| { let res = match val { ValueNs::LocalBinding(binding_id) => { let var = Local { parent: body_owner?, binding_id }; @@ -1039,14 +1059,14 @@ fn resolve_hir_path_( let items = || { resolver - .resolve_module_path_in_items(db.upcast(), path.mod_path()) + .resolve_module_path_in_items(db.upcast(), path.mod_path()?) .take_types() .map(|it| PathResolution::Def(it.into())) }; let macros = || { resolver - .resolve_path_as_macro(db.upcast(), path.mod_path()) + .resolve_path_as_macro(db.upcast(), path.mod_path()?, None) .map(|def| PathResolution::Def(ModuleDef::Macro(def.into()))) }; @@ -1074,7 +1094,7 @@ fn resolve_hir_path_qualifier( path: &Path, ) -> Option<PathResolution> { resolver - .resolve_path_in_type_ns_fully(db.upcast(), path.mod_path()) + .resolve_path_in_type_ns_fully(db.upcast(), &path) .map(|ty| match ty { TypeNs::SelfType(it) => PathResolution::SelfType(it.into()), TypeNs::GenericParam(id) => PathResolution::TypeParam(id.into()), @@ -1089,7 +1109,7 @@ fn resolve_hir_path_qualifier( }) .or_else(|| { resolver - .resolve_module_path_in_items(db.upcast(), path.mod_path()) + .resolve_module_path_in_items(db.upcast(), path.mod_path()?) .take_types() .map(|it| PathResolution::Def(it.into())) }) diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs index a9afa1c6f..43d957412 100644 --- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs +++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs @@ -2,23 +2,25 @@ use base_db::FileRange; use hir_def::{ - item_tree::ItemTreeNode, src::HasSource, AdtId, AssocItemId, AssocItemLoc, DefWithBodyId, - HasModule, ImplId, ItemContainerId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, + src::HasSource, AdtId, AssocItemId, DefWithBodyId, HasModule, ImplId, Lookup, MacroId, + ModuleDefId, ModuleId, TraitId, }; use hir_expand::{HirFileId, InFile}; use hir_ty::db::HirDatabase; use syntax::{ast::HasName, AstNode, SmolStr, SyntaxNode, SyntaxNodePtr}; -use crate::{Module, Semantics}; +use crate::{Module, ModuleDef, Semantics}; /// The actual data that is stored in the index. It should be as compact as /// possible. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct FileSymbol { + // even though name can be derived from the def, we store it for efficiency pub name: SmolStr, + pub def: ModuleDef, pub loc: DeclarationLocation, - pub kind: FileSymbolKind, pub container_name: Option<SmolStr>, + pub is_alias: bool, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -32,18 +34,26 @@ pub struct DeclarationLocation { } impl DeclarationLocation { - pub fn syntax<DB: HirDatabase>(&self, sema: &Semantics<'_, DB>) -> Option<SyntaxNode> { - let root = sema.parse_or_expand(self.hir_file_id)?; - Some(self.ptr.to_node(&root)) + pub fn syntax<DB: HirDatabase>(&self, sema: &Semantics<'_, DB>) -> SyntaxNode { + let root = sema.parse_or_expand(self.hir_file_id); + self.ptr.to_node(&root) } - pub fn original_range(&self, db: &dyn HirDatabase) -> Option<FileRange> { - let node = resolve_node(db, self.hir_file_id, &self.ptr)?; - Some(node.as_ref().original_file_range(db.upcast())) + pub fn original_range(&self, db: &dyn HirDatabase) -> FileRange { + if let Some(file_id) = self.hir_file_id.file_id() { + // fast path to prevent parsing + return FileRange { file_id, range: self.ptr.text_range() }; + } + let node = resolve_node(db, self.hir_file_id, &self.ptr); + node.as_ref().original_file_range(db.upcast()) } pub fn original_name_range(&self, db: &dyn HirDatabase) -> Option<FileRange> { - let node = resolve_node(db, self.hir_file_id, &self.name_ptr)?; + if let Some(file_id) = self.hir_file_id.file_id() { + // fast path to prevent parsing + return Some(FileRange { file_id, range: self.name_ptr.text_range() }); + } + let node = resolve_node(db, self.hir_file_id, &self.name_ptr); node.as_ref().original_file_range_opt(db.upcast()) } } @@ -52,38 +62,10 @@ fn resolve_node( db: &dyn HirDatabase, file_id: HirFileId, ptr: &SyntaxNodePtr, -) -> Option<InFile<SyntaxNode>> { - let root = db.parse_or_expand(file_id)?; +) -> InFile<SyntaxNode> { + let root = db.parse_or_expand(file_id); let node = ptr.to_node(&root); - Some(InFile::new(file_id, node)) -} - -#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] -pub enum FileSymbolKind { - Const, - Enum, - Function, - Macro, - Module, - Static, - Struct, - Trait, - TraitAlias, - TypeAlias, - Union, -} - -impl FileSymbolKind { - pub fn is_type(self: FileSymbolKind) -> bool { - matches!( - self, - FileSymbolKind::Struct - | FileSymbolKind::Enum - | FileSymbolKind::Trait - | FileSymbolKind::TypeAlias - | FileSymbolKind::Union - ) - } + InFile::new(file_id, node) } /// Represents an outstanding module that the symbol collector must collect symbols from. @@ -102,21 +84,33 @@ pub struct SymbolCollector<'a> { /// Given a [`ModuleId`] and a [`HirDatabase`], use the DefMap for the module's crate to collect /// all symbols that should be indexed for the given module. impl<'a> SymbolCollector<'a> { - pub fn collect(db: &dyn HirDatabase, module: Module) -> Vec<FileSymbol> { - let mut symbol_collector = SymbolCollector { + pub fn new(db: &'a dyn HirDatabase) -> Self { + SymbolCollector { db, symbols: Default::default(), + work: Default::default(), current_container_name: None, - // The initial work is the root module we're collecting, additional work will - // be populated as we traverse the module's definitions. - work: vec![SymbolCollectorWork { module_id: module.into(), parent: None }], - }; + } + } + + pub fn collect(&mut self, module: Module) { + // The initial work is the root module we're collecting, additional work will + // be populated as we traverse the module's definitions. + self.work.push(SymbolCollectorWork { module_id: module.into(), parent: None }); - while let Some(work) = symbol_collector.work.pop() { - symbol_collector.do_work(work); + while let Some(work) = self.work.pop() { + self.do_work(work); } + } + + pub fn finish(self) -> Vec<FileSymbol> { + self.symbols + } - symbol_collector.symbols + pub fn collect_module(db: &dyn HirDatabase, module: Module) -> Vec<FileSymbol> { + let mut symbol_collector = SymbolCollector::new(db); + symbol_collector.collect(module); + symbol_collector.finish() } fn do_work(&mut self, work: SymbolCollectorWork) { @@ -134,36 +128,34 @@ impl<'a> SymbolCollector<'a> { match module_def_id { ModuleDefId::ModuleId(id) => self.push_module(id), ModuleDefId::FunctionId(id) => { - self.push_decl_assoc(id, FileSymbolKind::Function); + self.push_decl(id); self.collect_from_body(id); } - ModuleDefId::AdtId(AdtId::StructId(id)) => { - self.push_decl(id, FileSymbolKind::Struct) - } - ModuleDefId::AdtId(AdtId::EnumId(id)) => self.push_decl(id, FileSymbolKind::Enum), - ModuleDefId::AdtId(AdtId::UnionId(id)) => self.push_decl(id, FileSymbolKind::Union), + ModuleDefId::AdtId(AdtId::StructId(id)) => self.push_decl(id), + ModuleDefId::AdtId(AdtId::EnumId(id)) => self.push_decl(id), + ModuleDefId::AdtId(AdtId::UnionId(id)) => self.push_decl(id), ModuleDefId::ConstId(id) => { - self.push_decl_assoc(id, FileSymbolKind::Const); + self.push_decl(id); self.collect_from_body(id); } ModuleDefId::StaticId(id) => { - self.push_decl_assoc(id, FileSymbolKind::Static); + self.push_decl(id); self.collect_from_body(id); } ModuleDefId::TraitId(id) => { - self.push_decl(id, FileSymbolKind::Trait); + self.push_decl(id); self.collect_from_trait(id); } ModuleDefId::TraitAliasId(id) => { - self.push_decl(id, FileSymbolKind::TraitAlias); + self.push_decl(id); } ModuleDefId::TypeAliasId(id) => { - self.push_decl_assoc(id, FileSymbolKind::TypeAlias); + self.push_decl(id); } ModuleDefId::MacroId(id) => match id { - MacroId::Macro2Id(id) => self.push_decl(id, FileSymbolKind::Macro), - MacroId::MacroRulesId(id) => self.push_decl(id, FileSymbolKind::Macro), - MacroId::ProcMacroId(id) => self.push_decl(id, FileSymbolKind::Macro), + MacroId::Macro2Id(id) => self.push_decl(id), + MacroId::MacroRulesId(id) => self.push_decl(id), + MacroId::ProcMacroId(id) => self.push_decl(id), }, // Don't index these. ModuleDefId::BuiltinType(_) => {} @@ -183,9 +175,9 @@ impl<'a> SymbolCollector<'a> { for &id in id { if id.module(self.db.upcast()) == module_id { match id { - MacroId::Macro2Id(id) => self.push_decl(id, FileSymbolKind::Macro), - MacroId::MacroRulesId(id) => self.push_decl(id, FileSymbolKind::Macro), - MacroId::ProcMacroId(id) => self.push_decl(id, FileSymbolKind::Macro), + MacroId::Macro2Id(id) => self.push_decl(id), + MacroId::MacroRulesId(id) => self.push_decl(id), + MacroId::ProcMacroId(id) => self.push_decl(id), } } } @@ -233,124 +225,95 @@ impl<'a> SymbolCollector<'a> { } } - fn current_container_name(&self) -> Option<SmolStr> { - self.current_container_name.clone() - } - fn def_with_body_id_name(&self, body_id: DefWithBodyId) -> Option<SmolStr> { match body_id { - DefWithBodyId::FunctionId(id) => Some( - id.lookup(self.db.upcast()).source(self.db.upcast()).value.name()?.text().into(), - ), - DefWithBodyId::StaticId(id) => Some( - id.lookup(self.db.upcast()).source(self.db.upcast()).value.name()?.text().into(), - ), - DefWithBodyId::ConstId(id) => Some( - id.lookup(self.db.upcast()).source(self.db.upcast()).value.name()?.text().into(), - ), - DefWithBodyId::VariantId(id) => Some({ - let db = self.db.upcast(); - id.parent.lookup(db).source(db).value.name()?.text().into() - }), + DefWithBodyId::FunctionId(id) => Some(self.db.function_data(id).name.to_smol_str()), + DefWithBodyId::StaticId(id) => Some(self.db.static_data(id).name.to_smol_str()), + DefWithBodyId::ConstId(id) => Some(self.db.const_data(id).name.as_ref()?.to_smol_str()), + DefWithBodyId::VariantId(id) => { + Some(self.db.enum_data(id.parent).variants[id.local_id].name.to_smol_str()) + } + DefWithBodyId::InTypeConstId(_) => Some("in type const".into()), } } fn push_assoc_item(&mut self, assoc_item_id: AssocItemId) { match assoc_item_id { - AssocItemId::FunctionId(id) => self.push_decl_assoc(id, FileSymbolKind::Function), - AssocItemId::ConstId(id) => self.push_decl_assoc(id, FileSymbolKind::Const), - AssocItemId::TypeAliasId(id) => self.push_decl_assoc(id, FileSymbolKind::TypeAlias), + AssocItemId::FunctionId(id) => self.push_decl(id), + AssocItemId::ConstId(id) => self.push_decl(id), + AssocItemId::TypeAliasId(id) => self.push_decl(id), } } - fn push_decl_assoc<L, T>(&mut self, id: L, kind: FileSymbolKind) + fn push_decl<L>(&mut self, id: L) where - L: Lookup<Data = AssocItemLoc<T>>, - T: ItemTreeNode, - <T as ItemTreeNode>::Source: HasName, + L: Lookup + Into<ModuleDefId>, + <L as Lookup>::Data: HasSource, + <<L as Lookup>::Data as HasSource>::Value: HasName, { - fn container_name(db: &dyn HirDatabase, container: ItemContainerId) -> Option<SmolStr> { - match container { - ItemContainerId::ModuleId(module_id) => { - let module = Module::from(module_id); - module.name(db).and_then(|name| name.as_text()) - } - ItemContainerId::TraitId(trait_id) => { - let trait_data = db.trait_data(trait_id); - trait_data.name.as_text() - } - ItemContainerId::ImplId(_) | ItemContainerId::ExternBlockId(_) => None, + let loc = id.lookup(self.db.upcast()); + let source = loc.source(self.db.upcast()); + let Some(name_node) = source.value.name() else { return }; + let def = ModuleDef::from(id.into()); + let dec_loc = DeclarationLocation { + hir_file_id: source.file_id, + ptr: SyntaxNodePtr::new(source.value.syntax()), + name_ptr: SyntaxNodePtr::new(name_node.syntax()), + }; + + if let Some(attrs) = def.attrs(self.db) { + for alias in attrs.doc_aliases() { + self.symbols.push(FileSymbol { + name: alias, + def, + loc: dec_loc.clone(), + container_name: self.current_container_name.clone(), + is_alias: true, + }); } } - self.push_file_symbol(|s| { - let loc = id.lookup(s.db.upcast()); - let source = loc.source(s.db.upcast()); - let name_node = source.value.name()?; - let container_name = - container_name(s.db, loc.container).or_else(|| s.current_container_name()); - - Some(FileSymbol { - name: name_node.text().into(), - kind, - container_name, - loc: DeclarationLocation { - hir_file_id: source.file_id, - ptr: SyntaxNodePtr::new(source.value.syntax()), - name_ptr: SyntaxNodePtr::new(name_node.syntax()), - }, - }) - }) - } - - fn push_decl<L>(&mut self, id: L, kind: FileSymbolKind) - where - L: Lookup, - <L as Lookup>::Data: HasSource, - <<L as Lookup>::Data as HasSource>::Value: HasName, - { - self.push_file_symbol(|s| { - let loc = id.lookup(s.db.upcast()); - let source = loc.source(s.db.upcast()); - let name_node = source.value.name()?; - - Some(FileSymbol { - name: name_node.text().into(), - kind, - container_name: s.current_container_name(), - loc: DeclarationLocation { - hir_file_id: source.file_id, - ptr: SyntaxNodePtr::new(source.value.syntax()), - name_ptr: SyntaxNodePtr::new(name_node.syntax()), - }, - }) - }) + self.symbols.push(FileSymbol { + name: name_node.text().into(), + def, + container_name: self.current_container_name.clone(), + loc: dec_loc, + is_alias: false, + }); } fn push_module(&mut self, module_id: ModuleId) { - self.push_file_symbol(|s| { - let def_map = module_id.def_map(s.db.upcast()); - let module_data = &def_map[module_id.local_id]; - let declaration = module_data.origin.declaration()?; - let module = declaration.to_node(s.db.upcast()); - let name_node = module.name()?; - - Some(FileSymbol { - name: name_node.text().into(), - kind: FileSymbolKind::Module, - container_name: s.current_container_name(), - loc: DeclarationLocation { - hir_file_id: declaration.file_id, - ptr: SyntaxNodePtr::new(module.syntax()), - name_ptr: SyntaxNodePtr::new(name_node.syntax()), - }, - }) - }) - } + let def_map = module_id.def_map(self.db.upcast()); + let module_data = &def_map[module_id.local_id]; + let Some(declaration) = module_data.origin.declaration() else { return }; + let module = declaration.to_node(self.db.upcast()); + let Some(name_node) = module.name() else { return }; + let dec_loc = DeclarationLocation { + hir_file_id: declaration.file_id, + ptr: SyntaxNodePtr::new(module.syntax()), + name_ptr: SyntaxNodePtr::new(name_node.syntax()), + }; - fn push_file_symbol(&mut self, f: impl FnOnce(&Self) -> Option<FileSymbol>) { - if let Some(file_symbol) = f(self) { - self.symbols.push(file_symbol); + let def = ModuleDef::Module(module_id.into()); + + if let Some(attrs) = def.attrs(self.db) { + for alias in attrs.doc_aliases() { + self.symbols.push(FileSymbol { + name: alias, + def, + loc: dec_loc.clone(), + container_name: self.current_container_name.clone(), + is_alias: true, + }); + } } + + self.symbols.push(FileSymbol { + name: name_node.text().into(), + def: ModuleDef::Module(module_id.into()), + container_name: self.current_container_name.clone(), + loc: dec_loc, + is_alias: false, + }); } } |