mod source_to_def;
-use std::{cell::RefCell, fmt};
+use std::{cell::RefCell, fmt, iter};
use base_db::{FileId, FileRange};
use hir_def::{
resolver::{self, HasResolver, Resolver, TypeNs},
AsMacroCall, FunctionId, TraitId, VariantId,
};
-use hir_expand::{name::AsName, ExpansionInfo};
-use hir_ty::{associated_type_shorthand_candidates, Interner};
+use hir_expand::{name::AsName, ExpansionInfo, MacroCallId};
+use hir_ty::Interner;
use itertools::Itertools;
use rustc_hash::{FxHashMap, FxHashSet};
use smallvec::{smallvec, SmallVec};
use syntax::{
algo::skip_trivia_token,
- ast::{self, HasAttrs, HasGenericParams, HasLoopBody},
+ ast::{self, HasAttrs as _, HasGenericParams, HasLoopBody},
match_ast, AstNode, Direction, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextSize,
};
use crate::{
db::HirDatabase,
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
- source_analyzer::{resolve_hir_path, resolve_hir_path_as_macro, SourceAnalyzer},
- Access, AssocItem, Callable, ConstParam, Crate, Field, Function, HasSource, HirFileId, Impl,
- InFile, Label, LifetimeParam, Local, MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait,
- Type, TypeAlias, TypeParam, VariantDef,
+ source_analyzer::{resolve_hir_path, SourceAnalyzer},
+ Access, AssocItem, BuiltinAttr, Callable, ConstParam, Crate, Field, Function, HasSource,
+ HirFileId, Impl, InFile, Label, LifetimeParam, Local, MacroDef, Module, ModuleDef, Name, Path,
+ ScopeDef, ToolModule, Trait, Type, TypeAlias, TypeParam, VariantDef,
};
#[derive(Debug, Clone, PartialEq, Eq)]
SelfType(Impl),
Macro(MacroDef),
AssocItem(AssocItem),
+ BuiltinAttr(BuiltinAttr),
+ ToolModule(ToolModule),
}
impl PathResolution {
- fn in_type_ns(&self) -> Option<TypeNs> {
+ pub(crate) fn in_type_ns(&self) -> Option<TypeNs> {
match self {
PathResolution::Def(ModuleDef::Adt(adt)) => Some(TypeNs::AdtId((*adt).into())),
PathResolution::Def(ModuleDef::BuiltinType(builtin)) => {
PathResolution::Def(ModuleDef::TypeAlias(alias)) => {
Some(TypeNs::TypeAliasId((*alias).into()))
}
- PathResolution::Local(_) | PathResolution::Macro(_) | PathResolution::ConstParam(_) => {
- None
- }
+ PathResolution::BuiltinAttr(_)
+ | PathResolution::ToolModule(_)
+ | PathResolution::Local(_)
+ | PathResolution::Macro(_)
+ | PathResolution::ConstParam(_) => None,
PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())),
PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())),
PathResolution::AssocItem(AssocItem::Const(_) | AssocItem::Function(_)) => None,
}
}
}
-
- /// Returns an iterator over associated types that may be specified after this path (using
- /// `Ty::Assoc` syntax).
- pub fn assoc_type_shorthand_candidates<R>(
- &self,
- db: &dyn HirDatabase,
- mut cb: impl FnMut(&Name, TypeAlias) -> Option<R>,
- ) -> Option<R> {
- associated_type_shorthand_candidates(db, self.in_type_ns()?, |name, _, id| {
- cb(name, id.into())
- })
- }
}
#[derive(Debug)]
self.imp.parse(file_id)
}
+ pub fn parse_or_expand(&self, file_id: HirFileId) -> Option<SyntaxNode> {
+ self.imp.parse_or_expand(file_id)
+ }
+
pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
self.imp.expand(macro_call)
}
self.imp.expand_attr_macro(item)
}
+ pub fn resolve_derive_macro(&self, derive: &ast::Attr) -> Option<Vec<Option<MacroDef>>> {
+ self.imp.resolve_derive_macro(derive)
+ }
+
pub fn expand_derive_macro(&self, derive: &ast::Attr) -> Option<Vec<SyntaxNode>> {
self.imp.expand_derive_macro(derive)
}
self.imp.is_attr_macro_call(item)
}
+ pub fn is_derive_annotated(&self, item: &ast::Adt) -> bool {
+ self.imp.is_derive_annotated(item)
+ }
+
pub fn speculative_expand(
&self,
actual_macro_call: &ast::MacroCall,
}
pub fn hir_file_for(&self, syntax_node: &SyntaxNode) -> HirFileId {
- self.imp.find_file(syntax_node.clone()).file_id
+ self.imp.find_file(syntax_node).file_id
}
+ /// Attempts to map the node out of macro expanded files returning the original file range.
+ /// If upmapping is not possible, this will fall back to the range of the macro call of the
+ /// macro file the node resides in.
pub fn original_range(&self, node: &SyntaxNode) -> FileRange {
self.imp.original_range(node)
}
+ /// Attempts to map the node out of macro expanded files returning the original file range.
pub fn original_range_opt(&self, node: &SyntaxNode) -> Option<FileRange> {
self.imp.original_range_opt(node)
}
+ /// Attempts to map the node out of macro expanded files.
+ /// This only work for attribute expansions, as other ones do not have nodes as input.
pub fn original_ast_node<N: AstNode>(&self, node: N) -> Option<N> {
self.imp.original_ast_node(node)
}
token.parent().into_iter().flat_map(move |it| self.ancestors_with_macros(it))
}
+ /// Iterates the ancestors of the given node, climbing up macro expansions while doing so.
pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ {
self.imp.ancestors_with_macros(node)
}
self.imp.resolve_path(path)
}
- pub fn resolve_path_as_macro(&self, path: &ast::Path) -> Option<MacroDef> {
- self.imp.resolve_path_as_macro(path)
- }
-
pub fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> {
self.imp.resolve_extern_crate(extern_crate)
}
self.imp.resolve_bind_pat_to_const(pat)
}
- // FIXME: use this instead?
- // pub fn resolve_name_ref(&self, name_ref: &ast::NameRef) -> Option<???>;
-
pub fn record_literal_missing_fields(&self, literal: &ast::RecordExpr) -> Vec<(Field, Type)> {
self.imp.record_literal_missing_fields(literal)
}
}
pub fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> {
- let src = self.imp.find_file(src.syntax().clone()).with_value(src).cloned();
+ let src = self.imp.find_file(src.syntax()).with_value(src).cloned();
T::to_def(&self.imp, src)
}
self.imp.scope(node)
}
- pub fn scope_at_offset(&self, token: &SyntaxToken, offset: TextSize) -> SemanticsScope<'db> {
- self.imp.scope_at_offset(&token.parent().unwrap(), offset)
+ pub fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db> {
+ self.imp.scope_at_offset(&node, offset)
}
pub fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> {
tree
}
- fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
- let sa = self.analyze(macro_call.syntax());
- let file_id = sa.expand(self.db, InFile::new(sa.file_id, macro_call))?;
+ fn parse_or_expand(&self, file_id: HirFileId) -> Option<SyntaxNode> {
let node = self.db.parse_or_expand(file_id)?;
self.cache(node.clone(), file_id);
Some(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)?;
+ Some(node)
+ }
+
fn expand_attr_macro(&self, item: &ast::Item) -> Option<SyntaxNode> {
- let sa = self.analyze(item.syntax());
- let src = InFile::new(sa.file_id, item.clone());
+ let src = self.wrap_node_infile(item.clone());
let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(src))?;
let file_id = macro_call_id.as_file();
- let node = self.db.parse_or_expand(file_id)?;
- self.cache(node.clone(), file_id);
+ let node = self.parse_or_expand(file_id)?;
Some(node)
}
+ fn resolve_derive_macro(&self, attr: &ast::Attr) -> Option<Vec<Option<MacroDef>>> {
+ let res = self
+ .derive_macro_calls(attr)?
+ .into_iter()
+ .map(|call| Some(MacroDef { id: self.db.lookup_intern_macro_call(call?).def }))
+ .collect();
+ Some(res)
+ }
+
fn expand_derive_macro(&self, attr: &ast::Attr) -> Option<Vec<SyntaxNode>> {
- let item = attr.syntax().parent().and_then(ast::Item::cast)?;
- let sa = self.analyze(item.syntax());
- let item = InFile::new(sa.file_id, &item);
- let src = InFile::new(sa.file_id, attr.clone());
+ let res: Vec<_> = self
+ .derive_macro_calls(attr)?
+ .into_iter()
+ .flat_map(|call| {
+ let file_id = call?.as_file();
+ let node = self.db.parse_or_expand(file_id)?;
+ self.cache(node.clone(), file_id);
+ Some(node)
+ })
+ .collect();
+ Some(res)
+ }
+
+ fn derive_macro_calls(&self, attr: &ast::Attr) -> Option<Vec<Option<MacroCallId>>> {
+ let adt = attr.syntax().parent().and_then(ast::Adt::cast)?;
+ let file_id = self.find_file(adt.syntax()).file_id;
+ let adt = InFile::new(file_id, &adt);
+ let src = InFile::new(file_id, attr.clone());
self.with_ctx(|ctx| {
- let macro_call_ids = ctx.attr_to_derive_macro_call(item, src)?;
-
- let expansions: Vec<_> = macro_call_ids
- .iter()
- .map(|call| call.as_file())
- .flat_map(|file_id| {
- let node = self.db.parse_or_expand(file_id)?;
- self.cache(node.clone(), file_id);
- Some(node)
- })
- .collect();
- if expansions.is_empty() {
- None
- } else {
- Some(expansions)
- }
+ let (.., res) = ctx.attr_to_derive_macro_call(adt, src)?;
+ Some(res.to_vec())
})
}
+ fn is_derive_annotated(&self, adt: &ast::Adt) -> bool {
+ let file_id = self.find_file(adt.syntax()).file_id;
+ let adt = InFile::new(file_id, adt);
+ self.with_ctx(|ctx| ctx.has_derives(adt))
+ }
+
fn is_attr_macro_call(&self, item: &ast::Item) -> bool {
- let sa = self.analyze(item.syntax());
- let src = InFile::new(sa.file_id, item.clone());
+ let file_id = self.find_file(item.syntax()).file_id;
+ let src = InFile::new(file_id, item.clone());
self.with_ctx(|ctx| ctx.item_to_macro_call(src).is_some())
}
speculative_args: &ast::TokenTree,
token_to_map: SyntaxToken,
) -> Option<(SyntaxNode, SyntaxToken)> {
- let sa = self.analyze(actual_macro_call.syntax());
- let macro_call = InFile::new(sa.file_id, actual_macro_call);
- let krate = sa.resolver.krate()?;
+ let SourceAnalyzer { file_id, resolver, .. } =
+ self.analyze_no_infer(actual_macro_call.syntax());
+ let macro_call = InFile::new(file_id, actual_macro_call);
+ let krate = resolver.krate()?;
let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| {
- sa.resolver.resolve_path_as_macro(self.db.upcast(), &path)
+ resolver.resolve_path_as_macro(self.db.upcast(), &path)
})?;
hir_expand::db::expand_speculative(
self.db.upcast(),
speculative_args: &ast::Item,
token_to_map: SyntaxToken,
) -> Option<(SyntaxNode, SyntaxToken)> {
- let sa = self.analyze(actual_macro_call.syntax());
- let macro_call = InFile::new(sa.file_id, actual_macro_call.clone());
+ let macro_call = self.wrap_node_infile(actual_macro_call.clone());
let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(macro_call))?;
hir_expand::db::expand_speculative(
self.db.upcast(),
if first == last {
self.descend_into_macros_impl(
first,
- |InFile { value, .. }| {
+ &mut |InFile { value, .. }| {
if let Some(node) = value.ancestors().find_map(N::cast) {
res.push(node)
}
let mut scratch: SmallVec<[_; 1]> = smallvec![];
self.descend_into_macros_impl(
first,
- |token| {
+ &mut |token| {
scratch.push(token);
},
false,
let mut scratch = scratch.into_iter();
self.descend_into_macros_impl(
last,
- |InFile { value: last, file_id: last_fid }| {
+ &mut |InFile { value: last, file_id: last_fid }| {
if let Some(InFile { value: first, file_id: first_fid }) = scratch.next() {
if first_fid == last_fid {
if let Some(p) = first.parent() {
fn descend_into_macros(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> {
let mut res = smallvec![];
- self.descend_into_macros_impl(token, |InFile { value, .. }| res.push(value), false);
+ self.descend_into_macros_impl(token, &mut |InFile { value, .. }| res.push(value), false);
res
}
fn descend_into_macros_single(&self, token: SyntaxToken) -> SyntaxToken {
let mut res = token.clone();
- self.descend_into_macros_impl(token, |InFile { value, .. }| res = value, true);
+ self.descend_into_macros_impl(token, &mut |InFile { value, .. }| res = value, true);
res
}
fn descend_into_macros_impl(
&self,
token: SyntaxToken,
- mut f: impl FnMut(InFile<SyntaxToken>),
+ f: &mut dyn FnMut(InFile<SyntaxToken>),
single: bool,
) {
let _p = profile::span("descend_into_macros");
Some(it) => it,
None => return,
};
- let sa = self.analyze(&parent);
+ let sa = self.analyze_no_infer(&parent);
let mut stack: SmallVec<[_; 4]> = smallvec![InFile::new(sa.file_id, token)];
let mut cache = self.expansion_info_cache.borrow_mut();
let mut mcache = self.macro_call_cache.borrow_mut();
// FIXME replace map.while_some with take_while once stable
token.value.ancestors().map(ast::TokenTree::cast).while_some().last()
{
- let macro_call = tt.syntax().parent().and_then(ast::MacroCall::cast)?;
+ let parent = tt.syntax().parent()?;
+ // check for derive attribute here
+ let macro_call = match_ast! {
+ match parent {
+ ast::MacroCall(mcall) => mcall,
+ // attribute we failed expansion for earlier, this might be a derive invocation
+ // so try downmapping the token into the pseudo derive expansion
+ ast::Meta(meta) => {
+ let attr = meta.parent_attr()?;
+ let adt = attr.syntax().parent().and_then(ast::Adt::cast)?;
+ let call_id = self.with_ctx(|ctx| {
+ let (_, call_id, _) = ctx.attr_to_derive_macro_call(token.with_value(&adt), token.with_value(attr))?;
+ Some(call_id)
+ })?;
+ let file_id = call_id.as_file();
+ return process_expansion_for_token(&mut stack,file_id,Some(adt.into()),token.as_ref(),);
+ },
+ _ => return None,
+ }
+ };
+
if tt.left_delimiter_token().map_or(false, |it| it == token.value) {
return None;
}
}
fn original_range(&self, node: &SyntaxNode) -> FileRange {
- let node = self.find_file(node.clone());
- node.as_ref().original_file_range(self.db.upcast())
+ let node = self.find_file(node);
+ node.original_file_range(self.db.upcast())
}
fn original_range_opt(&self, node: &SyntaxNode) -> Option<FileRange> {
- let node = self.find_file(node.clone());
- node.as_ref().original_file_range_opt(self.db.upcast())
+ let node = self.find_file(node);
+ node.original_file_range_opt(self.db.upcast())
}
fn original_ast_node<N: AstNode>(&self, node: N) -> Option<N> {
- let file = self.find_file(node.syntax().clone());
- file.with_value(node).original_ast_node(self.db.upcast()).map(|it| it.value)
+ self.wrap_node_infile(node).original_ast_node(self.db.upcast()).map(|it| it.value)
}
fn diagnostics_display_range(&self, src: InFile<SyntaxNodePtr>) -> FileRange {
- let root = self.db.parse_or_expand(src.file_id).unwrap();
- let node = src.value.to_node(&root);
- self.cache(root, src.file_id);
- src.with_value(&node).original_file_range(self.db.upcast())
+ let root = self.parse_or_expand(src.file_id).unwrap();
+ let node = src.map(|it| it.to_node(&root));
+ node.as_ref().original_file_range(self.db.upcast())
}
fn token_ancestors_with_macros(
&self,
node: SyntaxNode,
) -> impl Iterator<Item = SyntaxNode> + Clone + '_ {
- let node = self.find_file(node);
- node.ancestors_with_macros(self.db.upcast()).map(|it| it.value)
+ let node = self.find_file(&node);
+ let db = self.db.upcast();
+ iter::successors(Some(node.cloned()), move |&InFile { file_id, ref value }| {
+ match value.parent() {
+ Some(parent) => Some(InFile::new(file_id, parent)),
+ None => {
+ self.cache(value.clone(), file_id);
+ file_id.call_node(db)
+ }
+ }
+ })
+ .map(|it| it.value)
}
fn ancestors_at_offset_with_macros(
gpl.lifetime_params()
.find(|tp| tp.lifetime().as_ref().map(|lt| lt.text()).as_ref() == Some(&text))
})?;
- let src = self.find_file(lifetime_param.syntax().clone()).with_value(lifetime_param);
+ let src = self.wrap_node_infile(lifetime_param);
ToDef::to_def(self, src)
}
.map_or(false, |lt| lt.text() == text)
})
})?;
- let src = self.find_file(label.syntax().clone()).with_value(label);
+ let src = self.wrap_node_infile(label);
ToDef::to_def(self, src)
}
fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
let (func, subst) = self.analyze(call.syntax()).resolve_method_call(self.db, call)?;
- let ty = self.db.value_ty(func.into()).substitute(&Interner, &subst);
+ let ty = self.db.value_ty(func.into()).substitute(Interner, &subst);
let resolver = self.analyze(call.syntax()).resolver;
let ty = Type::new_with_resolver(self.db, &resolver, ty)?;
let mut res = ty.as_callable(self.db)?;
fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<MacroDef> {
let sa = self.analyze(macro_call.syntax());
- let macro_call = self.find_file(macro_call.syntax().clone()).with_value(macro_call);
+ let macro_call = self.find_file(macro_call.syntax()).with_value(macro_call);
sa.resolve_macro_call(self.db, macro_call)
}
fn resolve_attr_macro_call(&self, item: &ast::Item) -> Option<MacroDef> {
- let item_in_file = self.find_file(item.syntax().clone()).with_value(item.clone());
+ let item_in_file = self.wrap_node_infile(item.clone());
let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(item_in_file))?;
- Some(MacroDef { id: self.db.lookup_intern_macro(macro_call_id).def })
+ Some(MacroDef { id: self.db.lookup_intern_macro_call(macro_call_id).def })
}
fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> {
self.analyze(path.syntax()).resolve_path(self.db, path)
}
- // FIXME: This shouldn't exist, but is currently required to always resolve attribute paths in
- // the IDE layer due to namespace collisions
- fn resolve_path_as_macro(&self, path: &ast::Path) -> Option<MacroDef> {
- self.analyze(path.syntax()).resolve_path_as_macro(self.db, path)
- }
-
fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> {
let krate = self.scope(extern_crate.syntax()).krate()?;
krate.dependencies(self.db).into_iter().find_map(|dep| {
}
fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> {
- let SourceAnalyzer { file_id, resolver, .. } = self.analyze(node);
+ let SourceAnalyzer { file_id, resolver, .. } = self.analyze_no_infer(node);
SemanticsScope { db: self.db, file_id, resolver }
}
fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db> {
- let SourceAnalyzer { file_id, resolver, .. } = self.analyze_with_offset(node, offset);
+ let SourceAnalyzer { file_id, resolver, .. } =
+ self.analyze_with_offset_no_infer(node, offset);
SemanticsScope { db: self.db, file_id, resolver }
}
}
fn analyze(&self, node: &SyntaxNode) -> SourceAnalyzer {
- self.analyze_impl(node, None)
+ self.analyze_impl(node, None, true)
+ }
+
+ fn analyze_no_infer(&self, node: &SyntaxNode) -> SourceAnalyzer {
+ self.analyze_impl(node, None, false)
}
- fn analyze_with_offset(&self, node: &SyntaxNode, offset: TextSize) -> SourceAnalyzer {
- self.analyze_impl(node, Some(offset))
+ fn analyze_with_offset_no_infer(&self, node: &SyntaxNode, offset: TextSize) -> SourceAnalyzer {
+ self.analyze_impl(node, Some(offset), false)
}
- fn analyze_impl(&self, node: &SyntaxNode, offset: Option<TextSize>) -> SourceAnalyzer {
+ fn analyze_impl(
+ &self,
+ node: &SyntaxNode,
+ offset: Option<TextSize>,
+ infer_body: bool,
+ ) -> SourceAnalyzer {
let _p = profile::span("Semantics::analyze_impl");
- let node = self.find_file(node.clone());
- let node = node.as_ref();
+ let node = self.find_file(node);
let container = match self.with_ctx(|ctx| ctx.find_container(node)) {
Some(it) => it,
let resolver = match container {
ChildContainer::DefWithBodyId(def) => {
- return SourceAnalyzer::new_for_body(self.db, def, node, offset)
+ return if infer_body {
+ SourceAnalyzer::new_for_body(self.db, def, node, offset)
+ } else {
+ SourceAnalyzer::new_for_body_no_infer(self.db, def, node, offset)
+ }
}
ChildContainer::TraitId(it) => it.resolver(self.db.upcast()),
ChildContainer::ImplId(it) => it.resolver(self.db.upcast()),
}
fn assert_contains_node(&self, node: &SyntaxNode) {
- self.find_file(node.clone());
+ self.find_file(node);
}
fn lookup(&self, root_node: &SyntaxNode) -> Option<HirFileId> {
cache.get(root_node).copied()
}
- fn find_file(&self, node: SyntaxNode) -> InFile<SyntaxNode> {
- let root_node = find_root(&node);
+ fn wrap_node_infile<N: AstNode>(&self, node: N) -> InFile<N> {
+ let InFile { file_id, .. } = self.find_file(node.syntax());
+ InFile::new(file_id, node)
+ }
+
+ fn find_file<'node>(&self, node: &'node SyntaxNode) -> InFile<&'node SyntaxNode> {
+ let root_node = find_root(node);
let file_id = self.lookup(&root_node).unwrap_or_else(|| {
panic!(
"\n\nFailed to lookup {:?} in this Semantics.\n\
(crate::TypeParam, ast::TypeParam, type_param_to_def),
(crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def),
(crate::ConstParam, ast::ConstParam, const_param_to_def),
+ (crate::GenericParam, ast::GenericParam, generic_param_to_def),
(crate::MacroDef, ast::Macro, macro_to_def),
(crate::Local, ast::IdentPat, bind_pat_to_def),
(crate::Local, ast::SelfParam, self_param_to_def),
}
/// Note: `FxHashSet<TraitId>` should be treated as an opaque type, passed into `Type
- // FIXME: rename to visible_traits to not repeat scope?
- pub fn traits_in_scope(&self) -> FxHashSet<TraitId> {
+ pub fn visible_traits(&self) -> FxHashSet<TraitId> {
let resolver = &self.resolver;
resolver.traits_in_scope(self.db.upcast())
}
resolve_hir_path(self.db, &self.resolver, &path)
}
- /// 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.
- // FIXME: This special casing solely exists for attributes for now
- // ideally we should have a path resolution infra that properly knows about overlapping namespaces
- pub fn speculative_resolve_as_mac(&self, path: &ast::Path) -> Option<MacroDef> {
- let ctx = body::LowerCtx::new(self.db.upcast(), self.file_id);
- let path = Path::from_src(path.clone(), &ctx)?;
- resolve_hir_path_as_macro(self.db, &self.resolver, &path)
+ /// Iterates over associated types that may be specified after the given path (using
+ /// `Ty::Assoc` syntax).
+ pub fn assoc_type_shorthand_candidates<R>(
+ &self,
+ resolution: &PathResolution,
+ mut cb: impl FnMut(&Name, TypeAlias) -> Option<R>,
+ ) -> Option<R> {
+ let def = self.resolver.generic_def()?;
+ hir_ty::associated_type_shorthand_candidates(
+ self.db,
+ def,
+ resolution.in_type_ns()?,
+ |name, _, id| cb(name, id.into()),
+ )
}
}