pub mod diagnostics;
pub mod db;
+pub mod symbols;
mod display;
-use std::{iter, ops::ControlFlow, sync::Arc};
+use std::{collections::HashMap, iter, ops::ControlFlow, sync::Arc};
use arrayvec::ArrayVec;
-use base_db::{CrateDisplayName, CrateId, Edition, FileId};
+use base_db::{CrateDisplayName, CrateId, CrateOrigin, Edition, FileId};
use either::Either;
use hir_def::{
adt::{ReprKind, VariantData},
body::{BodyDiagnostic, SyntheticSyntax},
expr::{BindingAnnotation, LabelId, Pat, PatId},
+ item_tree::ItemTreeNode,
lang_item::LangItemTarget,
- nameres,
+ nameres::{self, diagnostics::DefDiagnostic},
per_ns::PerNs,
resolver::{HasResolver, Resolver},
- AttrDefId, ConstId, ConstParamId, EnumId, FunctionId, GenericDefId, HasModule, LifetimeParamId,
- LocalEnumVariantId, LocalFieldId, StaticId, StructId, TypeAliasId, TypeParamId, UnionId,
+ src::HasSource as _,
+ AdtId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId,
+ FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
+ LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId,
+ TypeParamId, UnionId,
};
-use hir_expand::{name::name, MacroCallKind, MacroDefKind};
+use hir_expand::{name::name, MacroCallKind, MacroDefId, MacroDefKind};
use hir_ty::{
autoderef,
- consteval::ConstExt,
+ consteval::{eval_const, ComputedExpr, ConstEvalCtx, ConstEvalError, ConstExt},
could_unify,
diagnostics::BodyValidationDiagnostic,
method_resolution::{self, TyFingerprint},
use rustc_hash::FxHashSet;
use stdx::{format_to, impl_from};
use syntax::{
- ast::{self, HasAttrs as _, HasName},
+ ast::{self, HasAttrs as _, HasDocComments, HasName},
AstNode, AstPtr, SmolStr, SyntaxKind, SyntaxNodePtr,
};
use tt::{Ident, Leaf, Literal, TokenTree};
hir_def::{
adt::StructKind,
attr::{Attr, Attrs, AttrsWithOwner, Documentation},
+ builtin_attr::AttributeTemplate,
find_path::PrefixKind,
import_map,
- item_scope::ItemScope,
- item_tree::ItemTreeNode,
- nameres::{DefMap, ModuleData, ModuleOrigin, ModuleSource},
+ nameres::ModuleSource,
path::{ModPath, PathKind},
- src::HasSource as DefHasSource, // xx: I don't like this shadowing of HasSource... :(
type_ref::{Mutability, TypeRef},
visibility::Visibility,
- AdtId,
- AssocContainerId,
- AssocItemId,
- AssocItemLoc,
- DefWithBodyId,
- ImplId,
- ItemLoc,
- Lookup,
- ModuleDefId,
- ModuleId,
- TraitId,
},
hir_expand::{
name::{known, Name},
- ExpandResult, HirFileId, InFile, MacroDefId, MacroFile, Origin,
+ ExpandResult, HirFileId, InFile, MacroFile, Origin,
},
hir_ty::display::HirDisplay,
};
}
impl Crate {
+ pub fn origin(self, db: &dyn HirDatabase) -> CrateOrigin {
+ db.crate_graph()[self.id].origin.clone()
+ }
+
pub fn dependencies(self, db: &dyn HirDatabase) -> Vec<CrateDependency> {
db.crate_graph()[self.id]
.dependencies
Module { id: def_map.module_id(def_map.root()) }
}
+ pub fn modules(self, db: &dyn HirDatabase) -> Vec<Module> {
+ let def_map = db.crate_def_map(self.id);
+ def_map.modules().map(|(id, _)| def_map.module_id(id).into()).collect()
+ }
+
pub fn root_file(self, db: &dyn HirDatabase) -> FileId {
db.crate_graph()[self.id].root_file_id
}
// FIXME: This is accidentally quadratic.
continue;
}
- match &diag.kind {
- DefDiagnosticKind::UnresolvedModule { ast: declaration, candidate } => {
- let decl = declaration.to_node(db.upcast());
- acc.push(
- UnresolvedModule {
- decl: InFile::new(declaration.file_id, AstPtr::new(&decl)),
- candidate: candidate.clone(),
- }
- .into(),
- )
- }
- DefDiagnosticKind::UnresolvedExternCrate { ast } => {
- let item = ast.to_node(db.upcast());
- acc.push(
- UnresolvedExternCrate {
- decl: InFile::new(ast.file_id, AstPtr::new(&item)),
- }
- .into(),
- );
- }
-
- DefDiagnosticKind::UnresolvedImport { id, index } => {
- let file_id = id.file_id();
- let item_tree = id.item_tree(db.upcast());
- let import = &item_tree[id.value];
-
- let use_tree = import.use_tree_to_ast(db.upcast(), file_id, *index);
- acc.push(
- UnresolvedImport { decl: InFile::new(file_id, AstPtr::new(&use_tree)) }
- .into(),
- );
- }
-
- DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } => {
- let item = ast.to_node(db.upcast());
- acc.push(
- InactiveCode {
- node: ast.with_value(AstPtr::new(&item).into()),
- cfg: cfg.clone(),
- opts: opts.clone(),
- }
- .into(),
- );
- }
-
- DefDiagnosticKind::UnresolvedProcMacro { ast } => {
- let mut precise_location = None;
- let (node, name) = match ast {
- MacroCallKind::FnLike { ast_id, .. } => {
- let node = ast_id.to_node(db.upcast());
- (ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))), None)
- }
- MacroCallKind::Derive { ast_id, derive_name, .. } => {
- let node = ast_id.to_node(db.upcast());
-
- // Compute the precise location of the macro name's token in the derive
- // list.
- // FIXME: This does not handle paths to the macro, but neither does the
- // rest of r-a.
- let derive_attrs =
- node.attrs().filter_map(|attr| match attr.as_simple_call() {
- Some((name, args)) if name == "derive" => Some(args),
- _ => None,
- });
- 'outer: for attr in derive_attrs {
- let tokens =
- attr.syntax().children_with_tokens().filter_map(|elem| {
- match elem {
- syntax::NodeOrToken::Node(_) => None,
- syntax::NodeOrToken::Token(tok) => Some(tok),
- }
- });
- for token in tokens {
- if token.kind() == SyntaxKind::IDENT
- && token.text() == &**derive_name
- {
- precise_location = Some(token.text_range());
- break 'outer;
- }
- }
- }
-
- (
- ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))),
- Some(derive_name.clone()),
- )
- }
- MacroCallKind::Attr { ast_id, invoc_attr_index, attr_name, .. } => {
- let node = ast_id.to_node(db.upcast());
- let attr =
- node.attrs().nth((*invoc_attr_index) as usize).unwrap_or_else(
- || panic!("cannot find attribute #{}", invoc_attr_index),
- );
- (
- ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))),
- Some(attr_name.clone()),
- )
- }
- };
- acc.push(
- UnresolvedProcMacro {
- node,
- precise_location,
- macro_name: name.map(Into::into),
- }
- .into(),
- );
- }
-
- DefDiagnosticKind::UnresolvedMacroCall { ast, path } => {
- let node = ast.to_node(db.upcast());
- acc.push(
- UnresolvedMacroCall {
- macro_call: InFile::new(ast.file_id, AstPtr::new(&node)),
- path: path.clone(),
- }
- .into(),
- );
- }
-
- DefDiagnosticKind::MacroError { ast, message } => {
- let node = match ast {
- MacroCallKind::FnLike { ast_id, .. } => {
- let node = ast_id.to_node(db.upcast());
- ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node)))
- }
- MacroCallKind::Derive { ast_id, .. }
- | MacroCallKind::Attr { ast_id, .. } => {
- // FIXME: point to the attribute instead, this creates very large diagnostics
- let node = ast_id.to_node(db.upcast());
- ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node)))
- }
- };
- acc.push(MacroError { node, message: message.clone() }.into());
- }
-
- DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => {
- let node = ast.to_node(db.upcast());
- // Must have a name, otherwise we wouldn't emit it.
- let name = node.name().expect("unimplemented builtin macro with no name");
- acc.push(
- UnimplementedBuiltinMacro {
- node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&name))),
- }
- .into(),
- );
- }
- DefDiagnosticKind::InvalidDeriveTarget { ast, id } => {
- let node = ast.to_node(db.upcast());
- let derive = node.attrs().nth(*id as usize);
- match derive {
- Some(derive) => {
- acc.push(
- InvalidDeriveTarget {
- node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&derive))),
- }
- .into(),
- );
- }
- None => stdx::never!("derive diagnostic on item without derive attribute"),
- }
- }
- DefDiagnosticKind::MalformedDerive { ast, id } => {
- let node = ast.to_node(db.upcast());
- let derive = node.attrs().nth(*id as usize);
- match derive {
- Some(derive) => {
- acc.push(
- MalformedDerive {
- node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&derive))),
- }
- .into(),
- );
- }
- None => stdx::never!("derive diagnostic on item without derive attribute"),
- }
- }
- }
+ emit_def_diagnostic(db, acc, diag);
}
for decl in self.declarations(db) {
match decl {
}
}
+fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag: &DefDiagnostic) {
+ match &diag.kind {
+ DefDiagnosticKind::UnresolvedModule { ast: declaration, candidate } => {
+ let decl = declaration.to_node(db.upcast());
+ acc.push(
+ UnresolvedModule {
+ decl: InFile::new(declaration.file_id, AstPtr::new(&decl)),
+ candidate: candidate.clone(),
+ }
+ .into(),
+ )
+ }
+ DefDiagnosticKind::UnresolvedExternCrate { ast } => {
+ let item = ast.to_node(db.upcast());
+ acc.push(
+ UnresolvedExternCrate { decl: InFile::new(ast.file_id, AstPtr::new(&item)) }.into(),
+ );
+ }
+
+ DefDiagnosticKind::UnresolvedImport { id, index } => {
+ let file_id = id.file_id();
+ let item_tree = id.item_tree(db.upcast());
+ let import = &item_tree[id.value];
+
+ let use_tree = import.use_tree_to_ast(db.upcast(), file_id, *index);
+ acc.push(
+ UnresolvedImport { decl: InFile::new(file_id, AstPtr::new(&use_tree)) }.into(),
+ );
+ }
+
+ DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } => {
+ let item = ast.to_node(db.upcast());
+ acc.push(
+ InactiveCode {
+ node: ast.with_value(AstPtr::new(&item).into()),
+ cfg: cfg.clone(),
+ opts: opts.clone(),
+ }
+ .into(),
+ );
+ }
+
+ DefDiagnosticKind::UnresolvedProcMacro { ast } => {
+ let mut precise_location = None;
+ let (node, name) = match ast {
+ MacroCallKind::FnLike { ast_id, .. } => {
+ let node = ast_id.to_node(db.upcast());
+ (ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))), None)
+ }
+ MacroCallKind::Derive { ast_id, derive_name, .. } => {
+ let node = ast_id.to_node(db.upcast());
+
+ // Compute the precise location of the macro name's token in the derive
+ // list.
+ // FIXME: This does not handle paths to the macro, but neither does the
+ // rest of r-a.
+ let derive_attrs =
+ node.attrs().filter_map(|attr| match attr.as_simple_call() {
+ Some((name, args)) if name == "derive" => Some(args),
+ _ => None,
+ });
+ 'outer: for attr in derive_attrs {
+ let tokens =
+ attr.syntax().children_with_tokens().filter_map(|elem| match elem {
+ syntax::NodeOrToken::Node(_) => None,
+ syntax::NodeOrToken::Token(tok) => Some(tok),
+ });
+ for token in tokens {
+ if token.kind() == SyntaxKind::IDENT && token.text() == &**derive_name {
+ precise_location = Some(token.text_range());
+ break 'outer;
+ }
+ }
+ }
+
+ (
+ ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))),
+ Some(derive_name.clone()),
+ )
+ }
+ MacroCallKind::Attr { ast_id, invoc_attr_index, attr_name, .. } => {
+ let node = ast_id.to_node(db.upcast());
+ let attr = node
+ .doc_comments_and_attrs()
+ .nth((*invoc_attr_index) as usize)
+ .and_then(Either::left)
+ .unwrap_or_else(|| panic!("cannot find attribute #{}", invoc_attr_index));
+ (
+ ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))),
+ Some(attr_name.clone()),
+ )
+ }
+ };
+ acc.push(
+ UnresolvedProcMacro { node, precise_location, macro_name: name.map(Into::into) }
+ .into(),
+ );
+ }
+
+ DefDiagnosticKind::UnresolvedMacroCall { ast, path } => {
+ let node = ast.to_node(db.upcast());
+ acc.push(
+ UnresolvedMacroCall {
+ macro_call: InFile::new(ast.file_id, AstPtr::new(&node)),
+ path: path.clone(),
+ }
+ .into(),
+ );
+ }
+
+ DefDiagnosticKind::MacroError { ast, message } => {
+ let node = match ast {
+ MacroCallKind::FnLike { ast_id, .. } => {
+ let node = ast_id.to_node(db.upcast());
+ ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node)))
+ }
+ MacroCallKind::Derive { ast_id, .. } => {
+ // FIXME: point to the attribute instead, this creates very large diagnostics
+ let node = ast_id.to_node(db.upcast());
+ ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node)))
+ }
+ MacroCallKind::Attr { ast_id, .. } => {
+ // FIXME: point to the attribute instead, this creates very large diagnostics
+ let node = ast_id.to_node(db.upcast());
+ ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node)))
+ }
+ };
+ acc.push(MacroError { node, message: message.clone() }.into());
+ }
+
+ DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => {
+ let node = ast.to_node(db.upcast());
+ // Must have a name, otherwise we wouldn't emit it.
+ let name = node.name().expect("unimplemented builtin macro with no name");
+ acc.push(
+ UnimplementedBuiltinMacro {
+ node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&name))),
+ }
+ .into(),
+ );
+ }
+ DefDiagnosticKind::InvalidDeriveTarget { ast, id } => {
+ let node = ast.to_node(db.upcast());
+ let derive = node.attrs().nth(*id as usize);
+ match derive {
+ Some(derive) => {
+ acc.push(
+ InvalidDeriveTarget {
+ node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&derive))),
+ }
+ .into(),
+ );
+ }
+ None => stdx::never!("derive diagnostic on item without derive attribute"),
+ }
+ }
+ DefDiagnosticKind::MalformedDerive { ast, id } => {
+ let node = ast.to_node(db.upcast());
+ let derive = node.attrs().nth(*id as usize);
+ match derive {
+ Some(derive) => {
+ acc.push(
+ MalformedDerive {
+ node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&derive))),
+ }
+ .into(),
+ );
+ }
+ None => stdx::never!("derive diagnostic on item without derive attribute"),
+ }
+ }
+ }
+}
+
impl HasVisibility for Module {
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
let def_map = self.id.def_map(db.upcast());
VariantDef::Variant(it) => it.parent.id.into(),
};
let substs = TyBuilder::type_params_subst(db, generic_def_id);
- let ty = db.field_types(var_id)[self.id].clone().substitute(&Interner, &substs);
+ let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs);
Type::new(db, self.parent.module(db).id.krate(), var_id, ty)
}
pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
let krate = self.module(db).id.krate();
- let source_map = db.body_with_source_map(self.into()).1;
+ let (body, source_map) = db.body_with_source_map(self.into());
+
+ for (_, def_map) in body.blocks(db.upcast()) {
+ for diag in def_map.diagnostics() {
+ emit_def_diagnostic(db, acc, diag);
+ }
+ }
+
for diag in source_map.diagnostics() {
match diag {
BodyDiagnostic::InactiveCode { node, cfg, opts } => acc.push(
if let ast::Expr::MatchExpr(match_expr) =
&source_ptr.value.to_node(&root)
{
- if let (Some(match_expr), Some(arms)) =
- (match_expr.expr(), match_expr.match_arm_list())
- {
+ if let Some(match_expr) = match_expr.expr() {
acc.push(
MissingMatchArms {
file: source_ptr.file_id,
match_expr: AstPtr::new(&match_expr),
- arms: AstPtr::new(&arms),
}
.into(),
- )
+ );
}
}
}
.params
.iter()
.enumerate()
- .map(|(idx, type_ref)| {
+ .map(|(idx, (_, type_ref))| {
let ty = Type { krate, env: environment.clone(), ty: ctx.lower_ty(type_ref) };
Param { func: self, ty, idx }
})
&self.ty
}
+ pub fn name(&self, db: &dyn HirDatabase) -> Option<Name> {
+ db.function_data(self.func.id).params[self.idx].0.clone()
+ }
+
pub fn as_local(&self, db: &dyn HirDatabase) -> Local {
let parent = DefWithBodyId::FunctionId(self.func.into());
let body = db.body(parent);
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,
.and_then(|params| params.self_param())
.map(|value| InFile { file_id, value })
}
+
+ pub fn ty(&self, db: &dyn HirDatabase) -> Type {
+ let resolver = self.func.resolver(db.upcast());
+ let krate = self.func.lookup(db.upcast()).container.module(db.upcast()).krate();
+ let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
+ let environment = db.trait_environment(self.func.into());
+
+ Type {
+ krate,
+ env: environment.clone(),
+ ty: ctx.lower_ty(&db.function_data(self.func).params[0].1),
+ }
+ }
}
impl HasVisibility for Function {
let ty = ctx.lower_ty(&data.type_ref);
Type::new_with_resolver_inner(db, krate.id, &resolver, ty)
}
+
+ pub fn eval(self, db: &dyn HirDatabase) -> Result<ComputedExpr, ConstEvalError> {
+ let body = db.body(self.id.into());
+ let root = &body.exprs[body.body_expr];
+ let infer = db.infer_query(self.id.into());
+ let infer = infer.as_ref();
+ let result = eval_const(
+ root,
+ &mut ConstEvalCtx {
+ exprs: &body.exprs,
+ pats: &body.pats,
+ local_data: HashMap::default(),
+ infer: &mut |x| infer[x].clone(),
+ },
+ );
+ result
+ }
}
impl HasVisibility for Const {
pub fn ty(self, db: &dyn HirDatabase) -> Type {
let data = db.static_data(self.id);
let resolver = self.id.resolver(db.upcast());
- let krate = self.id.lookup(db.upcast()).container.krate();
+ let krate = self.id.lookup(db.upcast()).container.module(db.upcast()).krate();
let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
let ty = ctx.lower_ty(&data.type_ref);
Type::new_with_resolver_inner(db, krate, &resolver, ty)
}
impl Trait {
+ pub fn lang(db: &dyn HirDatabase, krate: Crate, name: &Name) -> Option<Trait> {
+ db.lang_item(krate.into(), name.to_smol_str())
+ .and_then(LangItemTarget::as_trait)
+ .map(Into::into)
+ }
+
pub fn module(self, db: &dyn HirDatabase) -> Module {
Module { id: self.id.lookup(db.upcast()).container }
}
pub fn name(self) -> Name {
self.inner.as_name()
}
+
+ pub fn is_int(&self) -> bool {
+ matches!(self.inner, hir_def::builtin_type::BuiltinType::Int(_))
+ }
+
+ pub fn is_uint(&self) -> bool {
+ matches!(self.inner, hir_def::builtin_type::BuiltinType::Uint(_))
+ }
+
+ pub fn is_float(&self) -> bool {
+ matches!(self.inner, hir_def::builtin_type::BuiltinType::Float(_))
+ }
+
+ pub fn is_char(&self) -> bool {
+ matches!(self.inner, hir_def::builtin_type::BuiltinType::Char)
+ }
+
+ pub fn is_str(&self) -> bool {
+ matches!(self.inner, hir_def::builtin_type::BuiltinType::Str)
+ }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
MacroKind::Attr | MacroKind::Derive => false,
}
}
+
+ pub fn is_attr(&self) -> bool {
+ matches!(self.kind(), MacroKind::Attr)
+ }
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
AST: ItemTreeNode,
{
match id.lookup(db.upcast()).container {
- AssocContainerId::TraitId(_) | AssocContainerId::ImplId(_) => Some(ctor(DEF::from(id))),
- AssocContainerId::ModuleId(_) => None,
+ ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => Some(ctor(DEF::from(id))),
+ ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None,
}
}
AssocItem::TypeAlias(it) => it.id.lookup(db.upcast()).container,
};
match container {
- AssocContainerId::TraitId(id) => AssocItemContainer::Trait(id.into()),
- AssocContainerId::ImplId(id) => AssocItemContainer::Impl(id.into()),
- AssocContainerId::ModuleId(_) => panic!("invalid AssocItem"),
+ ItemContainerId::TraitId(id) => AssocItemContainer::Trait(id.into()),
+ ItemContainerId::ImplId(id) => AssocItemContainer::Impl(id.into()),
+ ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
+ panic!("invalid AssocItem")
+ }
}
}
}
}
+// FIXME: Wrong name? This is could also be a registered attribute
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct BuiltinAttr {
+ krate: Option<CrateId>,
+ idx: usize,
+}
+
+impl BuiltinAttr {
+ // FIXME: consider crates\hir_def\src\nameres\attr_resolution.rs?
+ pub(crate) fn by_name(db: &dyn HirDatabase, krate: Crate, name: &str) -> Option<Self> {
+ if let builtin @ Some(_) = Self::builtin(name) {
+ return builtin;
+ }
+ let idx = db.crate_def_map(krate.id).registered_attrs().iter().position(|it| it == name)?;
+ Some(BuiltinAttr { krate: Some(krate.id), idx })
+ }
+
+ pub(crate) fn builtin(name: &str) -> Option<Self> {
+ hir_def::builtin_attr::INERT_ATTRIBUTES
+ .iter()
+ .position(|tool| tool.name == name)
+ .map(|idx| BuiltinAttr { krate: None, idx })
+ }
+
+ pub fn name(&self, db: &dyn HirDatabase) -> SmolStr {
+ // FIXME: Return a `Name` here
+ match self.krate {
+ Some(krate) => db.crate_def_map(krate).registered_attrs()[self.idx].clone(),
+ None => SmolStr::new(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx].name),
+ }
+ }
+
+ pub fn template(&self, _: &dyn HirDatabase) -> Option<AttributeTemplate> {
+ match self.krate {
+ Some(_) => None,
+ None => Some(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx].template),
+ }
+ }
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct ToolModule {
+ krate: Option<CrateId>,
+ idx: usize,
+}
+
+impl ToolModule {
+ // FIXME: consider crates\hir_def\src\nameres\attr_resolution.rs?
+ pub(crate) fn by_name(db: &dyn HirDatabase, krate: Crate, name: &str) -> Option<Self> {
+ if let builtin @ Some(_) = Self::builtin(name) {
+ return builtin;
+ }
+ let idx = db.crate_def_map(krate.id).registered_tools().iter().position(|it| it == name)?;
+ Some(ToolModule { krate: Some(krate.id), idx })
+ }
+
+ pub(crate) fn builtin(name: &str) -> Option<Self> {
+ hir_def::builtin_attr::TOOL_MODULES
+ .iter()
+ .position(|&tool| tool == name)
+ .map(|idx| ToolModule { krate: None, idx })
+ }
+
+ pub fn name(&self, db: &dyn HirDatabase) -> SmolStr {
+ // FIXME: Return a `Name` here
+ match self.krate {
+ Some(krate) => db.crate_def_map(krate).registered_tools()[self.idx].clone(),
+ None => SmolStr::new(hir_def::builtin_attr::TOOL_MODULES[self.idx]),
+ }
+ }
+}
+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Label {
pub(crate) parent: DefWithBodyId,
pub fn ty(self, db: &dyn HirDatabase) -> Type {
let resolver = self.id.parent.resolver(db.upcast());
let krate = self.id.parent.module(db.upcast()).krate();
- let ty = TyKind::Placeholder(hir_ty::to_placeholder_idx(db, self.id)).intern(&Interner);
+ let ty = TyKind::Placeholder(hir_ty::to_placeholder_idx(db, self.id)).intern(Interner);
Type::new_with_resolver_inner(db, krate, &resolver, ty)
}
let krate = self.id.parent.module(db.upcast()).krate();
let ty = params.get(local_idx)?.clone();
let subst = TyBuilder::type_params_subst(db, self.id.parent);
- let ty = ty.substitute(&Interner, &subst_prefix(&subst, local_idx));
+ let ty = ty.substitute(Interner, &subst_prefix(&subst, local_idx));
Some(Type::new_with_resolver_inner(db, krate, &resolver, ty))
}
}
}
pub fn is_unit(&self) -> bool {
- matches!(self.ty.kind(&Interner), TyKind::Tuple(0, ..))
+ matches!(self.ty.kind(Interner), TyKind::Tuple(0, ..))
}
pub fn is_bool(&self) -> bool {
- matches!(self.ty.kind(&Interner), TyKind::Scalar(Scalar::Bool))
+ matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Bool))
}
pub fn is_never(&self) -> bool {
- matches!(self.ty.kind(&Interner), TyKind::Never)
+ matches!(self.ty.kind(Interner), TyKind::Never)
}
pub fn is_mutable_reference(&self) -> bool {
- matches!(self.ty.kind(&Interner), TyKind::Ref(hir_ty::Mutability::Mut, ..))
+ matches!(self.ty.kind(Interner), TyKind::Ref(hir_ty::Mutability::Mut, ..))
}
pub fn is_reference(&self) -> bool {
- matches!(self.ty.kind(&Interner), TyKind::Ref(..))
+ matches!(self.ty.kind(Interner), TyKind::Ref(..))
}
pub fn is_usize(&self) -> bool {
- matches!(self.ty.kind(&Interner), TyKind::Scalar(Scalar::Uint(UintTy::Usize)))
+ matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Uint(UintTy::Usize)))
}
pub fn remove_ref(&self) -> Option<Type> {
- match &self.ty.kind(&Interner) {
+ match &self.ty.kind(Interner) {
TyKind::Ref(.., ty) => Some(self.derived(ty.clone())),
_ => None,
}
let krate = self.krate;
let std_future_trait =
- db.lang_item(krate, "future_trait".into()).and_then(|it| it.as_trait());
+ db.lang_item(krate, SmolStr::new_inline("future_trait")).and_then(|it| it.as_trait());
let std_future_trait = match std_future_trait {
Some(it) => it,
None => return false,
};
let canonical_ty =
- Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(&Interner) };
+ Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) };
method_resolution::implements_trait(
&canonical_ty,
db,
};
let canonical_ty =
- Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(&Interner) };
+ Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) };
method_resolution::implements_trait_unique(
&canonical_ty,
db,
.build();
let goal = Canonical {
- value: hir_ty::InEnvironment::new(&self.env.env, trait_ref.cast(&Interner)),
- binders: CanonicalVarKinds::empty(&Interner),
+ value: hir_ty::InEnvironment::new(&self.env.env, trait_ref.cast(Interner)),
+ binders: CanonicalVarKinds::empty(Interner),
};
db.trait_solve(self.krate, goal).is_some()
AliasEq {
alias: AliasTy::Projection(projection),
ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
- .intern(&Interner),
+ .intern(Interner),
}
- .cast(&Interner),
+ .cast(Interner),
),
[TyVariableKind::General].into_iter(),
);
Solution::Unique(s) => s
.value
.subst
- .as_slice(&Interner)
+ .as_slice(Interner)
.first()
- .map(|ty| self.derived(ty.assert_ty_ref(&Interner).clone())),
+ .map(|ty| self.derived(ty.assert_ty_ref(Interner).clone())),
Solution::Ambig(_) => None,
}
}
pub fn is_copy(&self, db: &dyn HirDatabase) -> bool {
- let lang_item = db.lang_item(self.krate, SmolStr::new("copy"));
+ let lang_item = db.lang_item(self.krate, SmolStr::new_inline("copy"));
let copy_trait = match lang_item {
Some(LangItemTarget::TraitId(it)) => it,
_ => return false,
}
pub fn is_closure(&self) -> bool {
- matches!(&self.ty.kind(&Interner), TyKind::Closure { .. })
+ matches!(&self.ty.kind(Interner), TyKind::Closure { .. })
}
pub fn is_fn(&self) -> bool {
- matches!(&self.ty.kind(&Interner), TyKind::FnDef(..) | TyKind::Function { .. })
+ matches!(&self.ty.kind(Interner), TyKind::FnDef(..) | TyKind::Function { .. })
+ }
+
+ pub fn is_array(&self) -> bool {
+ matches!(&self.ty.kind(Interner), TyKind::Array(..))
}
pub fn is_packed(&self, db: &dyn HirDatabase) -> bool {
- let adt_id = match *self.ty.kind(&Interner) {
+ let adt_id = match *self.ty.kind(Interner) {
TyKind::Adt(hir_ty::AdtId(adt_id), ..) => adt_id,
_ => return false,
};
}
pub fn is_raw_ptr(&self) -> bool {
- matches!(&self.ty.kind(&Interner), TyKind::Raw(..))
+ matches!(&self.ty.kind(Interner), TyKind::Raw(..))
}
pub fn contains_unknown(&self) -> bool {
return go(&self.ty);
fn go(ty: &Ty) -> bool {
- match ty.kind(&Interner) {
+ match ty.kind(Interner) {
TyKind::Error => true,
TyKind::Adt(_, substs)
| TyKind::OpaqueType(_, substs)
| TyKind::FnDef(_, substs)
| TyKind::Closure(_, substs) => {
- substs.iter(&Interner).filter_map(|a| a.ty(&Interner)).any(go)
+ substs.iter(Interner).filter_map(|a| a.ty(Interner)).any(go)
}
TyKind::Array(_ty, len) if len.is_unknown() => true,
}
pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> {
- let (variant_id, substs) = match self.ty.kind(&Interner) {
+ let (variant_id, substs) = match self.ty.kind(Interner) {
TyKind::Adt(hir_ty::AdtId(AdtId::StructId(s)), substs) => ((*s).into(), substs),
TyKind::Adt(hir_ty::AdtId(AdtId::UnionId(u)), substs) => ((*u).into(), substs),
_ => return Vec::new(),
.iter()
.map(|(local_id, ty)| {
let def = Field { parent: variant_id.into(), id: local_id };
- let ty = ty.clone().substitute(&Interner, substs);
+ let ty = ty.clone().substitute(Interner, substs);
(def, self.derived(ty))
})
.collect()
}
pub fn tuple_fields(&self, _db: &dyn HirDatabase) -> Vec<Type> {
- if let TyKind::Tuple(_, substs) = &self.ty.kind(&Interner) {
+ if let TyKind::Tuple(_, substs) = &self.ty.kind(Interner) {
substs
- .iter(&Interner)
- .map(|ty| self.derived(ty.assert_ty_ref(&Interner).clone()))
+ .iter(Interner)
+ .map(|ty| self.derived(ty.assert_ty_ref(Interner).clone()))
.collect()
} else {
Vec::new()
}
pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a {
+ self.autoderef_(db).map(move |ty| self.derived(ty))
+ }
+
+ pub fn autoderef_<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Ty> + 'a {
// There should be no inference vars in types passed here
let canonical = hir_ty::replace_errors_with_variables(&self.ty);
let environment = self.env.env.clone();
let ty = InEnvironment { goal: canonical, environment };
- autoderef(db, Some(self.krate), ty)
- .map(|canonical| canonical.value)
- .map(move |ty| self.derived(ty))
+ autoderef(db, Some(self.krate), ty).map(|canonical| canonical.value)
}
// This would be nicer if it just returned an iterator, but that runs into
// lifetime problems, because we need to borrow temp `CrateImplDefs`.
pub fn iterate_assoc_items<T>(
- self,
+ &self,
db: &dyn HirDatabase,
krate: Crate,
mut callback: impl FnMut(AssocItem) -> Option<T>,
}
fn iterate_assoc_items_dyn(
- self,
+ &self,
db: &dyn HirDatabase,
krate: Crate,
callback: &mut dyn FnMut(AssocItemId) -> bool,
.strip_references()
.as_adt()
.into_iter()
- .flat_map(|(_, substs)| substs.iter(&Interner))
- .filter_map(|arg| arg.ty(&Interner).cloned())
+ .flat_map(|(_, substs)| substs.iter(Interner))
+ .filter_map(|arg| arg.ty(Interner).cloned())
.map(move |ty| self.derived(ty))
}
db: &dyn HirDatabase,
krate: Crate,
traits_in_scope: &FxHashSet<TraitId>,
+ with_local_impls: Option<Module>,
name: Option<&Name>,
mut callback: impl FnMut(Type, Function) -> Option<T>,
) -> Option<T> {
let _p = profile::span("iterate_method_candidates");
let mut slot = None;
+
self.iterate_method_candidates_dyn(
db,
krate,
traits_in_scope,
+ with_local_impls,
name,
&mut |ty, assoc_item_id| {
if let AssocItemId::FunctionId(func) = assoc_item_id {
db: &dyn HirDatabase,
krate: Crate,
traits_in_scope: &FxHashSet<TraitId>,
+ with_local_impls: Option<Module>,
name: Option<&Name>,
callback: &mut dyn FnMut(&Ty, AssocItemId) -> ControlFlow<()>,
) {
env,
krate,
traits_in_scope,
- None,
+ with_local_impls.and_then(|b| b.id.containing_block()).into(),
name,
method_resolution::LookupMode::MethodCall,
&mut |ty, id| callback(&ty.value, id),
db: &dyn HirDatabase,
krate: Crate,
traits_in_scope: &FxHashSet<TraitId>,
+ with_local_impls: Option<Module>,
name: Option<&Name>,
mut callback: impl FnMut(Type, AssocItem) -> Option<T>,
) -> Option<T> {
db,
krate,
traits_in_scope,
+ with_local_impls,
name,
&mut |ty, assoc_item_id| {
if let Some(res) = callback(self.derived(ty.clone()), assoc_item_id.into()) {
db: &dyn HirDatabase,
krate: Crate,
traits_in_scope: &FxHashSet<TraitId>,
+ with_local_impls: Option<Module>,
name: Option<&Name>,
callback: &mut dyn FnMut(&Ty, AssocItemId) -> ControlFlow<()>,
) {
env,
krate,
traits_in_scope,
- None,
+ with_local_impls.and_then(|b| b.id.containing_block()).into(),
name,
method_resolution::LookupMode::Path,
&mut |ty, id| callback(&ty.value, id),
db: &'a dyn HirDatabase,
) -> impl Iterator<Item = Trait> + 'a {
let _p = profile::span("applicable_inherent_traits");
- self.autoderef(db)
- .filter_map(|derefed_type| derefed_type.ty.dyn_trait())
+ self.autoderef_(db)
+ .filter_map(|ty| ty.dyn_trait())
.flat_map(move |dyn_trait_id| hir_ty::all_super_traits(db.upcast(), dyn_trait_id))
.map(Trait::from)
}
- pub fn as_impl_traits(&self, db: &dyn HirDatabase) -> Option<Vec<Trait>> {
+ pub fn env_traits<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Trait> + 'a {
+ let _p = profile::span("env_traits");
+ self.autoderef_(db)
+ .filter(|ty| matches!(ty.kind(Interner), TyKind::Placeholder(_)))
+ .flat_map(|ty| {
+ self.env
+ .traits_in_scope_from_clauses(ty)
+ .flat_map(|t| hir_ty::all_super_traits(db.upcast(), t))
+ })
+ .map(Trait::from)
+ }
+
+ pub fn as_impl_traits(&self, db: &dyn HirDatabase) -> Option<impl Iterator<Item = Trait>> {
self.ty.impl_trait_bounds(db).map(|it| {
- it.into_iter()
- .filter_map(|pred| match pred.skip_binders() {
- hir_ty::WhereClause::Implemented(trait_ref) => {
- Some(Trait::from(trait_ref.hir_trait_id()))
- }
- _ => None,
- })
- .collect()
+ it.into_iter().filter_map(|pred| match pred.skip_binders() {
+ hir_ty::WhereClause::Implemented(trait_ref) => {
+ Some(Trait::from(trait_ref.hir_trait_id()))
+ }
+ _ => None,
+ })
})
}
substs: &Substitution,
cb: &mut impl FnMut(Type),
) {
- for ty in substs.iter(&Interner).filter_map(|a| a.ty(&Interner)) {
+ for ty in substs.iter(Interner).filter_map(|a| a.ty(Interner)) {
walk_type(db, &type_.derived(ty.clone()), cb);
}
}
if let WhereClause::Implemented(trait_ref) = pred.skip_binders() {
cb(type_.clone());
// skip the self type. it's likely the type we just got the bounds from
- for ty in trait_ref
- .substitution
- .iter(&Interner)
- .skip(1)
- .filter_map(|a| a.ty(&Interner))
+ for ty in
+ trait_ref.substitution.iter(Interner).skip(1).filter_map(|a| a.ty(Interner))
{
walk_type(db, &type_.derived(ty.clone()), cb);
}
fn walk_type(db: &dyn HirDatabase, type_: &Type, cb: &mut impl FnMut(Type)) {
let ty = type_.ty.strip_references();
- match ty.kind(&Interner) {
+ match ty.kind(Interner) {
TyKind::Adt(_, substs) => {
cb(type_.derived(ty.clone()));
walk_substs(db, type_, substs, cb);
}
/// For IDE only
-#[derive(Debug, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum ScopeDef {
ModuleDef(ModuleDef),
MacroDef(MacroDef),