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