summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/hir
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
commitdc0db358abe19481e475e10c32149b53370f1a1c (patch)
treeab8ce99c4b255ce46f99ef402c27916055b899ee /src/tools/rust-analyzer/crates/hir
parentReleasing progress-linux version 1.71.1+dfsg1-2~progress7.99u1. (diff)
downloadrustc-dc0db358abe19481e475e10c32149b53370f1a1c.tar.xz
rustc-dc0db358abe19481e475e10c32149b53370f1a1c.zip
Merging upstream version 1.72.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tools/rust-analyzer/crates/hir')
-rw-r--r--src/tools/rust-analyzer/crates/hir/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/attrs.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/db.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/diagnostics.rs59
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/display.rs72
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/from_id.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs796
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs66
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs94
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/symbols.rs297
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 &params.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((&lt.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,
+ });
}
}