mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-11-01 20:31:59 +00:00
refactor: Lower type-refs before type inference
This refactors how we deal with items in hir-def lowering. - It now lowers all of them through an "ExpressionStore" (kind of a misnomer as this point) as their so called *Signatures. - We now uniformly lower type AST into TypeRefs before type inference. - Likewise, this moves macro expansion out of type inference, resulting in a single place where we do non-defmap macro expansion. - Finally, this PR removes a lot of information from ItemTree, making the DefMap a lot less likely to be recomputed and have it only depend on actual early name resolution related information (not 100% true, we still have ADT fields in there but thats a follow up removal).
This commit is contained in:
parent
588948f267
commit
1fd9520c92
127 changed files with 6733 additions and 7993 deletions
|
|
@ -76,7 +76,6 @@ impl Attrs {
|
|||
let _p = tracing::info_span!("fields_attrs_query").entered();
|
||||
// FIXME: There should be some proper form of mapping between item tree field ids and hir field ids
|
||||
let mut res = ArenaMap::default();
|
||||
|
||||
let item_tree;
|
||||
let (parent, fields, krate) = match v {
|
||||
VariantId::EnumVariantId(it) => {
|
||||
|
|
|
|||
|
|
@ -1,605 +0,0 @@
|
|||
//! Contains basic data about various HIR declarations.
|
||||
|
||||
pub mod adt;
|
||||
|
||||
use base_db::Crate;
|
||||
use hir_expand::name::Name;
|
||||
use intern::{Symbol, sym};
|
||||
use la_arena::{Idx, RawIdx};
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
ConstId, ExternCrateId, FunctionId, HasModule, ImplId, ItemContainerId, ItemLoc, Lookup,
|
||||
Macro2Id, MacroRulesId, ProcMacroId, StaticId, TraitAliasId, TraitId, TypeAliasId,
|
||||
db::DefDatabase,
|
||||
item_tree::{self, FnFlags, ModItem, StaticFlags},
|
||||
nameres::proc_macro::{ProcMacroKind, parse_macro_name_and_helper_attrs},
|
||||
path::ImportAlias,
|
||||
type_ref::{TraitRef, TypeBound, TypeRefId, TypesMap},
|
||||
visibility::RawVisibility,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct FunctionData {
|
||||
pub name: Name,
|
||||
pub params: Box<[TypeRefId]>,
|
||||
pub ret_type: TypeRefId,
|
||||
pub visibility: RawVisibility,
|
||||
pub abi: Option<Symbol>,
|
||||
pub legacy_const_generics_indices: Option<Box<Box<[u32]>>>,
|
||||
pub types_map: Arc<TypesMap>,
|
||||
pub flags: FnFlags,
|
||||
}
|
||||
|
||||
impl FunctionData {
|
||||
pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<FunctionData> {
|
||||
let loc = func.lookup(db);
|
||||
let krate = loc.container.module(db).krate;
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let func = &item_tree[loc.id.value];
|
||||
let visibility = if let ItemContainerId::TraitId(trait_id) = loc.container {
|
||||
trait_vis(db, trait_id)
|
||||
} else {
|
||||
item_tree[func.visibility].clone()
|
||||
};
|
||||
|
||||
let cfg_options = krate.cfg_options(db);
|
||||
let attr_owner = |idx| {
|
||||
item_tree::AttrOwner::Param(loc.id.value, Idx::from_raw(RawIdx::from(idx as u32)))
|
||||
};
|
||||
|
||||
let mut flags = func.flags;
|
||||
if flags.contains(FnFlags::HAS_SELF_PARAM) {
|
||||
// If there's a self param in the syntax, but it is cfg'd out, remove the flag.
|
||||
let is_cfgd_out =
|
||||
!item_tree.attrs(db, krate, attr_owner(0usize)).is_cfg_enabled(cfg_options);
|
||||
if is_cfgd_out {
|
||||
cov_mark::hit!(cfgd_out_self_param);
|
||||
flags.remove(FnFlags::HAS_SELF_PARAM);
|
||||
}
|
||||
}
|
||||
if flags.contains(FnFlags::IS_VARARGS) {
|
||||
if let Some((_, param)) = func.params.iter().enumerate().rev().find(|&(idx, _)| {
|
||||
item_tree.attrs(db, krate, attr_owner(idx)).is_cfg_enabled(cfg_options)
|
||||
}) {
|
||||
if param.type_ref.is_some() {
|
||||
flags.remove(FnFlags::IS_VARARGS);
|
||||
}
|
||||
} else {
|
||||
flags.remove(FnFlags::IS_VARARGS);
|
||||
}
|
||||
}
|
||||
|
||||
let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into());
|
||||
if attrs.by_key(&sym::rustc_allow_incoherent_impl).exists() {
|
||||
flags |= FnFlags::RUSTC_ALLOW_INCOHERENT_IMPL;
|
||||
}
|
||||
if flags.contains(FnFlags::HAS_UNSAFE_KW)
|
||||
&& attrs.by_key(&sym::rustc_deprecated_safe_2024).exists()
|
||||
{
|
||||
flags.remove(FnFlags::HAS_UNSAFE_KW);
|
||||
flags.insert(FnFlags::DEPRECATED_SAFE_2024);
|
||||
}
|
||||
|
||||
if attrs.by_key(&sym::target_feature).exists() {
|
||||
flags.insert(FnFlags::HAS_TARGET_FEATURE);
|
||||
}
|
||||
|
||||
Arc::new(FunctionData {
|
||||
name: func.name.clone(),
|
||||
params: func
|
||||
.params
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|&(idx, _)| {
|
||||
item_tree.attrs(db, krate, attr_owner(idx)).is_cfg_enabled(cfg_options)
|
||||
})
|
||||
.filter_map(|(_, param)| param.type_ref)
|
||||
.collect(),
|
||||
ret_type: func.ret_type,
|
||||
visibility,
|
||||
abi: func.abi.clone(),
|
||||
legacy_const_generics_indices: attrs.rustc_legacy_const_generics(),
|
||||
types_map: func.types_map.clone(),
|
||||
flags,
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn has_body(&self) -> bool {
|
||||
self.flags.contains(FnFlags::HAS_BODY)
|
||||
}
|
||||
|
||||
/// True if the first param is `self`. This is relevant to decide whether this
|
||||
/// can be called as a method.
|
||||
#[inline]
|
||||
pub fn has_self_param(&self) -> bool {
|
||||
self.flags.contains(FnFlags::HAS_SELF_PARAM)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_default(&self) -> bool {
|
||||
self.flags.contains(FnFlags::HAS_DEFAULT_KW)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_const(&self) -> bool {
|
||||
self.flags.contains(FnFlags::HAS_CONST_KW)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_async(&self) -> bool {
|
||||
self.flags.contains(FnFlags::HAS_ASYNC_KW)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_unsafe(&self) -> bool {
|
||||
self.flags.contains(FnFlags::HAS_UNSAFE_KW)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_deprecated_safe_2024(&self) -> bool {
|
||||
self.flags.contains(FnFlags::DEPRECATED_SAFE_2024)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_safe(&self) -> bool {
|
||||
self.flags.contains(FnFlags::HAS_SAFE_KW)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_varargs(&self) -> bool {
|
||||
self.flags.contains(FnFlags::IS_VARARGS)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn has_target_feature(&self) -> bool {
|
||||
self.flags.contains(FnFlags::HAS_TARGET_FEATURE)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn rustc_allow_incoherent_impl(&self) -> bool {
|
||||
self.flags.contains(FnFlags::RUSTC_ALLOW_INCOHERENT_IMPL)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct TypeAliasData {
|
||||
pub name: Name,
|
||||
pub type_ref: Option<TypeRefId>,
|
||||
pub visibility: RawVisibility,
|
||||
pub flags: TypeAliasFlags,
|
||||
/// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl).
|
||||
pub bounds: Box<[TypeBound]>,
|
||||
pub types_map: Arc<TypesMap>,
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct TypeAliasFlags: u8 {
|
||||
const IS_EXTERN = 1 << 0;
|
||||
const RUSTC_HAS_INCOHERENT_INHERENT_IMPLS = 1 << 1;
|
||||
const RUSTC_ALLOW_INCOHERENT_IMPL = 1 << 2;
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeAliasData {
|
||||
#[inline]
|
||||
pub fn is_extern(&self) -> bool {
|
||||
self.flags.contains(TypeAliasFlags::IS_EXTERN)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn rustc_has_incoherent_inherent_impls(&self) -> bool {
|
||||
self.flags.contains(TypeAliasFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn rustc_allow_incoherent_impl(&self) -> bool {
|
||||
self.flags.contains(TypeAliasFlags::RUSTC_ALLOW_INCOHERENT_IMPL)
|
||||
}
|
||||
|
||||
pub(crate) fn type_alias_data_query(
|
||||
db: &dyn DefDatabase,
|
||||
typ: TypeAliasId,
|
||||
) -> Arc<TypeAliasData> {
|
||||
let loc = typ.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let typ = &item_tree[loc.id.value];
|
||||
let visibility = if let ItemContainerId::TraitId(trait_id) = loc.container {
|
||||
trait_vis(db, trait_id)
|
||||
} else {
|
||||
item_tree[typ.visibility].clone()
|
||||
};
|
||||
|
||||
let attrs = item_tree.attrs(
|
||||
db,
|
||||
loc.container.module(db).krate(),
|
||||
ModItem::from(loc.id.value).into(),
|
||||
);
|
||||
|
||||
let mut flags = TypeAliasFlags::empty();
|
||||
|
||||
if matches!(loc.container, ItemContainerId::ExternBlockId(_)) {
|
||||
flags |= TypeAliasFlags::IS_EXTERN;
|
||||
}
|
||||
if attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists() {
|
||||
flags |= TypeAliasFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS;
|
||||
}
|
||||
if attrs.by_key(&sym::rustc_allow_incoherent_impl).exists() {
|
||||
flags |= TypeAliasFlags::RUSTC_ALLOW_INCOHERENT_IMPL;
|
||||
}
|
||||
|
||||
Arc::new(TypeAliasData {
|
||||
name: typ.name.clone(),
|
||||
type_ref: typ.type_ref,
|
||||
visibility,
|
||||
flags,
|
||||
bounds: typ.bounds.clone(),
|
||||
types_map: typ.types_map.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
|
||||
pub struct TraitFlags: u16 {
|
||||
const IS_AUTO = 1 << 0;
|
||||
const IS_UNSAFE = 1 << 1;
|
||||
const IS_FUNDAMENTAL = 1 << 2;
|
||||
const RUSTC_HAS_INCOHERENT_INHERENT_IMPLS = 1 << 3;
|
||||
const SKIP_ARRAY_DURING_METHOD_DISPATCH = 1 << 4;
|
||||
const SKIP_BOXED_SLICE_DURING_METHOD_DISPATCH = 1 << 5;
|
||||
const RUSTC_PAREN_SUGAR = 1 << 6;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct TraitData {
|
||||
pub name: Name,
|
||||
pub flags: TraitFlags,
|
||||
pub visibility: RawVisibility,
|
||||
}
|
||||
|
||||
impl TraitData {
|
||||
#[inline]
|
||||
pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> {
|
||||
let ItemLoc { container: module_id, id: tree_id } = tr.lookup(db);
|
||||
let item_tree = tree_id.item_tree(db);
|
||||
let tr_def = &item_tree[tree_id.value];
|
||||
let name = tr_def.name.clone();
|
||||
let visibility = item_tree[tr_def.visibility].clone();
|
||||
let attrs = item_tree.attrs(db, module_id.krate(), ModItem::from(tree_id.value).into());
|
||||
|
||||
let mut flags = TraitFlags::empty();
|
||||
|
||||
if tr_def.is_auto {
|
||||
flags |= TraitFlags::IS_AUTO;
|
||||
}
|
||||
if tr_def.is_unsafe {
|
||||
flags |= TraitFlags::IS_UNSAFE;
|
||||
}
|
||||
if attrs.by_key(&sym::fundamental).exists() {
|
||||
flags |= TraitFlags::IS_FUNDAMENTAL;
|
||||
}
|
||||
if attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists() {
|
||||
flags |= TraitFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS;
|
||||
}
|
||||
if attrs.by_key(&sym::rustc_paren_sugar).exists() {
|
||||
flags |= TraitFlags::RUSTC_PAREN_SUGAR;
|
||||
}
|
||||
|
||||
let mut skip_array_during_method_dispatch =
|
||||
attrs.by_key(&sym::rustc_skip_array_during_method_dispatch).exists();
|
||||
let mut skip_boxed_slice_during_method_dispatch = false;
|
||||
for tt in attrs.by_key(&sym::rustc_skip_during_method_dispatch).tt_values() {
|
||||
for tt in tt.iter() {
|
||||
if let tt::iter::TtElement::Leaf(tt::Leaf::Ident(ident)) = tt {
|
||||
skip_array_during_method_dispatch |= ident.sym == sym::array;
|
||||
skip_boxed_slice_during_method_dispatch |= ident.sym == sym::boxed_slice;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if skip_array_during_method_dispatch {
|
||||
flags |= TraitFlags::SKIP_ARRAY_DURING_METHOD_DISPATCH;
|
||||
}
|
||||
if skip_boxed_slice_during_method_dispatch {
|
||||
flags |= TraitFlags::SKIP_BOXED_SLICE_DURING_METHOD_DISPATCH;
|
||||
}
|
||||
|
||||
Arc::new(TraitData { name, visibility, flags })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct TraitAliasData {
|
||||
pub name: Name,
|
||||
pub visibility: RawVisibility,
|
||||
}
|
||||
|
||||
impl TraitAliasData {
|
||||
pub(crate) fn trait_alias_query(db: &dyn DefDatabase, id: TraitAliasId) -> Arc<TraitAliasData> {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let alias = &item_tree[loc.id.value];
|
||||
let visibility = item_tree[alias.visibility].clone();
|
||||
|
||||
Arc::new(TraitAliasData { name: alias.name.clone(), visibility })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct ImplData {
|
||||
pub target_trait: Option<TraitRef>,
|
||||
pub self_ty: TypeRefId,
|
||||
pub is_negative: bool,
|
||||
pub is_unsafe: bool,
|
||||
pub types_map: Arc<TypesMap>,
|
||||
}
|
||||
|
||||
impl ImplData {
|
||||
#[inline]
|
||||
pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData> {
|
||||
let _p = tracing::info_span!("impl_data_query").entered();
|
||||
let ItemLoc { id: tree_id, .. } = id.lookup(db);
|
||||
|
||||
let item_tree = tree_id.item_tree(db);
|
||||
let impl_def = &item_tree[tree_id.value];
|
||||
let target_trait = impl_def.target_trait;
|
||||
let self_ty = impl_def.self_ty;
|
||||
let is_negative = impl_def.is_negative;
|
||||
let is_unsafe = impl_def.is_unsafe;
|
||||
|
||||
Arc::new(ImplData {
|
||||
target_trait,
|
||||
self_ty,
|
||||
is_negative,
|
||||
is_unsafe,
|
||||
types_map: impl_def.types_map.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Macro2Data {
|
||||
pub name: Name,
|
||||
pub visibility: RawVisibility,
|
||||
// It's a bit wasteful as currently this is only for builtin `Default` derive macro, but macro2
|
||||
// are rarely used in practice so I think it's okay for now.
|
||||
/// Derive helpers, if this is a derive rustc_builtin_macro
|
||||
pub helpers: Option<Box<[Name]>>,
|
||||
}
|
||||
|
||||
impl Macro2Data {
|
||||
pub(crate) fn macro2_data_query(db: &dyn DefDatabase, makro: Macro2Id) -> Arc<Macro2Data> {
|
||||
let loc = makro.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let makro = &item_tree[loc.id.value];
|
||||
let attrs = item_tree.attrs(db, loc.container.krate(), ModItem::from(loc.id.value).into());
|
||||
|
||||
let helpers = attrs
|
||||
.by_key(&sym::rustc_builtin_macro)
|
||||
.tt_values()
|
||||
.next()
|
||||
.and_then(parse_macro_name_and_helper_attrs)
|
||||
.map(|(_, helpers)| helpers);
|
||||
|
||||
Arc::new(Macro2Data {
|
||||
name: makro.name.clone(),
|
||||
visibility: item_tree[makro.visibility].clone(),
|
||||
helpers,
|
||||
})
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct MacroRulesData {
|
||||
pub name: Name,
|
||||
pub macro_export: bool,
|
||||
}
|
||||
|
||||
impl MacroRulesData {
|
||||
pub(crate) fn macro_rules_data_query(
|
||||
db: &dyn DefDatabase,
|
||||
makro: MacroRulesId,
|
||||
) -> Arc<MacroRulesData> {
|
||||
let loc = makro.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let makro = &item_tree[loc.id.value];
|
||||
let attrs = item_tree.attrs(db, loc.container.krate(), ModItem::from(loc.id.value).into());
|
||||
|
||||
let macro_export = attrs.by_key(&sym::macro_export).exists();
|
||||
|
||||
Arc::new(MacroRulesData { name: makro.name.clone(), macro_export })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ProcMacroData {
|
||||
pub name: Name,
|
||||
/// Derive helpers, if this is a derive
|
||||
pub helpers: Option<Box<[Name]>>,
|
||||
}
|
||||
|
||||
impl ProcMacroData {
|
||||
pub(crate) fn proc_macro_data_query(
|
||||
db: &dyn DefDatabase,
|
||||
makro: ProcMacroId,
|
||||
) -> Arc<ProcMacroData> {
|
||||
let loc = makro.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let makro = &item_tree[loc.id.value];
|
||||
let attrs = item_tree.attrs(db, loc.container.krate(), ModItem::from(loc.id.value).into());
|
||||
|
||||
let (name, helpers) = if let Some(def) = attrs.parse_proc_macro_decl(&makro.name) {
|
||||
(
|
||||
def.name,
|
||||
match def.kind {
|
||||
ProcMacroKind::Derive { helpers } => Some(helpers),
|
||||
ProcMacroKind::Bang | ProcMacroKind::Attr => None,
|
||||
},
|
||||
)
|
||||
} else {
|
||||
// eeeh...
|
||||
stdx::never!("proc macro declaration is not a proc macro");
|
||||
(makro.name.clone(), None)
|
||||
};
|
||||
|
||||
Arc::new(ProcMacroData { name, helpers })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ExternCrateDeclData {
|
||||
pub name: Name,
|
||||
pub alias: Option<ImportAlias>,
|
||||
pub visibility: RawVisibility,
|
||||
pub crate_id: Option<Crate>,
|
||||
}
|
||||
|
||||
impl ExternCrateDeclData {
|
||||
pub(crate) fn extern_crate_decl_data_query(
|
||||
db: &dyn DefDatabase,
|
||||
extern_crate: ExternCrateId,
|
||||
) -> Arc<ExternCrateDeclData> {
|
||||
let loc = extern_crate.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let extern_crate = &item_tree[loc.id.value];
|
||||
|
||||
let name = extern_crate.name.clone();
|
||||
let krate = loc.container.krate();
|
||||
let crate_id = if name == sym::self_.clone() {
|
||||
Some(krate)
|
||||
} else {
|
||||
krate.data(db).dependencies.iter().find_map(|dep| {
|
||||
if dep.name.symbol() == name.symbol() { Some(dep.crate_id) } else { None }
|
||||
})
|
||||
};
|
||||
|
||||
Arc::new(Self {
|
||||
name,
|
||||
visibility: item_tree[extern_crate.visibility].clone(),
|
||||
alias: extern_crate.alias.clone(),
|
||||
crate_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ConstData {
|
||||
/// `None` for `const _: () = ();`
|
||||
pub name: Option<Name>,
|
||||
pub type_ref: TypeRefId,
|
||||
pub visibility: RawVisibility,
|
||||
pub types_map: Arc<TypesMap>,
|
||||
pub flags: ConstFlags,
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct ConstFlags: u8 {
|
||||
const RUSTC_ALLOW_INCOHERENT_IMPL = 1 << 0;
|
||||
const HAS_BODY = 1 << 1;
|
||||
}
|
||||
}
|
||||
|
||||
impl ConstData {
|
||||
pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc<ConstData> {
|
||||
let loc = konst.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let konst = &item_tree[loc.id.value];
|
||||
let visibility = if let ItemContainerId::TraitId(trait_id) = loc.container {
|
||||
trait_vis(db, trait_id)
|
||||
} else {
|
||||
item_tree[konst.visibility].clone()
|
||||
};
|
||||
let attrs = item_tree.attrs(
|
||||
db,
|
||||
loc.container.module(db).krate(),
|
||||
ModItem::from(loc.id.value).into(),
|
||||
);
|
||||
|
||||
let mut flags = ConstFlags::empty();
|
||||
if attrs.by_key(&sym::rustc_allow_incoherent_impl).exists() {
|
||||
flags |= ConstFlags::RUSTC_ALLOW_INCOHERENT_IMPL;
|
||||
}
|
||||
if konst.has_body {
|
||||
flags |= ConstFlags::HAS_BODY;
|
||||
}
|
||||
|
||||
Arc::new(ConstData {
|
||||
name: konst.name.clone(),
|
||||
type_ref: konst.type_ref,
|
||||
visibility,
|
||||
flags,
|
||||
types_map: konst.types_map.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn rustc_allow_incoherent_impl(&self) -> bool {
|
||||
self.flags.contains(ConstFlags::RUSTC_ALLOW_INCOHERENT_IMPL)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn has_body(&self) -> bool {
|
||||
self.flags.contains(ConstFlags::HAS_BODY)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct StaticData {
|
||||
pub name: Name,
|
||||
pub type_ref: TypeRefId,
|
||||
pub visibility: RawVisibility,
|
||||
pub types_map: Arc<TypesMap>,
|
||||
pub flags: StaticFlags,
|
||||
}
|
||||
|
||||
impl StaticData {
|
||||
pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<StaticData> {
|
||||
let loc = konst.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let statik = &item_tree[loc.id.value];
|
||||
|
||||
let mut flags = statik.flags;
|
||||
if matches!(loc.container, ItemContainerId::ExternBlockId(_)) {
|
||||
flags |= StaticFlags::IS_EXTERN;
|
||||
}
|
||||
|
||||
Arc::new(StaticData {
|
||||
name: statik.name.clone(),
|
||||
type_ref: statik.type_ref,
|
||||
visibility: item_tree[statik.visibility].clone(),
|
||||
flags,
|
||||
types_map: statik.types_map.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_extern(&self) -> bool {
|
||||
self.flags.contains(StaticFlags::IS_EXTERN)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn mutable(&self) -> bool {
|
||||
self.flags.contains(StaticFlags::MUTABLE)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn has_safe_kw(&self) -> bool {
|
||||
self.flags.contains(StaticFlags::HAS_SAFE_KW)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn has_unsafe_kw(&self) -> bool {
|
||||
self.flags.contains(StaticFlags::HAS_UNSAFE_KW)
|
||||
}
|
||||
}
|
||||
|
||||
fn trait_vis(db: &dyn DefDatabase, trait_id: TraitId) -> RawVisibility {
|
||||
let ItemLoc { id: tree_id, .. } = trait_id.lookup(db);
|
||||
let item_tree = tree_id.item_tree(db);
|
||||
let tr_def = &item_tree[tree_id.value];
|
||||
item_tree[tr_def.visibility].clone()
|
||||
}
|
||||
|
|
@ -1,412 +0,0 @@
|
|||
//! Defines hir-level representation of structs, enums and unions
|
||||
|
||||
use base_db::Crate;
|
||||
use bitflags::bitflags;
|
||||
use cfg::CfgOptions;
|
||||
|
||||
use hir_expand::name::Name;
|
||||
use intern::sym;
|
||||
use la_arena::Arena;
|
||||
use rustc_abi::{IntegerType, ReprOptions};
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
EnumId, EnumVariantId, LocalFieldId, LocalModuleId, Lookup, StructId, UnionId, VariantId,
|
||||
db::DefDatabase,
|
||||
hir::Expr,
|
||||
item_tree::{
|
||||
AttrOwner, Field, FieldParent, FieldsShape, ItemTree, ModItem, RawVisibilityId, TreeId,
|
||||
},
|
||||
lang_item::LangItem,
|
||||
nameres::diagnostics::{DefDiagnostic, DefDiagnostics},
|
||||
type_ref::{TypeRefId, TypesMap},
|
||||
visibility::RawVisibility,
|
||||
};
|
||||
|
||||
/// Note that we use `StructData` for unions as well!
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct StructData {
|
||||
pub name: Name,
|
||||
pub repr: Option<ReprOptions>,
|
||||
pub visibility: RawVisibility,
|
||||
pub flags: StructFlags,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct StructFlags: u8 {
|
||||
const NO_FLAGS = 0;
|
||||
/// Indicates whether the struct is `PhantomData`.
|
||||
const IS_PHANTOM_DATA = 1 << 2;
|
||||
/// Indicates whether the struct has a `#[fundamental]` attribute.
|
||||
const IS_FUNDAMENTAL = 1 << 3;
|
||||
// FIXME: should this be a flag?
|
||||
/// Indicates whether the struct has a `#[rustc_has_incoherent_inherent_impls]` attribute.
|
||||
const IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL = 1 << 4;
|
||||
/// Indicates whether this struct is `Box`.
|
||||
const IS_BOX = 1 << 5;
|
||||
/// Indicates whether this struct is `ManuallyDrop`.
|
||||
const IS_MANUALLY_DROP = 1 << 6;
|
||||
/// Indicates whether this struct is `UnsafeCell`.
|
||||
const IS_UNSAFE_CELL = 1 << 7;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct EnumData {
|
||||
pub name: Name,
|
||||
pub repr: Option<ReprOptions>,
|
||||
pub visibility: RawVisibility,
|
||||
pub rustc_has_incoherent_inherent_impls: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct EnumVariants {
|
||||
pub variants: Box<[(EnumVariantId, Name)]>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct EnumVariantData {
|
||||
pub name: Name,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum VariantData {
|
||||
Record { fields: Arena<FieldData>, types_map: Arc<TypesMap> },
|
||||
Tuple { fields: Arena<FieldData>, types_map: Arc<TypesMap> },
|
||||
Unit,
|
||||
}
|
||||
|
||||
impl VariantData {
|
||||
#[inline]
|
||||
pub(crate) fn variant_data_query(db: &dyn DefDatabase, id: VariantId) -> Arc<VariantData> {
|
||||
db.variant_data_with_diagnostics(id).0
|
||||
}
|
||||
|
||||
pub(crate) fn variant_data_with_diagnostics_query(
|
||||
db: &dyn DefDatabase,
|
||||
id: VariantId,
|
||||
) -> (Arc<VariantData>, DefDiagnostics) {
|
||||
let (shape, types_map, (fields, diagnostics)) = match id {
|
||||
VariantId::EnumVariantId(id) => {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let parent = loc.parent.lookup(db);
|
||||
let krate = parent.container.krate;
|
||||
let variant = &item_tree[loc.id.value];
|
||||
(
|
||||
variant.shape,
|
||||
variant.types_map.clone(),
|
||||
lower_fields(
|
||||
db,
|
||||
krate,
|
||||
parent.container.local_id,
|
||||
loc.id.tree_id(),
|
||||
&item_tree,
|
||||
krate.cfg_options(db),
|
||||
FieldParent::EnumVariant(loc.id.value),
|
||||
&variant.fields,
|
||||
Some(item_tree[parent.id.value].visibility),
|
||||
),
|
||||
)
|
||||
}
|
||||
VariantId::StructId(id) => {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let krate = loc.container.krate;
|
||||
let strukt = &item_tree[loc.id.value];
|
||||
(
|
||||
strukt.shape,
|
||||
strukt.types_map.clone(),
|
||||
lower_fields(
|
||||
db,
|
||||
krate,
|
||||
loc.container.local_id,
|
||||
loc.id.tree_id(),
|
||||
&item_tree,
|
||||
krate.cfg_options(db),
|
||||
FieldParent::Struct(loc.id.value),
|
||||
&strukt.fields,
|
||||
None,
|
||||
),
|
||||
)
|
||||
}
|
||||
VariantId::UnionId(id) => {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let krate = loc.container.krate;
|
||||
let union = &item_tree[loc.id.value];
|
||||
(
|
||||
FieldsShape::Record,
|
||||
union.types_map.clone(),
|
||||
lower_fields(
|
||||
db,
|
||||
krate,
|
||||
loc.container.local_id,
|
||||
loc.id.tree_id(),
|
||||
&item_tree,
|
||||
krate.cfg_options(db),
|
||||
FieldParent::Union(loc.id.value),
|
||||
&union.fields,
|
||||
None,
|
||||
),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
(
|
||||
Arc::new(match shape {
|
||||
FieldsShape::Record => VariantData::Record { fields, types_map },
|
||||
FieldsShape::Tuple => VariantData::Tuple { fields, types_map },
|
||||
FieldsShape::Unit => VariantData::Unit,
|
||||
}),
|
||||
DefDiagnostics::new(diagnostics),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// A single field of an enum variant or struct
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct FieldData {
|
||||
pub name: Name,
|
||||
pub type_ref: TypeRefId,
|
||||
pub visibility: RawVisibility,
|
||||
pub is_unsafe: bool,
|
||||
}
|
||||
|
||||
fn repr_from_value(
|
||||
db: &dyn DefDatabase,
|
||||
krate: Crate,
|
||||
item_tree: &ItemTree,
|
||||
of: AttrOwner,
|
||||
) -> Option<ReprOptions> {
|
||||
item_tree.attrs(db, krate, of).repr()
|
||||
}
|
||||
|
||||
impl StructData {
|
||||
#[inline]
|
||||
pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> {
|
||||
let loc = id.lookup(db);
|
||||
let krate = loc.container.krate;
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
|
||||
let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into());
|
||||
|
||||
let mut flags = StructFlags::NO_FLAGS;
|
||||
if attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists() {
|
||||
flags |= StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL;
|
||||
}
|
||||
if attrs.by_key(&sym::fundamental).exists() {
|
||||
flags |= StructFlags::IS_FUNDAMENTAL;
|
||||
}
|
||||
if let Some(lang) = attrs.lang_item() {
|
||||
match lang {
|
||||
LangItem::PhantomData => flags |= StructFlags::IS_PHANTOM_DATA,
|
||||
LangItem::OwnedBox => flags |= StructFlags::IS_BOX,
|
||||
LangItem::ManuallyDrop => flags |= StructFlags::IS_MANUALLY_DROP,
|
||||
LangItem::UnsafeCell => flags |= StructFlags::IS_UNSAFE_CELL,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
let strukt = &item_tree[loc.id.value];
|
||||
Arc::new(StructData {
|
||||
name: strukt.name.clone(),
|
||||
repr,
|
||||
visibility: item_tree[strukt.visibility].clone(),
|
||||
flags,
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> {
|
||||
let loc = id.lookup(db);
|
||||
let krate = loc.container.krate;
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
|
||||
let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into());
|
||||
let mut flags = StructFlags::NO_FLAGS;
|
||||
|
||||
if attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists() {
|
||||
flags |= StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL;
|
||||
}
|
||||
if attrs.by_key(&sym::fundamental).exists() {
|
||||
flags |= StructFlags::IS_FUNDAMENTAL;
|
||||
}
|
||||
|
||||
let union = &item_tree[loc.id.value];
|
||||
|
||||
Arc::new(StructData {
|
||||
name: union.name.clone(),
|
||||
repr,
|
||||
visibility: item_tree[union.visibility].clone(),
|
||||
flags,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl EnumVariants {
|
||||
pub(crate) fn enum_variants_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumVariants> {
|
||||
let loc = e.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
|
||||
Arc::new(EnumVariants {
|
||||
variants: loc.container.def_map(db).enum_definitions[&e]
|
||||
.iter()
|
||||
.map(|&id| (id, item_tree[id.lookup(db).id.value].name.clone()))
|
||||
.collect(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn variant(&self, name: &Name) -> Option<EnumVariantId> {
|
||||
let &(id, _) = self.variants.iter().find(|(_id, n)| n == name)?;
|
||||
Some(id)
|
||||
}
|
||||
|
||||
// [Adopted from rustc](https://github.com/rust-lang/rust/blob/bd53aa3bf7a24a70d763182303bd75e5fc51a9af/compiler/rustc_middle/src/ty/adt.rs#L446-L448)
|
||||
pub fn is_payload_free(&self, db: &dyn DefDatabase) -> bool {
|
||||
self.variants.iter().all(|&(v, _)| {
|
||||
// The condition check order is slightly modified from rustc
|
||||
// to improve performance by early returning with relatively fast checks
|
||||
let variant = &db.variant_data(v.into());
|
||||
if !variant.fields().is_empty() {
|
||||
return false;
|
||||
}
|
||||
// The outer if condition is whether this variant has const ctor or not
|
||||
if !matches!(variant.kind(), StructKind::Unit) {
|
||||
let body = db.body(v.into());
|
||||
// A variant with explicit discriminant
|
||||
if body.exprs[body.body_expr] != Expr::Missing {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl EnumData {
|
||||
pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumData> {
|
||||
let loc = e.lookup(db);
|
||||
let krate = loc.container.krate;
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
|
||||
let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into());
|
||||
|
||||
let rustc_has_incoherent_inherent_impls =
|
||||
attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists();
|
||||
|
||||
let enum_ = &item_tree[loc.id.value];
|
||||
|
||||
Arc::new(EnumData {
|
||||
name: enum_.name.clone(),
|
||||
repr,
|
||||
visibility: item_tree[enum_.visibility].clone(),
|
||||
rustc_has_incoherent_inherent_impls,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn variant_body_type(&self) -> IntegerType {
|
||||
match self.repr {
|
||||
Some(ReprOptions { int: Some(builtin), .. }) => builtin,
|
||||
_ => IntegerType::Pointer(true),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EnumVariantData {
|
||||
#[inline]
|
||||
pub(crate) fn enum_variant_data_query(
|
||||
db: &dyn DefDatabase,
|
||||
e: EnumVariantId,
|
||||
) -> Arc<EnumVariantData> {
|
||||
let loc = e.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let variant = &item_tree[loc.id.value];
|
||||
|
||||
Arc::new(EnumVariantData { name: variant.name.clone() })
|
||||
}
|
||||
}
|
||||
|
||||
impl VariantData {
|
||||
pub fn fields(&self) -> &Arena<FieldData> {
|
||||
const EMPTY: &Arena<FieldData> = &Arena::new();
|
||||
match self {
|
||||
VariantData::Record { fields, .. } | VariantData::Tuple { fields, .. } => fields,
|
||||
_ => EMPTY,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn types_map(&self) -> &TypesMap {
|
||||
match self {
|
||||
VariantData::Record { types_map, .. } | VariantData::Tuple { types_map, .. } => {
|
||||
types_map
|
||||
}
|
||||
VariantData::Unit => TypesMap::EMPTY,
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Linear lookup
|
||||
pub fn field(&self, name: &Name) -> Option<LocalFieldId> {
|
||||
self.fields().iter().find_map(|(id, data)| if &data.name == name { Some(id) } else { None })
|
||||
}
|
||||
|
||||
pub fn kind(&self) -> StructKind {
|
||||
match self {
|
||||
VariantData::Record { .. } => StructKind::Record,
|
||||
VariantData::Tuple { .. } => StructKind::Tuple,
|
||||
VariantData::Unit => StructKind::Unit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum StructKind {
|
||||
Tuple,
|
||||
Record,
|
||||
Unit,
|
||||
}
|
||||
|
||||
fn lower_fields(
|
||||
db: &dyn DefDatabase,
|
||||
krate: Crate,
|
||||
container: LocalModuleId,
|
||||
tree_id: TreeId,
|
||||
item_tree: &ItemTree,
|
||||
cfg_options: &CfgOptions,
|
||||
parent: FieldParent,
|
||||
fields: &[Field],
|
||||
override_visibility: Option<RawVisibilityId>,
|
||||
) -> (Arena<FieldData>, Vec<DefDiagnostic>) {
|
||||
let mut diagnostics = Vec::new();
|
||||
let mut arena = Arena::new();
|
||||
for (idx, field) in fields.iter().enumerate() {
|
||||
let attr_owner = AttrOwner::make_field_indexed(parent, idx);
|
||||
let attrs = item_tree.attrs(db, krate, attr_owner);
|
||||
if attrs.is_cfg_enabled(cfg_options) {
|
||||
arena.alloc(lower_field(item_tree, field, override_visibility));
|
||||
} else {
|
||||
diagnostics.push(DefDiagnostic::unconfigured_code(
|
||||
container,
|
||||
tree_id,
|
||||
attr_owner,
|
||||
attrs.cfg().unwrap(),
|
||||
cfg_options.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
(arena, diagnostics)
|
||||
}
|
||||
|
||||
fn lower_field(
|
||||
item_tree: &ItemTree,
|
||||
field: &Field,
|
||||
override_visibility: Option<RawVisibilityId>,
|
||||
) -> FieldData {
|
||||
FieldData {
|
||||
name: field.name.clone(),
|
||||
type_ref: field.type_ref,
|
||||
visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(),
|
||||
is_unsafe: field.is_unsafe,
|
||||
}
|
||||
}
|
||||
|
|
@ -6,34 +6,35 @@ use intern::sym;
|
|||
use la_arena::ArenaMap;
|
||||
use span::{EditionedFileId, MacroCallId};
|
||||
use syntax::{AstPtr, ast};
|
||||
use thin_vec::ThinVec;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstBlockLoc, ConstId, ConstLoc, DefWithBodyId,
|
||||
EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId,
|
||||
ExternCrateLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, InTypeConstId,
|
||||
InTypeConstLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroId, MacroRulesId, MacroRulesLoc,
|
||||
MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc,
|
||||
TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc,
|
||||
UseId, UseLoc, VariantId,
|
||||
AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, EnumVariantId,
|
||||
EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId,
|
||||
FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroId,
|
||||
MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId,
|
||||
StaticLoc, StructId, StructLoc, TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, TypeAliasId,
|
||||
TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId,
|
||||
attr::{Attrs, AttrsWithOwner},
|
||||
data::{
|
||||
ConstData, ExternCrateDeclData, FunctionData, ImplData, Macro2Data, MacroRulesData,
|
||||
ProcMacroData, StaticData, TraitAliasData, TraitData, TypeAliasData,
|
||||
adt::{EnumData, EnumVariantData, EnumVariants, StructData, VariantData},
|
||||
expr_store::{
|
||||
Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap, scope::ExprScopes,
|
||||
},
|
||||
expr_store::{Body, BodySourceMap, scope::ExprScopes},
|
||||
generics::GenericParams,
|
||||
hir::generics::GenericParams,
|
||||
import_map::ImportMap,
|
||||
item_tree::{AttrOwner, ItemTree, ItemTreeSourceMaps},
|
||||
item_tree::{AttrOwner, ItemTree},
|
||||
lang_item::{self, LangItem, LangItemTarget, LangItems},
|
||||
nameres::{
|
||||
DefMap, LocalDefMap,
|
||||
assoc::{ImplItems, TraitItems},
|
||||
diagnostics::DefDiagnostics,
|
||||
},
|
||||
signatures::{
|
||||
ConstSignature, EnumSignature, EnumVariants, FunctionSignature, ImplSignature,
|
||||
InactiveEnumVariantCode, StaticSignature, StructSignature, TraitAliasSignature,
|
||||
TraitSignature, TypeAliasSignature, UnionSignature, VariantFields,
|
||||
},
|
||||
tt,
|
||||
type_ref::TypesSourceMap,
|
||||
visibility::{self, Visibility},
|
||||
};
|
||||
|
||||
|
|
@ -96,11 +97,6 @@ pub trait InternDatabase: RootQueryDb {
|
|||
|
||||
#[salsa::interned]
|
||||
fn intern_block(&self, loc: BlockLoc) -> BlockId;
|
||||
#[salsa::interned]
|
||||
fn intern_anonymous_const(&self, id: ConstBlockLoc) -> ConstBlockId;
|
||||
|
||||
#[salsa::interned]
|
||||
fn intern_in_type_const(&self, id: InTypeConstLoc) -> InTypeConstId;
|
||||
}
|
||||
|
||||
#[query_group::query_group]
|
||||
|
|
@ -122,18 +118,6 @@ pub trait DefDatabase:
|
|||
#[salsa::invoke_actual(ItemTree::block_item_tree_query)]
|
||||
fn block_item_tree(&self, block_id: BlockId) -> Arc<ItemTree>;
|
||||
|
||||
#[salsa::invoke(ItemTree::file_item_tree_with_source_map_query)]
|
||||
fn file_item_tree_with_source_map(
|
||||
&self,
|
||||
file_id: HirFileId,
|
||||
) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>);
|
||||
|
||||
#[salsa::invoke_actual(ItemTree::block_item_tree_with_source_map_query)]
|
||||
fn block_item_tree_with_source_map(
|
||||
&self,
|
||||
block_id: BlockId,
|
||||
) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>);
|
||||
|
||||
#[salsa::invoke_actual(DefMap::crate_local_def_map_query)]
|
||||
fn crate_local_def_map(&self, krate: Crate) -> (Arc<DefMap>, Arc<LocalDefMap>);
|
||||
|
||||
|
|
@ -150,30 +134,22 @@ pub trait DefDatabase:
|
|||
|
||||
// region:data
|
||||
|
||||
#[salsa::transparent]
|
||||
#[salsa::invoke_actual(VariantData::variant_data_query)]
|
||||
fn variant_data(&self, id: VariantId) -> Arc<VariantData>;
|
||||
#[salsa::invoke_actual(VariantFields::query)]
|
||||
fn variant_fields_with_source_map(
|
||||
&self,
|
||||
id: VariantId,
|
||||
) -> (Arc<VariantFields>, Arc<ExpressionStoreSourceMap>);
|
||||
|
||||
#[salsa::invoke_actual(VariantData::variant_data_with_diagnostics_query)]
|
||||
fn variant_data_with_diagnostics(&self, id: VariantId) -> (Arc<VariantData>, DefDiagnostics);
|
||||
|
||||
#[salsa::invoke_actual(StructData::struct_data_query)]
|
||||
fn struct_data(&self, id: StructId) -> Arc<StructData>;
|
||||
|
||||
#[salsa::invoke_actual(StructData::union_data_query)]
|
||||
fn union_data(&self, id: UnionId) -> Arc<StructData>;
|
||||
|
||||
#[salsa::invoke_actual(EnumData::enum_data_query)]
|
||||
fn enum_data(&self, e: EnumId) -> Arc<EnumData>;
|
||||
#[salsa::tracked]
|
||||
fn enum_variants(&self, id: EnumId) -> Arc<EnumVariants> {
|
||||
self.enum_variants_with_diagnostics(id).0
|
||||
}
|
||||
|
||||
#[salsa::invoke_actual(EnumVariants::enum_variants_query)]
|
||||
fn enum_variants(&self, e: EnumId) -> Arc<EnumVariants>;
|
||||
|
||||
#[salsa::invoke_actual(EnumVariantData::enum_variant_data_query)]
|
||||
fn enum_variant_data(&self, id: EnumVariantId) -> Arc<EnumVariantData>;
|
||||
|
||||
#[salsa::invoke_actual(ImplData::impl_data_query)]
|
||||
fn impl_data(&self, e: ImplId) -> Arc<ImplData>;
|
||||
fn enum_variants_with_diagnostics(
|
||||
&self,
|
||||
id: EnumId,
|
||||
) -> (Arc<EnumVariants>, Option<Arc<ThinVec<InactiveEnumVariantCode>>>);
|
||||
|
||||
#[salsa::transparent]
|
||||
#[salsa::invoke_actual(ImplItems::impl_items_query)]
|
||||
|
|
@ -182,9 +158,6 @@ pub trait DefDatabase:
|
|||
#[salsa::invoke_actual(ImplItems::impl_items_with_diagnostics_query)]
|
||||
fn impl_items_with_diagnostics(&self, e: ImplId) -> (Arc<ImplItems>, DefDiagnostics);
|
||||
|
||||
#[salsa::invoke_actual(TraitData::trait_data_query)]
|
||||
fn trait_data(&self, e: TraitId) -> Arc<TraitData>;
|
||||
|
||||
#[salsa::transparent]
|
||||
#[salsa::invoke_actual(TraitItems::trait_items_query)]
|
||||
fn trait_items(&self, e: TraitId) -> Arc<TraitItems>;
|
||||
|
|
@ -192,32 +165,120 @@ pub trait DefDatabase:
|
|||
#[salsa::invoke_actual(TraitItems::trait_items_with_diagnostics_query)]
|
||||
fn trait_items_with_diagnostics(&self, tr: TraitId) -> (Arc<TraitItems>, DefDiagnostics);
|
||||
|
||||
#[salsa::invoke_actual(TraitAliasData::trait_alias_query)]
|
||||
fn trait_alias_data(&self, e: TraitAliasId) -> Arc<TraitAliasData>;
|
||||
#[salsa::tracked]
|
||||
fn variant_fields(&self, id: VariantId) -> Arc<VariantFields> {
|
||||
self.variant_fields_with_source_map(id).0
|
||||
}
|
||||
|
||||
#[salsa::invoke_actual(TypeAliasData::type_alias_data_query)]
|
||||
fn type_alias_data(&self, e: TypeAliasId) -> Arc<TypeAliasData>;
|
||||
#[salsa::tracked]
|
||||
fn trait_signature(&self, trait_: TraitId) -> Arc<TraitSignature> {
|
||||
self.trait_signature_with_source_map(trait_).0
|
||||
}
|
||||
|
||||
#[salsa::invoke_actual(FunctionData::fn_data_query)]
|
||||
fn function_data(&self, func: FunctionId) -> Arc<FunctionData>;
|
||||
#[salsa::tracked]
|
||||
fn impl_signature(&self, impl_: ImplId) -> Arc<ImplSignature> {
|
||||
self.impl_signature_with_source_map(impl_).0
|
||||
}
|
||||
|
||||
#[salsa::invoke_actual(ConstData::const_data_query)]
|
||||
fn const_data(&self, konst: ConstId) -> Arc<ConstData>;
|
||||
#[salsa::tracked]
|
||||
fn struct_signature(&self, struct_: StructId) -> Arc<StructSignature> {
|
||||
self.struct_signature_with_source_map(struct_).0
|
||||
}
|
||||
|
||||
#[salsa::invoke_actual(StaticData::static_data_query)]
|
||||
fn static_data(&self, statik: StaticId) -> Arc<StaticData>;
|
||||
#[salsa::tracked]
|
||||
fn union_signature(&self, union_: UnionId) -> Arc<UnionSignature> {
|
||||
self.union_signature_with_source_map(union_).0
|
||||
}
|
||||
|
||||
#[salsa::invoke_actual(Macro2Data::macro2_data_query)]
|
||||
fn macro2_data(&self, makro: Macro2Id) -> Arc<Macro2Data>;
|
||||
#[salsa::tracked]
|
||||
fn enum_signature(&self, e: EnumId) -> Arc<EnumSignature> {
|
||||
self.enum_signature_with_source_map(e).0
|
||||
}
|
||||
|
||||
#[salsa::invoke_actual(MacroRulesData::macro_rules_data_query)]
|
||||
fn macro_rules_data(&self, makro: MacroRulesId) -> Arc<MacroRulesData>;
|
||||
#[salsa::tracked]
|
||||
fn const_signature(&self, e: ConstId) -> Arc<ConstSignature> {
|
||||
self.const_signature_with_source_map(e).0
|
||||
}
|
||||
|
||||
#[salsa::invoke_actual(ProcMacroData::proc_macro_data_query)]
|
||||
fn proc_macro_data(&self, makro: ProcMacroId) -> Arc<ProcMacroData>;
|
||||
#[salsa::tracked]
|
||||
fn static_signature(&self, e: StaticId) -> Arc<StaticSignature> {
|
||||
self.static_signature_with_source_map(e).0
|
||||
}
|
||||
|
||||
#[salsa::invoke_actual(ExternCrateDeclData::extern_crate_decl_data_query)]
|
||||
fn extern_crate_decl_data(&self, extern_crate: ExternCrateId) -> Arc<ExternCrateDeclData>;
|
||||
#[salsa::tracked]
|
||||
fn function_signature(&self, e: FunctionId) -> Arc<FunctionSignature> {
|
||||
self.function_signature_with_source_map(e).0
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn trait_alias_signature(&self, e: TraitAliasId) -> Arc<TraitAliasSignature> {
|
||||
self.trait_alias_signature_with_source_map(e).0
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn type_alias_signature(&self, e: TypeAliasId) -> Arc<TypeAliasSignature> {
|
||||
self.type_alias_signature_with_source_map(e).0
|
||||
}
|
||||
|
||||
#[salsa::invoke_actual(TraitSignature::query)]
|
||||
fn trait_signature_with_source_map(
|
||||
&self,
|
||||
trait_: TraitId,
|
||||
) -> (Arc<TraitSignature>, Arc<ExpressionStoreSourceMap>);
|
||||
|
||||
#[salsa::invoke_actual(ImplSignature::query)]
|
||||
fn impl_signature_with_source_map(
|
||||
&self,
|
||||
impl_: ImplId,
|
||||
) -> (Arc<ImplSignature>, Arc<ExpressionStoreSourceMap>);
|
||||
|
||||
#[salsa::invoke_actual(StructSignature::query)]
|
||||
fn struct_signature_with_source_map(
|
||||
&self,
|
||||
struct_: StructId,
|
||||
) -> (Arc<StructSignature>, Arc<ExpressionStoreSourceMap>);
|
||||
|
||||
#[salsa::invoke_actual(UnionSignature::query)]
|
||||
fn union_signature_with_source_map(
|
||||
&self,
|
||||
union_: UnionId,
|
||||
) -> (Arc<UnionSignature>, Arc<ExpressionStoreSourceMap>);
|
||||
|
||||
#[salsa::invoke_actual(EnumSignature::query)]
|
||||
fn enum_signature_with_source_map(
|
||||
&self,
|
||||
e: EnumId,
|
||||
) -> (Arc<EnumSignature>, Arc<ExpressionStoreSourceMap>);
|
||||
|
||||
#[salsa::invoke_actual(ConstSignature::query)]
|
||||
fn const_signature_with_source_map(
|
||||
&self,
|
||||
e: ConstId,
|
||||
) -> (Arc<ConstSignature>, Arc<ExpressionStoreSourceMap>);
|
||||
|
||||
#[salsa::invoke_actual(StaticSignature::query)]
|
||||
fn static_signature_with_source_map(
|
||||
&self,
|
||||
e: StaticId,
|
||||
) -> (Arc<StaticSignature>, Arc<ExpressionStoreSourceMap>);
|
||||
|
||||
#[salsa::invoke_actual(FunctionSignature::query)]
|
||||
fn function_signature_with_source_map(
|
||||
&self,
|
||||
e: FunctionId,
|
||||
) -> (Arc<FunctionSignature>, Arc<ExpressionStoreSourceMap>);
|
||||
|
||||
#[salsa::invoke_actual(TraitAliasSignature::query)]
|
||||
fn trait_alias_signature_with_source_map(
|
||||
&self,
|
||||
e: TraitAliasId,
|
||||
) -> (Arc<TraitAliasSignature>, Arc<ExpressionStoreSourceMap>);
|
||||
|
||||
#[salsa::invoke_actual(TypeAliasSignature::query)]
|
||||
fn type_alias_signature_with_source_map(
|
||||
&self,
|
||||
e: TypeAliasId,
|
||||
) -> (Arc<TypeAliasSignature>, Arc<ExpressionStoreSourceMap>);
|
||||
|
||||
// endregion:data
|
||||
|
||||
|
|
@ -231,15 +292,23 @@ pub trait DefDatabase:
|
|||
#[salsa::invoke_actual(ExprScopes::expr_scopes_query)]
|
||||
fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>;
|
||||
|
||||
#[salsa::invoke_actual(GenericParams::generic_params_query)]
|
||||
#[salsa::transparent]
|
||||
#[salsa::invoke(GenericParams::new)]
|
||||
fn generic_params(&self, def: GenericDefId) -> Arc<GenericParams>;
|
||||
|
||||
/// If this returns `None` for the source map, that means it is the same as with the item tree.
|
||||
#[salsa::invoke_actual(GenericParams::generic_params_with_source_map_query)]
|
||||
fn generic_params_with_source_map(
|
||||
#[salsa::transparent]
|
||||
#[salsa::invoke(GenericParams::generic_params_and_store)]
|
||||
fn generic_params_and_store(
|
||||
&self,
|
||||
def: GenericDefId,
|
||||
) -> (Arc<GenericParams>, Option<Arc<TypesSourceMap>>);
|
||||
) -> (Arc<GenericParams>, Arc<ExpressionStore>);
|
||||
|
||||
#[salsa::transparent]
|
||||
#[salsa::invoke(GenericParams::generic_params_and_store_and_source_map)]
|
||||
fn generic_params_and_store_and_source_map(
|
||||
&self,
|
||||
def: GenericDefId,
|
||||
) -> (Arc<GenericParams>, Arc<ExpressionStore>, Arc<ExpressionStoreSourceMap>);
|
||||
|
||||
// region:attrs
|
||||
|
||||
|
|
@ -270,16 +339,20 @@ pub trait DefDatabase:
|
|||
|
||||
// region:visibilities
|
||||
|
||||
#[salsa::invoke(visibility::field_visibilities_query)]
|
||||
#[salsa::invoke_actual(visibility::field_visibilities_query)]
|
||||
fn field_visibilities(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Visibility>>;
|
||||
|
||||
// FIXME: unify function_visibility and const_visibility?
|
||||
|
||||
#[salsa::invoke_actual(visibility::function_visibility_query)]
|
||||
fn function_visibility(&self, def: FunctionId) -> Visibility;
|
||||
|
||||
#[salsa::invoke_actual(visibility::const_visibility_query)]
|
||||
fn const_visibility(&self, def: ConstId) -> Visibility;
|
||||
|
||||
#[salsa::invoke_actual(visibility::type_alias_visibility_query)]
|
||||
fn type_alias_visibility(&self, def: TypeAliasId) -> Visibility;
|
||||
|
||||
// endregion:visibilities
|
||||
|
||||
#[salsa::invoke_actual(LangItems::crate_lang_items_query)]
|
||||
|
|
|
|||
|
|
@ -1,236 +0,0 @@
|
|||
//! Macro expansion utilities.
|
||||
|
||||
use std::cell::OnceCell;
|
||||
|
||||
use base_db::Crate;
|
||||
use cfg::CfgOptions;
|
||||
use drop_bomb::DropBomb;
|
||||
use hir_expand::{
|
||||
ExpandError, ExpandErrorKind, ExpandResult, HirFileId, InFile, Lookup, MacroCallId,
|
||||
attrs::RawAttrs, mod_path::ModPath, span_map::SpanMap,
|
||||
};
|
||||
use span::{Edition, SyntaxContext};
|
||||
use syntax::{Parse, ast};
|
||||
|
||||
use crate::type_ref::{TypesMap, TypesSourceMap};
|
||||
use crate::{
|
||||
AsMacroCall, MacroId, ModuleId, UnresolvedMacro, attr::Attrs, db::DefDatabase, lower::LowerCtx,
|
||||
path::Path,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Expander {
|
||||
span_map: OnceCell<SpanMap>,
|
||||
current_file_id: HirFileId,
|
||||
pub(crate) module: ModuleId,
|
||||
/// `recursion_depth == usize::MAX` indicates that the recursion limit has been reached.
|
||||
recursion_depth: u32,
|
||||
recursion_limit: usize,
|
||||
}
|
||||
|
||||
impl Expander {
|
||||
pub fn new(db: &dyn DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander {
|
||||
let recursion_limit = module.def_map(db).recursion_limit() as usize;
|
||||
let recursion_limit = if cfg!(test) {
|
||||
// Without this, `body::tests::your_stack_belongs_to_me` stack-overflows in debug
|
||||
std::cmp::min(32, recursion_limit)
|
||||
} else {
|
||||
recursion_limit
|
||||
};
|
||||
Expander {
|
||||
current_file_id,
|
||||
module,
|
||||
recursion_depth: 0,
|
||||
recursion_limit,
|
||||
span_map: OnceCell::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn span_map(&self, db: &dyn DefDatabase) -> &SpanMap {
|
||||
self.span_map.get_or_init(|| db.span_map(self.current_file_id))
|
||||
}
|
||||
|
||||
pub fn krate(&self) -> Crate {
|
||||
self.module.krate
|
||||
}
|
||||
|
||||
pub fn syntax_context(&self) -> SyntaxContext {
|
||||
// FIXME:
|
||||
SyntaxContext::root(Edition::CURRENT_FIXME)
|
||||
}
|
||||
|
||||
pub fn enter_expand<T: ast::AstNode>(
|
||||
&mut self,
|
||||
db: &dyn DefDatabase,
|
||||
macro_call: ast::MacroCall,
|
||||
resolver: impl Fn(&ModPath) -> Option<MacroId>,
|
||||
) -> Result<ExpandResult<Option<(Mark, Parse<T>)>>, UnresolvedMacro> {
|
||||
// FIXME: within_limit should support this, instead of us having to extract the error
|
||||
let mut unresolved_macro_err = None;
|
||||
|
||||
let result = self.within_limit(db, |this| {
|
||||
let macro_call = this.in_file(¯o_call);
|
||||
match macro_call.as_call_id_with_errors(db.upcast(), this.module.krate(), |path| {
|
||||
resolver(path).map(|it| db.macro_def(it))
|
||||
}) {
|
||||
Ok(call_id) => call_id,
|
||||
Err(resolve_err) => {
|
||||
unresolved_macro_err = Some(resolve_err);
|
||||
ExpandResult { value: None, err: None }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(err) = unresolved_macro_err { Err(err) } else { Ok(result) }
|
||||
}
|
||||
|
||||
pub fn enter_expand_id<T: ast::AstNode>(
|
||||
&mut self,
|
||||
db: &dyn DefDatabase,
|
||||
call_id: MacroCallId,
|
||||
) -> ExpandResult<Option<(Mark, Parse<T>)>> {
|
||||
self.within_limit(db, |_this| ExpandResult::ok(Some(call_id)))
|
||||
}
|
||||
|
||||
pub fn exit(&mut self, mut mark: Mark) {
|
||||
self.span_map = mark.span_map;
|
||||
self.current_file_id = mark.file_id;
|
||||
if self.recursion_depth == u32::MAX {
|
||||
// Recursion limit has been reached somewhere in the macro expansion tree. Reset the
|
||||
// depth only when we get out of the tree.
|
||||
if !self.current_file_id.is_macro() {
|
||||
self.recursion_depth = 0;
|
||||
}
|
||||
} else {
|
||||
self.recursion_depth -= 1;
|
||||
}
|
||||
mark.bomb.defuse();
|
||||
}
|
||||
|
||||
pub fn ctx<'a>(
|
||||
&self,
|
||||
db: &'a dyn DefDatabase,
|
||||
types_map: &'a mut TypesMap,
|
||||
types_source_map: &'a mut TypesSourceMap,
|
||||
) -> LowerCtx<'a> {
|
||||
LowerCtx::with_span_map_cell(
|
||||
db,
|
||||
self.current_file_id,
|
||||
self.span_map.clone(),
|
||||
types_map,
|
||||
types_source_map,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn in_file<T>(&self, value: T) -> InFile<T> {
|
||||
InFile { file_id: self.current_file_id, value }
|
||||
}
|
||||
|
||||
pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs {
|
||||
Attrs::filter(
|
||||
db,
|
||||
self.krate(),
|
||||
RawAttrs::new(
|
||||
db.upcast(),
|
||||
owner,
|
||||
self.span_map.get_or_init(|| db.span_map(self.current_file_id)).as_ref(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn cfg_options<'db>(&self, db: &'db dyn DefDatabase) -> &'db CfgOptions {
|
||||
self.module.krate.cfg_options(db)
|
||||
}
|
||||
|
||||
pub fn current_file_id(&self) -> HirFileId {
|
||||
self.current_file_id
|
||||
}
|
||||
|
||||
pub(crate) fn parse_path(
|
||||
&mut self,
|
||||
db: &dyn DefDatabase,
|
||||
path: ast::Path,
|
||||
types_map: &mut TypesMap,
|
||||
types_source_map: &mut TypesSourceMap,
|
||||
) -> Option<Path> {
|
||||
let mut ctx = LowerCtx::with_span_map_cell(
|
||||
db,
|
||||
self.current_file_id,
|
||||
self.span_map.clone(),
|
||||
types_map,
|
||||
types_source_map,
|
||||
);
|
||||
Path::from_src(&mut ctx, path)
|
||||
}
|
||||
|
||||
fn within_limit<F, T: ast::AstNode>(
|
||||
&mut self,
|
||||
db: &dyn DefDatabase,
|
||||
op: F,
|
||||
) -> ExpandResult<Option<(Mark, Parse<T>)>>
|
||||
where
|
||||
F: FnOnce(&mut Self) -> ExpandResult<Option<MacroCallId>>,
|
||||
{
|
||||
if self.recursion_depth == u32::MAX {
|
||||
// Recursion limit has been reached somewhere in the macro expansion tree. We should
|
||||
// stop expanding other macro calls in this tree, or else this may result in
|
||||
// exponential number of macro expansions, leading to a hang.
|
||||
//
|
||||
// The overflow error should have been reported when it occurred (see the next branch),
|
||||
// so don't return overflow error here to avoid diagnostics duplication.
|
||||
cov_mark::hit!(overflow_but_not_me);
|
||||
return ExpandResult::ok(None);
|
||||
}
|
||||
|
||||
let ExpandResult { value, err } = op(self);
|
||||
let Some(call_id) = value else {
|
||||
return ExpandResult { value: None, err };
|
||||
};
|
||||
if self.recursion_depth as usize > self.recursion_limit {
|
||||
self.recursion_depth = u32::MAX;
|
||||
cov_mark::hit!(your_stack_belongs_to_me);
|
||||
return ExpandResult::only_err(ExpandError::new(
|
||||
db.macro_arg_considering_derives(call_id, &call_id.lookup(db.upcast()).kind).2,
|
||||
ExpandErrorKind::RecursionOverflow,
|
||||
));
|
||||
}
|
||||
|
||||
let macro_file = call_id.as_macro_file();
|
||||
let res = db.parse_macro_expansion(macro_file);
|
||||
|
||||
let err = err.or(res.err);
|
||||
ExpandResult {
|
||||
value: match &err {
|
||||
// If proc-macro is disabled or unresolved, we want to expand to a missing expression
|
||||
// instead of an empty tree which might end up in an empty block.
|
||||
Some(e) if matches!(e.kind(), ExpandErrorKind::MissingProcMacroExpander(_)) => None,
|
||||
_ => (|| {
|
||||
let parse = res.value.0.cast::<T>()?;
|
||||
|
||||
self.recursion_depth += 1;
|
||||
let old_span_map = OnceCell::new();
|
||||
if let Some(prev) = self.span_map.take() {
|
||||
_ = old_span_map.set(prev);
|
||||
};
|
||||
_ = self.span_map.set(SpanMap::ExpansionSpanMap(res.value.1));
|
||||
let old_file_id =
|
||||
std::mem::replace(&mut self.current_file_id, macro_file.into());
|
||||
let mark = Mark {
|
||||
file_id: old_file_id,
|
||||
span_map: old_span_map,
|
||||
bomb: DropBomb::new("expansion mark dropped"),
|
||||
};
|
||||
Some((mark, parse))
|
||||
})(),
|
||||
},
|
||||
err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Mark {
|
||||
file_id: HirFileId,
|
||||
span_map: OnceCell<SpanMap>,
|
||||
bomb: DropBomb,
|
||||
}
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
//! Defines `ExpressionStore`: a lowered representation of functions, statics and
|
||||
//! consts.
|
||||
mod body;
|
||||
mod lower;
|
||||
mod pretty;
|
||||
pub mod body;
|
||||
mod expander;
|
||||
pub mod lower;
|
||||
pub mod path;
|
||||
pub(crate) mod pretty;
|
||||
pub mod scope;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
|
|
@ -12,7 +13,7 @@ use std::ops::{Deref, Index};
|
|||
|
||||
use cfg::{CfgExpr, CfgOptions};
|
||||
use either::Either;
|
||||
use hir_expand::{ExpandError, InFile, name::Name};
|
||||
use hir_expand::{ExpandError, InFile, mod_path::ModPath, name::Name};
|
||||
use la_arena::{Arena, ArenaMap};
|
||||
use rustc_hash::FxHashMap;
|
||||
use smallvec::SmallVec;
|
||||
|
|
@ -22,18 +23,19 @@ use triomphe::Arc;
|
|||
use tt::TextRange;
|
||||
|
||||
use crate::{
|
||||
BlockId, DefWithBodyId, Lookup, SyntheticSyntax,
|
||||
BlockId, SyntheticSyntax,
|
||||
db::DefDatabase,
|
||||
expr_store::path::Path,
|
||||
hir::{
|
||||
Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, Label, LabelId, Pat,
|
||||
PatId, RecordFieldPat, Statement,
|
||||
},
|
||||
nameres::DefMap,
|
||||
path::{ModPath, Path},
|
||||
type_ref::{TypeRef, TypeRefId, TypesMap, TypesSourceMap},
|
||||
type_ref::{PathId, TypeRef, TypeRefId},
|
||||
};
|
||||
|
||||
pub use self::body::{Body, BodySourceMap};
|
||||
pub use self::lower::hir_segment_to_ast_segment;
|
||||
|
||||
/// A wrapper around [`span::SyntaxContextId`] that is intended only for comparisons.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
|
|
@ -80,16 +82,19 @@ pub type ExprOrPatSource = InFile<ExprOrPatPtr>;
|
|||
pub type SelfParamPtr = AstPtr<ast::SelfParam>;
|
||||
pub type MacroCallPtr = AstPtr<ast::MacroCall>;
|
||||
|
||||
pub type TypePtr = AstPtr<ast::Type>;
|
||||
pub type TypeSource = InFile<TypePtr>;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct ExpressionStore {
|
||||
pub exprs: Arena<Expr>,
|
||||
pub pats: Arena<Pat>,
|
||||
pub bindings: Arena<Binding>,
|
||||
pub labels: Arena<Label>,
|
||||
pub types: Arena<TypeRef>,
|
||||
/// Id of the closure/coroutine that owns the corresponding binding. If a binding is owned by the
|
||||
/// top level expression, it will not be listed in here.
|
||||
pub binding_owners: FxHashMap<BindingId, ExprId>,
|
||||
pub types: TypesMap,
|
||||
/// Block expressions in this store that may contain inner items.
|
||||
block_scopes: Box<[BlockId]>,
|
||||
|
||||
|
|
@ -128,15 +133,16 @@ pub struct ExpressionStoreSourceMap {
|
|||
field_map_back: FxHashMap<ExprId, FieldSource>,
|
||||
pat_field_map_back: FxHashMap<PatId, PatFieldSource>,
|
||||
|
||||
pub types: TypesSourceMap,
|
||||
types_map_back: ArenaMap<TypeRefId, TypeSource>,
|
||||
types_map: FxHashMap<TypeSource, TypeRefId>,
|
||||
|
||||
template_map: Option<Box<FormatTemplate>>,
|
||||
|
||||
expansions: FxHashMap<InFile<MacroCallPtr>, MacroFileId>,
|
||||
pub expansions: FxHashMap<InFile<MacroCallPtr>, MacroFileId>,
|
||||
|
||||
/// Diagnostics accumulated during lowering. These contain `AstPtr`s and so are stored in
|
||||
/// the source map (since they're just as volatile).
|
||||
diagnostics: Vec<ExpressionStoreDiagnostics>,
|
||||
pub diagnostics: Vec<ExpressionStoreDiagnostics>,
|
||||
}
|
||||
|
||||
/// The body of an item (function, const etc.).
|
||||
|
|
@ -147,7 +153,7 @@ pub struct ExpressionStoreBuilder {
|
|||
pub bindings: Arena<Binding>,
|
||||
pub labels: Arena<Label>,
|
||||
pub binding_owners: FxHashMap<BindingId, ExprId>,
|
||||
pub types: TypesMap,
|
||||
pub types: Arena<TypeRef>,
|
||||
block_scopes: Vec<BlockId>,
|
||||
binding_hygiene: FxHashMap<BindingId, HygieneId>,
|
||||
ident_hygiene: FxHashMap<ExprOrPatId, HygieneId>,
|
||||
|
|
@ -178,7 +184,7 @@ pub enum ExpressionStoreDiagnostics {
|
|||
}
|
||||
|
||||
impl ExpressionStoreBuilder {
|
||||
fn finish(self) -> ExpressionStore {
|
||||
pub fn finish(self) -> ExpressionStore {
|
||||
let Self {
|
||||
block_scopes,
|
||||
mut exprs,
|
||||
|
|
@ -601,6 +607,17 @@ impl Index<TypeRefId> for ExpressionStore {
|
|||
&self.types[b]
|
||||
}
|
||||
}
|
||||
impl Index<PathId> for ExpressionStore {
|
||||
type Output = Path;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, index: PathId) -> &Self::Output {
|
||||
let TypeRef::Path(path) = &self[index.type_ref()] else {
|
||||
unreachable!("`PathId` always points to `TypeRef::Path`");
|
||||
};
|
||||
path
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Change `node_` prefix to something more reasonable.
|
||||
// Perhaps `expr_syntax` and `expr_id`?
|
||||
|
|
@ -638,6 +655,14 @@ impl ExpressionStoreSourceMap {
|
|||
self.pat_map.get(&node.map(AstPtr::new)).cloned()
|
||||
}
|
||||
|
||||
pub fn type_syntax(&self, id: TypeRefId) -> Result<TypeSource, SyntheticSyntax> {
|
||||
self.types_map_back.get(id).cloned().ok_or(SyntheticSyntax)
|
||||
}
|
||||
|
||||
pub fn node_type(&self, node: InFile<&ast::Type>) -> Option<TypeRefId> {
|
||||
self.types_map.get(&node.map(AstPtr::new)).cloned()
|
||||
}
|
||||
|
||||
pub fn label_syntax(&self, label: LabelId) -> LabelSource {
|
||||
self.label_map_back[label]
|
||||
}
|
||||
|
|
@ -668,6 +693,10 @@ impl ExpressionStoreSourceMap {
|
|||
self.expansions.iter()
|
||||
}
|
||||
|
||||
pub fn expansion(&self, node: InFile<&ast::MacroCall>) -> Option<MacroFileId> {
|
||||
self.expansions.get(&node.map(AstPtr::new)).copied()
|
||||
}
|
||||
|
||||
pub fn implicit_format_args(
|
||||
&self,
|
||||
node: InFile<&ast::FormatArgsExpr>,
|
||||
|
|
@ -717,7 +746,8 @@ impl ExpressionStoreSourceMap {
|
|||
template_map,
|
||||
diagnostics,
|
||||
binding_definitions,
|
||||
types,
|
||||
types_map,
|
||||
types_map_back,
|
||||
} = self;
|
||||
if let Some(template_map) = template_map {
|
||||
let FormatTemplate {
|
||||
|
|
@ -740,6 +770,7 @@ impl ExpressionStoreSourceMap {
|
|||
expansions.shrink_to_fit();
|
||||
diagnostics.shrink_to_fit();
|
||||
binding_definitions.shrink_to_fit();
|
||||
types.shrink_to_fit();
|
||||
types_map.shrink_to_fit();
|
||||
types_map_back.shrink_to_fit();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
use std::ops;
|
||||
|
||||
use hir_expand::{InFile, Lookup};
|
||||
use la_arena::{Idx, RawIdx};
|
||||
use span::Edition;
|
||||
use syntax::ast;
|
||||
use triomphe::Arc;
|
||||
|
|
@ -11,10 +10,10 @@ use triomphe::Arc;
|
|||
use crate::{
|
||||
DefWithBodyId, HasModule,
|
||||
db::DefDatabase,
|
||||
expander::Expander,
|
||||
expr_store::{ExpressionStore, ExpressionStoreSourceMap, SelfParamPtr, lower, pretty},
|
||||
expr_store::{
|
||||
ExpressionStore, ExpressionStoreSourceMap, SelfParamPtr, lower::lower_body, pretty,
|
||||
},
|
||||
hir::{BindingId, ExprId, PatId},
|
||||
item_tree::AttrOwner,
|
||||
src::HasSource,
|
||||
};
|
||||
|
||||
|
|
@ -79,30 +78,10 @@ impl Body {
|
|||
let InFile { file_id, value: body } = {
|
||||
match def {
|
||||
DefWithBodyId::FunctionId(f) => {
|
||||
let data = db.function_data(f);
|
||||
let f = f.lookup(db);
|
||||
let src = f.source(db);
|
||||
params = src.value.param_list().map(move |param_list| {
|
||||
let item_tree = f.id.item_tree(db);
|
||||
let func = &item_tree[f.id.value];
|
||||
let krate = f.container.module(db).krate;
|
||||
(
|
||||
param_list,
|
||||
(0..func.params.len()).map(move |idx| {
|
||||
item_tree
|
||||
.attrs(
|
||||
db,
|
||||
krate,
|
||||
AttrOwner::Param(
|
||||
f.id.value,
|
||||
Idx::from_raw(RawIdx::from(idx as u32)),
|
||||
),
|
||||
)
|
||||
.is_cfg_enabled(krate.cfg_options(db))
|
||||
}),
|
||||
)
|
||||
});
|
||||
is_async_fn = data.is_async();
|
||||
params = src.value.param_list();
|
||||
is_async_fn = src.value.async_token().is_some();
|
||||
src.map(|it| it.body().map(ast::Expr::from))
|
||||
}
|
||||
DefWithBodyId::ConstId(c) => {
|
||||
|
|
@ -120,13 +99,11 @@ impl Body {
|
|||
let src = s.source(db);
|
||||
src.map(|it| it.expr())
|
||||
}
|
||||
DefWithBodyId::InTypeConstId(c) => c.lookup(db).id.map(|_| c.source(db).expr()),
|
||||
}
|
||||
};
|
||||
let module = def.module(db);
|
||||
let expander = Expander::new(db, file_id, module);
|
||||
let (body, mut source_map) =
|
||||
lower::lower_body(db, def, expander, params, body, module.krate, is_async_fn);
|
||||
lower_body(db, def, file_id, module, params, body, is_async_fn);
|
||||
source_map.store.shrink_to_fit();
|
||||
|
||||
(Arc::new(body), Arc::new(source_map))
|
||||
|
|
|
|||
223
crates/hir-def/src/expr_store/expander.rs
Normal file
223
crates/hir-def/src/expr_store/expander.rs
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
//! Macro expansion utilities.
|
||||
|
||||
use std::mem;
|
||||
|
||||
use base_db::Crate;
|
||||
use drop_bomb::DropBomb;
|
||||
use hir_expand::attrs::RawAttrs;
|
||||
use hir_expand::eager::EagerCallBackFn;
|
||||
use hir_expand::{
|
||||
ExpandError, ExpandErrorKind, ExpandResult, HirFileId, InFile, Lookup, MacroCallId,
|
||||
mod_path::ModPath, span_map::SpanMap,
|
||||
};
|
||||
use span::{AstIdMap, Edition, SyntaxContext};
|
||||
use syntax::ast::HasAttrs;
|
||||
use syntax::{Parse, ast};
|
||||
use triomphe::Arc;
|
||||
use tt::TextRange;
|
||||
|
||||
use crate::attr::Attrs;
|
||||
use crate::expr_store::HygieneId;
|
||||
use crate::nameres::DefMap;
|
||||
use crate::{AsMacroCall, MacroId, UnresolvedMacro, db::DefDatabase};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct Expander {
|
||||
span_map: SpanMap,
|
||||
current_file_id: HirFileId,
|
||||
ast_id_map: Arc<AstIdMap>,
|
||||
/// `recursion_depth == usize::MAX` indicates that the recursion limit has been reached.
|
||||
recursion_depth: u32,
|
||||
recursion_limit: usize,
|
||||
}
|
||||
|
||||
impl Expander {
|
||||
pub(super) fn new(
|
||||
db: &dyn DefDatabase,
|
||||
current_file_id: HirFileId,
|
||||
def_map: &DefMap,
|
||||
) -> Expander {
|
||||
let recursion_limit = def_map.recursion_limit() as usize;
|
||||
let recursion_limit = if cfg!(test) {
|
||||
// Without this, `body::tests::your_stack_belongs_to_me` stack-overflows in debug
|
||||
std::cmp::min(32, recursion_limit)
|
||||
} else {
|
||||
recursion_limit
|
||||
};
|
||||
Expander {
|
||||
current_file_id,
|
||||
recursion_depth: 0,
|
||||
recursion_limit,
|
||||
span_map: db.span_map(current_file_id),
|
||||
ast_id_map: db.ast_id_map(current_file_id),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn ctx_for_range(&self, range: TextRange) -> SyntaxContext {
|
||||
self.span_map.span_for_range(range).ctx
|
||||
}
|
||||
|
||||
pub(super) fn hygiene_for_range(&self, db: &dyn DefDatabase, range: TextRange) -> HygieneId {
|
||||
match self.span_map.as_ref() {
|
||||
hir_expand::span_map::SpanMapRef::ExpansionSpanMap(span_map) => {
|
||||
HygieneId::new(span_map.span_at(range.start()).ctx.opaque_and_semitransparent(db))
|
||||
}
|
||||
hir_expand::span_map::SpanMapRef::RealSpanMap(_) => HygieneId::ROOT,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn attrs(
|
||||
&self,
|
||||
db: &dyn DefDatabase,
|
||||
krate: Crate,
|
||||
has_attrs: &dyn HasAttrs,
|
||||
) -> Attrs {
|
||||
Attrs::filter(db, krate, RawAttrs::new(db.upcast(), has_attrs, self.span_map.as_ref()))
|
||||
}
|
||||
|
||||
pub(super) fn is_cfg_enabled(
|
||||
&self,
|
||||
db: &dyn DefDatabase,
|
||||
krate: Crate,
|
||||
has_attrs: &dyn HasAttrs,
|
||||
) -> bool {
|
||||
self.attrs(db, krate, has_attrs).is_cfg_enabled(krate.cfg_options(db))
|
||||
}
|
||||
|
||||
pub(super) fn call_syntax_ctx(&self) -> SyntaxContext {
|
||||
// FIXME:
|
||||
SyntaxContext::root(Edition::CURRENT_FIXME)
|
||||
}
|
||||
|
||||
pub(super) fn enter_expand<T: ast::AstNode>(
|
||||
&mut self,
|
||||
db: &dyn DefDatabase,
|
||||
macro_call: ast::MacroCall,
|
||||
krate: Crate,
|
||||
resolver: impl Fn(&ModPath) -> Option<MacroId>,
|
||||
eager_callback: EagerCallBackFn<'_>,
|
||||
) -> Result<ExpandResult<Option<(Mark, Option<Parse<T>>)>>, UnresolvedMacro> {
|
||||
// FIXME: within_limit should support this, instead of us having to extract the error
|
||||
let mut unresolved_macro_err = None;
|
||||
|
||||
let result = self.within_limit(db, |this| {
|
||||
let macro_call = this.in_file(¯o_call);
|
||||
match macro_call.as_call_id_with_errors(
|
||||
db.upcast(),
|
||||
krate,
|
||||
|path| resolver(path).map(|it| db.macro_def(it)),
|
||||
eager_callback,
|
||||
) {
|
||||
Ok(call_id) => call_id,
|
||||
Err(resolve_err) => {
|
||||
unresolved_macro_err = Some(resolve_err);
|
||||
ExpandResult { value: None, err: None }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(err) = unresolved_macro_err { Err(err) } else { Ok(result) }
|
||||
}
|
||||
|
||||
pub(super) fn enter_expand_id<T: ast::AstNode>(
|
||||
&mut self,
|
||||
db: &dyn DefDatabase,
|
||||
call_id: MacroCallId,
|
||||
) -> ExpandResult<Option<(Mark, Option<Parse<T>>)>> {
|
||||
self.within_limit(db, |_this| ExpandResult::ok(Some(call_id)))
|
||||
}
|
||||
|
||||
pub(super) fn exit(&mut self, Mark { file_id, span_map, ast_id_map, mut bomb }: Mark) {
|
||||
self.span_map = span_map;
|
||||
self.current_file_id = file_id;
|
||||
self.ast_id_map = ast_id_map;
|
||||
if self.recursion_depth == u32::MAX {
|
||||
// Recursion limit has been reached somewhere in the macro expansion tree. Reset the
|
||||
// depth only when we get out of the tree.
|
||||
if !self.current_file_id.is_macro() {
|
||||
self.recursion_depth = 0;
|
||||
}
|
||||
} else {
|
||||
self.recursion_depth -= 1;
|
||||
}
|
||||
bomb.defuse();
|
||||
}
|
||||
|
||||
pub(super) fn in_file<T>(&self, value: T) -> InFile<T> {
|
||||
InFile { file_id: self.current_file_id, value }
|
||||
}
|
||||
|
||||
pub(super) fn current_file_id(&self) -> HirFileId {
|
||||
self.current_file_id
|
||||
}
|
||||
|
||||
fn within_limit<F, T: ast::AstNode>(
|
||||
&mut self,
|
||||
db: &dyn DefDatabase,
|
||||
op: F,
|
||||
) -> ExpandResult<Option<(Mark, Option<Parse<T>>)>>
|
||||
where
|
||||
F: FnOnce(&mut Self) -> ExpandResult<Option<MacroCallId>>,
|
||||
{
|
||||
if self.recursion_depth == u32::MAX {
|
||||
// Recursion limit has been reached somewhere in the macro expansion tree. We should
|
||||
// stop expanding other macro calls in this tree, or else this may result in
|
||||
// exponential number of macro expansions, leading to a hang.
|
||||
//
|
||||
// The overflow error should have been reported when it occurred (see the next branch),
|
||||
// so don't return overflow error here to avoid diagnostics duplication.
|
||||
cov_mark::hit!(overflow_but_not_me);
|
||||
return ExpandResult::ok(None);
|
||||
}
|
||||
|
||||
let ExpandResult { value, err } = op(self);
|
||||
let Some(call_id) = value else {
|
||||
return ExpandResult { value: None, err };
|
||||
};
|
||||
if self.recursion_depth as usize > self.recursion_limit {
|
||||
self.recursion_depth = u32::MAX;
|
||||
cov_mark::hit!(your_stack_belongs_to_me);
|
||||
return ExpandResult::only_err(ExpandError::new(
|
||||
db.macro_arg_considering_derives(call_id, &call_id.lookup(db.upcast()).kind).2,
|
||||
ExpandErrorKind::RecursionOverflow,
|
||||
));
|
||||
}
|
||||
|
||||
let macro_file = call_id.as_macro_file();
|
||||
let res = db.parse_macro_expansion(macro_file);
|
||||
|
||||
let err = err.or(res.err);
|
||||
ExpandResult {
|
||||
value: {
|
||||
let parse = res.value.0.cast::<T>();
|
||||
|
||||
self.recursion_depth += 1;
|
||||
let old_file_id = std::mem::replace(&mut self.current_file_id, macro_file.into());
|
||||
let old_span_map =
|
||||
std::mem::replace(&mut self.span_map, db.span_map(self.current_file_id));
|
||||
let prev_ast_id_map =
|
||||
mem::replace(&mut self.ast_id_map, db.ast_id_map(self.current_file_id));
|
||||
let mark = Mark {
|
||||
file_id: old_file_id,
|
||||
span_map: old_span_map,
|
||||
ast_id_map: prev_ast_id_map,
|
||||
bomb: DropBomb::new("expansion mark dropped"),
|
||||
};
|
||||
Some((mark, parse))
|
||||
},
|
||||
err,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn ast_id_map(&self) -> &AstIdMap {
|
||||
&self.ast_id_map
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct Mark {
|
||||
file_id: HirFileId,
|
||||
span_map: SpanMap,
|
||||
ast_id_map: Arc<AstIdMap>,
|
||||
bomb: DropBomb,
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -11,6 +11,7 @@ use tt::TextRange;
|
|||
use crate::{
|
||||
expr_store::lower::{ExprCollector, FxIndexSet},
|
||||
hir::{AsmOperand, AsmOptions, Expr, ExprId, InlineAsm, InlineAsmRegOrRegClass},
|
||||
type_ref::TypeRef,
|
||||
};
|
||||
|
||||
impl ExprCollector<'_> {
|
||||
|
|
@ -158,7 +159,10 @@ impl ExprCollector<'_> {
|
|||
AsmOperand::Const(self.collect_expr_opt(c.expr()))
|
||||
}
|
||||
ast::AsmOperand::AsmSym(s) => {
|
||||
let Some(path) = s.path().and_then(|p| self.parse_path(p)) else {
|
||||
let Some(path) = s
|
||||
.path()
|
||||
.and_then(|p| self.lower_path(p, &mut |_| TypeRef::Error))
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
AsmOperand::Sym(path)
|
||||
|
|
|
|||
277
crates/hir-def/src/expr_store/lower/generics.rs
Normal file
277
crates/hir-def/src/expr_store/lower/generics.rs
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
//! Many kinds of items or constructs can have generic parameters: functions,
|
||||
//! structs, impls, traits, etc. This module provides a common HIR for these
|
||||
//! generic parameters. See also the `Generics` type and the `generics_of` query
|
||||
//! in rustc.
|
||||
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use either::Either;
|
||||
use hir_expand::name::{AsName, Name};
|
||||
use intern::sym;
|
||||
use la_arena::Arena;
|
||||
use syntax::ast::{self, HasName, HasTypeBounds};
|
||||
use thin_vec::ThinVec;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
GenericDefId, TypeOrConstParamId, TypeParamId,
|
||||
expr_store::lower::ExprCollector,
|
||||
hir::generics::{
|
||||
ConstParamData, GenericParams, LifetimeParamData, TypeOrConstParamData, TypeParamData,
|
||||
TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
|
||||
},
|
||||
type_ref::{LifetimeRef, TypeBound, TypeRef, TypeRefId},
|
||||
};
|
||||
|
||||
pub(crate) struct GenericParamsCollector<'db, 'c> {
|
||||
expr_collector: &'c mut ExprCollector<'db>,
|
||||
type_or_consts: Arena<TypeOrConstParamData>,
|
||||
lifetimes: Arena<LifetimeParamData>,
|
||||
where_predicates: Vec<WherePredicate>,
|
||||
parent: GenericDefId,
|
||||
}
|
||||
|
||||
impl<'db, 'c> GenericParamsCollector<'db, 'c> {
|
||||
pub(crate) fn new(expr_collector: &'c mut ExprCollector<'db>, parent: GenericDefId) -> Self {
|
||||
Self {
|
||||
expr_collector,
|
||||
type_or_consts: Default::default(),
|
||||
lifetimes: Default::default(),
|
||||
where_predicates: Default::default(),
|
||||
parent,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn fill_self_param(&mut self, bounds: Option<ast::TypeBoundList>) {
|
||||
let self_ = Name::new_symbol_root(sym::Self_.clone());
|
||||
let idx = self.type_or_consts.alloc(
|
||||
TypeParamData {
|
||||
name: Some(self_.clone()),
|
||||
default: None,
|
||||
provenance: TypeParamProvenance::TraitSelf,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
let type_ref = TypeRef::TypeParam(TypeParamId::from_unchecked(TypeOrConstParamId {
|
||||
parent: self.parent,
|
||||
local_id: idx,
|
||||
}));
|
||||
let self_ = self.expr_collector.alloc_type_ref_desugared(type_ref);
|
||||
if let Some(bounds) = bounds {
|
||||
self.lower_bounds(Some(bounds), Either::Left(self_));
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn lower(
|
||||
&mut self,
|
||||
generic_param_list: Option<ast::GenericParamList>,
|
||||
where_clause: Option<ast::WhereClause>,
|
||||
) {
|
||||
if let Some(params) = generic_param_list {
|
||||
self.lower_param_list(params)
|
||||
}
|
||||
if let Some(where_clause) = where_clause {
|
||||
self.lower_where_predicates(where_clause);
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_param_list(&mut self, params: ast::GenericParamList) {
|
||||
for generic_param in params.generic_params() {
|
||||
let enabled = self.expr_collector.expander.is_cfg_enabled(
|
||||
self.expr_collector.db,
|
||||
self.expr_collector.module.krate(),
|
||||
&generic_param,
|
||||
);
|
||||
if !enabled {
|
||||
continue;
|
||||
}
|
||||
|
||||
match generic_param {
|
||||
ast::GenericParam::TypeParam(type_param) => {
|
||||
let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
|
||||
let default = type_param
|
||||
.default_type()
|
||||
.map(|it| self.expr_collector.lower_type_ref(it, &mut |_| TypeRef::Error));
|
||||
let param = TypeParamData {
|
||||
name: Some(name.clone()),
|
||||
default,
|
||||
provenance: TypeParamProvenance::TypeParamList,
|
||||
};
|
||||
let idx = self.type_or_consts.alloc(param.into());
|
||||
let type_ref =
|
||||
TypeRef::TypeParam(TypeParamId::from_unchecked(TypeOrConstParamId {
|
||||
parent: self.parent,
|
||||
local_id: idx,
|
||||
}));
|
||||
let type_ref = self.expr_collector.alloc_type_ref_desugared(type_ref);
|
||||
self.lower_bounds(type_param.type_bound_list(), Either::Left(type_ref));
|
||||
}
|
||||
ast::GenericParam::ConstParam(const_param) => {
|
||||
let name = const_param.name().map_or_else(Name::missing, |it| it.as_name());
|
||||
let ty = self
|
||||
.expr_collector
|
||||
.lower_type_ref_opt(const_param.ty(), &mut |_| TypeRef::Error);
|
||||
let param = ConstParamData {
|
||||
name,
|
||||
ty,
|
||||
default: const_param
|
||||
.default_val()
|
||||
.map(|it| self.expr_collector.lower_const_arg(it)),
|
||||
};
|
||||
let _idx = self.type_or_consts.alloc(param.into());
|
||||
}
|
||||
ast::GenericParam::LifetimeParam(lifetime_param) => {
|
||||
let lifetime_ref =
|
||||
self.expr_collector.lower_lifetime_ref_opt(lifetime_param.lifetime());
|
||||
let param = LifetimeParamData { name: lifetime_ref.name.clone() };
|
||||
let _idx = self.lifetimes.alloc(param);
|
||||
self.lower_bounds(
|
||||
lifetime_param.type_bound_list(),
|
||||
Either::Right(lifetime_ref),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_where_predicates(&mut self, where_clause: ast::WhereClause) {
|
||||
for pred in where_clause.predicates() {
|
||||
let target = if let Some(type_ref) = pred.ty() {
|
||||
Either::Left(self.expr_collector.lower_type_ref(type_ref, &mut |_| TypeRef::Error))
|
||||
} else if let Some(lifetime) = pred.lifetime() {
|
||||
Either::Right(self.expr_collector.lower_lifetime_ref(lifetime))
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let lifetimes: Option<Box<_>> = pred.generic_param_list().map(|param_list| {
|
||||
// Higher-Ranked Trait Bounds
|
||||
param_list
|
||||
.lifetime_params()
|
||||
.map(|lifetime_param| {
|
||||
lifetime_param
|
||||
.lifetime()
|
||||
.map_or_else(Name::missing, |lt| Name::new_lifetime(<))
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) {
|
||||
self.lower_type_bound_as_predicate(bound, lifetimes.as_deref(), target.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_bounds(
|
||||
&mut self,
|
||||
type_bounds: Option<ast::TypeBoundList>,
|
||||
target: Either<TypeRefId, LifetimeRef>,
|
||||
) {
|
||||
for bound in type_bounds.iter().flat_map(|type_bound_list| type_bound_list.bounds()) {
|
||||
self.lower_type_bound_as_predicate(bound, None, target.clone());
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_type_bound_as_predicate(
|
||||
&mut self,
|
||||
bound: ast::TypeBound,
|
||||
hrtb_lifetimes: Option<&[Name]>,
|
||||
target: Either<TypeRefId, LifetimeRef>,
|
||||
) {
|
||||
let bound = self.expr_collector.lower_type_bound(
|
||||
bound,
|
||||
&mut Self::lower_argument_impl_trait(
|
||||
&mut self.type_or_consts,
|
||||
&mut self.where_predicates,
|
||||
self.parent,
|
||||
),
|
||||
);
|
||||
let predicate = match (target, bound) {
|
||||
(_, TypeBound::Error | TypeBound::Use(_)) => return,
|
||||
(Either::Left(type_ref), bound) => match hrtb_lifetimes {
|
||||
Some(hrtb_lifetimes) => WherePredicate::ForLifetime {
|
||||
lifetimes: hrtb_lifetimes.to_vec().into_boxed_slice(),
|
||||
target: WherePredicateTypeTarget::TypeRef(type_ref),
|
||||
bound,
|
||||
},
|
||||
None => WherePredicate::TypeBound {
|
||||
target: WherePredicateTypeTarget::TypeRef(type_ref),
|
||||
bound,
|
||||
},
|
||||
},
|
||||
(Either::Right(lifetime), TypeBound::Lifetime(bound)) => {
|
||||
WherePredicate::Lifetime { target: lifetime, bound }
|
||||
}
|
||||
(Either::Right(_), TypeBound::ForLifetime(..) | TypeBound::Path(..)) => return,
|
||||
};
|
||||
self.where_predicates.push(predicate);
|
||||
}
|
||||
|
||||
pub(crate) fn collect_impl_trait<R>(
|
||||
&mut self,
|
||||
cb: impl FnOnce(&mut ExprCollector<'_>, &mut dyn FnMut(ThinVec<TypeBound>) -> TypeRef) -> R,
|
||||
) -> R {
|
||||
cb(
|
||||
self.expr_collector,
|
||||
&mut Self::lower_argument_impl_trait(
|
||||
&mut self.type_or_consts,
|
||||
&mut self.where_predicates,
|
||||
self.parent,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fn lower_argument_impl_trait(
|
||||
type_or_consts: &mut Arena<TypeOrConstParamData>,
|
||||
where_predicates: &mut Vec<WherePredicate>,
|
||||
parent: GenericDefId,
|
||||
) -> impl FnMut(ThinVec<TypeBound>) -> TypeRef {
|
||||
move |impl_trait_bounds| {
|
||||
let param = TypeParamData {
|
||||
name: None,
|
||||
default: None,
|
||||
provenance: TypeParamProvenance::ArgumentImplTrait,
|
||||
};
|
||||
let param_id = type_or_consts.alloc(param.into());
|
||||
for bound in impl_trait_bounds {
|
||||
where_predicates.push(WherePredicate::TypeBound {
|
||||
target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
|
||||
bound: bound.clone(),
|
||||
});
|
||||
}
|
||||
TypeRef::TypeParam(TypeParamId::from_unchecked(TypeOrConstParamId {
|
||||
parent,
|
||||
local_id: param_id,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn finish(self) -> Arc<GenericParams> {
|
||||
let Self {
|
||||
mut lifetimes,
|
||||
mut type_or_consts,
|
||||
mut where_predicates,
|
||||
expr_collector: _,
|
||||
parent: _,
|
||||
} = self;
|
||||
|
||||
if lifetimes.is_empty() && type_or_consts.is_empty() && where_predicates.is_empty() {
|
||||
static EMPTY: LazyLock<Arc<GenericParams>> = LazyLock::new(|| {
|
||||
Arc::new(GenericParams {
|
||||
lifetimes: Arena::new(),
|
||||
type_or_consts: Arena::new(),
|
||||
where_predicates: Box::default(),
|
||||
})
|
||||
});
|
||||
return Arc::clone(&EMPTY);
|
||||
}
|
||||
|
||||
lifetimes.shrink_to_fit();
|
||||
type_or_consts.shrink_to_fit();
|
||||
where_predicates.shrink_to_fit();
|
||||
Arc::new(GenericParams {
|
||||
type_or_consts,
|
||||
lifetimes,
|
||||
where_predicates: where_predicates.into_boxed_slice(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +1,26 @@
|
|||
//! Transforms syntax into `Path` objects, ideally with accounting for hygiene
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use std::iter;
|
||||
|
||||
use crate::{lower::LowerCtx, path::NormalPath, type_ref::ConstRef};
|
||||
use crate::expr_store::{lower::ExprCollector, path::NormalPath};
|
||||
|
||||
use hir_expand::{
|
||||
mod_path::resolve_crate_root,
|
||||
mod_path::{ModPath, PathKind, resolve_crate_root},
|
||||
name::{AsName, Name},
|
||||
};
|
||||
use intern::{Interned, sym};
|
||||
use syntax::ast::{self, AstNode, HasGenericArgs, HasTypeBounds};
|
||||
use syntax::{
|
||||
AstPtr,
|
||||
ast::{self, AstNode, HasGenericArgs},
|
||||
};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::{
|
||||
path::{
|
||||
AssociatedTypeBinding, GenericArg, GenericArgs, GenericArgsParentheses, ModPath, Path,
|
||||
PathKind,
|
||||
},
|
||||
type_ref::{LifetimeRef, TypeBound, TypeRef},
|
||||
expr_store::path::{GenericArg, GenericArgs, Path},
|
||||
type_ref::{TypeBound, TypeRef},
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
@ -30,7 +33,11 @@ thread_local! {
|
|||
/// It correctly handles `$crate` based path from macro call.
|
||||
// If you modify the logic of the lowering, make sure to check if `hir_segment_to_ast_segment()`
|
||||
// also needs an update.
|
||||
pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<Path> {
|
||||
pub(super) fn lower_path(
|
||||
collector: &mut ExprCollector<'_>,
|
||||
mut path: ast::Path,
|
||||
impl_trait_lower_fn: &mut impl FnMut(ThinVec<TypeBound>) -> TypeRef,
|
||||
) -> Option<Path> {
|
||||
let mut kind = PathKind::Plain;
|
||||
let mut type_anchor = None;
|
||||
let mut segments = Vec::new();
|
||||
|
|
@ -46,9 +53,20 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<
|
|||
segments.push(name);
|
||||
};
|
||||
loop {
|
||||
let segment = path.segment()?;
|
||||
let Some(segment) = path.segment() else {
|
||||
segments.push(Name::missing());
|
||||
// We can end up here if for `path::`
|
||||
match qualifier(&path) {
|
||||
Some(it) => {
|
||||
path = it;
|
||||
continue;
|
||||
}
|
||||
None => break,
|
||||
}
|
||||
};
|
||||
|
||||
if segment.coloncolon_token().is_some() {
|
||||
debug_assert!(path.qualifier().is_none()); // this can only occur at the first segment
|
||||
kind = PathKind::Abs;
|
||||
}
|
||||
|
||||
|
|
@ -60,8 +78,8 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<
|
|||
return None;
|
||||
}
|
||||
break kind = resolve_crate_root(
|
||||
ctx.db.upcast(),
|
||||
ctx.span_map().span_for_range(name_ref.syntax().text_range()).ctx,
|
||||
collector.db.upcast(),
|
||||
collector.expander.ctx_for_range(name_ref.syntax().text_range()),
|
||||
)
|
||||
.map(PathKind::DollarCrate)
|
||||
.unwrap_or(PathKind::Crate);
|
||||
|
|
@ -69,12 +87,12 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<
|
|||
let name = name_ref.as_name();
|
||||
let args = segment
|
||||
.generic_arg_list()
|
||||
.and_then(|it| lower_generic_args(ctx, it))
|
||||
.and_then(|it| collector.lower_generic_args(it, impl_trait_lower_fn))
|
||||
.or_else(|| {
|
||||
lower_generic_args_from_fn_path(
|
||||
ctx,
|
||||
collector.lower_generic_args_from_fn_path(
|
||||
segment.parenthesized_arg_list(),
|
||||
segment.ret_type(),
|
||||
impl_trait_lower_fn,
|
||||
)
|
||||
})
|
||||
.or_else(|| {
|
||||
|
|
@ -90,9 +108,9 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<
|
|||
push_segment(&segment, &mut segments, Name::new_symbol_root(sym::Self_.clone()));
|
||||
}
|
||||
ast::PathSegmentKind::Type { type_ref, trait_ref } => {
|
||||
assert!(path.qualifier().is_none()); // this can only occur at the first segment
|
||||
debug_assert!(path.qualifier().is_none()); // this can only occur at the first segment
|
||||
|
||||
let self_type = TypeRef::from_ast(ctx, type_ref?);
|
||||
let self_type = collector.lower_type_ref(type_ref?, impl_trait_lower_fn);
|
||||
|
||||
match trait_ref {
|
||||
// <T>::foo
|
||||
|
|
@ -102,7 +120,12 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<
|
|||
}
|
||||
// <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
|
||||
Some(trait_ref) => {
|
||||
let path = Path::from_src(ctx, trait_ref.path()?)?;
|
||||
let path = collector.lower_path(trait_ref.path()?, impl_trait_lower_fn)?;
|
||||
// FIXME: Unnecessary clone
|
||||
collector.alloc_type_ref(
|
||||
TypeRef::Path(path.clone()),
|
||||
AstPtr::new(&trait_ref).upcast(),
|
||||
);
|
||||
let mod_path = path.mod_path()?;
|
||||
let path_generic_args = path.generic_args();
|
||||
let num_segments = mod_path.segments().len();
|
||||
|
|
@ -190,10 +213,10 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<
|
|||
// We follow what it did anyway :)
|
||||
if segments.len() == 1 && kind == PathKind::Plain {
|
||||
if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) {
|
||||
let syn_ctxt = ctx.span_map().span_for_range(path.segment()?.syntax().text_range()).ctx;
|
||||
if let Some(macro_call_id) = syn_ctxt.outer_expn(ctx.db) {
|
||||
if ctx.db.lookup_intern_macro_call(macro_call_id).def.local_inner {
|
||||
kind = match resolve_crate_root(ctx.db.upcast(), syn_ctxt) {
|
||||
let syn_ctxt = collector.expander.ctx_for_range(path.segment()?.syntax().text_range());
|
||||
if let Some(macro_call_id) = syn_ctxt.outer_expn(collector.db) {
|
||||
if collector.db.lookup_intern_macro_call(macro_call_id).def.local_inner {
|
||||
kind = match resolve_crate_root(collector.db.upcast(), syn_ctxt) {
|
||||
Some(crate_root) => PathKind::DollarCrate(crate_root),
|
||||
None => PathKind::Crate,
|
||||
}
|
||||
|
|
@ -214,9 +237,9 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<
|
|||
return Some(Path::BarePath(mod_path));
|
||||
} else {
|
||||
return Some(Path::Normal(Box::new(NormalPath {
|
||||
generic_args: generic_args.into_boxed_slice(),
|
||||
type_anchor,
|
||||
mod_path,
|
||||
generic_args: generic_args.into_boxed_slice(),
|
||||
})));
|
||||
}
|
||||
|
||||
|
|
@ -266,112 +289,3 @@ pub fn hir_segment_to_ast_segment(path: &ast::Path, segment_idx: u32) -> Option<
|
|||
.nth(segment_idx as usize)
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn lower_generic_args(
|
||||
lower_ctx: &mut LowerCtx<'_>,
|
||||
node: ast::GenericArgList,
|
||||
) -> Option<GenericArgs> {
|
||||
let mut args = Vec::new();
|
||||
let mut bindings = Vec::new();
|
||||
for generic_arg in node.generic_args() {
|
||||
match generic_arg {
|
||||
ast::GenericArg::TypeArg(type_arg) => {
|
||||
let type_ref = TypeRef::from_ast_opt(lower_ctx, type_arg.ty());
|
||||
lower_ctx.update_impl_traits_bounds_from_type_ref(type_ref);
|
||||
args.push(GenericArg::Type(type_ref));
|
||||
}
|
||||
ast::GenericArg::AssocTypeArg(assoc_type_arg) => {
|
||||
if assoc_type_arg.param_list().is_some() {
|
||||
// We currently ignore associated return type bounds.
|
||||
continue;
|
||||
}
|
||||
if let Some(name_ref) = assoc_type_arg.name_ref() {
|
||||
// Nested impl traits like `impl Foo<Assoc = impl Bar>` are allowed
|
||||
lower_ctx.with_outer_impl_trait_scope(false, |lower_ctx| {
|
||||
let name = name_ref.as_name();
|
||||
let args = assoc_type_arg
|
||||
.generic_arg_list()
|
||||
.and_then(|args| lower_generic_args(lower_ctx, args))
|
||||
.or_else(|| {
|
||||
assoc_type_arg
|
||||
.return_type_syntax()
|
||||
.map(|_| GenericArgs::return_type_notation())
|
||||
});
|
||||
let type_ref =
|
||||
assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it));
|
||||
let type_ref = type_ref
|
||||
.inspect(|&tr| lower_ctx.update_impl_traits_bounds_from_type_ref(tr));
|
||||
let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
|
||||
l.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect()
|
||||
} else {
|
||||
Box::default()
|
||||
};
|
||||
bindings.push(AssociatedTypeBinding { name, args, type_ref, bounds });
|
||||
});
|
||||
}
|
||||
}
|
||||
ast::GenericArg::LifetimeArg(lifetime_arg) => {
|
||||
if let Some(lifetime) = lifetime_arg.lifetime() {
|
||||
let lifetime_ref = LifetimeRef::new(&lifetime);
|
||||
args.push(GenericArg::Lifetime(lifetime_ref))
|
||||
}
|
||||
}
|
||||
ast::GenericArg::ConstArg(arg) => {
|
||||
let arg = ConstRef::from_const_arg(lower_ctx, Some(arg));
|
||||
args.push(GenericArg::Const(arg))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if args.is_empty() && bindings.is_empty() {
|
||||
return None;
|
||||
}
|
||||
Some(GenericArgs {
|
||||
args: args.into_boxed_slice(),
|
||||
has_self_type: false,
|
||||
bindings: bindings.into_boxed_slice(),
|
||||
parenthesized: GenericArgsParentheses::No,
|
||||
})
|
||||
}
|
||||
|
||||
/// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y)
|
||||
/// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`).
|
||||
fn lower_generic_args_from_fn_path(
|
||||
ctx: &mut LowerCtx<'_>,
|
||||
args: Option<ast::ParenthesizedArgList>,
|
||||
ret_type: Option<ast::RetType>,
|
||||
) -> Option<GenericArgs> {
|
||||
let params = args?;
|
||||
let mut param_types = Vec::new();
|
||||
for param in params.type_args() {
|
||||
let type_ref = TypeRef::from_ast_opt(ctx, param.ty());
|
||||
param_types.push(type_ref);
|
||||
}
|
||||
let args = Box::new([GenericArg::Type(
|
||||
ctx.alloc_type_ref_desugared(TypeRef::Tuple(ThinVec::from_iter(param_types))),
|
||||
)]);
|
||||
let bindings = if let Some(ret_type) = ret_type {
|
||||
let type_ref = TypeRef::from_ast_opt(ctx, ret_type.ty());
|
||||
Box::new([AssociatedTypeBinding {
|
||||
name: Name::new_symbol_root(sym::Output.clone()),
|
||||
args: None,
|
||||
type_ref: Some(type_ref),
|
||||
bounds: Box::default(),
|
||||
}])
|
||||
} else {
|
||||
// -> ()
|
||||
let type_ref = ctx.alloc_type_ref_desugared(TypeRef::unit());
|
||||
Box::new([AssociatedTypeBinding {
|
||||
name: Name::new_symbol_root(sym::Output.clone()),
|
||||
args: None,
|
||||
type_ref: Some(type_ref),
|
||||
bounds: Box::default(),
|
||||
}])
|
||||
};
|
||||
Some(GenericArgs {
|
||||
args,
|
||||
has_self_type: false,
|
||||
bindings,
|
||||
parenthesized: GenericArgsParentheses::ParenSugar,
|
||||
})
|
||||
}
|
||||
|
|
@ -4,23 +4,27 @@ use syntax::ast::{self, make};
|
|||
use test_fixture::WithFixture;
|
||||
|
||||
use crate::{
|
||||
lower::LowerCtx,
|
||||
path::{
|
||||
Path,
|
||||
lower::{SEGMENT_LOWERING_MAP, hir_segment_to_ast_segment},
|
||||
db::DefDatabase,
|
||||
expr_store::{
|
||||
ExpressionStore,
|
||||
lower::{
|
||||
ExprCollector,
|
||||
path::{SEGMENT_LOWERING_MAP, hir_segment_to_ast_segment},
|
||||
},
|
||||
path::Path,
|
||||
pretty,
|
||||
},
|
||||
test_db::TestDB,
|
||||
type_ref::{TypesMap, TypesSourceMap},
|
||||
type_ref::TypeRef,
|
||||
};
|
||||
|
||||
fn lower_path(path: ast::Path) -> (TestDB, TypesMap, Option<Path>) {
|
||||
fn lower_path(path: ast::Path) -> (TestDB, ExpressionStore, Option<Path>) {
|
||||
let (db, file_id) = TestDB::with_single_file("");
|
||||
let mut types_map = TypesMap::default();
|
||||
let mut types_source_map = TypesSourceMap::default();
|
||||
let mut ctx = LowerCtx::new(&db, file_id.into(), &mut types_map, &mut types_source_map);
|
||||
let lowered_path = ctx.lower_path(path);
|
||||
(db, types_map, lowered_path)
|
||||
let krate = db.fetch_test_crate();
|
||||
let mut ctx = ExprCollector::new(&db, db.crate_def_map(krate).root_module_id(), file_id.into());
|
||||
let lowered_path = ctx.lower_path(path, &mut TypeRef::ImplTrait);
|
||||
let store = ctx.store.finish();
|
||||
(db, store, lowered_path)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
|
|
@ -111,11 +115,9 @@ fn keywords_in_middle_fail_lowering3() {
|
|||
|
||||
#[track_caller]
|
||||
fn check_path_lowering(path: &str, expected: Expect) {
|
||||
let (db, types_map, lowered_path) = lower_path(make::path_from_text(path));
|
||||
let (db, store, lowered_path) = lower_path(make::path_from_text(path));
|
||||
let lowered_path = lowered_path.expect("failed to lower path");
|
||||
let mut buf = String::new();
|
||||
pretty::print_path(&db, &lowered_path, &types_map, &mut buf, Edition::CURRENT)
|
||||
.expect("failed to pretty-print path");
|
||||
let buf = pretty::print_path(&db, &store, &lowered_path, Edition::CURRENT);
|
||||
expected.assert_eq(&buf);
|
||||
}
|
||||
|
||||
|
|
@ -1,53 +1,16 @@
|
|||
//! A desugared representation of paths like `crate::foo` or `<Type as Trait>::bar`.
|
||||
mod lower;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use std::{
|
||||
fmt::{self, Display},
|
||||
iter,
|
||||
};
|
||||
use std::iter;
|
||||
|
||||
use crate::{
|
||||
lang_item::LangItemTarget,
|
||||
lower::LowerCtx,
|
||||
type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRefId},
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
use hir_expand::{
|
||||
mod_path::{ModPath, PathKind},
|
||||
name::Name,
|
||||
};
|
||||
use intern::Interned;
|
||||
use span::Edition;
|
||||
use syntax::ast;
|
||||
|
||||
pub use hir_expand::mod_path::{ModPath, PathKind, path};
|
||||
|
||||
pub use lower::hir_segment_to_ast_segment;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ImportAlias {
|
||||
/// Unnamed alias, as in `use Foo as _;`
|
||||
Underscore,
|
||||
/// Named alias
|
||||
Alias(Name),
|
||||
}
|
||||
|
||||
impl ImportAlias {
|
||||
pub fn display(&self, edition: Edition) -> impl Display + '_ {
|
||||
ImportAliasDisplay { value: self, edition }
|
||||
}
|
||||
}
|
||||
|
||||
struct ImportAliasDisplay<'a> {
|
||||
value: &'a ImportAlias,
|
||||
edition: Edition,
|
||||
}
|
||||
impl Display for ImportAliasDisplay<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.value {
|
||||
ImportAlias::Underscore => f.write_str("_"),
|
||||
ImportAlias::Alias(name) => Display::fmt(&name.display_no_db(self.edition), f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Path {
|
||||
|
|
@ -133,12 +96,6 @@ pub enum GenericArg {
|
|||
}
|
||||
|
||||
impl Path {
|
||||
/// Converts an `ast::Path` to `Path`. Works with use trees.
|
||||
/// It correctly handles `$crate` based path from macro call.
|
||||
pub fn from_src(ctx: &mut LowerCtx<'_>, path: ast::Path) -> Option<Path> {
|
||||
lower::lower_path(ctx, path)
|
||||
}
|
||||
|
||||
/// Converts a known mod path to `Path`.
|
||||
pub fn from_known_path(path: ModPath, generic_args: Vec<Option<GenericArgs>>) -> Path {
|
||||
Path::Normal(Box::new(NormalPath {
|
||||
|
|
@ -328,13 +285,6 @@ impl<'a> PathSegments<'a> {
|
|||
}
|
||||
|
||||
impl GenericArgs {
|
||||
pub(crate) fn from_ast(
|
||||
lower_ctx: &mut LowerCtx<'_>,
|
||||
node: ast::GenericArgList,
|
||||
) -> Option<GenericArgs> {
|
||||
lower::lower_generic_args(lower_ctx, node)
|
||||
}
|
||||
|
||||
pub(crate) fn empty() -> GenericArgs {
|
||||
GenericArgs {
|
||||
args: Box::default(),
|
||||
|
|
@ -1,25 +1,52 @@
|
|||
//! A pretty-printer for HIR.
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::fmt::{self, Write};
|
||||
use std::{
|
||||
fmt::{self, Write},
|
||||
mem,
|
||||
};
|
||||
|
||||
use hir_expand::{Lookup, mod_path::PathKind};
|
||||
use itertools::Itertools;
|
||||
use span::Edition;
|
||||
|
||||
use crate::{
|
||||
hir::{Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, Movability, Statement},
|
||||
pretty::{print_generic_args, print_path, print_type_ref},
|
||||
DefWithBodyId, ItemTreeLoc, TypeParamId,
|
||||
expr_store::path::{GenericArg, GenericArgs},
|
||||
hir::{
|
||||
Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, Movability, Statement,
|
||||
generics::{GenericParams, WherePredicate, WherePredicateTypeTarget},
|
||||
},
|
||||
lang_item::LangItemTarget,
|
||||
signatures::{FnFlags, FunctionSignature, StructSignature},
|
||||
type_ref::{ConstRef, Mutability, TraitBoundModifier, TypeBound, UseArgRef},
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
macro_rules! w {
|
||||
($dst:expr, $($arg:tt)*) => {
|
||||
{ let _ = write!($dst, $($arg)*); }
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! wln {
|
||||
($dst:expr) => {
|
||||
{ $dst.newline(); }
|
||||
};
|
||||
($dst:expr, $($arg:tt)*) => {
|
||||
{ let _ = w!($dst, $($arg)*); $dst.newline(); }
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(super) enum LineFormat {
|
||||
pub(crate) enum LineFormat {
|
||||
Oneline,
|
||||
Newline,
|
||||
Indentation,
|
||||
}
|
||||
|
||||
pub(super) fn print_body_hir(
|
||||
pub(crate) fn print_body_hir(
|
||||
db: &dyn DefDatabase,
|
||||
body: &Body,
|
||||
owner: DefWithBodyId,
|
||||
|
|
@ -43,7 +70,6 @@ pub(super) fn print_body_hir(
|
|||
}
|
||||
)
|
||||
}),
|
||||
DefWithBodyId::InTypeConstId(_) => "In type const = ".to_owned(),
|
||||
DefWithBodyId::VariantId(it) => {
|
||||
let loc = it.lookup(db);
|
||||
let enum_loc = loc.parent.lookup(db);
|
||||
|
|
@ -63,22 +89,14 @@ pub(super) fn print_body_hir(
|
|||
line_format: LineFormat::Newline,
|
||||
edition,
|
||||
};
|
||||
if let DefWithBodyId::FunctionId(it) = owner {
|
||||
if let DefWithBodyId::FunctionId(_) = owner {
|
||||
p.buf.push('(');
|
||||
let function_data = db.function_data(it);
|
||||
let (mut params, ret_type) = (function_data.params.iter(), &function_data.ret_type);
|
||||
if let Some(self_param) = body.self_param {
|
||||
p.print_binding(self_param);
|
||||
p.buf.push_str(": ");
|
||||
if let Some(ty) = params.next() {
|
||||
p.print_type_ref(*ty, &function_data.types_map);
|
||||
p.buf.push_str(", ");
|
||||
}
|
||||
}
|
||||
body.params.iter().zip(params).for_each(|(¶m, ty)| {
|
||||
p.print_pat(param);
|
||||
p.buf.push_str(": ");
|
||||
p.print_type_ref(*ty, &function_data.types_map);
|
||||
body.params.iter().for_each(|param| {
|
||||
p.print_pat(*param);
|
||||
p.buf.push_str(", ");
|
||||
});
|
||||
// remove the last ", " in param list
|
||||
|
|
@ -86,9 +104,6 @@ pub(super) fn print_body_hir(
|
|||
p.buf.truncate(p.buf.len() - 2);
|
||||
}
|
||||
p.buf.push(')');
|
||||
// return type
|
||||
p.buf.push_str(" -> ");
|
||||
p.print_type_ref(*ret_type, &function_data.types_map);
|
||||
p.buf.push(' ');
|
||||
}
|
||||
p.print_expr(body.body_expr);
|
||||
|
|
@ -98,7 +113,240 @@ pub(super) fn print_body_hir(
|
|||
p.buf
|
||||
}
|
||||
|
||||
pub(super) fn print_expr_hir(
|
||||
pub(crate) fn print_path(
|
||||
db: &dyn DefDatabase,
|
||||
store: &ExpressionStore,
|
||||
path: &Path,
|
||||
edition: Edition,
|
||||
) -> String {
|
||||
let mut p = Printer {
|
||||
db,
|
||||
store,
|
||||
buf: String::new(),
|
||||
indent_level: 0,
|
||||
line_format: LineFormat::Newline,
|
||||
edition,
|
||||
};
|
||||
p.print_path(path);
|
||||
p.buf
|
||||
}
|
||||
|
||||
pub(crate) fn print_struct(
|
||||
db: &dyn DefDatabase,
|
||||
StructSignature { name, generic_params, store, flags, shape, repr }: &StructSignature,
|
||||
edition: Edition,
|
||||
) -> String {
|
||||
use crate::item_tree::FieldsShape;
|
||||
use crate::signatures::StructFlags;
|
||||
|
||||
let mut p = Printer {
|
||||
db,
|
||||
store,
|
||||
buf: String::new(),
|
||||
indent_level: 0,
|
||||
line_format: LineFormat::Newline,
|
||||
edition,
|
||||
};
|
||||
if let Some(repr) = repr {
|
||||
if repr.c() {
|
||||
wln!(p, "#[repr(C)]");
|
||||
}
|
||||
if let Some(align) = repr.align {
|
||||
wln!(p, "#[repr(align({}))]", align.bytes());
|
||||
}
|
||||
if let Some(pack) = repr.pack {
|
||||
wln!(p, "#[repr(pack({}))]", pack.bytes());
|
||||
}
|
||||
}
|
||||
if flags.contains(StructFlags::IS_FUNDAMENTAL) {
|
||||
wln!(p, "#[fundamental]");
|
||||
}
|
||||
w!(p, "struct ");
|
||||
w!(p, "{}", name.display(db.upcast(), edition));
|
||||
print_generic_params(db, generic_params, &mut p);
|
||||
match shape {
|
||||
FieldsShape::Record => wln!(p, " {{...}}"),
|
||||
FieldsShape::Tuple => wln!(p, "(...)"),
|
||||
FieldsShape::Unit => (),
|
||||
}
|
||||
|
||||
print_where_clauses(db, generic_params, &mut p);
|
||||
|
||||
match shape {
|
||||
FieldsShape::Record => wln!(p),
|
||||
FieldsShape::Tuple => wln!(p, ";"),
|
||||
FieldsShape::Unit => wln!(p, ";"),
|
||||
}
|
||||
|
||||
p.buf
|
||||
}
|
||||
|
||||
pub(crate) fn print_function(
|
||||
db: &dyn DefDatabase,
|
||||
FunctionSignature {
|
||||
name,
|
||||
generic_params,
|
||||
store,
|
||||
params,
|
||||
ret_type,
|
||||
abi,
|
||||
flags,
|
||||
legacy_const_generics_indices,
|
||||
}: &FunctionSignature,
|
||||
edition: Edition,
|
||||
) -> String {
|
||||
let mut p = Printer {
|
||||
db,
|
||||
store,
|
||||
buf: String::new(),
|
||||
indent_level: 0,
|
||||
line_format: LineFormat::Newline,
|
||||
edition,
|
||||
};
|
||||
if flags.contains(FnFlags::HAS_CONST_KW) {
|
||||
w!(p, "const ");
|
||||
}
|
||||
if flags.contains(FnFlags::HAS_ASYNC_KW) {
|
||||
w!(p, "async ");
|
||||
}
|
||||
if flags.contains(FnFlags::HAS_UNSAFE_KW) {
|
||||
w!(p, "unsafe ");
|
||||
}
|
||||
if flags.contains(FnFlags::HAS_SAFE_KW) {
|
||||
w!(p, "safe ");
|
||||
}
|
||||
if let Some(abi) = abi {
|
||||
w!(p, "extern \"{}\" ", abi.as_str());
|
||||
}
|
||||
w!(p, "fn ");
|
||||
w!(p, "{}", name.display(db.upcast(), edition));
|
||||
print_generic_params(db, generic_params, &mut p);
|
||||
w!(p, "(");
|
||||
for (i, param) in params.iter().enumerate() {
|
||||
if i != 0 {
|
||||
w!(p, ", ");
|
||||
}
|
||||
if legacy_const_generics_indices.as_ref().is_some_and(|idx| idx.contains(&(i as u32))) {
|
||||
w!(p, "const: ");
|
||||
}
|
||||
p.print_type_ref(*param);
|
||||
}
|
||||
w!(p, ")");
|
||||
if let Some(ret_type) = ret_type {
|
||||
w!(p, " -> ");
|
||||
p.print_type_ref(*ret_type);
|
||||
}
|
||||
|
||||
print_where_clauses(db, generic_params, &mut p);
|
||||
wln!(p, " {{...}}");
|
||||
|
||||
p.buf
|
||||
}
|
||||
|
||||
fn print_where_clauses(db: &dyn DefDatabase, generic_params: &GenericParams, p: &mut Printer<'_>) {
|
||||
if !generic_params.where_predicates.is_empty() {
|
||||
w!(p, "\nwhere\n");
|
||||
p.indented(|p| {
|
||||
for (i, pred) in generic_params.where_predicates.iter().enumerate() {
|
||||
if i != 0 {
|
||||
w!(p, ",\n");
|
||||
}
|
||||
match pred {
|
||||
WherePredicate::TypeBound { target, bound } => match target {
|
||||
&WherePredicateTypeTarget::TypeRef(idx) => {
|
||||
p.print_type_ref(idx);
|
||||
w!(p, ": ");
|
||||
p.print_type_bounds(std::slice::from_ref(bound));
|
||||
}
|
||||
WherePredicateTypeTarget::TypeOrConstParam(idx) => {
|
||||
match generic_params[*idx].name() {
|
||||
Some(name) => w!(p, "{}", name.display(db.upcast(), p.edition)),
|
||||
None => w!(p, "Param[{}]", idx.into_raw()),
|
||||
}
|
||||
w!(p, ": ");
|
||||
p.print_type_bounds(std::slice::from_ref(bound));
|
||||
}
|
||||
},
|
||||
WherePredicate::Lifetime { target, bound } => {
|
||||
w!(
|
||||
p,
|
||||
"{}: {}",
|
||||
target.name.display(db.upcast(), p.edition),
|
||||
bound.name.display(db.upcast(), p.edition)
|
||||
);
|
||||
}
|
||||
WherePredicate::ForLifetime { lifetimes, target, bound } => {
|
||||
w!(p, "for<");
|
||||
for (i, lifetime) in lifetimes.iter().enumerate() {
|
||||
if i != 0 {
|
||||
w!(p, ", ");
|
||||
}
|
||||
w!(p, "{}", lifetime.display(db.upcast(), p.edition));
|
||||
}
|
||||
w!(p, "> ");
|
||||
match target {
|
||||
WherePredicateTypeTarget::TypeRef(idx) => {
|
||||
p.print_type_ref(*idx);
|
||||
w!(p, ": ");
|
||||
p.print_type_bounds(std::slice::from_ref(bound));
|
||||
}
|
||||
WherePredicateTypeTarget::TypeOrConstParam(idx) => {
|
||||
match generic_params[*idx].name() {
|
||||
Some(name) => w!(p, "{}", name.display(db.upcast(), p.edition)),
|
||||
None => w!(p, "Param[{}]", idx.into_raw()),
|
||||
}
|
||||
w!(p, ": ");
|
||||
p.print_type_bounds(std::slice::from_ref(bound));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
wln!(p);
|
||||
}
|
||||
}
|
||||
|
||||
fn print_generic_params(db: &dyn DefDatabase, generic_params: &GenericParams, p: &mut Printer<'_>) {
|
||||
if !generic_params.is_empty() {
|
||||
w!(p, "<");
|
||||
let mut first = true;
|
||||
for (_i, param) in generic_params.iter_lt() {
|
||||
if !first {
|
||||
w!(p, ", ");
|
||||
}
|
||||
first = false;
|
||||
w!(p, "{}", param.name.display(db.upcast(), p.edition));
|
||||
}
|
||||
for (i, param) in generic_params.iter_type_or_consts() {
|
||||
if !first {
|
||||
w!(p, ", ");
|
||||
}
|
||||
first = false;
|
||||
if let Some(const_param) = param.const_param() {
|
||||
w!(p, "const {}: ", const_param.name.display(db.upcast(), p.edition));
|
||||
p.print_type_ref(const_param.ty);
|
||||
if let Some(default) = const_param.default {
|
||||
w!(p, " = ");
|
||||
p.print_expr(default.expr);
|
||||
}
|
||||
}
|
||||
if let Some(type_param) = param.type_param() {
|
||||
match &type_param.name {
|
||||
Some(name) => w!(p, "{}", name.display(db.upcast(), p.edition)),
|
||||
None => w!(p, "Param[{}]", i.into_raw()),
|
||||
}
|
||||
if let Some(default) = type_param.default {
|
||||
w!(p, " = ");
|
||||
p.print_type_ref(default);
|
||||
}
|
||||
}
|
||||
}
|
||||
w!(p, ">");
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn print_expr_hir(
|
||||
db: &dyn DefDatabase,
|
||||
store: &ExpressionStore,
|
||||
_owner: DefWithBodyId,
|
||||
|
|
@ -117,7 +365,7 @@ pub(super) fn print_expr_hir(
|
|||
p.buf
|
||||
}
|
||||
|
||||
pub(super) fn print_pat_hir(
|
||||
pub(crate) fn print_pat_hir(
|
||||
db: &dyn DefDatabase,
|
||||
store: &ExpressionStore,
|
||||
_owner: DefWithBodyId,
|
||||
|
|
@ -137,21 +385,6 @@ pub(super) fn print_pat_hir(
|
|||
p.buf
|
||||
}
|
||||
|
||||
macro_rules! w {
|
||||
($dst:expr, $($arg:tt)*) => {
|
||||
{ let _ = write!($dst, $($arg)*); }
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! wln {
|
||||
($dst:expr) => {
|
||||
{ $dst.newline(); }
|
||||
};
|
||||
($dst:expr, $($arg:tt)*) => {
|
||||
{ let _ = w!($dst, $($arg)*); $dst.newline(); }
|
||||
};
|
||||
}
|
||||
|
||||
struct Printer<'a> {
|
||||
db: &'a dyn DefDatabase,
|
||||
store: &'a ExpressionStore,
|
||||
|
|
@ -238,7 +471,7 @@ impl Printer<'_> {
|
|||
Expr::InlineAsm(_) => w!(self, "builtin#asm(_)"),
|
||||
Expr::OffsetOf(offset_of) => {
|
||||
w!(self, "builtin#offset_of(");
|
||||
self.print_type_ref(offset_of.container, &self.store.types);
|
||||
self.print_type_ref(offset_of.container);
|
||||
let edition = self.edition;
|
||||
w!(
|
||||
self,
|
||||
|
|
@ -291,8 +524,7 @@ impl Printer<'_> {
|
|||
w!(self, ".{}", method_name.display(self.db.upcast(), self.edition));
|
||||
if let Some(args) = generic_args {
|
||||
w!(self, "::<");
|
||||
let edition = self.edition;
|
||||
print_generic_args(self.db, args, &self.store.types, self, edition).unwrap();
|
||||
self.print_generic_args(args);
|
||||
w!(self, ">");
|
||||
}
|
||||
w!(self, "(");
|
||||
|
|
@ -401,7 +633,7 @@ impl Printer<'_> {
|
|||
Expr::Cast { expr, type_ref } => {
|
||||
self.print_expr(*expr);
|
||||
w!(self, " as ");
|
||||
self.print_type_ref(*type_ref, &self.store.types);
|
||||
self.print_type_ref(*type_ref);
|
||||
}
|
||||
Expr::Ref { expr, rawness, mutability } => {
|
||||
w!(self, "&");
|
||||
|
|
@ -489,13 +721,13 @@ impl Printer<'_> {
|
|||
self.print_pat(*pat);
|
||||
if let Some(ty) = ty {
|
||||
w!(self, ": ");
|
||||
self.print_type_ref(*ty, &self.store.types);
|
||||
self.print_type_ref(*ty);
|
||||
}
|
||||
}
|
||||
w!(self, "|");
|
||||
if let Some(ret_ty) = ret_type {
|
||||
w!(self, " -> ");
|
||||
self.print_type_ref(*ret_ty, &self.store.types);
|
||||
self.print_type_ref(*ret_ty);
|
||||
}
|
||||
self.whitespace();
|
||||
self.print_expr(*body);
|
||||
|
|
@ -731,7 +963,7 @@ impl Printer<'_> {
|
|||
self.print_pat(*pat);
|
||||
if let Some(ty) = type_ref {
|
||||
w!(self, ": ");
|
||||
self.print_type_ref(*ty, &self.store.types);
|
||||
self.print_type_ref(*ty);
|
||||
}
|
||||
if let Some(init) = initializer {
|
||||
w!(self, " = ");
|
||||
|
|
@ -782,16 +1014,6 @@ impl Printer<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
fn print_type_ref(&mut self, ty: TypeRefId, map: &TypesMap) {
|
||||
let edition = self.edition;
|
||||
print_type_ref(self.db, ty, map, self, edition).unwrap();
|
||||
}
|
||||
|
||||
fn print_path(&mut self, path: &Path) {
|
||||
let edition = self.edition;
|
||||
print_path(self.db, path, &self.store.types, self, edition).unwrap();
|
||||
}
|
||||
|
||||
fn print_binding(&mut self, id: BindingId) {
|
||||
let Binding { name, mode, .. } = &self.store.bindings[id];
|
||||
let mode = match mode {
|
||||
|
|
@ -802,4 +1024,274 @@ impl Printer<'_> {
|
|||
};
|
||||
w!(self, "{}{}", mode, name.display(self.db.upcast(), self.edition));
|
||||
}
|
||||
|
||||
fn print_path(&mut self, path: &Path) {
|
||||
if let Path::LangItem(it, s) = path {
|
||||
w!(self, "builtin#lang(");
|
||||
macro_rules! write_name {
|
||||
($it:ident) => {{
|
||||
let loc = $it.lookup(self.db);
|
||||
let tree = loc.item_tree_id().item_tree(self.db);
|
||||
let name = &tree[loc.id.value].name;
|
||||
w!(self, "{}", name.display(self.db.upcast(), self.edition));
|
||||
}};
|
||||
}
|
||||
match *it {
|
||||
LangItemTarget::ImplDef(it) => w!(self, "{it:?}"),
|
||||
LangItemTarget::EnumId(it) => write_name!(it),
|
||||
LangItemTarget::Function(it) => write_name!(it),
|
||||
LangItemTarget::Static(it) => write_name!(it),
|
||||
LangItemTarget::Struct(it) => write_name!(it),
|
||||
LangItemTarget::Union(it) => write_name!(it),
|
||||
LangItemTarget::TypeAlias(it) => write_name!(it),
|
||||
LangItemTarget::Trait(it) => write_name!(it),
|
||||
LangItemTarget::EnumVariant(it) => write_name!(it),
|
||||
}
|
||||
|
||||
if let Some(s) = s {
|
||||
w!(self, "::{}", s.display(self.db.upcast(), self.edition));
|
||||
}
|
||||
return w!(self, ")");
|
||||
}
|
||||
match path.type_anchor() {
|
||||
Some(anchor) => {
|
||||
w!(self, "<");
|
||||
self.print_type_ref(anchor);
|
||||
w!(self, ">::");
|
||||
}
|
||||
None => match path.kind() {
|
||||
PathKind::Plain => {}
|
||||
&PathKind::SELF => w!(self, "self"),
|
||||
PathKind::Super(n) => {
|
||||
for i in 0..*n {
|
||||
if i == 0 {
|
||||
w!(self, "super");
|
||||
} else {
|
||||
w!(self, "::super");
|
||||
}
|
||||
}
|
||||
}
|
||||
PathKind::Crate => w!(self, "crate"),
|
||||
PathKind::Abs => {}
|
||||
PathKind::DollarCrate(krate) => w!(
|
||||
self,
|
||||
"{}",
|
||||
krate
|
||||
.extra_data(self.db)
|
||||
.display_name
|
||||
.as_ref()
|
||||
.map(|it| it.crate_name().symbol().as_str())
|
||||
.unwrap_or("$crate")
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
for (i, segment) in path.segments().iter().enumerate() {
|
||||
if i != 0 || !matches!(path.kind(), PathKind::Plain) {
|
||||
w!(self, "::");
|
||||
}
|
||||
|
||||
w!(self, "{}", segment.name.display(self.db.upcast(), self.edition));
|
||||
if let Some(generics) = segment.args_and_bindings {
|
||||
w!(self, "::<");
|
||||
self.print_generic_args(generics);
|
||||
|
||||
w!(self, ">");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn print_generic_args(&mut self, generics: &GenericArgs) {
|
||||
let mut first = true;
|
||||
let args = if generics.has_self_type {
|
||||
let (self_ty, args) = generics.args.split_first().unwrap();
|
||||
w!(self, "Self=");
|
||||
self.print_generic_arg(self_ty);
|
||||
first = false;
|
||||
args
|
||||
} else {
|
||||
&generics.args
|
||||
};
|
||||
for arg in args {
|
||||
if !first {
|
||||
w!(self, ", ");
|
||||
}
|
||||
first = false;
|
||||
self.print_generic_arg(arg);
|
||||
}
|
||||
for binding in generics.bindings.iter() {
|
||||
if !first {
|
||||
w!(self, ", ");
|
||||
}
|
||||
first = false;
|
||||
w!(self, "{}", binding.name.display(self.db.upcast(), self.edition));
|
||||
if !binding.bounds.is_empty() {
|
||||
w!(self, ": ");
|
||||
self.print_type_bounds(&binding.bounds);
|
||||
}
|
||||
if let Some(ty) = binding.type_ref {
|
||||
w!(self, " = ");
|
||||
self.print_type_ref(ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn print_generic_arg(&mut self, arg: &GenericArg) {
|
||||
match arg {
|
||||
GenericArg::Type(ty) => self.print_type_ref(*ty),
|
||||
GenericArg::Const(ConstRef { expr }) => self.print_expr(*expr),
|
||||
GenericArg::Lifetime(lt) => {
|
||||
w!(self, "{}", lt.name.display(self.db.upcast(), self.edition))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn print_type_param(&mut self, param: TypeParamId) {
|
||||
let generic_params = self.db.generic_params(param.parent());
|
||||
|
||||
match generic_params[param.local_id()].name() {
|
||||
Some(name) => w!(self, "{}", name.display(self.db.upcast(), self.edition)),
|
||||
None => w!(self, "Param[{}]", param.local_id().into_raw()),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn print_type_ref(&mut self, type_ref: TypeRefId) {
|
||||
// FIXME: deduplicate with `HirDisplay` impl
|
||||
match &self.store[type_ref] {
|
||||
TypeRef::Never => w!(self, "!"),
|
||||
&TypeRef::TypeParam(p) => self.print_type_param(p),
|
||||
TypeRef::Placeholder => w!(self, "_"),
|
||||
TypeRef::Tuple(fields) => {
|
||||
w!(self, "(");
|
||||
for (i, field) in fields.iter().enumerate() {
|
||||
if i != 0 {
|
||||
w!(self, ", ");
|
||||
}
|
||||
self.print_type_ref(*field);
|
||||
}
|
||||
w!(self, ")");
|
||||
}
|
||||
TypeRef::Path(path) => self.print_path(path),
|
||||
TypeRef::RawPtr(pointee, mtbl) => {
|
||||
let mtbl = match mtbl {
|
||||
Mutability::Shared => "*const",
|
||||
Mutability::Mut => "*mut",
|
||||
};
|
||||
w!(self, "{mtbl} ");
|
||||
self.print_type_ref(*pointee);
|
||||
}
|
||||
TypeRef::Reference(ref_) => {
|
||||
let mtbl = match ref_.mutability {
|
||||
Mutability::Shared => "",
|
||||
Mutability::Mut => "mut ",
|
||||
};
|
||||
w!(self, "&");
|
||||
if let Some(lt) = &ref_.lifetime {
|
||||
w!(self, "{} ", lt.name.display(self.db.upcast(), self.edition));
|
||||
}
|
||||
w!(self, "{mtbl}");
|
||||
self.print_type_ref(ref_.ty);
|
||||
}
|
||||
TypeRef::Array(array) => {
|
||||
w!(self, "[");
|
||||
self.print_type_ref(array.ty);
|
||||
w!(self, "; ");
|
||||
self.print_generic_arg(&GenericArg::Const(array.len));
|
||||
w!(self, "]");
|
||||
}
|
||||
TypeRef::Slice(elem) => {
|
||||
w!(self, "[");
|
||||
self.print_type_ref(*elem);
|
||||
w!(self, "]");
|
||||
}
|
||||
TypeRef::Fn(fn_) => {
|
||||
let ((_, return_type), args) =
|
||||
fn_.params.split_last().expect("TypeRef::Fn is missing return type");
|
||||
if fn_.is_unsafe {
|
||||
w!(self, "unsafe ");
|
||||
}
|
||||
if let Some(abi) = &fn_.abi {
|
||||
w!(self, "extern ");
|
||||
w!(self, "{}", abi.as_str());
|
||||
w!(self, " ");
|
||||
}
|
||||
w!(self, "fn(");
|
||||
for (i, (_, typeref)) in args.iter().enumerate() {
|
||||
if i != 0 {
|
||||
w!(self, ", ");
|
||||
}
|
||||
self.print_type_ref(*typeref);
|
||||
}
|
||||
if fn_.is_varargs {
|
||||
if !args.is_empty() {
|
||||
w!(self, ", ");
|
||||
}
|
||||
w!(self, "...");
|
||||
}
|
||||
w!(self, ") -> ");
|
||||
self.print_type_ref(*return_type);
|
||||
}
|
||||
TypeRef::Error => w!(self, "{{error}}"),
|
||||
TypeRef::ImplTrait(bounds) => {
|
||||
w!(self, "impl ");
|
||||
self.print_type_bounds(bounds);
|
||||
}
|
||||
TypeRef::DynTrait(bounds) => {
|
||||
w!(self, "dyn ");
|
||||
self.print_type_bounds(bounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn print_type_bounds(&mut self, bounds: &[TypeBound]) {
|
||||
for (i, bound) in bounds.iter().enumerate() {
|
||||
if i != 0 {
|
||||
w!(self, " + ");
|
||||
}
|
||||
|
||||
match bound {
|
||||
TypeBound::Path(path, modifier) => {
|
||||
match modifier {
|
||||
TraitBoundModifier::None => (),
|
||||
TraitBoundModifier::Maybe => w!(self, "?"),
|
||||
}
|
||||
self.print_path(&self.store[*path]);
|
||||
}
|
||||
TypeBound::ForLifetime(lifetimes, path) => {
|
||||
w!(
|
||||
self,
|
||||
"for<{}> ",
|
||||
lifetimes
|
||||
.iter()
|
||||
.map(|it| it.display(self.db.upcast(), self.edition))
|
||||
.format(", ")
|
||||
.to_string()
|
||||
);
|
||||
self.print_path(&self.store[*path]);
|
||||
}
|
||||
TypeBound::Lifetime(lt) => {
|
||||
w!(self, "{}", lt.name.display(self.db.upcast(), self.edition))
|
||||
}
|
||||
TypeBound::Use(args) => {
|
||||
w!(self, "use<");
|
||||
let mut first = true;
|
||||
for arg in args {
|
||||
if !mem::take(&mut first) {
|
||||
w!(self, ", ");
|
||||
}
|
||||
match arg {
|
||||
UseArgRef::Name(it) => {
|
||||
w!(self, "{}", it.display(self.db.upcast(), self.edition))
|
||||
}
|
||||
UseArgRef::Lifetime(it) => {
|
||||
w!(self, "{}", it.name.display(self.db.upcast(), self.edition))
|
||||
}
|
||||
}
|
||||
}
|
||||
w!(self, ">")
|
||||
}
|
||||
TypeBound::Error => w!(self, "{{unknown}}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use la_arena::{Arena, ArenaMap, Idx, IdxRange, RawIdx};
|
|||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
BlockId, ConstBlockId, DefWithBodyId,
|
||||
BlockId, DefWithBodyId,
|
||||
db::DefDatabase,
|
||||
expr_store::{Body, ExpressionStore, HygieneId},
|
||||
hir::{Binding, BindingId, Expr, ExprId, Item, LabelId, Pat, PatId, Statement},
|
||||
|
|
@ -53,9 +53,7 @@ pub struct ScopeData {
|
|||
impl ExprScopes {
|
||||
pub(crate) fn expr_scopes_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<ExprScopes> {
|
||||
let body = db.body(def);
|
||||
let mut scopes = ExprScopes::new_body(&body, |const_block| {
|
||||
db.lookup_intern_anonymous_const(const_block).root
|
||||
});
|
||||
let mut scopes = ExprScopes::new_body(&body);
|
||||
scopes.shrink_to_fit();
|
||||
Arc::new(scopes)
|
||||
}
|
||||
|
|
@ -104,10 +102,7 @@ fn empty_entries(idx: usize) -> IdxRange<ScopeEntry> {
|
|||
}
|
||||
|
||||
impl ExprScopes {
|
||||
fn new_body(
|
||||
body: &Body,
|
||||
resolve_const_block: impl (Fn(ConstBlockId) -> ExprId) + Copy,
|
||||
) -> ExprScopes {
|
||||
fn new_body(body: &Body) -> ExprScopes {
|
||||
let mut scopes = ExprScopes {
|
||||
scopes: Arena::default(),
|
||||
scope_entries: Arena::default(),
|
||||
|
|
@ -118,7 +113,7 @@ impl ExprScopes {
|
|||
scopes.add_bindings(body, root, self_param, body.binding_hygiene(self_param));
|
||||
}
|
||||
scopes.add_params_bindings(body, root, &body.params);
|
||||
compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root, resolve_const_block);
|
||||
compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root);
|
||||
scopes
|
||||
}
|
||||
|
||||
|
|
@ -221,23 +216,22 @@ fn compute_block_scopes(
|
|||
store: &ExpressionStore,
|
||||
scopes: &mut ExprScopes,
|
||||
scope: &mut ScopeId,
|
||||
resolve_const_block: impl (Fn(ConstBlockId) -> ExprId) + Copy,
|
||||
) {
|
||||
for stmt in statements {
|
||||
match stmt {
|
||||
Statement::Let { pat, initializer, else_branch, .. } => {
|
||||
if let Some(expr) = initializer {
|
||||
compute_expr_scopes(*expr, store, scopes, scope, resolve_const_block);
|
||||
compute_expr_scopes(*expr, store, scopes, scope);
|
||||
}
|
||||
if let Some(expr) = else_branch {
|
||||
compute_expr_scopes(*expr, store, scopes, scope, resolve_const_block);
|
||||
compute_expr_scopes(*expr, store, scopes, scope);
|
||||
}
|
||||
|
||||
*scope = scopes.new_scope(*scope);
|
||||
scopes.add_pat_bindings(store, *scope, *pat);
|
||||
}
|
||||
Statement::Expr { expr, .. } => {
|
||||
compute_expr_scopes(*expr, store, scopes, scope, resolve_const_block);
|
||||
compute_expr_scopes(*expr, store, scopes, scope);
|
||||
}
|
||||
Statement::Item(Item::MacroDef(macro_id)) => {
|
||||
*scope = scopes.new_macro_def_scope(*scope, macro_id.clone());
|
||||
|
|
@ -246,7 +240,7 @@ fn compute_block_scopes(
|
|||
}
|
||||
}
|
||||
if let Some(expr) = tail {
|
||||
compute_expr_scopes(expr, store, scopes, scope, resolve_const_block);
|
||||
compute_expr_scopes(expr, store, scopes, scope);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -255,13 +249,12 @@ fn compute_expr_scopes(
|
|||
store: &ExpressionStore,
|
||||
scopes: &mut ExprScopes,
|
||||
scope: &mut ScopeId,
|
||||
resolve_const_block: impl (Fn(ConstBlockId) -> ExprId) + Copy,
|
||||
) {
|
||||
let make_label =
|
||||
|label: &Option<LabelId>| label.map(|label| (label, store.labels[label].name.clone()));
|
||||
|
||||
let compute_expr_scopes = |scopes: &mut ExprScopes, expr: ExprId, scope: &mut ScopeId| {
|
||||
compute_expr_scopes(expr, store, scopes, scope, resolve_const_block)
|
||||
compute_expr_scopes(expr, store, scopes, scope)
|
||||
};
|
||||
|
||||
scopes.set_scope(expr, *scope);
|
||||
|
|
@ -271,18 +264,18 @@ fn compute_expr_scopes(
|
|||
// Overwrite the old scope for the block expr, so that every block scope can be found
|
||||
// via the block itself (important for blocks that only contain items, no expressions).
|
||||
scopes.set_scope(expr, scope);
|
||||
compute_block_scopes(statements, *tail, store, scopes, &mut scope, resolve_const_block);
|
||||
compute_block_scopes(statements, *tail, store, scopes, &mut scope);
|
||||
}
|
||||
Expr::Const(id) => {
|
||||
let mut scope = scopes.root_scope();
|
||||
compute_expr_scopes(scopes, resolve_const_block(*id), &mut scope);
|
||||
compute_expr_scopes(scopes, *id, &mut scope);
|
||||
}
|
||||
Expr::Unsafe { id, statements, tail } | Expr::Async { id, statements, tail } => {
|
||||
let mut scope = scopes.new_block_scope(*scope, *id, None);
|
||||
// Overwrite the old scope for the block expr, so that every block scope can be found
|
||||
// via the block itself (important for blocks that only contain items, no expressions).
|
||||
scopes.set_scope(expr, scope);
|
||||
compute_block_scopes(statements, *tail, store, scopes, &mut scope, resolve_const_block);
|
||||
compute_block_scopes(statements, *tail, store, scopes, &mut scope);
|
||||
}
|
||||
Expr::Loop { body: body_expr, label } => {
|
||||
let mut scope = scopes.new_labeled_scope(*scope, make_label(label));
|
||||
|
|
|
|||
|
|
@ -1,503 +1,2 @@
|
|||
mod block;
|
||||
|
||||
use crate::{ModuleDefId, hir::MatchArm, test_db::TestDB};
|
||||
use expect_test::{Expect, expect};
|
||||
use la_arena::RawIdx;
|
||||
use test_fixture::WithFixture;
|
||||
|
||||
use super::*;
|
||||
|
||||
fn lower(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (TestDB, Arc<Body>, DefWithBodyId) {
|
||||
let db = TestDB::with_files(ra_fixture);
|
||||
|
||||
let krate = db.fetch_test_crate();
|
||||
let def_map = db.crate_def_map(krate);
|
||||
let mut fn_def = None;
|
||||
'outer: for (_, module) in def_map.modules() {
|
||||
for decl in module.scope.declarations() {
|
||||
if let ModuleDefId::FunctionId(it) = decl {
|
||||
fn_def = Some(it);
|
||||
break 'outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
let fn_def = fn_def.unwrap().into();
|
||||
|
||||
let body = db.body(fn_def);
|
||||
(db, body, fn_def)
|
||||
}
|
||||
|
||||
fn def_map_at(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String {
|
||||
let (db, position) = TestDB::with_position(ra_fixture);
|
||||
|
||||
let module = db.module_at_position(position);
|
||||
module.def_map(&db).dump(&db)
|
||||
}
|
||||
|
||||
fn check_block_scopes_at(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
|
||||
let (db, position) = TestDB::with_position(ra_fixture);
|
||||
|
||||
let module = db.module_at_position(position);
|
||||
let actual = module.def_map(&db).dump_block_scopes(&db);
|
||||
expect.assert_eq(&actual);
|
||||
}
|
||||
|
||||
fn check_at(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
|
||||
let actual = def_map_at(ra_fixture);
|
||||
expect.assert_eq(&actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn your_stack_belongs_to_me() {
|
||||
cov_mark::check!(your_stack_belongs_to_me);
|
||||
lower(
|
||||
r#"
|
||||
#![recursion_limit = "32"]
|
||||
macro_rules! n_nuple {
|
||||
($e:tt) => ();
|
||||
($($rest:tt)*) => {{
|
||||
(n_nuple!($($rest)*)None,)
|
||||
}};
|
||||
}
|
||||
fn main() { n_nuple!(1,2,3); }
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn your_stack_belongs_to_me2() {
|
||||
cov_mark::check!(overflow_but_not_me);
|
||||
lower(
|
||||
r#"
|
||||
#![recursion_limit = "32"]
|
||||
macro_rules! foo {
|
||||
() => {{ foo!(); foo!(); }}
|
||||
}
|
||||
fn main() { foo!(); }
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recursion_limit() {
|
||||
lower(
|
||||
r#"
|
||||
#![recursion_limit = "2"]
|
||||
macro_rules! n_nuple {
|
||||
($e:tt) => ();
|
||||
($first:tt $($rest:tt)*) => {{
|
||||
n_nuple!($($rest)*)
|
||||
}};
|
||||
}
|
||||
fn main() { n_nuple!(1,2,3); }
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_3642_bad_macro_stackover() {
|
||||
lower(
|
||||
r#"
|
||||
#[macro_export]
|
||||
macro_rules! match_ast {
|
||||
(match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
|
||||
|
||||
(match ($node:expr) {
|
||||
$( ast::$ast:ident($it:ident) => $res:expr, )*
|
||||
_ => $catch_all:expr $(,)?
|
||||
}) => {{
|
||||
$( if let Some($it) = ast::$ast::cast($node.clone()) { $res } else )*
|
||||
{ $catch_all }
|
||||
}};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let anchor = match_ast! {
|
||||
match parent {
|
||||
as => {},
|
||||
_ => return None
|
||||
}
|
||||
};
|
||||
}"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn macro_resolve() {
|
||||
// Regression test for a path resolution bug introduced with inner item handling.
|
||||
lower(
|
||||
r#"
|
||||
macro_rules! vec {
|
||||
() => { () };
|
||||
($elem:expr; $n:expr) => { () };
|
||||
($($x:expr),+ $(,)?) => { () };
|
||||
}
|
||||
mod m {
|
||||
fn outer() {
|
||||
let _ = vec![FileSet::default(); self.len()];
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn desugar_for_loop() {
|
||||
let (db, body, def) = lower(
|
||||
r#"
|
||||
//- minicore: iterator
|
||||
fn main() {
|
||||
for ident in 0..10 {
|
||||
foo();
|
||||
bar()
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
||||
expect![[r#"
|
||||
fn main() -> () {
|
||||
match builtin#lang(into_iter)(
|
||||
(0) ..(10) ,
|
||||
) {
|
||||
mut <ra@gennew>11 => loop {
|
||||
match builtin#lang(next)(
|
||||
&mut <ra@gennew>11,
|
||||
) {
|
||||
builtin#lang(None) => break,
|
||||
builtin#lang(Some)(ident) => {
|
||||
foo();
|
||||
bar()
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
}"#]]
|
||||
.assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn desugar_builtin_format_args() {
|
||||
let (db, body, def) = lower(
|
||||
r#"
|
||||
//- minicore: fmt
|
||||
fn main() {
|
||||
let are = "are";
|
||||
let count = 10;
|
||||
builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", last = "!");
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
||||
expect![[r#"
|
||||
fn main() -> () {
|
||||
let are = "are";
|
||||
let count = 10;
|
||||
builtin#lang(Arguments::new_v1_formatted)(
|
||||
&[
|
||||
"\u{1b}hello ", " ", " friends, we ", " ", "",
|
||||
],
|
||||
&[
|
||||
builtin#lang(Argument::new_display)(
|
||||
&count,
|
||||
), builtin#lang(Argument::new_display)(
|
||||
&"fancy",
|
||||
), builtin#lang(Argument::new_debug)(
|
||||
&are,
|
||||
), builtin#lang(Argument::new_display)(
|
||||
&"!",
|
||||
),
|
||||
],
|
||||
&[
|
||||
builtin#lang(Placeholder::new)(
|
||||
0usize,
|
||||
' ',
|
||||
builtin#lang(Alignment::Unknown),
|
||||
8u32,
|
||||
builtin#lang(Count::Implied),
|
||||
builtin#lang(Count::Is)(
|
||||
2,
|
||||
),
|
||||
), builtin#lang(Placeholder::new)(
|
||||
1usize,
|
||||
' ',
|
||||
builtin#lang(Alignment::Unknown),
|
||||
0u32,
|
||||
builtin#lang(Count::Implied),
|
||||
builtin#lang(Count::Implied),
|
||||
), builtin#lang(Placeholder::new)(
|
||||
2usize,
|
||||
' ',
|
||||
builtin#lang(Alignment::Unknown),
|
||||
0u32,
|
||||
builtin#lang(Count::Implied),
|
||||
builtin#lang(Count::Implied),
|
||||
), builtin#lang(Placeholder::new)(
|
||||
1usize,
|
||||
' ',
|
||||
builtin#lang(Alignment::Unknown),
|
||||
0u32,
|
||||
builtin#lang(Count::Implied),
|
||||
builtin#lang(Count::Implied),
|
||||
), builtin#lang(Placeholder::new)(
|
||||
3usize,
|
||||
' ',
|
||||
builtin#lang(Alignment::Unknown),
|
||||
0u32,
|
||||
builtin#lang(Count::Implied),
|
||||
builtin#lang(Count::Implied),
|
||||
),
|
||||
],
|
||||
unsafe {
|
||||
builtin#lang(UnsafeArg::new)()
|
||||
},
|
||||
);
|
||||
}"#]]
|
||||
.assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_macro_hygiene() {
|
||||
let (db, body, def) = lower(
|
||||
r##"
|
||||
//- minicore: fmt, from
|
||||
//- /main.rs
|
||||
mod error;
|
||||
|
||||
use crate::error::error;
|
||||
|
||||
fn main() {
|
||||
// _ = forces body expansion instead of block def map expansion
|
||||
_ = error!("Failed to resolve path `{}`", node.text());
|
||||
}
|
||||
//- /error.rs
|
||||
macro_rules! _error {
|
||||
($fmt:expr, $($arg:tt)+) => {$crate::error::intermediate!(format_args!($fmt, $($arg)+))}
|
||||
}
|
||||
pub(crate) use _error as error;
|
||||
macro_rules! _intermediate {
|
||||
($arg:expr) => {$crate::error::SsrError::new($arg)}
|
||||
}
|
||||
pub(crate) use _intermediate as intermediate;
|
||||
|
||||
pub struct SsrError(pub(crate) core::fmt::Arguments);
|
||||
|
||||
impl SsrError {
|
||||
pub(crate) fn new(message: impl Into<core::fmt::Arguments>) -> SsrError {
|
||||
SsrError(message.into())
|
||||
}
|
||||
}
|
||||
"##,
|
||||
);
|
||||
|
||||
assert_eq!(db.body_with_source_map(def).1.diagnostics(), &[]);
|
||||
expect![[r#"
|
||||
fn main() -> () {
|
||||
_ = ra_test_fixture::error::SsrError::new(
|
||||
builtin#lang(Arguments::new_v1_formatted)(
|
||||
&[
|
||||
"Failed to resolve path `", "`",
|
||||
],
|
||||
&[
|
||||
builtin#lang(Argument::new_display)(
|
||||
&node.text(),
|
||||
),
|
||||
],
|
||||
&[
|
||||
builtin#lang(Placeholder::new)(
|
||||
0usize,
|
||||
' ',
|
||||
builtin#lang(Alignment::Unknown),
|
||||
0u32,
|
||||
builtin#lang(Count::Implied),
|
||||
builtin#lang(Count::Implied),
|
||||
),
|
||||
],
|
||||
unsafe {
|
||||
builtin#lang(UnsafeArg::new)()
|
||||
},
|
||||
),
|
||||
);
|
||||
}"#]]
|
||||
.assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn regression_10300() {
|
||||
let (db, body, def) = lower(
|
||||
r#"
|
||||
//- minicore: concat, panic
|
||||
mod private {
|
||||
pub use core::concat;
|
||||
}
|
||||
|
||||
macro_rules! m {
|
||||
() => {
|
||||
panic!(concat!($crate::private::concat!("cc")));
|
||||
};
|
||||
}
|
||||
|
||||
fn f(a: i32, b: u32) -> String {
|
||||
m!();
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
||||
let (_, source_map) = db.body_with_source_map(def);
|
||||
assert_eq!(source_map.diagnostics(), &[]);
|
||||
|
||||
for (_, def_map) in body.blocks(&db) {
|
||||
assert_eq!(def_map.diagnostics(), &[]);
|
||||
}
|
||||
|
||||
expect![[r#"
|
||||
fn f(a: i32, b: u32) -> String {
|
||||
{
|
||||
core::panicking::panic_fmt(
|
||||
builtin#lang(Arguments::new_v1_formatted)(
|
||||
&[
|
||||
"cc",
|
||||
],
|
||||
&[],
|
||||
&[],
|
||||
unsafe {
|
||||
builtin#lang(UnsafeArg::new)()
|
||||
},
|
||||
),
|
||||
);
|
||||
};
|
||||
}"#]]
|
||||
.assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn destructuring_assignment_tuple_macro() {
|
||||
// This is a funny one. `let m!()() = Bar()` is an error in rustc, because `m!()()` isn't a valid pattern,
|
||||
// but in destructuring assignment it is valid, because `m!()()` is a valid expression, and destructuring
|
||||
// assignments start their lives as expressions. So we have to do the same.
|
||||
|
||||
let (db, body, def) = lower(
|
||||
r#"
|
||||
struct Bar();
|
||||
|
||||
macro_rules! m {
|
||||
() => { Bar };
|
||||
}
|
||||
|
||||
fn foo() {
|
||||
m!()() = Bar();
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
||||
let (_, source_map) = db.body_with_source_map(def);
|
||||
assert_eq!(source_map.diagnostics(), &[]);
|
||||
|
||||
for (_, def_map) in body.blocks(&db) {
|
||||
assert_eq!(def_map.diagnostics(), &[]);
|
||||
}
|
||||
|
||||
expect![[r#"
|
||||
fn foo() -> () {
|
||||
Bar() = Bar();
|
||||
}"#]]
|
||||
.assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shadowing_record_variant() {
|
||||
let (_, body, _) = lower(
|
||||
r#"
|
||||
enum A {
|
||||
B { field: i32 },
|
||||
}
|
||||
fn f() {
|
||||
use A::*;
|
||||
match () {
|
||||
B => {}
|
||||
};
|
||||
}
|
||||
"#,
|
||||
);
|
||||
assert_eq!(body.bindings.len(), 1, "should have a binding for `B`");
|
||||
assert_eq!(
|
||||
body.bindings[BindingId::from_raw(RawIdx::from_u32(0))].name.as_str(),
|
||||
"B",
|
||||
"should have a binding for `B`",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn regression_pretty_print_bind_pat() {
|
||||
let (db, body, owner) = lower(
|
||||
r#"
|
||||
fn foo() {
|
||||
let v @ u = 123;
|
||||
}
|
||||
"#,
|
||||
);
|
||||
let printed = body.pretty_print(&db, owner, Edition::CURRENT);
|
||||
assert_eq!(
|
||||
printed,
|
||||
r#"fn foo() -> () {
|
||||
let v @ u = 123;
|
||||
}"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn skip_skips_body() {
|
||||
let (db, body, owner) = lower(
|
||||
r#"
|
||||
#[rust_analyzer::skip]
|
||||
async fn foo(a: (), b: i32) -> u32 {
|
||||
0 + 1 + b()
|
||||
}
|
||||
"#,
|
||||
);
|
||||
let printed = body.pretty_print(&db, owner, Edition::CURRENT);
|
||||
expect!["fn foo(<28>: (), <20>: i32) -> impl ::core::future::Future::<Output = u32> <20>"]
|
||||
.assert_eq(&printed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn range_bounds_are_hir_exprs() {
|
||||
let (_, body, _) = lower(
|
||||
r#"
|
||||
pub const L: i32 = 6;
|
||||
mod x {
|
||||
pub const R: i32 = 100;
|
||||
}
|
||||
const fn f(x: i32) -> i32 {
|
||||
match x {
|
||||
-1..=5 => x * 10,
|
||||
L..=x::R => x * 100,
|
||||
_ => x,
|
||||
}
|
||||
}"#,
|
||||
);
|
||||
|
||||
let mtch_arms = body
|
||||
.exprs
|
||||
.iter()
|
||||
.find_map(|(_, expr)| {
|
||||
if let Expr::Match { arms, .. } = expr {
|
||||
return Some(arms);
|
||||
}
|
||||
|
||||
None
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let MatchArm { pat, .. } = mtch_arms[1];
|
||||
match body.pats[pat] {
|
||||
Pat::Range { start, end } => {
|
||||
let hir_start = &body.exprs[start.unwrap()];
|
||||
let hir_end = &body.exprs[end.unwrap()];
|
||||
|
||||
assert!(matches!(hir_start, Expr::Path { .. }));
|
||||
assert!(matches!(hir_end, Expr::Path { .. }));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
mod body;
|
||||
mod signatures;
|
||||
|
|
|
|||
502
crates/hir-def/src/expr_store/tests/body.rs
Normal file
502
crates/hir-def/src/expr_store/tests/body.rs
Normal file
|
|
@ -0,0 +1,502 @@
|
|||
mod block;
|
||||
|
||||
use crate::{DefWithBodyId, ModuleDefId, hir::MatchArm, test_db::TestDB};
|
||||
use expect_test::{Expect, expect};
|
||||
use la_arena::RawIdx;
|
||||
use test_fixture::WithFixture;
|
||||
|
||||
use super::super::*;
|
||||
|
||||
fn lower(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (TestDB, Arc<Body>, DefWithBodyId) {
|
||||
let db = TestDB::with_files(ra_fixture);
|
||||
|
||||
let krate = db.fetch_test_crate();
|
||||
let def_map = db.crate_def_map(krate);
|
||||
let mut fn_def = None;
|
||||
'outer: for (_, module) in def_map.modules() {
|
||||
for decl in module.scope.declarations() {
|
||||
if let ModuleDefId::FunctionId(it) = decl {
|
||||
fn_def = Some(it);
|
||||
break 'outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
let fn_def = fn_def.unwrap().into();
|
||||
|
||||
let body = db.body(fn_def);
|
||||
(db, body, fn_def)
|
||||
}
|
||||
|
||||
fn def_map_at(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String {
|
||||
let (db, position) = TestDB::with_position(ra_fixture);
|
||||
|
||||
let module = db.module_at_position(position);
|
||||
module.def_map(&db).dump(&db)
|
||||
}
|
||||
|
||||
fn check_block_scopes_at(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
|
||||
let (db, position) = TestDB::with_position(ra_fixture);
|
||||
|
||||
let module = db.module_at_position(position);
|
||||
let actual = module.def_map(&db).dump_block_scopes(&db);
|
||||
expect.assert_eq(&actual);
|
||||
}
|
||||
|
||||
fn check_at(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
|
||||
let actual = def_map_at(ra_fixture);
|
||||
expect.assert_eq(&actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn your_stack_belongs_to_me() {
|
||||
cov_mark::check!(your_stack_belongs_to_me);
|
||||
lower(
|
||||
r#"
|
||||
#![recursion_limit = "32"]
|
||||
macro_rules! n_nuple {
|
||||
($e:tt) => ();
|
||||
($($rest:tt)*) => {{
|
||||
(n_nuple!($($rest)*)None,)
|
||||
}};
|
||||
}
|
||||
fn main() { n_nuple!(1,2,3); }
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn your_stack_belongs_to_me2() {
|
||||
cov_mark::check!(overflow_but_not_me);
|
||||
lower(
|
||||
r#"
|
||||
#![recursion_limit = "32"]
|
||||
macro_rules! foo {
|
||||
() => {{ foo!(); foo!(); }}
|
||||
}
|
||||
fn main() { foo!(); }
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recursion_limit() {
|
||||
lower(
|
||||
r#"
|
||||
#![recursion_limit = "2"]
|
||||
macro_rules! n_nuple {
|
||||
($e:tt) => ();
|
||||
($first:tt $($rest:tt)*) => {{
|
||||
n_nuple!($($rest)*)
|
||||
}};
|
||||
}
|
||||
fn main() { n_nuple!(1,2,3); }
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_3642_bad_macro_stackover() {
|
||||
lower(
|
||||
r#"
|
||||
#[macro_export]
|
||||
macro_rules! match_ast {
|
||||
(match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
|
||||
|
||||
(match ($node:expr) {
|
||||
$( ast::$ast:ident($it:ident) => $res:expr, )*
|
||||
_ => $catch_all:expr $(,)?
|
||||
}) => {{
|
||||
$( if let Some($it) = ast::$ast::cast($node.clone()) { $res } else )*
|
||||
{ $catch_all }
|
||||
}};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let anchor = match_ast! {
|
||||
match parent {
|
||||
as => {},
|
||||
_ => return None
|
||||
}
|
||||
};
|
||||
}"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn macro_resolve() {
|
||||
// Regression test for a path resolution bug introduced with inner item handling.
|
||||
lower(
|
||||
r#"
|
||||
macro_rules! vec {
|
||||
() => { () };
|
||||
($elem:expr; $n:expr) => { () };
|
||||
($($x:expr),+ $(,)?) => { () };
|
||||
}
|
||||
mod m {
|
||||
fn outer() {
|
||||
let _ = vec![FileSet::default(); self.len()];
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn desugar_for_loop() {
|
||||
let (db, body, def) = lower(
|
||||
r#"
|
||||
//- minicore: iterator
|
||||
fn main() {
|
||||
for ident in 0..10 {
|
||||
foo();
|
||||
bar()
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
||||
expect![[r#"
|
||||
fn main() {
|
||||
match builtin#lang(into_iter)(
|
||||
(0) ..(10) ,
|
||||
) {
|
||||
mut <ra@gennew>11 => loop {
|
||||
match builtin#lang(next)(
|
||||
&mut <ra@gennew>11,
|
||||
) {
|
||||
builtin#lang(None) => break,
|
||||
builtin#lang(Some)(ident) => {
|
||||
foo();
|
||||
bar()
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
}"#]]
|
||||
.assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn desugar_builtin_format_args() {
|
||||
let (db, body, def) = lower(
|
||||
r#"
|
||||
//- minicore: fmt
|
||||
fn main() {
|
||||
let are = "are";
|
||||
let count = 10;
|
||||
builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", last = "!");
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
||||
expect![[r#"
|
||||
fn main() {
|
||||
let are = "are";
|
||||
let count = 10;
|
||||
builtin#lang(Arguments::new_v1_formatted)(
|
||||
&[
|
||||
"\u{1b}hello ", " ", " friends, we ", " ", "",
|
||||
],
|
||||
&[
|
||||
builtin#lang(Argument::new_display)(
|
||||
&count,
|
||||
), builtin#lang(Argument::new_display)(
|
||||
&"fancy",
|
||||
), builtin#lang(Argument::new_debug)(
|
||||
&are,
|
||||
), builtin#lang(Argument::new_display)(
|
||||
&"!",
|
||||
),
|
||||
],
|
||||
&[
|
||||
builtin#lang(Placeholder::new)(
|
||||
0usize,
|
||||
' ',
|
||||
builtin#lang(Alignment::Unknown),
|
||||
8u32,
|
||||
builtin#lang(Count::Implied),
|
||||
builtin#lang(Count::Is)(
|
||||
2,
|
||||
),
|
||||
), builtin#lang(Placeholder::new)(
|
||||
1usize,
|
||||
' ',
|
||||
builtin#lang(Alignment::Unknown),
|
||||
0u32,
|
||||
builtin#lang(Count::Implied),
|
||||
builtin#lang(Count::Implied),
|
||||
), builtin#lang(Placeholder::new)(
|
||||
2usize,
|
||||
' ',
|
||||
builtin#lang(Alignment::Unknown),
|
||||
0u32,
|
||||
builtin#lang(Count::Implied),
|
||||
builtin#lang(Count::Implied),
|
||||
), builtin#lang(Placeholder::new)(
|
||||
1usize,
|
||||
' ',
|
||||
builtin#lang(Alignment::Unknown),
|
||||
0u32,
|
||||
builtin#lang(Count::Implied),
|
||||
builtin#lang(Count::Implied),
|
||||
), builtin#lang(Placeholder::new)(
|
||||
3usize,
|
||||
' ',
|
||||
builtin#lang(Alignment::Unknown),
|
||||
0u32,
|
||||
builtin#lang(Count::Implied),
|
||||
builtin#lang(Count::Implied),
|
||||
),
|
||||
],
|
||||
unsafe {
|
||||
builtin#lang(UnsafeArg::new)()
|
||||
},
|
||||
);
|
||||
}"#]]
|
||||
.assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_macro_hygiene() {
|
||||
let (db, body, def) = lower(
|
||||
r##"
|
||||
//- minicore: fmt, from
|
||||
//- /main.rs
|
||||
mod error;
|
||||
|
||||
use crate::error::error;
|
||||
|
||||
fn main() {
|
||||
// _ = forces body expansion instead of block def map expansion
|
||||
_ = error!("Failed to resolve path `{}`", node.text());
|
||||
}
|
||||
//- /error.rs
|
||||
macro_rules! _error {
|
||||
($fmt:expr, $($arg:tt)+) => {$crate::error::intermediate!(format_args!($fmt, $($arg)+))}
|
||||
}
|
||||
pub(crate) use _error as error;
|
||||
macro_rules! _intermediate {
|
||||
($arg:expr) => {$crate::error::SsrError::new($arg)}
|
||||
}
|
||||
pub(crate) use _intermediate as intermediate;
|
||||
|
||||
pub struct SsrError(pub(crate) core::fmt::Arguments);
|
||||
|
||||
impl SsrError {
|
||||
pub(crate) fn new(message: impl Into<core::fmt::Arguments>) -> SsrError {
|
||||
SsrError(message.into())
|
||||
}
|
||||
}
|
||||
"##,
|
||||
);
|
||||
|
||||
assert_eq!(db.body_with_source_map(def).1.diagnostics(), &[]);
|
||||
expect![[r#"
|
||||
fn main() {
|
||||
_ = ra_test_fixture::error::SsrError::new(
|
||||
builtin#lang(Arguments::new_v1_formatted)(
|
||||
&[
|
||||
"Failed to resolve path `", "`",
|
||||
],
|
||||
&[
|
||||
builtin#lang(Argument::new_display)(
|
||||
&node.text(),
|
||||
),
|
||||
],
|
||||
&[
|
||||
builtin#lang(Placeholder::new)(
|
||||
0usize,
|
||||
' ',
|
||||
builtin#lang(Alignment::Unknown),
|
||||
0u32,
|
||||
builtin#lang(Count::Implied),
|
||||
builtin#lang(Count::Implied),
|
||||
),
|
||||
],
|
||||
unsafe {
|
||||
builtin#lang(UnsafeArg::new)()
|
||||
},
|
||||
),
|
||||
);
|
||||
}"#]]
|
||||
.assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn regression_10300() {
|
||||
let (db, body, def) = lower(
|
||||
r#"
|
||||
//- minicore: concat, panic
|
||||
mod private {
|
||||
pub use core::concat;
|
||||
}
|
||||
|
||||
macro_rules! m {
|
||||
() => {
|
||||
panic!(concat!($crate::private::concat!("cc")));
|
||||
};
|
||||
}
|
||||
|
||||
fn f(a: i32, b: u32) -> String {
|
||||
m!();
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
||||
let (_, source_map) = db.body_with_source_map(def);
|
||||
assert_eq!(source_map.diagnostics(), &[]);
|
||||
|
||||
for (_, def_map) in body.blocks(&db) {
|
||||
assert_eq!(def_map.diagnostics(), &[]);
|
||||
}
|
||||
|
||||
expect![[r#"
|
||||
fn f(a, b) {
|
||||
{
|
||||
core::panicking::panic_fmt(
|
||||
builtin#lang(Arguments::new_v1_formatted)(
|
||||
&[
|
||||
"cc",
|
||||
],
|
||||
&[],
|
||||
&[],
|
||||
unsafe {
|
||||
builtin#lang(UnsafeArg::new)()
|
||||
},
|
||||
),
|
||||
);
|
||||
};
|
||||
}"#]]
|
||||
.assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn destructuring_assignment_tuple_macro() {
|
||||
// This is a funny one. `let m!()() = Bar()` is an error in rustc, because `m!()()` isn't a valid pattern,
|
||||
// but in destructuring assignment it is valid, because `m!()()` is a valid expression, and destructuring
|
||||
// assignments start their lives as expressions. So we have to do the same.
|
||||
|
||||
let (db, body, def) = lower(
|
||||
r#"
|
||||
struct Bar();
|
||||
|
||||
macro_rules! m {
|
||||
() => { Bar };
|
||||
}
|
||||
|
||||
fn foo() {
|
||||
m!()() = Bar();
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
||||
let (_, source_map) = db.body_with_source_map(def);
|
||||
assert_eq!(source_map.diagnostics(), &[]);
|
||||
|
||||
for (_, def_map) in body.blocks(&db) {
|
||||
assert_eq!(def_map.diagnostics(), &[]);
|
||||
}
|
||||
|
||||
expect![[r#"
|
||||
fn foo() {
|
||||
Bar() = Bar();
|
||||
}"#]]
|
||||
.assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shadowing_record_variant() {
|
||||
let (_, body, _) = lower(
|
||||
r#"
|
||||
enum A {
|
||||
B { field: i32 },
|
||||
}
|
||||
fn f() {
|
||||
use A::*;
|
||||
match () {
|
||||
B => {}
|
||||
};
|
||||
}
|
||||
"#,
|
||||
);
|
||||
assert_eq!(body.bindings.len(), 1, "should have a binding for `B`");
|
||||
assert_eq!(
|
||||
body.bindings[BindingId::from_raw(RawIdx::from_u32(0))].name.as_str(),
|
||||
"B",
|
||||
"should have a binding for `B`",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn regression_pretty_print_bind_pat() {
|
||||
let (db, body, owner) = lower(
|
||||
r#"
|
||||
fn foo() {
|
||||
let v @ u = 123;
|
||||
}
|
||||
"#,
|
||||
);
|
||||
let printed = body.pretty_print(&db, owner, Edition::CURRENT);
|
||||
|
||||
expect![[r#"
|
||||
fn foo() {
|
||||
let v @ u = 123;
|
||||
}"#]]
|
||||
.assert_eq(&printed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn skip_skips_body() {
|
||||
let (db, body, owner) = lower(
|
||||
r#"
|
||||
#[rust_analyzer::skip]
|
||||
async fn foo(a: (), b: i32) -> u32 {
|
||||
0 + 1 + b()
|
||||
}
|
||||
"#,
|
||||
);
|
||||
let printed = body.pretty_print(&db, owner, Edition::CURRENT);
|
||||
expect!["fn foo(<28>, <20>) <20>"].assert_eq(&printed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn range_bounds_are_hir_exprs() {
|
||||
let (_, body, _) = lower(
|
||||
r#"
|
||||
pub const L: i32 = 6;
|
||||
mod x {
|
||||
pub const R: i32 = 100;
|
||||
}
|
||||
const fn f(x: i32) -> i32 {
|
||||
match x {
|
||||
-1..=5 => x * 10,
|
||||
L..=x::R => x * 100,
|
||||
_ => x,
|
||||
}
|
||||
}"#,
|
||||
);
|
||||
|
||||
let mtch_arms = body
|
||||
.exprs
|
||||
.iter()
|
||||
.find_map(|(_, expr)| {
|
||||
if let Expr::Match { arms, .. } = expr {
|
||||
return Some(arms);
|
||||
}
|
||||
|
||||
None
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let MatchArm { pat, .. } = mtch_arms[1];
|
||||
match body.pats[pat] {
|
||||
Pat::Range { start, end } => {
|
||||
let hir_start = &body.exprs[start.unwrap()];
|
||||
let hir_end = &body.exprs[end.unwrap()];
|
||||
|
||||
assert!(matches!(hir_start, Expr::Path { .. }));
|
||||
assert!(matches!(hir_end, Expr::Path { .. }));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -189,8 +189,8 @@ fn f() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
BlockId(4c01) in BlockRelativeModuleId { block: Some(BlockId(4c00)), local_id: Idx::<ModuleData>(1) }
|
||||
BlockId(4c00) in BlockRelativeModuleId { block: None, local_id: Idx::<ModuleData>(0) }
|
||||
BlockId(4801) in BlockRelativeModuleId { block: Some(BlockId(4800)), local_id: Idx::<ModuleData>(1) }
|
||||
BlockId(4800) in BlockRelativeModuleId { block: None, local_id: Idx::<ModuleData>(0) }
|
||||
crate scope
|
||||
"#]],
|
||||
);
|
||||
190
crates/hir-def/src/expr_store/tests/signatures.rs
Normal file
190
crates/hir-def/src/expr_store/tests/signatures.rs
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
use crate::{
|
||||
GenericDefId, ModuleDefId,
|
||||
expr_store::pretty::{print_function, print_struct},
|
||||
test_db::TestDB,
|
||||
};
|
||||
use expect_test::{Expect, expect};
|
||||
use test_fixture::WithFixture;
|
||||
|
||||
use super::super::*;
|
||||
|
||||
fn lower_and_print(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
|
||||
let db = TestDB::with_files(ra_fixture);
|
||||
|
||||
let krate = db.fetch_test_crate();
|
||||
let def_map = db.crate_def_map(krate);
|
||||
let mut defs = vec![];
|
||||
for (_, module) in def_map.modules() {
|
||||
for decl in module.scope.declarations() {
|
||||
let def: GenericDefId = match decl {
|
||||
ModuleDefId::ModuleId(_) => continue,
|
||||
ModuleDefId::FunctionId(id) => id.into(),
|
||||
ModuleDefId::AdtId(id) => id.into(),
|
||||
ModuleDefId::ConstId(id) => id.into(),
|
||||
ModuleDefId::StaticId(id) => id.into(),
|
||||
ModuleDefId::TraitId(id) => id.into(),
|
||||
ModuleDefId::TraitAliasId(id) => id.into(),
|
||||
ModuleDefId::TypeAliasId(id) => id.into(),
|
||||
ModuleDefId::EnumVariantId(_) => continue,
|
||||
ModuleDefId::BuiltinType(_) => continue,
|
||||
ModuleDefId::MacroId(_) => continue,
|
||||
};
|
||||
defs.push(def);
|
||||
}
|
||||
}
|
||||
|
||||
let mut out = String::new();
|
||||
for def in defs {
|
||||
match def {
|
||||
GenericDefId::AdtId(adt_id) => match adt_id {
|
||||
crate::AdtId::StructId(struct_id) => {
|
||||
out += &print_struct(&db, &db.struct_signature(struct_id), Edition::CURRENT);
|
||||
}
|
||||
crate::AdtId::UnionId(_id) => (),
|
||||
crate::AdtId::EnumId(_id) => (),
|
||||
},
|
||||
GenericDefId::ConstId(_id) => (),
|
||||
GenericDefId::FunctionId(function_id) => {
|
||||
out += &print_function(&db, &db.function_signature(function_id), Edition::CURRENT)
|
||||
}
|
||||
|
||||
GenericDefId::ImplId(_id) => (),
|
||||
GenericDefId::StaticId(_id) => (),
|
||||
GenericDefId::TraitAliasId(_id) => (),
|
||||
GenericDefId::TraitId(_id) => (),
|
||||
GenericDefId::TypeAliasId(_id) => (),
|
||||
}
|
||||
}
|
||||
|
||||
expect.assert_eq(&out);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn structs() {
|
||||
lower_and_print(
|
||||
r"
|
||||
struct S { field: foo, }
|
||||
struct S(i32, u32, &'static str);
|
||||
#[repr(Rust)]
|
||||
struct S;
|
||||
|
||||
struct S<'a, 'b, T: Clone, const C: usize = 3, X = ()> where X: Default, for<'a, 'c> fn() -> i32: for<'b> Trait<'a, Item = Boo>;
|
||||
#[repr(C, packed)]
|
||||
struct S {}
|
||||
",
|
||||
expect![[r#"
|
||||
struct S {...}
|
||||
struct S(...)
|
||||
;
|
||||
struct S;
|
||||
struct S<'a, 'b, T, const C: usize = 3, X = ()>
|
||||
where
|
||||
T: Clone,
|
||||
X: Default,
|
||||
for<'a, 'c> fn() -> i32: for<'b> Trait::<'a, Item = Boo>
|
||||
;
|
||||
#[repr(C)]
|
||||
#[repr(pack(1))]
|
||||
struct S {...}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn functions() {
|
||||
lower_and_print(
|
||||
r#"
|
||||
fn foo<'a, const C: usize = 314235, T: Trait<Item = A> = B>(Struct { foo: bar }: &Struct, _: (), a: u32) -> &'a dyn Fn() -> i32 where (): Default {}
|
||||
const async unsafe extern "C" fn a() {}
|
||||
fn ret_impl_trait() -> impl Trait {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo<'a, const C: usize = 314235, T = B>(&Struct, (), u32) -> &'a dyn Fn::<(), Output = i32>
|
||||
where
|
||||
T: Trait::<Item = A>,
|
||||
(): Default
|
||||
{...}
|
||||
const async unsafe extern "C" fn a() -> impl ::core::future::Future::<Output = ()> {...}
|
||||
fn ret_impl_trait() -> impl Trait {...}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn argument_position_impl_trait_functions() {
|
||||
lower_and_print(
|
||||
r"
|
||||
fn impl_trait_args<T>(_: impl Trait) {}
|
||||
fn impl_trait_args2<T>(_: impl Trait<impl Trait>) {}
|
||||
|
||||
fn impl_trait_ret<T>() -> impl Trait {}
|
||||
fn impl_trait_ret2<T>() -> impl Trait<impl Trait> {}
|
||||
|
||||
fn not_allowed1(f: impl Fn(impl Foo)) {
|
||||
let foo = S;
|
||||
f(foo);
|
||||
}
|
||||
|
||||
// This caused stack overflow in #17498
|
||||
fn not_allowed2(f: impl Fn(&impl Foo)) {
|
||||
let foo = S;
|
||||
f(&foo);
|
||||
}
|
||||
|
||||
fn not_allowed3(bar: impl Bar<impl Foo>) {}
|
||||
|
||||
// This also caused stack overflow
|
||||
fn not_allowed4(bar: impl Bar<&impl Foo>) {}
|
||||
|
||||
fn allowed1(baz: impl Baz<Assoc = impl Foo>) {}
|
||||
|
||||
fn allowed2<'a>(baz: impl Baz<Assoc = &'a (impl Foo + 'a)>) {}
|
||||
|
||||
fn allowed3(baz: impl Baz<Assoc = Qux<impl Foo>>) {}
|
||||
",
|
||||
expect![[r#"
|
||||
fn impl_trait_args<T, Param[1]>(Param[1])
|
||||
where
|
||||
Param[1]: Trait
|
||||
{...}
|
||||
fn impl_trait_args2<T, Param[1]>(Param[1])
|
||||
where
|
||||
Param[1]: Trait::<{error}>
|
||||
{...}
|
||||
fn impl_trait_ret<T>() -> impl Trait {...}
|
||||
fn impl_trait_ret2<T>() -> impl Trait::<{error}> {...}
|
||||
fn not_allowed1<Param[0]>(Param[0])
|
||||
where
|
||||
Param[0]: Fn::<({error}), Output = ()>
|
||||
{...}
|
||||
fn not_allowed2<Param[0]>(Param[0])
|
||||
where
|
||||
Param[0]: Fn::<(&{error}), Output = ()>
|
||||
{...}
|
||||
fn not_allowed3<Param[0]>(Param[0])
|
||||
where
|
||||
Param[0]: Bar::<{error}>
|
||||
{...}
|
||||
fn not_allowed4<Param[0]>(Param[0])
|
||||
where
|
||||
Param[0]: Bar::<&{error}>
|
||||
{...}
|
||||
fn allowed1<Param[0], Param[1]>(Param[1])
|
||||
where
|
||||
Param[0]: Foo,
|
||||
Param[1]: Baz::<Assoc = Param[0]>
|
||||
{...}
|
||||
fn allowed2<'a, Param[0], Param[1]>(Param[1])
|
||||
where
|
||||
Param[0]: Foo,
|
||||
Param[0]: 'a,
|
||||
Param[1]: Baz::<Assoc = &'a Param[0]>
|
||||
{...}
|
||||
fn allowed3<Param[0], Param[1]>(Param[1])
|
||||
where
|
||||
Param[0]: Foo,
|
||||
Param[1]: Baz::<Assoc = Qux::<Param[0]>>
|
||||
{...}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ use std::{cell::Cell, cmp::Ordering, iter};
|
|||
use base_db::{Crate, CrateOrigin, LangCrateOrigin};
|
||||
use hir_expand::{
|
||||
Lookup,
|
||||
mod_path::{ModPath, PathKind},
|
||||
name::{AsName, Name},
|
||||
};
|
||||
use intern::sym;
|
||||
|
|
@ -15,7 +16,6 @@ use crate::{
|
|||
db::DefDatabase,
|
||||
item_scope::ItemInNs,
|
||||
nameres::DefMap,
|
||||
path::{ModPath, PathKind},
|
||||
visibility::{Visibility, VisibilityExplicitness},
|
||||
};
|
||||
|
||||
|
|
@ -134,10 +134,11 @@ fn find_path_inner(ctx: &FindPathCtx<'_>, item: ItemInNs, max_len: usize) -> Opt
|
|||
|
||||
if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() {
|
||||
// - if the item is an enum variant, refer to it via the enum
|
||||
if let Some(mut path) =
|
||||
find_path_inner(ctx, ItemInNs::Types(variant.lookup(ctx.db).parent.into()), max_len)
|
||||
{
|
||||
path.push_segment(ctx.db.enum_variant_data(variant).name.clone());
|
||||
let loc = variant.lookup(ctx.db);
|
||||
if let Some(mut path) = find_path_inner(ctx, ItemInNs::Types(loc.parent.into()), max_len) {
|
||||
path.push_segment(
|
||||
ctx.db.enum_variants(loc.parent).variants[loc.index as usize].1.clone(),
|
||||
);
|
||||
return Some(path);
|
||||
}
|
||||
// If this doesn't work, it seems we have no way of referring to the
|
||||
|
|
|
|||
|
|
@ -1,922 +0,0 @@
|
|||
//! Many kinds of items or constructs can have generic parameters: functions,
|
||||
//! structs, impls, traits, etc. This module provides a common HIR for these
|
||||
//! generic parameters. See also the `Generics` type and the `generics_of` query
|
||||
//! in rustc.
|
||||
|
||||
use std::{ops, sync::LazyLock};
|
||||
|
||||
use either::Either;
|
||||
use hir_expand::{
|
||||
ExpandResult,
|
||||
name::{AsName, Name},
|
||||
};
|
||||
use intern::sym;
|
||||
use la_arena::{Arena, RawIdx};
|
||||
use stdx::impl_from;
|
||||
use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds};
|
||||
use thin_vec::ThinVec;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
AdtId, ConstParamId, GenericDefId, HasModule, ItemTreeLoc, LifetimeParamId,
|
||||
LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
|
||||
db::DefDatabase,
|
||||
expander::Expander,
|
||||
item_tree::{AttrOwner, FileItemTreeId, GenericModItem, GenericsItemTreeNode, ItemTree},
|
||||
lower::LowerCtx,
|
||||
nameres::{DefMap, LocalDefMap, MacroSubNs},
|
||||
path::{AssociatedTypeBinding, GenericArg, GenericArgs, NormalPath, Path},
|
||||
type_ref::{
|
||||
ArrayType, ConstRef, FnType, LifetimeRef, PathId, RefType, TypeBound, TypeRef, TypeRefId,
|
||||
TypesMap, TypesSourceMap,
|
||||
},
|
||||
};
|
||||
|
||||
/// The index of the self param in the generic of the non-parent definition.
|
||||
const SELF_PARAM_ID_IN_SELF: la_arena::Idx<TypeOrConstParamData> =
|
||||
LocalTypeOrConstParamId::from_raw(RawIdx::from_u32(0));
|
||||
|
||||
/// Data about a generic type parameter (to a function, struct, impl, ...).
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct TypeParamData {
|
||||
/// [`None`] only if the type ref is an [`TypeRef::ImplTrait`]. FIXME: Might be better to just
|
||||
/// make it always be a value, giving impl trait a special name.
|
||||
pub name: Option<Name>,
|
||||
pub default: Option<TypeRefId>,
|
||||
pub provenance: TypeParamProvenance,
|
||||
}
|
||||
|
||||
/// Data about a generic lifetime parameter (to a function, struct, impl, ...).
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct LifetimeParamData {
|
||||
pub name: Name,
|
||||
}
|
||||
|
||||
/// Data about a generic const parameter (to a function, struct, impl, ...).
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct ConstParamData {
|
||||
pub name: Name,
|
||||
pub ty: TypeRefId,
|
||||
pub default: Option<ConstRef>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum TypeParamProvenance {
|
||||
TypeParamList,
|
||||
TraitSelf,
|
||||
ArgumentImplTrait,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum TypeOrConstParamData {
|
||||
TypeParamData(TypeParamData),
|
||||
ConstParamData(ConstParamData),
|
||||
}
|
||||
|
||||
impl TypeOrConstParamData {
|
||||
pub fn name(&self) -> Option<&Name> {
|
||||
match self {
|
||||
TypeOrConstParamData::TypeParamData(it) => it.name.as_ref(),
|
||||
TypeOrConstParamData::ConstParamData(it) => Some(&it.name),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_default(&self) -> bool {
|
||||
match self {
|
||||
TypeOrConstParamData::TypeParamData(it) => it.default.is_some(),
|
||||
TypeOrConstParamData::ConstParamData(it) => it.default.is_some(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_param(&self) -> Option<&TypeParamData> {
|
||||
match self {
|
||||
TypeOrConstParamData::TypeParamData(it) => Some(it),
|
||||
TypeOrConstParamData::ConstParamData(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn const_param(&self) -> Option<&ConstParamData> {
|
||||
match self {
|
||||
TypeOrConstParamData::TypeParamData(_) => None,
|
||||
TypeOrConstParamData::ConstParamData(it) => Some(it),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_trait_self(&self) -> bool {
|
||||
match self {
|
||||
TypeOrConstParamData::TypeParamData(it) => {
|
||||
it.provenance == TypeParamProvenance::TraitSelf
|
||||
}
|
||||
TypeOrConstParamData::ConstParamData(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_from!(TypeParamData, ConstParamData for TypeOrConstParamData);
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum GenericParamData {
|
||||
TypeParamData(TypeParamData),
|
||||
ConstParamData(ConstParamData),
|
||||
LifetimeParamData(LifetimeParamData),
|
||||
}
|
||||
|
||||
impl GenericParamData {
|
||||
pub fn name(&self) -> Option<&Name> {
|
||||
match self {
|
||||
GenericParamData::TypeParamData(it) => it.name.as_ref(),
|
||||
GenericParamData::ConstParamData(it) => Some(&it.name),
|
||||
GenericParamData::LifetimeParamData(it) => Some(&it.name),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_param(&self) -> Option<&TypeParamData> {
|
||||
match self {
|
||||
GenericParamData::TypeParamData(it) => Some(it),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn const_param(&self) -> Option<&ConstParamData> {
|
||||
match self {
|
||||
GenericParamData::ConstParamData(it) => Some(it),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lifetime_param(&self) -> Option<&LifetimeParamData> {
|
||||
match self {
|
||||
GenericParamData::LifetimeParamData(it) => Some(it),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_from!(TypeParamData, ConstParamData, LifetimeParamData for GenericParamData);
|
||||
|
||||
pub enum GenericParamDataRef<'a> {
|
||||
TypeParamData(&'a TypeParamData),
|
||||
ConstParamData(&'a ConstParamData),
|
||||
LifetimeParamData(&'a LifetimeParamData),
|
||||
}
|
||||
|
||||
/// Data about the generic parameters of a function, struct, impl, etc.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct GenericParams {
|
||||
type_or_consts: Arena<TypeOrConstParamData>,
|
||||
lifetimes: Arena<LifetimeParamData>,
|
||||
where_predicates: Box<[WherePredicate]>,
|
||||
pub types_map: TypesMap,
|
||||
}
|
||||
|
||||
impl ops::Index<LocalTypeOrConstParamId> for GenericParams {
|
||||
type Output = TypeOrConstParamData;
|
||||
fn index(&self, index: LocalTypeOrConstParamId) -> &TypeOrConstParamData {
|
||||
&self.type_or_consts[index]
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Index<LocalLifetimeParamId> for GenericParams {
|
||||
type Output = LifetimeParamData;
|
||||
fn index(&self, index: LocalLifetimeParamId) -> &LifetimeParamData {
|
||||
&self.lifetimes[index]
|
||||
}
|
||||
}
|
||||
|
||||
/// A single predicate from a where clause, i.e. `where Type: Trait`. Combined
|
||||
/// where clauses like `where T: Foo + Bar` are turned into multiple of these.
|
||||
/// It might still result in multiple actual predicates though, because of
|
||||
/// associated type bindings like `Iterator<Item = u32>`.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum WherePredicate {
|
||||
TypeBound { target: WherePredicateTypeTarget, bound: TypeBound },
|
||||
Lifetime { target: LifetimeRef, bound: LifetimeRef },
|
||||
ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound },
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum WherePredicateTypeTarget {
|
||||
TypeRef(TypeRefId),
|
||||
/// For desugared where predicates that can directly refer to a type param.
|
||||
TypeOrConstParam(LocalTypeOrConstParamId),
|
||||
}
|
||||
|
||||
impl GenericParams {
|
||||
/// Number of Generic parameters (type_or_consts + lifetimes)
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
self.type_or_consts.len() + self.lifetimes.len()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn len_lifetimes(&self) -> usize {
|
||||
self.lifetimes.len()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn len_type_or_consts(&self) -> usize {
|
||||
self.type_or_consts.len()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn no_predicates(&self) -> bool {
|
||||
self.where_predicates.is_empty()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn where_predicates(&self) -> std::slice::Iter<'_, WherePredicate> {
|
||||
self.where_predicates.iter()
|
||||
}
|
||||
|
||||
/// Iterator of type_or_consts field
|
||||
#[inline]
|
||||
pub fn iter_type_or_consts(
|
||||
&self,
|
||||
) -> impl DoubleEndedIterator<Item = (LocalTypeOrConstParamId, &TypeOrConstParamData)> {
|
||||
self.type_or_consts.iter()
|
||||
}
|
||||
|
||||
/// Iterator of lifetimes field
|
||||
#[inline]
|
||||
pub fn iter_lt(
|
||||
&self,
|
||||
) -> impl DoubleEndedIterator<Item = (LocalLifetimeParamId, &LifetimeParamData)> {
|
||||
self.lifetimes.iter()
|
||||
}
|
||||
|
||||
pub fn find_type_by_name(&self, name: &Name, parent: GenericDefId) -> Option<TypeParamId> {
|
||||
self.type_or_consts.iter().find_map(|(id, p)| {
|
||||
if p.name().as_ref() == Some(&name) && p.type_param().is_some() {
|
||||
Some(TypeParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent }))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn find_const_by_name(&self, name: &Name, parent: GenericDefId) -> Option<ConstParamId> {
|
||||
self.type_or_consts.iter().find_map(|(id, p)| {
|
||||
if p.name().as_ref() == Some(&name) && p.const_param().is_some() {
|
||||
Some(ConstParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent }))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn trait_self_param(&self) -> Option<LocalTypeOrConstParamId> {
|
||||
if self.type_or_consts.is_empty() {
|
||||
return None;
|
||||
}
|
||||
matches!(
|
||||
self.type_or_consts[SELF_PARAM_ID_IN_SELF],
|
||||
TypeOrConstParamData::TypeParamData(TypeParamData {
|
||||
provenance: TypeParamProvenance::TraitSelf,
|
||||
..
|
||||
})
|
||||
)
|
||||
.then(|| SELF_PARAM_ID_IN_SELF)
|
||||
}
|
||||
|
||||
pub fn find_lifetime_by_name(
|
||||
&self,
|
||||
name: &Name,
|
||||
parent: GenericDefId,
|
||||
) -> Option<LifetimeParamId> {
|
||||
self.lifetimes.iter().find_map(|(id, p)| {
|
||||
if &p.name == name { Some(LifetimeParamId { local_id: id, parent }) } else { None }
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn generic_params_query(
|
||||
db: &dyn DefDatabase,
|
||||
def: GenericDefId,
|
||||
) -> Arc<GenericParams> {
|
||||
db.generic_params_with_source_map(def).0
|
||||
}
|
||||
|
||||
pub(crate) fn generic_params_with_source_map_query(
|
||||
db: &dyn DefDatabase,
|
||||
def: GenericDefId,
|
||||
) -> (Arc<GenericParams>, Option<Arc<TypesSourceMap>>) {
|
||||
let _p = tracing::info_span!("generic_params_query").entered();
|
||||
|
||||
let krate = def.krate(db);
|
||||
let cfg_options = &krate.cfg_options(db);
|
||||
|
||||
// Returns the generic parameters that are enabled under the current `#[cfg]` options
|
||||
let enabled_params =
|
||||
|params: &Arc<GenericParams>, item_tree: &ItemTree, parent: GenericModItem| {
|
||||
let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options);
|
||||
let attr_owner_ct = |param| AttrOwner::TypeOrConstParamData(parent, param);
|
||||
let attr_owner_lt = |param| AttrOwner::LifetimeParamData(parent, param);
|
||||
|
||||
// In the common case, no parameters will by disabled by `#[cfg]` attributes.
|
||||
// Therefore, make a first pass to check if all parameters are enabled and, if so,
|
||||
// clone the `Interned<GenericParams>` instead of recreating an identical copy.
|
||||
let all_type_or_consts_enabled =
|
||||
params.type_or_consts.iter().all(|(idx, _)| enabled(attr_owner_ct(idx)));
|
||||
let all_lifetimes_enabled =
|
||||
params.lifetimes.iter().all(|(idx, _)| enabled(attr_owner_lt(idx)));
|
||||
|
||||
if all_type_or_consts_enabled && all_lifetimes_enabled {
|
||||
params.clone()
|
||||
} else {
|
||||
Arc::new(GenericParams {
|
||||
type_or_consts: if all_type_or_consts_enabled {
|
||||
params.type_or_consts.clone()
|
||||
} else {
|
||||
{
|
||||
params
|
||||
.type_or_consts
|
||||
.iter()
|
||||
.filter(|&(idx, _)| enabled(attr_owner_ct(idx)))
|
||||
.map(|(_, param)| param.clone())
|
||||
.collect()
|
||||
}
|
||||
},
|
||||
lifetimes: if all_lifetimes_enabled {
|
||||
params.lifetimes.clone()
|
||||
} else {
|
||||
{
|
||||
params
|
||||
.lifetimes
|
||||
.iter()
|
||||
.filter(|&(idx, _)| enabled(attr_owner_lt(idx)))
|
||||
.map(|(_, param)| param.clone())
|
||||
.collect()
|
||||
}
|
||||
},
|
||||
where_predicates: params.where_predicates.clone(),
|
||||
types_map: params.types_map.clone(),
|
||||
})
|
||||
}
|
||||
};
|
||||
fn id_to_generics<Id: GenericsItemTreeNode>(
|
||||
db: &dyn DefDatabase,
|
||||
id: impl Lookup<Database = dyn DefDatabase, Data = impl ItemTreeLoc<Id = Id>>,
|
||||
enabled_params: impl Fn(
|
||||
&Arc<GenericParams>,
|
||||
&ItemTree,
|
||||
GenericModItem,
|
||||
) -> Arc<GenericParams>,
|
||||
) -> (Arc<GenericParams>, Option<Arc<TypesSourceMap>>)
|
||||
where
|
||||
FileItemTreeId<Id>: Into<GenericModItem>,
|
||||
{
|
||||
let id = id.lookup(db).item_tree_id();
|
||||
let tree = id.item_tree(db);
|
||||
let item = &tree[id.value];
|
||||
|
||||
(enabled_params(item.generic_params(), &tree, id.value.into()), None)
|
||||
}
|
||||
|
||||
match def {
|
||||
GenericDefId::FunctionId(id) => {
|
||||
let loc = id.lookup(db);
|
||||
let tree = loc.id.item_tree(db);
|
||||
let item = &tree[loc.id.value];
|
||||
|
||||
let enabled_params =
|
||||
enabled_params(&item.explicit_generic_params, &tree, loc.id.value.into());
|
||||
|
||||
let module = loc.container.module(db);
|
||||
let func_data = db.function_data(id);
|
||||
if func_data.params.is_empty() {
|
||||
(enabled_params, None)
|
||||
} else {
|
||||
let source_maps = loc.id.item_tree_with_source_map(db).1;
|
||||
let item_source_maps = source_maps.function(loc.id.value);
|
||||
let mut generic_params = GenericParamsCollector {
|
||||
type_or_consts: enabled_params.type_or_consts.clone(),
|
||||
lifetimes: enabled_params.lifetimes.clone(),
|
||||
where_predicates: enabled_params.where_predicates.clone().into(),
|
||||
};
|
||||
|
||||
let (mut types_map, mut types_source_maps) =
|
||||
(enabled_params.types_map.clone(), item_source_maps.generics().clone());
|
||||
// Don't create an `Expander` if not needed since this
|
||||
// could cause a reparse after the `ItemTree` has been created due to the spanmap.
|
||||
let mut expander = None;
|
||||
for ¶m in func_data.params.iter() {
|
||||
generic_params.fill_implicit_impl_trait_args(
|
||||
db,
|
||||
&mut types_map,
|
||||
&mut types_source_maps,
|
||||
&mut expander,
|
||||
&mut || {
|
||||
let (def_map, local_def_map) = module.local_def_map(db);
|
||||
(
|
||||
def_map,
|
||||
local_def_map,
|
||||
Expander::new(db, loc.id.file_id(), module),
|
||||
)
|
||||
},
|
||||
param,
|
||||
&item.types_map,
|
||||
item_source_maps.item(),
|
||||
);
|
||||
}
|
||||
let generics = generic_params.finish(types_map, &mut types_source_maps);
|
||||
(generics, Some(Arc::new(types_source_maps)))
|
||||
}
|
||||
}
|
||||
GenericDefId::AdtId(AdtId::StructId(id)) => id_to_generics(db, id, enabled_params),
|
||||
GenericDefId::AdtId(AdtId::EnumId(id)) => id_to_generics(db, id, enabled_params),
|
||||
GenericDefId::AdtId(AdtId::UnionId(id)) => id_to_generics(db, id, enabled_params),
|
||||
GenericDefId::TraitId(id) => id_to_generics(db, id, enabled_params),
|
||||
GenericDefId::TraitAliasId(id) => id_to_generics(db, id, enabled_params),
|
||||
GenericDefId::TypeAliasId(id) => id_to_generics(db, id, enabled_params),
|
||||
GenericDefId::ImplId(id) => id_to_generics(db, id, enabled_params),
|
||||
GenericDefId::ConstId(_) | GenericDefId::StaticId(_) => (
|
||||
Arc::new(GenericParams {
|
||||
type_or_consts: Default::default(),
|
||||
lifetimes: Default::default(),
|
||||
where_predicates: Default::default(),
|
||||
types_map: Default::default(),
|
||||
}),
|
||||
None,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub(crate) struct GenericParamsCollector {
|
||||
type_or_consts: Arena<TypeOrConstParamData>,
|
||||
lifetimes: Arena<LifetimeParamData>,
|
||||
where_predicates: Vec<WherePredicate>,
|
||||
}
|
||||
|
||||
impl GenericParamsCollector {
|
||||
pub(crate) fn fill_self_param(&mut self) {
|
||||
self.type_or_consts.alloc(
|
||||
TypeParamData {
|
||||
name: Some(Name::new_symbol_root(sym::Self_.clone())),
|
||||
default: None,
|
||||
provenance: TypeParamProvenance::TraitSelf,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn fill(
|
||||
&mut self,
|
||||
lower_ctx: &mut LowerCtx<'_>,
|
||||
node: &dyn HasGenericParams,
|
||||
add_param_attrs: impl FnMut(
|
||||
Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
|
||||
ast::GenericParam,
|
||||
),
|
||||
) {
|
||||
if let Some(params) = node.generic_param_list() {
|
||||
self.fill_params(lower_ctx, params, add_param_attrs)
|
||||
}
|
||||
if let Some(where_clause) = node.where_clause() {
|
||||
self.fill_where_predicates(lower_ctx, where_clause);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn fill_bounds(
|
||||
&mut self,
|
||||
lower_ctx: &mut LowerCtx<'_>,
|
||||
type_bounds: Option<ast::TypeBoundList>,
|
||||
target: Either<TypeRefId, LifetimeRef>,
|
||||
) {
|
||||
for bound in type_bounds.iter().flat_map(|type_bound_list| type_bound_list.bounds()) {
|
||||
self.add_where_predicate_from_bound(lower_ctx, bound, None, target.clone());
|
||||
}
|
||||
}
|
||||
|
||||
fn fill_params(
|
||||
&mut self,
|
||||
lower_ctx: &mut LowerCtx<'_>,
|
||||
params: ast::GenericParamList,
|
||||
mut add_param_attrs: impl FnMut(
|
||||
Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
|
||||
ast::GenericParam,
|
||||
),
|
||||
) {
|
||||
for type_or_const_param in params.type_or_const_params() {
|
||||
match type_or_const_param {
|
||||
ast::TypeOrConstParam::Type(type_param) => {
|
||||
let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
|
||||
// FIXME: Use `Path::from_src`
|
||||
let default =
|
||||
type_param.default_type().map(|it| TypeRef::from_ast(lower_ctx, it));
|
||||
let param = TypeParamData {
|
||||
name: Some(name.clone()),
|
||||
default,
|
||||
provenance: TypeParamProvenance::TypeParamList,
|
||||
};
|
||||
let idx = self.type_or_consts.alloc(param.into());
|
||||
let type_ref = lower_ctx.alloc_type_ref_desugared(TypeRef::Path(name.into()));
|
||||
self.fill_bounds(
|
||||
lower_ctx,
|
||||
type_param.type_bound_list(),
|
||||
Either::Left(type_ref),
|
||||
);
|
||||
add_param_attrs(Either::Left(idx), ast::GenericParam::TypeParam(type_param));
|
||||
}
|
||||
ast::TypeOrConstParam::Const(const_param) => {
|
||||
let name = const_param.name().map_or_else(Name::missing, |it| it.as_name());
|
||||
let ty = TypeRef::from_ast_opt(lower_ctx, const_param.ty());
|
||||
let param = ConstParamData {
|
||||
name,
|
||||
ty,
|
||||
default: ConstRef::from_const_param(lower_ctx, &const_param),
|
||||
};
|
||||
let idx = self.type_or_consts.alloc(param.into());
|
||||
add_param_attrs(Either::Left(idx), ast::GenericParam::ConstParam(const_param));
|
||||
}
|
||||
}
|
||||
}
|
||||
for lifetime_param in params.lifetime_params() {
|
||||
let name =
|
||||
lifetime_param.lifetime().map_or_else(Name::missing, |lt| Name::new_lifetime(<));
|
||||
let param = LifetimeParamData { name: name.clone() };
|
||||
let idx = self.lifetimes.alloc(param);
|
||||
let lifetime_ref = LifetimeRef::new_name(name);
|
||||
self.fill_bounds(
|
||||
lower_ctx,
|
||||
lifetime_param.type_bound_list(),
|
||||
Either::Right(lifetime_ref),
|
||||
);
|
||||
add_param_attrs(Either::Right(idx), ast::GenericParam::LifetimeParam(lifetime_param));
|
||||
}
|
||||
}
|
||||
|
||||
fn fill_where_predicates(
|
||||
&mut self,
|
||||
lower_ctx: &mut LowerCtx<'_>,
|
||||
where_clause: ast::WhereClause,
|
||||
) {
|
||||
for pred in where_clause.predicates() {
|
||||
let target = if let Some(type_ref) = pred.ty() {
|
||||
Either::Left(TypeRef::from_ast(lower_ctx, type_ref))
|
||||
} else if let Some(lifetime) = pred.lifetime() {
|
||||
Either::Right(LifetimeRef::new(&lifetime))
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let lifetimes: Option<Box<_>> = pred.generic_param_list().map(|param_list| {
|
||||
// Higher-Ranked Trait Bounds
|
||||
param_list
|
||||
.lifetime_params()
|
||||
.map(|lifetime_param| {
|
||||
lifetime_param
|
||||
.lifetime()
|
||||
.map_or_else(Name::missing, |lt| Name::new_lifetime(<))
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) {
|
||||
self.add_where_predicate_from_bound(
|
||||
lower_ctx,
|
||||
bound,
|
||||
lifetimes.as_deref(),
|
||||
target.clone(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_where_predicate_from_bound(
|
||||
&mut self,
|
||||
lower_ctx: &mut LowerCtx<'_>,
|
||||
bound: ast::TypeBound,
|
||||
hrtb_lifetimes: Option<&[Name]>,
|
||||
target: Either<TypeRefId, LifetimeRef>,
|
||||
) {
|
||||
let bound = TypeBound::from_ast(lower_ctx, bound);
|
||||
self.fill_impl_trait_bounds(lower_ctx.take_impl_traits_bounds());
|
||||
let predicate = match (target, bound) {
|
||||
(Either::Left(type_ref), bound) => match hrtb_lifetimes {
|
||||
Some(hrtb_lifetimes) => WherePredicate::ForLifetime {
|
||||
lifetimes: hrtb_lifetimes.to_vec().into_boxed_slice(),
|
||||
target: WherePredicateTypeTarget::TypeRef(type_ref),
|
||||
bound,
|
||||
},
|
||||
None => WherePredicate::TypeBound {
|
||||
target: WherePredicateTypeTarget::TypeRef(type_ref),
|
||||
bound,
|
||||
},
|
||||
},
|
||||
(Either::Right(lifetime), TypeBound::Lifetime(bound)) => {
|
||||
WherePredicate::Lifetime { target: lifetime, bound }
|
||||
}
|
||||
_ => return,
|
||||
};
|
||||
self.where_predicates.push(predicate);
|
||||
}
|
||||
|
||||
fn fill_impl_trait_bounds(&mut self, impl_bounds: Vec<ThinVec<TypeBound>>) {
|
||||
for bounds in impl_bounds {
|
||||
let param = TypeParamData {
|
||||
name: None,
|
||||
default: None,
|
||||
provenance: TypeParamProvenance::ArgumentImplTrait,
|
||||
};
|
||||
let param_id = self.type_or_consts.alloc(param.into());
|
||||
for bound in &bounds {
|
||||
self.where_predicates.push(WherePredicate::TypeBound {
|
||||
target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
|
||||
bound: bound.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fill_implicit_impl_trait_args(
|
||||
&mut self,
|
||||
db: &dyn DefDatabase,
|
||||
generics_types_map: &mut TypesMap,
|
||||
generics_types_source_map: &mut TypesSourceMap,
|
||||
// FIXME: Change this back to `LazyCell` if https://github.com/rust-lang/libs-team/issues/429 is accepted.
|
||||
exp: &mut Option<(Arc<DefMap>, Arc<LocalDefMap>, Expander)>,
|
||||
exp_fill: &mut dyn FnMut() -> (Arc<DefMap>, Arc<LocalDefMap>, Expander),
|
||||
type_ref: TypeRefId,
|
||||
types_map: &TypesMap,
|
||||
types_source_map: &TypesSourceMap,
|
||||
) {
|
||||
TypeRef::walk(type_ref, types_map, &mut |type_ref| {
|
||||
if let TypeRef::ImplTrait(bounds) = type_ref {
|
||||
let param = TypeParamData {
|
||||
name: None,
|
||||
default: None,
|
||||
provenance: TypeParamProvenance::ArgumentImplTrait,
|
||||
};
|
||||
let param_id = self.type_or_consts.alloc(param.into());
|
||||
for bound in bounds {
|
||||
let bound = copy_type_bound(
|
||||
bound,
|
||||
types_map,
|
||||
types_source_map,
|
||||
generics_types_map,
|
||||
generics_types_source_map,
|
||||
);
|
||||
self.where_predicates.push(WherePredicate::TypeBound {
|
||||
target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
|
||||
bound,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if let TypeRef::Macro(mc) = type_ref {
|
||||
let macro_call = mc.to_node(db.upcast());
|
||||
let (def_map, local_def_map, expander) = exp.get_or_insert_with(&mut *exp_fill);
|
||||
|
||||
let module = expander.module.local_id;
|
||||
let resolver = |path: &_| {
|
||||
def_map
|
||||
.resolve_path(
|
||||
local_def_map,
|
||||
db,
|
||||
module,
|
||||
path,
|
||||
crate::item_scope::BuiltinShadowMode::Other,
|
||||
Some(MacroSubNs::Bang),
|
||||
)
|
||||
.0
|
||||
.take_macros()
|
||||
};
|
||||
if let Ok(ExpandResult { value: Some((mark, expanded)), .. }) =
|
||||
expander.enter_expand(db, macro_call, resolver)
|
||||
{
|
||||
let (mut macro_types_map, mut macro_types_source_map) =
|
||||
(TypesMap::default(), TypesSourceMap::default());
|
||||
let mut ctx =
|
||||
expander.ctx(db, &mut macro_types_map, &mut macro_types_source_map);
|
||||
let type_ref = TypeRef::from_ast(&mut ctx, expanded.tree());
|
||||
self.fill_implicit_impl_trait_args(
|
||||
db,
|
||||
generics_types_map,
|
||||
generics_types_source_map,
|
||||
&mut *exp,
|
||||
exp_fill,
|
||||
type_ref,
|
||||
¯o_types_map,
|
||||
¯o_types_source_map,
|
||||
);
|
||||
exp.get_or_insert_with(&mut *exp_fill).2.exit(mark);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn finish(
|
||||
self,
|
||||
mut generics_types_map: TypesMap,
|
||||
generics_types_source_map: &mut TypesSourceMap,
|
||||
) -> Arc<GenericParams> {
|
||||
let Self { mut lifetimes, mut type_or_consts, mut where_predicates } = self;
|
||||
|
||||
if lifetimes.is_empty() && type_or_consts.is_empty() && where_predicates.is_empty() {
|
||||
static EMPTY: LazyLock<Arc<GenericParams>> = LazyLock::new(|| {
|
||||
Arc::new(GenericParams {
|
||||
lifetimes: Arena::new(),
|
||||
type_or_consts: Arena::new(),
|
||||
where_predicates: Box::default(),
|
||||
types_map: TypesMap::default(),
|
||||
})
|
||||
});
|
||||
return Arc::clone(&EMPTY);
|
||||
}
|
||||
|
||||
lifetimes.shrink_to_fit();
|
||||
type_or_consts.shrink_to_fit();
|
||||
where_predicates.shrink_to_fit();
|
||||
generics_types_map.shrink_to_fit();
|
||||
generics_types_source_map.shrink_to_fit();
|
||||
Arc::new(GenericParams {
|
||||
type_or_consts,
|
||||
lifetimes,
|
||||
where_predicates: where_predicates.into_boxed_slice(),
|
||||
types_map: generics_types_map,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Copies a `TypeRef` from a `TypesMap` (accompanied with `TypesSourceMap`) into another `TypesMap`
|
||||
/// (and `TypesSourceMap`).
|
||||
fn copy_type_ref(
|
||||
type_ref: TypeRefId,
|
||||
from: &TypesMap,
|
||||
from_source_map: &TypesSourceMap,
|
||||
to: &mut TypesMap,
|
||||
to_source_map: &mut TypesSourceMap,
|
||||
) -> TypeRefId {
|
||||
let result = match &from[type_ref] {
|
||||
TypeRef::Fn(fn_) => {
|
||||
let params = fn_.params.iter().map(|(name, param_type)| {
|
||||
(name.clone(), copy_type_ref(*param_type, from, from_source_map, to, to_source_map))
|
||||
});
|
||||
TypeRef::Fn(Box::new(FnType {
|
||||
params: params.collect(),
|
||||
is_varargs: fn_.is_varargs,
|
||||
is_unsafe: fn_.is_unsafe,
|
||||
abi: fn_.abi.clone(),
|
||||
}))
|
||||
}
|
||||
TypeRef::Tuple(types) => TypeRef::Tuple(ThinVec::from_iter(
|
||||
types.iter().map(|&t| copy_type_ref(t, from, from_source_map, to, to_source_map)),
|
||||
)),
|
||||
&TypeRef::RawPtr(type_ref, mutbl) => TypeRef::RawPtr(
|
||||
copy_type_ref(type_ref, from, from_source_map, to, to_source_map),
|
||||
mutbl,
|
||||
),
|
||||
TypeRef::Reference(ref_) => TypeRef::Reference(Box::new(RefType {
|
||||
ty: copy_type_ref(ref_.ty, from, from_source_map, to, to_source_map),
|
||||
lifetime: ref_.lifetime.clone(),
|
||||
mutability: ref_.mutability,
|
||||
})),
|
||||
TypeRef::Array(array) => TypeRef::Array(Box::new(ArrayType {
|
||||
ty: copy_type_ref(array.ty, from, from_source_map, to, to_source_map),
|
||||
len: array.len.clone(),
|
||||
})),
|
||||
&TypeRef::Slice(type_ref) => {
|
||||
TypeRef::Slice(copy_type_ref(type_ref, from, from_source_map, to, to_source_map))
|
||||
}
|
||||
TypeRef::ImplTrait(bounds) => TypeRef::ImplTrait(ThinVec::from_iter(copy_type_bounds(
|
||||
bounds,
|
||||
from,
|
||||
from_source_map,
|
||||
to,
|
||||
to_source_map,
|
||||
))),
|
||||
TypeRef::DynTrait(bounds) => TypeRef::DynTrait(ThinVec::from_iter(copy_type_bounds(
|
||||
bounds,
|
||||
from,
|
||||
from_source_map,
|
||||
to,
|
||||
to_source_map,
|
||||
))),
|
||||
TypeRef::Path(path) => {
|
||||
TypeRef::Path(copy_path(path, from, from_source_map, to, to_source_map))
|
||||
}
|
||||
TypeRef::Never => TypeRef::Never,
|
||||
TypeRef::Placeholder => TypeRef::Placeholder,
|
||||
TypeRef::Macro(macro_call) => TypeRef::Macro(*macro_call),
|
||||
TypeRef::Error => TypeRef::Error,
|
||||
};
|
||||
let id = to.types.alloc(result);
|
||||
if let Some(&ptr) = from_source_map.types_map_back.get(id) {
|
||||
to_source_map.types_map_back.insert(id, ptr);
|
||||
}
|
||||
id
|
||||
}
|
||||
|
||||
fn copy_path(
|
||||
path: &Path,
|
||||
from: &TypesMap,
|
||||
from_source_map: &TypesSourceMap,
|
||||
to: &mut TypesMap,
|
||||
to_source_map: &mut TypesSourceMap,
|
||||
) -> Path {
|
||||
match path {
|
||||
Path::BarePath(mod_path) => Path::BarePath(mod_path.clone()),
|
||||
Path::Normal(path) => {
|
||||
let type_anchor = path
|
||||
.type_anchor
|
||||
.map(|type_ref| copy_type_ref(type_ref, from, from_source_map, to, to_source_map));
|
||||
let mod_path = path.mod_path.clone();
|
||||
let generic_args = path.generic_args.iter().map(|generic_args| {
|
||||
copy_generic_args(generic_args, from, from_source_map, to, to_source_map)
|
||||
});
|
||||
Path::Normal(Box::new(NormalPath {
|
||||
generic_args: generic_args.collect(),
|
||||
type_anchor,
|
||||
mod_path,
|
||||
}))
|
||||
}
|
||||
Path::LangItem(lang_item, name) => Path::LangItem(*lang_item, name.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
fn copy_generic_args(
|
||||
generic_args: &Option<GenericArgs>,
|
||||
from: &TypesMap,
|
||||
from_source_map: &TypesSourceMap,
|
||||
to: &mut TypesMap,
|
||||
to_source_map: &mut TypesSourceMap,
|
||||
) -> Option<GenericArgs> {
|
||||
generic_args.as_ref().map(|generic_args| {
|
||||
let args = generic_args
|
||||
.args
|
||||
.iter()
|
||||
.map(|arg| match arg {
|
||||
&GenericArg::Type(ty) => {
|
||||
GenericArg::Type(copy_type_ref(ty, from, from_source_map, to, to_source_map))
|
||||
}
|
||||
GenericArg::Lifetime(lifetime) => GenericArg::Lifetime(lifetime.clone()),
|
||||
GenericArg::Const(konst) => GenericArg::Const(konst.clone()),
|
||||
})
|
||||
.collect();
|
||||
let bindings = generic_args
|
||||
.bindings
|
||||
.iter()
|
||||
.map(|binding| {
|
||||
let name = binding.name.clone();
|
||||
let args =
|
||||
copy_generic_args(&binding.args, from, from_source_map, to, to_source_map);
|
||||
let type_ref = binding.type_ref.map(|type_ref| {
|
||||
copy_type_ref(type_ref, from, from_source_map, to, to_source_map)
|
||||
});
|
||||
let bounds =
|
||||
copy_type_bounds(&binding.bounds, from, from_source_map, to, to_source_map)
|
||||
.collect();
|
||||
AssociatedTypeBinding { name, args, type_ref, bounds }
|
||||
})
|
||||
.collect();
|
||||
GenericArgs {
|
||||
args,
|
||||
has_self_type: generic_args.has_self_type,
|
||||
bindings,
|
||||
parenthesized: generic_args.parenthesized,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn copy_type_bounds<'a>(
|
||||
bounds: &'a [TypeBound],
|
||||
from: &'a TypesMap,
|
||||
from_source_map: &'a TypesSourceMap,
|
||||
to: &'a mut TypesMap,
|
||||
to_source_map: &'a mut TypesSourceMap,
|
||||
) -> impl Iterator<Item = TypeBound> + 'a {
|
||||
bounds.iter().map(|bound| copy_type_bound(bound, from, from_source_map, to, to_source_map))
|
||||
}
|
||||
|
||||
fn copy_type_bound(
|
||||
bound: &TypeBound,
|
||||
from: &TypesMap,
|
||||
from_source_map: &TypesSourceMap,
|
||||
to: &mut TypesMap,
|
||||
to_source_map: &mut TypesSourceMap,
|
||||
) -> TypeBound {
|
||||
let mut copy_path_id = |path: PathId| {
|
||||
let new_path = copy_path(&from[path], from, from_source_map, to, to_source_map);
|
||||
let new_path_id = to.types.alloc(TypeRef::Path(new_path));
|
||||
if let Some(&ptr) = from_source_map.types_map_back.get(path.type_ref()) {
|
||||
to_source_map.types_map_back.insert(new_path_id, ptr);
|
||||
}
|
||||
PathId::from_type_ref_unchecked(new_path_id)
|
||||
};
|
||||
|
||||
match bound {
|
||||
&TypeBound::Path(path, modifier) => TypeBound::Path(copy_path_id(path), modifier),
|
||||
TypeBound::ForLifetime(lifetimes, path) => {
|
||||
TypeBound::ForLifetime(lifetimes.clone(), copy_path_id(*path))
|
||||
}
|
||||
TypeBound::Lifetime(lifetime) => TypeBound::Lifetime(lifetime.clone()),
|
||||
TypeBound::Use(use_args) => TypeBound::Use(use_args.clone()),
|
||||
TypeBound::Error => TypeBound::Error,
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
//! See also a neighboring `body` module.
|
||||
|
||||
pub mod format_args;
|
||||
pub mod generics;
|
||||
pub mod type_ref;
|
||||
|
||||
use std::fmt;
|
||||
|
|
@ -25,9 +26,9 @@ use syntax::ast;
|
|||
use type_ref::TypeRefId;
|
||||
|
||||
use crate::{
|
||||
BlockId, ConstBlockId,
|
||||
BlockId,
|
||||
builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
|
||||
path::{GenericArgs, Path},
|
||||
expr_store::path::{GenericArgs, Path},
|
||||
type_ref::{Mutability, Rawness},
|
||||
};
|
||||
|
||||
|
|
@ -208,7 +209,7 @@ pub enum Expr {
|
|||
statements: Box<[Statement]>,
|
||||
tail: Option<ExprId>,
|
||||
},
|
||||
Const(ConstBlockId),
|
||||
Const(ExprId),
|
||||
// FIXME: Fold this into Block with an unsafe flag?
|
||||
Unsafe {
|
||||
id: Option<BlockId>,
|
||||
|
|
|
|||
408
crates/hir-def/src/hir/generics.rs
Normal file
408
crates/hir-def/src/hir/generics.rs
Normal file
|
|
@ -0,0 +1,408 @@
|
|||
//! Pre-type IR item generics
|
||||
use std::{ops, sync::LazyLock};
|
||||
|
||||
use hir_expand::name::Name;
|
||||
use la_arena::{Arena, Idx, RawIdx};
|
||||
use stdx::impl_from;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
AdtId, ConstParamId, GenericDefId, LifetimeParamId, TypeOrConstParamId, TypeParamId,
|
||||
db::DefDatabase,
|
||||
expr_store::{ExpressionStore, ExpressionStoreSourceMap},
|
||||
type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRefId},
|
||||
};
|
||||
|
||||
/// The index of the self param in the generic of the non-parent definition.
|
||||
const SELF_PARAM_ID_IN_SELF: la_arena::Idx<TypeOrConstParamData> =
|
||||
LocalTypeOrConstParamId::from_raw(RawIdx::from_u32(0));
|
||||
|
||||
pub type LocalTypeOrConstParamId = Idx<TypeOrConstParamData>;
|
||||
pub type LocalLifetimeParamId = Idx<LifetimeParamData>;
|
||||
|
||||
/// Data about a generic type parameter (to a function, struct, impl, ...).
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct TypeParamData {
|
||||
/// [`None`] only if the type ref is an [`TypeRef::ImplTrait`]. FIXME: Might be better to just
|
||||
/// make it always be a value, giving impl trait a special name.
|
||||
pub name: Option<Name>,
|
||||
pub default: Option<TypeRefId>,
|
||||
pub provenance: TypeParamProvenance,
|
||||
}
|
||||
|
||||
/// Data about a generic lifetime parameter (to a function, struct, impl, ...).
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct LifetimeParamData {
|
||||
pub name: Name,
|
||||
}
|
||||
|
||||
/// Data about a generic const parameter (to a function, struct, impl, ...).
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct ConstParamData {
|
||||
pub name: Name,
|
||||
pub ty: TypeRefId,
|
||||
pub default: Option<ConstRef>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum TypeParamProvenance {
|
||||
TypeParamList,
|
||||
TraitSelf,
|
||||
ArgumentImplTrait,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum TypeOrConstParamData {
|
||||
TypeParamData(TypeParamData),
|
||||
ConstParamData(ConstParamData),
|
||||
}
|
||||
|
||||
impl TypeOrConstParamData {
|
||||
pub fn name(&self) -> Option<&Name> {
|
||||
match self {
|
||||
TypeOrConstParamData::TypeParamData(it) => it.name.as_ref(),
|
||||
TypeOrConstParamData::ConstParamData(it) => Some(&it.name),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_default(&self) -> bool {
|
||||
match self {
|
||||
TypeOrConstParamData::TypeParamData(it) => it.default.is_some(),
|
||||
TypeOrConstParamData::ConstParamData(it) => it.default.is_some(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_param(&self) -> Option<&TypeParamData> {
|
||||
match self {
|
||||
TypeOrConstParamData::TypeParamData(it) => Some(it),
|
||||
TypeOrConstParamData::ConstParamData(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn const_param(&self) -> Option<&ConstParamData> {
|
||||
match self {
|
||||
TypeOrConstParamData::TypeParamData(_) => None,
|
||||
TypeOrConstParamData::ConstParamData(it) => Some(it),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_trait_self(&self) -> bool {
|
||||
match self {
|
||||
TypeOrConstParamData::TypeParamData(it) => {
|
||||
it.provenance == TypeParamProvenance::TraitSelf
|
||||
}
|
||||
TypeOrConstParamData::ConstParamData(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_from!(TypeParamData, ConstParamData for TypeOrConstParamData);
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum GenericParamData {
|
||||
TypeParamData(TypeParamData),
|
||||
ConstParamData(ConstParamData),
|
||||
LifetimeParamData(LifetimeParamData),
|
||||
}
|
||||
|
||||
impl GenericParamData {
|
||||
pub fn name(&self) -> Option<&Name> {
|
||||
match self {
|
||||
GenericParamData::TypeParamData(it) => it.name.as_ref(),
|
||||
GenericParamData::ConstParamData(it) => Some(&it.name),
|
||||
GenericParamData::LifetimeParamData(it) => Some(&it.name),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_param(&self) -> Option<&TypeParamData> {
|
||||
match self {
|
||||
GenericParamData::TypeParamData(it) => Some(it),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn const_param(&self) -> Option<&ConstParamData> {
|
||||
match self {
|
||||
GenericParamData::ConstParamData(it) => Some(it),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lifetime_param(&self) -> Option<&LifetimeParamData> {
|
||||
match self {
|
||||
GenericParamData::LifetimeParamData(it) => Some(it),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_from!(TypeParamData, ConstParamData, LifetimeParamData for GenericParamData);
|
||||
|
||||
pub enum GenericParamDataRef<'a> {
|
||||
TypeParamData(&'a TypeParamData),
|
||||
ConstParamData(&'a ConstParamData),
|
||||
LifetimeParamData(&'a LifetimeParamData),
|
||||
}
|
||||
|
||||
/// Data about the generic parameters of a function, struct, impl, etc.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct GenericParams {
|
||||
pub(crate) type_or_consts: Arena<TypeOrConstParamData>,
|
||||
pub(crate) lifetimes: Arena<LifetimeParamData>,
|
||||
pub(crate) where_predicates: Box<[WherePredicate]>,
|
||||
}
|
||||
|
||||
impl ops::Index<LocalTypeOrConstParamId> for GenericParams {
|
||||
type Output = TypeOrConstParamData;
|
||||
fn index(&self, index: LocalTypeOrConstParamId) -> &TypeOrConstParamData {
|
||||
&self.type_or_consts[index]
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Index<LocalLifetimeParamId> for GenericParams {
|
||||
type Output = LifetimeParamData;
|
||||
fn index(&self, index: LocalLifetimeParamId) -> &LifetimeParamData {
|
||||
&self.lifetimes[index]
|
||||
}
|
||||
}
|
||||
|
||||
/// A single predicate from a where clause, i.e. `where Type: Trait`. Combined
|
||||
/// where clauses like `where T: Foo + Bar` are turned into multiple of these.
|
||||
/// It might still result in multiple actual predicates though, because of
|
||||
/// associated type bindings like `Iterator<Item = u32>`.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum WherePredicate {
|
||||
TypeBound { target: WherePredicateTypeTarget, bound: TypeBound },
|
||||
Lifetime { target: LifetimeRef, bound: LifetimeRef },
|
||||
ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound },
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum WherePredicateTypeTarget {
|
||||
TypeRef(TypeRefId),
|
||||
// FIXME: This can be folded into the above now that `TypeRef` can refer to `TypeParam`?
|
||||
/// For desugared where predicates that can directly refer to a type param.
|
||||
TypeOrConstParam(LocalTypeOrConstParamId),
|
||||
}
|
||||
|
||||
static EMPTY: LazyLock<Arc<GenericParams>> = LazyLock::new(|| {
|
||||
Arc::new(GenericParams {
|
||||
type_or_consts: Arena::default(),
|
||||
lifetimes: Arena::default(),
|
||||
where_predicates: Box::default(),
|
||||
})
|
||||
});
|
||||
impl GenericParams {
|
||||
pub fn new(db: &dyn DefDatabase, def: GenericDefId) -> Arc<GenericParams> {
|
||||
match def {
|
||||
GenericDefId::AdtId(AdtId::EnumId(it)) => db.enum_signature(it).generic_params.clone(),
|
||||
GenericDefId::AdtId(AdtId::StructId(it)) => {
|
||||
db.struct_signature(it).generic_params.clone()
|
||||
}
|
||||
GenericDefId::AdtId(AdtId::UnionId(it)) => {
|
||||
db.union_signature(it).generic_params.clone()
|
||||
}
|
||||
GenericDefId::ConstId(_) => EMPTY.clone(),
|
||||
GenericDefId::FunctionId(function_id) => {
|
||||
db.function_signature(function_id).generic_params.clone()
|
||||
}
|
||||
GenericDefId::ImplId(impl_id) => db.impl_signature(impl_id).generic_params.clone(),
|
||||
GenericDefId::StaticId(_) => EMPTY.clone(),
|
||||
GenericDefId::TraitAliasId(trait_alias_id) => {
|
||||
db.trait_alias_signature(trait_alias_id).generic_params.clone()
|
||||
}
|
||||
GenericDefId::TraitId(trait_id) => db.trait_signature(trait_id).generic_params.clone(),
|
||||
GenericDefId::TypeAliasId(type_alias_id) => {
|
||||
db.type_alias_signature(type_alias_id).generic_params.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generic_params_and_store(
|
||||
db: &dyn DefDatabase,
|
||||
def: GenericDefId,
|
||||
) -> (Arc<GenericParams>, Arc<ExpressionStore>) {
|
||||
match def {
|
||||
GenericDefId::AdtId(AdtId::EnumId(id)) => {
|
||||
let sig = db.enum_signature(id);
|
||||
(sig.generic_params.clone(), sig.store.clone())
|
||||
}
|
||||
GenericDefId::AdtId(AdtId::StructId(id)) => {
|
||||
let sig = db.struct_signature(id);
|
||||
(sig.generic_params.clone(), sig.store.clone())
|
||||
}
|
||||
GenericDefId::AdtId(AdtId::UnionId(id)) => {
|
||||
let sig = db.union_signature(id);
|
||||
(sig.generic_params.clone(), sig.store.clone())
|
||||
}
|
||||
GenericDefId::ConstId(id) => {
|
||||
let sig = db.const_signature(id);
|
||||
(EMPTY.clone(), sig.store.clone())
|
||||
}
|
||||
GenericDefId::FunctionId(id) => {
|
||||
let sig = db.function_signature(id);
|
||||
(sig.generic_params.clone(), sig.store.clone())
|
||||
}
|
||||
GenericDefId::ImplId(id) => {
|
||||
let sig = db.impl_signature(id);
|
||||
(sig.generic_params.clone(), sig.store.clone())
|
||||
}
|
||||
GenericDefId::StaticId(id) => {
|
||||
let sig = db.static_signature(id);
|
||||
(EMPTY.clone(), sig.store.clone())
|
||||
}
|
||||
GenericDefId::TraitAliasId(id) => {
|
||||
let sig = db.trait_alias_signature(id);
|
||||
(sig.generic_params.clone(), sig.store.clone())
|
||||
}
|
||||
GenericDefId::TraitId(id) => {
|
||||
let sig = db.trait_signature(id);
|
||||
(sig.generic_params.clone(), sig.store.clone())
|
||||
}
|
||||
GenericDefId::TypeAliasId(id) => {
|
||||
let sig = db.type_alias_signature(id);
|
||||
(sig.generic_params.clone(), sig.store.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generic_params_and_store_and_source_map(
|
||||
db: &dyn DefDatabase,
|
||||
def: GenericDefId,
|
||||
) -> (Arc<GenericParams>, Arc<ExpressionStore>, Arc<ExpressionStoreSourceMap>) {
|
||||
match def {
|
||||
GenericDefId::AdtId(AdtId::EnumId(id)) => {
|
||||
let (sig, sm) = db.enum_signature_with_source_map(id);
|
||||
(sig.generic_params.clone(), sig.store.clone(), sm)
|
||||
}
|
||||
GenericDefId::AdtId(AdtId::StructId(id)) => {
|
||||
let (sig, sm) = db.struct_signature_with_source_map(id);
|
||||
(sig.generic_params.clone(), sig.store.clone(), sm)
|
||||
}
|
||||
GenericDefId::AdtId(AdtId::UnionId(id)) => {
|
||||
let (sig, sm) = db.union_signature_with_source_map(id);
|
||||
(sig.generic_params.clone(), sig.store.clone(), sm)
|
||||
}
|
||||
GenericDefId::ConstId(id) => {
|
||||
let (sig, sm) = db.const_signature_with_source_map(id);
|
||||
(EMPTY.clone(), sig.store.clone(), sm)
|
||||
}
|
||||
GenericDefId::FunctionId(id) => {
|
||||
let (sig, sm) = db.function_signature_with_source_map(id);
|
||||
(sig.generic_params.clone(), sig.store.clone(), sm)
|
||||
}
|
||||
GenericDefId::ImplId(id) => {
|
||||
let (sig, sm) = db.impl_signature_with_source_map(id);
|
||||
(sig.generic_params.clone(), sig.store.clone(), sm)
|
||||
}
|
||||
GenericDefId::StaticId(id) => {
|
||||
let (sig, sm) = db.static_signature_with_source_map(id);
|
||||
(EMPTY.clone(), sig.store.clone(), sm)
|
||||
}
|
||||
GenericDefId::TraitAliasId(id) => {
|
||||
let (sig, sm) = db.trait_alias_signature_with_source_map(id);
|
||||
(sig.generic_params.clone(), sig.store.clone(), sm)
|
||||
}
|
||||
GenericDefId::TraitId(id) => {
|
||||
let (sig, sm) = db.trait_signature_with_source_map(id);
|
||||
(sig.generic_params.clone(), sig.store.clone(), sm)
|
||||
}
|
||||
GenericDefId::TypeAliasId(id) => {
|
||||
let (sig, sm) = db.type_alias_signature_with_source_map(id);
|
||||
(sig.generic_params.clone(), sig.store.clone(), sm)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Number of Generic parameters (type_or_consts + lifetimes)
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
self.type_or_consts.len() + self.lifetimes.len()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn len_lifetimes(&self) -> usize {
|
||||
self.lifetimes.len()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn len_type_or_consts(&self) -> usize {
|
||||
self.type_or_consts.len()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn no_predicates(&self) -> bool {
|
||||
self.where_predicates.is_empty()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn where_predicates(&self) -> std::slice::Iter<'_, WherePredicate> {
|
||||
self.where_predicates.iter()
|
||||
}
|
||||
|
||||
/// Iterator of type_or_consts field
|
||||
#[inline]
|
||||
pub fn iter_type_or_consts(
|
||||
&self,
|
||||
) -> impl DoubleEndedIterator<Item = (LocalTypeOrConstParamId, &TypeOrConstParamData)> {
|
||||
self.type_or_consts.iter()
|
||||
}
|
||||
|
||||
/// Iterator of lifetimes field
|
||||
#[inline]
|
||||
pub fn iter_lt(
|
||||
&self,
|
||||
) -> impl DoubleEndedIterator<Item = (LocalLifetimeParamId, &LifetimeParamData)> {
|
||||
self.lifetimes.iter()
|
||||
}
|
||||
|
||||
pub fn find_type_by_name(&self, name: &Name, parent: GenericDefId) -> Option<TypeParamId> {
|
||||
self.type_or_consts.iter().find_map(|(id, p)| {
|
||||
if p.name().as_ref() == Some(&name) && p.type_param().is_some() {
|
||||
Some(TypeParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent }))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn find_const_by_name(&self, name: &Name, parent: GenericDefId) -> Option<ConstParamId> {
|
||||
self.type_or_consts.iter().find_map(|(id, p)| {
|
||||
if p.name().as_ref() == Some(&name) && p.const_param().is_some() {
|
||||
Some(ConstParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent }))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn trait_self_param(&self) -> Option<LocalTypeOrConstParamId> {
|
||||
if self.type_or_consts.is_empty() {
|
||||
return None;
|
||||
}
|
||||
matches!(
|
||||
self.type_or_consts[SELF_PARAM_ID_IN_SELF],
|
||||
TypeOrConstParamData::TypeParamData(TypeParamData {
|
||||
provenance: TypeParamProvenance::TraitSelf,
|
||||
..
|
||||
})
|
||||
)
|
||||
.then(|| SELF_PARAM_ID_IN_SELF)
|
||||
}
|
||||
|
||||
pub fn find_lifetime_by_name(
|
||||
&self,
|
||||
name: &Name,
|
||||
parent: GenericDefId,
|
||||
) -> Option<LifetimeParamId> {
|
||||
self.lifetimes.iter().find_map(|(id, p)| {
|
||||
if &p.name == name { Some(LifetimeParamId { local_id: id, parent }) } else { None }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +1,22 @@
|
|||
//! HIR for references to types. Paths in these are not yet resolved. They can
|
||||
//! be directly created from an ast::TypeRef, without further queries.
|
||||
|
||||
use core::fmt;
|
||||
use std::{fmt::Write, ops::Index};
|
||||
use std::fmt::Write;
|
||||
|
||||
use hir_expand::{
|
||||
AstId, InFile,
|
||||
db::ExpandDatabase,
|
||||
name::{AsName, Name},
|
||||
};
|
||||
use intern::{Symbol, sym};
|
||||
use la_arena::{Arena, ArenaMap, Idx};
|
||||
use span::Edition;
|
||||
use syntax::{
|
||||
AstPtr,
|
||||
ast::{self, HasGenericArgs, HasName, IsString},
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
use intern::Symbol;
|
||||
use la_arena::Idx;
|
||||
use syntax::ast;
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::{
|
||||
SyntheticSyntax,
|
||||
TypeParamId,
|
||||
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
|
||||
hir::Literal,
|
||||
lower::LowerCtx,
|
||||
expr_store::{
|
||||
ExpressionStore,
|
||||
path::{GenericArg, Path},
|
||||
},
|
||||
hir::{ExprId, Literal},
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
|
|
@ -106,20 +99,6 @@ pub struct TraitRef {
|
|||
pub path: PathId,
|
||||
}
|
||||
|
||||
impl TraitRef {
|
||||
/// Converts an `ast::PathType` to a `hir::TraitRef`.
|
||||
pub(crate) fn from_ast(ctx: &mut LowerCtx<'_>, node: ast::Type) -> Option<Self> {
|
||||
// FIXME: Use `Path::from_src`
|
||||
match &node {
|
||||
ast::Type::PathType(path) => path
|
||||
.path()
|
||||
.and_then(|it| ctx.lower_path(it))
|
||||
.map(|path| TraitRef { path: ctx.alloc_path(path, AstPtr::new(&node)) }),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct FnType {
|
||||
pub params: Box<[(Option<Name>, TypeRefId)]>,
|
||||
|
|
@ -131,7 +110,6 @@ pub struct FnType {
|
|||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct ArrayType {
|
||||
pub ty: TypeRefId,
|
||||
// FIXME: This should be Ast<ConstArg>
|
||||
pub len: ConstRef,
|
||||
}
|
||||
|
||||
|
|
@ -151,13 +129,13 @@ pub enum TypeRef {
|
|||
Path(Path),
|
||||
RawPtr(TypeRefId, Mutability),
|
||||
Reference(Box<RefType>),
|
||||
Array(Box<ArrayType>),
|
||||
Array(ArrayType),
|
||||
Slice(TypeRefId),
|
||||
/// A fn pointer. Last element of the vector is the return type.
|
||||
Fn(Box<FnType>),
|
||||
ImplTrait(ThinVec<TypeBound>),
|
||||
DynTrait(ThinVec<TypeBound>),
|
||||
Macro(AstId<ast::MacroCall>),
|
||||
TypeParam(TypeParamId),
|
||||
Error,
|
||||
}
|
||||
|
||||
|
|
@ -166,72 +144,12 @@ const _: () = assert!(size_of::<TypeRef>() == 16);
|
|||
|
||||
pub type TypeRefId = Idx<TypeRef>;
|
||||
|
||||
#[derive(Default, Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct TypesMap {
|
||||
pub(crate) types: Arena<TypeRef>,
|
||||
}
|
||||
|
||||
impl TypesMap {
|
||||
pub const EMPTY: &TypesMap = &TypesMap { types: Arena::new() };
|
||||
|
||||
pub(crate) fn shrink_to_fit(&mut self) {
|
||||
let TypesMap { types } = self;
|
||||
types.shrink_to_fit();
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<TypeRefId> for TypesMap {
|
||||
type Output = TypeRef;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, index: TypeRefId) -> &Self::Output {
|
||||
&self.types[index]
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<PathId> for TypesMap {
|
||||
type Output = Path;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, index: PathId) -> &Self::Output {
|
||||
let TypeRef::Path(path) = &self[index.type_ref()] else {
|
||||
unreachable!("`PathId` always points to `TypeRef::Path`");
|
||||
};
|
||||
path
|
||||
}
|
||||
}
|
||||
|
||||
pub type TypePtr = AstPtr<ast::Type>;
|
||||
pub type TypeSource = InFile<TypePtr>;
|
||||
|
||||
#[derive(Default, Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct TypesSourceMap {
|
||||
pub(crate) types_map_back: ArenaMap<TypeRefId, TypeSource>,
|
||||
}
|
||||
|
||||
impl TypesSourceMap {
|
||||
pub const EMPTY: Self = Self { types_map_back: ArenaMap::new() };
|
||||
|
||||
pub fn type_syntax(&self, id: TypeRefId) -> Result<TypeSource, SyntheticSyntax> {
|
||||
self.types_map_back.get(id).cloned().ok_or(SyntheticSyntax)
|
||||
}
|
||||
|
||||
pub(crate) fn shrink_to_fit(&mut self) {
|
||||
let TypesSourceMap { types_map_back } = self;
|
||||
types_map_back.shrink_to_fit();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct LifetimeRef {
|
||||
pub name: Name,
|
||||
}
|
||||
|
||||
impl LifetimeRef {
|
||||
pub(crate) fn new_name(name: Name) -> Self {
|
||||
LifetimeRef { name }
|
||||
}
|
||||
|
||||
pub(crate) fn new(lifetime: &ast::Lifetime) -> Self {
|
||||
LifetimeRef { name: Name::new_lifetime(lifetime) }
|
||||
}
|
||||
|
|
@ -268,124 +186,14 @@ pub enum TraitBoundModifier {
|
|||
}
|
||||
|
||||
impl TypeRef {
|
||||
/// Converts an `ast::TypeRef` to a `hir::TypeRef`.
|
||||
pub fn from_ast(ctx: &mut LowerCtx<'_>, node: ast::Type) -> TypeRefId {
|
||||
let ty = match &node {
|
||||
ast::Type::ParenType(inner) => return TypeRef::from_ast_opt(ctx, inner.ty()),
|
||||
ast::Type::TupleType(inner) => TypeRef::Tuple(ThinVec::from_iter(Vec::from_iter(
|
||||
inner.fields().map(|it| TypeRef::from_ast(ctx, it)),
|
||||
))),
|
||||
ast::Type::NeverType(..) => TypeRef::Never,
|
||||
ast::Type::PathType(inner) => {
|
||||
// FIXME: Use `Path::from_src`
|
||||
inner
|
||||
.path()
|
||||
.and_then(|it| ctx.lower_path(it))
|
||||
.map(TypeRef::Path)
|
||||
.unwrap_or(TypeRef::Error)
|
||||
}
|
||||
ast::Type::PtrType(inner) => {
|
||||
let inner_ty = TypeRef::from_ast_opt(ctx, inner.ty());
|
||||
let mutability = Mutability::from_mutable(inner.mut_token().is_some());
|
||||
TypeRef::RawPtr(inner_ty, mutability)
|
||||
}
|
||||
ast::Type::ArrayType(inner) => {
|
||||
let len = ConstRef::from_const_arg(ctx, inner.const_arg());
|
||||
TypeRef::Array(Box::new(ArrayType {
|
||||
ty: TypeRef::from_ast_opt(ctx, inner.ty()),
|
||||
len,
|
||||
}))
|
||||
}
|
||||
ast::Type::SliceType(inner) => TypeRef::Slice(TypeRef::from_ast_opt(ctx, inner.ty())),
|
||||
ast::Type::RefType(inner) => {
|
||||
let inner_ty = TypeRef::from_ast_opt(ctx, inner.ty());
|
||||
let lifetime = inner.lifetime().map(|lt| LifetimeRef::new(<));
|
||||
let mutability = Mutability::from_mutable(inner.mut_token().is_some());
|
||||
TypeRef::Reference(Box::new(RefType { ty: inner_ty, lifetime, mutability }))
|
||||
}
|
||||
ast::Type::InferType(_inner) => TypeRef::Placeholder,
|
||||
ast::Type::FnPtrType(inner) => {
|
||||
let ret_ty = inner
|
||||
.ret_type()
|
||||
.and_then(|rt| rt.ty())
|
||||
.map(|it| TypeRef::from_ast(ctx, it))
|
||||
.unwrap_or_else(|| ctx.alloc_type_ref_desugared(TypeRef::unit()));
|
||||
let mut is_varargs = false;
|
||||
let mut params = if let Some(pl) = inner.param_list() {
|
||||
if let Some(param) = pl.params().last() {
|
||||
is_varargs = param.dotdotdot_token().is_some();
|
||||
}
|
||||
|
||||
pl.params()
|
||||
.map(|it| {
|
||||
let type_ref = TypeRef::from_ast_opt(ctx, it.ty());
|
||||
let name = match it.pat() {
|
||||
Some(ast::Pat::IdentPat(it)) => Some(
|
||||
it.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing),
|
||||
),
|
||||
_ => None,
|
||||
};
|
||||
(name, type_ref)
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
Vec::with_capacity(1)
|
||||
};
|
||||
fn lower_abi(abi: ast::Abi) -> Symbol {
|
||||
match abi.abi_string() {
|
||||
Some(tok) => Symbol::intern(tok.text_without_quotes()),
|
||||
// `extern` default to be `extern "C"`.
|
||||
_ => sym::C.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
let abi = inner.abi().map(lower_abi);
|
||||
params.push((None, ret_ty));
|
||||
TypeRef::Fn(Box::new(FnType {
|
||||
params: params.into(),
|
||||
is_varargs,
|
||||
is_unsafe: inner.unsafe_token().is_some(),
|
||||
abi,
|
||||
}))
|
||||
}
|
||||
// for types are close enough for our purposes to the inner type for now...
|
||||
ast::Type::ForType(inner) => return TypeRef::from_ast_opt(ctx, inner.ty()),
|
||||
ast::Type::ImplTraitType(inner) => {
|
||||
if ctx.outer_impl_trait() {
|
||||
// Disallow nested impl traits
|
||||
TypeRef::Error
|
||||
} else {
|
||||
ctx.with_outer_impl_trait_scope(true, |ctx| {
|
||||
TypeRef::ImplTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))
|
||||
})
|
||||
}
|
||||
}
|
||||
ast::Type::DynTraitType(inner) => {
|
||||
TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))
|
||||
}
|
||||
ast::Type::MacroType(mt) => match mt.macro_call() {
|
||||
Some(mc) => TypeRef::Macro(ctx.ast_id(&mc)),
|
||||
None => TypeRef::Error,
|
||||
},
|
||||
};
|
||||
ctx.alloc_type_ref(ty, AstPtr::new(&node))
|
||||
}
|
||||
|
||||
pub(crate) fn from_ast_opt(ctx: &mut LowerCtx<'_>, node: Option<ast::Type>) -> TypeRefId {
|
||||
match node {
|
||||
Some(node) => TypeRef::from_ast(ctx, node),
|
||||
None => ctx.alloc_error_type(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn unit() -> TypeRef {
|
||||
TypeRef::Tuple(ThinVec::new())
|
||||
}
|
||||
|
||||
pub fn walk(this: TypeRefId, map: &TypesMap, f: &mut impl FnMut(&TypeRef)) {
|
||||
pub fn walk(this: TypeRefId, map: &ExpressionStore, f: &mut impl FnMut(&TypeRef)) {
|
||||
go(this, f, map);
|
||||
|
||||
fn go(type_ref: TypeRefId, f: &mut impl FnMut(&TypeRef), map: &TypesMap) {
|
||||
fn go(type_ref: TypeRefId, f: &mut impl FnMut(&TypeRef), map: &ExpressionStore) {
|
||||
let type_ref = &map[type_ref];
|
||||
f(type_ref);
|
||||
match type_ref {
|
||||
|
|
@ -407,11 +215,11 @@ impl TypeRef {
|
|||
}
|
||||
}
|
||||
TypeRef::Path(path) => go_path(path, f, map),
|
||||
TypeRef::Never | TypeRef::Placeholder | TypeRef::Macro(_) | TypeRef::Error => {}
|
||||
TypeRef::Never | TypeRef::Placeholder | TypeRef::Error | TypeRef::TypeParam(_) => {}
|
||||
};
|
||||
}
|
||||
|
||||
fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef), map: &TypesMap) {
|
||||
fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef), map: &ExpressionStore) {
|
||||
if let Some(type_ref) = path.type_anchor() {
|
||||
go(type_ref, f, map);
|
||||
}
|
||||
|
|
@ -444,71 +252,8 @@ impl TypeRef {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn type_bounds_from_ast(
|
||||
lower_ctx: &mut LowerCtx<'_>,
|
||||
type_bounds_opt: Option<ast::TypeBoundList>,
|
||||
) -> ThinVec<TypeBound> {
|
||||
if let Some(type_bounds) = type_bounds_opt {
|
||||
ThinVec::from_iter(Vec::from_iter(
|
||||
type_bounds.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)),
|
||||
))
|
||||
} else {
|
||||
ThinVec::from_iter([])
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeBound {
|
||||
pub(crate) fn from_ast(ctx: &mut LowerCtx<'_>, node: ast::TypeBound) -> Self {
|
||||
let mut lower_path_type = |path_type: &ast::PathType| ctx.lower_path(path_type.path()?);
|
||||
|
||||
match node.kind() {
|
||||
ast::TypeBoundKind::PathType(path_type) => {
|
||||
let m = match node.question_mark_token() {
|
||||
Some(_) => TraitBoundModifier::Maybe,
|
||||
None => TraitBoundModifier::None,
|
||||
};
|
||||
lower_path_type(&path_type)
|
||||
.map(|p| {
|
||||
TypeBound::Path(ctx.alloc_path(p, AstPtr::new(&path_type).upcast()), m)
|
||||
})
|
||||
.unwrap_or(TypeBound::Error)
|
||||
}
|
||||
ast::TypeBoundKind::ForType(for_type) => {
|
||||
let lt_refs = match for_type.generic_param_list() {
|
||||
Some(gpl) => gpl
|
||||
.lifetime_params()
|
||||
.flat_map(|lp| lp.lifetime().map(|lt| Name::new_lifetime(<)))
|
||||
.collect(),
|
||||
None => Box::default(),
|
||||
};
|
||||
let path = for_type.ty().and_then(|ty| match &ty {
|
||||
ast::Type::PathType(path_type) => lower_path_type(path_type).map(|p| (p, ty)),
|
||||
_ => None,
|
||||
});
|
||||
match path {
|
||||
Some((p, ty)) => {
|
||||
TypeBound::ForLifetime(lt_refs, ctx.alloc_path(p, AstPtr::new(&ty)))
|
||||
}
|
||||
None => TypeBound::Error,
|
||||
}
|
||||
}
|
||||
ast::TypeBoundKind::Use(gal) => TypeBound::Use(
|
||||
gal.use_bound_generic_args()
|
||||
.map(|p| match p {
|
||||
ast::UseBoundGenericArg::Lifetime(l) => {
|
||||
UseArgRef::Lifetime(LifetimeRef::new(&l))
|
||||
}
|
||||
ast::UseBoundGenericArg::NameRef(n) => UseArgRef::Name(n.as_name()),
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
ast::TypeBoundKind::Lifetime(lifetime) => {
|
||||
TypeBound::Lifetime(LifetimeRef::new(&lifetime))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_path<'a>(&self, map: &'a TypesMap) -> Option<(&'a Path, TraitBoundModifier)> {
|
||||
pub fn as_path<'a>(&self, map: &'a ExpressionStore) -> Option<(&'a Path, TraitBoundModifier)> {
|
||||
match self {
|
||||
&TypeBound::Path(p, m) => Some((&map[p], m)),
|
||||
&TypeBound::ForLifetime(_, p) => Some((&map[p], TraitBoundModifier::None)),
|
||||
|
|
@ -517,90 +262,9 @@ impl TypeBound {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum ConstRef {
|
||||
Scalar(Box<LiteralConstRef>),
|
||||
Path(Name),
|
||||
Complex(AstId<ast::ConstArg>),
|
||||
}
|
||||
|
||||
impl ConstRef {
|
||||
pub(crate) fn from_const_arg(lower_ctx: &LowerCtx<'_>, arg: Option<ast::ConstArg>) -> Self {
|
||||
if let Some(arg) = arg {
|
||||
if let Some(expr) = arg.expr() {
|
||||
return Self::from_expr(expr, Some(lower_ctx.ast_id(&arg)));
|
||||
}
|
||||
}
|
||||
Self::Scalar(Box::new(LiteralConstRef::Unknown))
|
||||
}
|
||||
|
||||
pub(crate) fn from_const_param(
|
||||
lower_ctx: &LowerCtx<'_>,
|
||||
param: &ast::ConstParam,
|
||||
) -> Option<Self> {
|
||||
param.default_val().map(|default| Self::from_const_arg(lower_ctx, Some(default)))
|
||||
}
|
||||
|
||||
pub fn display<'a>(
|
||||
&'a self,
|
||||
db: &'a dyn ExpandDatabase,
|
||||
edition: Edition,
|
||||
) -> impl fmt::Display + 'a {
|
||||
struct Display<'a>(&'a dyn ExpandDatabase, &'a ConstRef, Edition);
|
||||
impl fmt::Display for Display<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.1 {
|
||||
ConstRef::Scalar(s) => s.fmt(f),
|
||||
ConstRef::Path(n) => n.display(self.0, self.2).fmt(f),
|
||||
ConstRef::Complex(_) => f.write_str("{const}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
Display(db, self, edition)
|
||||
}
|
||||
|
||||
// We special case literals and single identifiers, to speed up things.
|
||||
fn from_expr(expr: ast::Expr, ast_id: Option<AstId<ast::ConstArg>>) -> Self {
|
||||
fn is_path_ident(p: &ast::PathExpr) -> bool {
|
||||
let Some(path) = p.path() else {
|
||||
return false;
|
||||
};
|
||||
if path.coloncolon_token().is_some() {
|
||||
return false;
|
||||
}
|
||||
if let Some(s) = path.segment() {
|
||||
if s.coloncolon_token().is_some() || s.generic_arg_list().is_some() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
match expr {
|
||||
ast::Expr::PathExpr(p) if is_path_ident(&p) => {
|
||||
match p.path().and_then(|it| it.segment()).and_then(|it| it.name_ref()) {
|
||||
Some(it) => Self::Path(it.as_name()),
|
||||
None => Self::Scalar(Box::new(LiteralConstRef::Unknown)),
|
||||
}
|
||||
}
|
||||
ast::Expr::Literal(literal) => Self::Scalar(Box::new(match literal.kind() {
|
||||
ast::LiteralKind::IntNumber(num) => {
|
||||
num.value().map(LiteralConstRef::UInt).unwrap_or(LiteralConstRef::Unknown)
|
||||
}
|
||||
ast::LiteralKind::Char(c) => {
|
||||
c.value().map(LiteralConstRef::Char).unwrap_or(LiteralConstRef::Unknown)
|
||||
}
|
||||
ast::LiteralKind::Bool(f) => LiteralConstRef::Bool(f),
|
||||
_ => LiteralConstRef::Unknown,
|
||||
})),
|
||||
_ => {
|
||||
if let Some(ast_id) = ast_id {
|
||||
Self::Complex(ast_id)
|
||||
} else {
|
||||
Self::Scalar(Box::new(LiteralConstRef::Unknown))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct ConstRef {
|
||||
pub expr: ExprId,
|
||||
}
|
||||
|
||||
/// A literal constant value
|
||||
|
|
|
|||
|
|
@ -453,7 +453,7 @@ impl ItemScope {
|
|||
)
|
||||
}
|
||||
|
||||
pub(crate) fn macro_invoc(&self, call: AstId<ast::MacroCall>) -> Option<MacroCallId> {
|
||||
pub fn macro_invoc(&self, call: AstId<ast::MacroCall>) -> Option<MacroCallId> {
|
||||
self.macro_invocations.get(&call).copied()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,8 +45,12 @@ use std::{
|
|||
|
||||
use ast::{AstNode, StructKind};
|
||||
use base_db::Crate;
|
||||
use either::Either;
|
||||
use hir_expand::{ExpandTo, HirFileId, InFile, attrs::RawAttrs, name::Name};
|
||||
use hir_expand::{
|
||||
ExpandTo, HirFileId, InFile,
|
||||
attrs::RawAttrs,
|
||||
mod_path::{ModPath, PathKind},
|
||||
name::Name,
|
||||
};
|
||||
use intern::{Interned, Symbol};
|
||||
use la_arena::{Arena, Idx, RawIdx};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
|
@ -56,15 +60,7 @@ use stdx::never;
|
|||
use syntax::{SyntaxKind, ast, match_ast};
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
BlockId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup,
|
||||
attr::Attrs,
|
||||
db::DefDatabase,
|
||||
generics::GenericParams,
|
||||
path::{GenericArgs, ImportAlias, ModPath, Path, PathKind},
|
||||
type_ref::{Mutability, TraitRef, TypeBound, TypeRefId, TypesMap, TypesSourceMap},
|
||||
visibility::{RawVisibility, VisibilityExplicitness},
|
||||
};
|
||||
use crate::{BlockId, Lookup, attr::Attrs, db::DefDatabase};
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub struct RawVisibilityId(u32);
|
||||
|
|
@ -100,20 +96,13 @@ pub struct ItemTree {
|
|||
|
||||
impl ItemTree {
|
||||
pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
|
||||
db.file_item_tree_with_source_map(file_id).0
|
||||
}
|
||||
|
||||
pub(crate) fn file_item_tree_with_source_map_query(
|
||||
db: &dyn DefDatabase,
|
||||
file_id: HirFileId,
|
||||
) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
|
||||
let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered();
|
||||
static EMPTY: OnceLock<(Arc<ItemTree>, Arc<ItemTreeSourceMaps>)> = OnceLock::new();
|
||||
static EMPTY: OnceLock<Arc<ItemTree>> = OnceLock::new();
|
||||
|
||||
let ctx = lower::Ctx::new(db, file_id);
|
||||
let syntax = db.parse_or_expand(file_id);
|
||||
let mut top_attrs = None;
|
||||
let (mut item_tree, source_maps) = match_ast! {
|
||||
let mut item_tree = match_ast! {
|
||||
match syntax {
|
||||
ast::SourceFile(file) => {
|
||||
top_attrs = Some(RawAttrs::new(db.upcast(), &file, ctx.span_map()));
|
||||
|
|
@ -143,55 +132,42 @@ impl ItemTree {
|
|||
{
|
||||
EMPTY
|
||||
.get_or_init(|| {
|
||||
(
|
||||
Arc::new(ItemTree {
|
||||
top_level: SmallVec::new_const(),
|
||||
attrs: FxHashMap::default(),
|
||||
data: None,
|
||||
}),
|
||||
Arc::default(),
|
||||
)
|
||||
})
|
||||
})
|
||||
.clone()
|
||||
} else {
|
||||
item_tree.shrink_to_fit();
|
||||
(Arc::new(item_tree), Arc::new(source_maps))
|
||||
Arc::new(item_tree)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc<ItemTree> {
|
||||
db.block_item_tree_with_source_map(block).0
|
||||
}
|
||||
|
||||
pub(crate) fn block_item_tree_with_source_map_query(
|
||||
db: &dyn DefDatabase,
|
||||
block: BlockId,
|
||||
) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
|
||||
let _p = tracing::info_span!("block_item_tree_query", ?block).entered();
|
||||
static EMPTY: OnceLock<(Arc<ItemTree>, Arc<ItemTreeSourceMaps>)> = OnceLock::new();
|
||||
static EMPTY: OnceLock<Arc<ItemTree>> = OnceLock::new();
|
||||
|
||||
let loc = block.lookup(db);
|
||||
let block = loc.ast_id.to_node(db.upcast());
|
||||
|
||||
let ctx = lower::Ctx::new(db, loc.ast_id.file_id);
|
||||
let (mut item_tree, source_maps) = ctx.lower_block(&block);
|
||||
let mut item_tree = ctx.lower_block(&block);
|
||||
if item_tree.data.is_none() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty()
|
||||
{
|
||||
EMPTY
|
||||
.get_or_init(|| {
|
||||
(
|
||||
Arc::new(ItemTree {
|
||||
top_level: SmallVec::new_const(),
|
||||
attrs: FxHashMap::default(),
|
||||
data: None,
|
||||
}),
|
||||
Arc::default(),
|
||||
)
|
||||
})
|
||||
})
|
||||
.clone()
|
||||
} else {
|
||||
item_tree.shrink_to_fit();
|
||||
(Arc::new(item_tree), Arc::new(source_maps))
|
||||
Arc::new(item_tree)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -353,160 +329,6 @@ pub struct ItemTreeDataStats {
|
|||
pub macro_rules: usize,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Eq, PartialEq)]
|
||||
pub struct ItemTreeSourceMaps {
|
||||
all_concatenated: Box<[TypesSourceMap]>,
|
||||
structs_offset: u32,
|
||||
unions_offset: u32,
|
||||
enum_generics_offset: u32,
|
||||
variants_offset: u32,
|
||||
consts_offset: u32,
|
||||
statics_offset: u32,
|
||||
trait_generics_offset: u32,
|
||||
trait_alias_generics_offset: u32,
|
||||
impls_offset: u32,
|
||||
type_aliases_offset: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct GenericItemSourceMap<'a>(&'a [TypesSourceMap; 2]);
|
||||
|
||||
impl<'a> GenericItemSourceMap<'a> {
|
||||
#[inline]
|
||||
pub fn item(self) -> &'a TypesSourceMap {
|
||||
&self.0[0]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn generics(self) -> &'a TypesSourceMap {
|
||||
&self.0[1]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Eq, PartialEq)]
|
||||
pub struct GenericItemSourceMapBuilder {
|
||||
pub item: TypesSourceMap,
|
||||
pub generics: TypesSourceMap,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Eq, PartialEq)]
|
||||
struct ItemTreeSourceMapsBuilder {
|
||||
functions: Vec<GenericItemSourceMapBuilder>,
|
||||
structs: Vec<GenericItemSourceMapBuilder>,
|
||||
unions: Vec<GenericItemSourceMapBuilder>,
|
||||
enum_generics: Vec<TypesSourceMap>,
|
||||
variants: Vec<TypesSourceMap>,
|
||||
consts: Vec<TypesSourceMap>,
|
||||
statics: Vec<TypesSourceMap>,
|
||||
trait_generics: Vec<TypesSourceMap>,
|
||||
trait_alias_generics: Vec<TypesSourceMap>,
|
||||
impls: Vec<GenericItemSourceMapBuilder>,
|
||||
type_aliases: Vec<GenericItemSourceMapBuilder>,
|
||||
}
|
||||
|
||||
impl ItemTreeSourceMapsBuilder {
|
||||
fn build(self) -> ItemTreeSourceMaps {
|
||||
let ItemTreeSourceMapsBuilder {
|
||||
functions,
|
||||
structs,
|
||||
unions,
|
||||
enum_generics,
|
||||
variants,
|
||||
consts,
|
||||
statics,
|
||||
trait_generics,
|
||||
trait_alias_generics,
|
||||
impls,
|
||||
type_aliases,
|
||||
} = self;
|
||||
let structs_offset = functions.len() as u32 * 2;
|
||||
let unions_offset = structs_offset + (structs.len() as u32 * 2);
|
||||
let enum_generics_offset = unions_offset + (unions.len() as u32 * 2);
|
||||
let variants_offset = enum_generics_offset + (enum_generics.len() as u32);
|
||||
let consts_offset = variants_offset + (variants.len() as u32);
|
||||
let statics_offset = consts_offset + (consts.len() as u32);
|
||||
let trait_generics_offset = statics_offset + (statics.len() as u32);
|
||||
let trait_alias_generics_offset = trait_generics_offset + (trait_generics.len() as u32);
|
||||
let impls_offset = trait_alias_generics_offset + (trait_alias_generics.len() as u32);
|
||||
let type_aliases_offset = impls_offset + (impls.len() as u32 * 2);
|
||||
let all_concatenated = generics_concat(functions)
|
||||
.chain(generics_concat(structs))
|
||||
.chain(generics_concat(unions))
|
||||
.chain(enum_generics)
|
||||
.chain(variants)
|
||||
.chain(consts)
|
||||
.chain(statics)
|
||||
.chain(trait_generics)
|
||||
.chain(trait_alias_generics)
|
||||
.chain(generics_concat(impls))
|
||||
.chain(generics_concat(type_aliases))
|
||||
.collect();
|
||||
return ItemTreeSourceMaps {
|
||||
all_concatenated,
|
||||
structs_offset,
|
||||
unions_offset,
|
||||
enum_generics_offset,
|
||||
variants_offset,
|
||||
consts_offset,
|
||||
statics_offset,
|
||||
trait_generics_offset,
|
||||
trait_alias_generics_offset,
|
||||
impls_offset,
|
||||
type_aliases_offset,
|
||||
};
|
||||
|
||||
fn generics_concat(
|
||||
source_maps: Vec<GenericItemSourceMapBuilder>,
|
||||
) -> impl Iterator<Item = TypesSourceMap> {
|
||||
source_maps.into_iter().flat_map(|it| [it.item, it.generics])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ItemTreeSourceMaps {
|
||||
#[inline]
|
||||
fn generic_item(&self, offset: u32, index: u32) -> GenericItemSourceMap<'_> {
|
||||
GenericItemSourceMap(
|
||||
self.all_concatenated[(offset + (index * 2)) as usize..][..2].try_into().unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn non_generic_item(&self, offset: u32, index: u32) -> &TypesSourceMap {
|
||||
&self.all_concatenated[(offset + index) as usize]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn function(&self, index: FileItemTreeId<Function>) -> GenericItemSourceMap<'_> {
|
||||
self.generic_item(0, index.0.into_raw().into_u32())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! index_item_source_maps {
|
||||
( $( $name:ident; $field:ident[$tree_id:ident]; $fn:ident; $ret:ty, )* ) => {
|
||||
impl ItemTreeSourceMaps {
|
||||
$(
|
||||
#[inline]
|
||||
pub fn $name(&self, index: FileItemTreeId<$tree_id>) -> $ret {
|
||||
self.$fn(self.$field, index.0.into_raw().into_u32())
|
||||
}
|
||||
)*
|
||||
}
|
||||
};
|
||||
}
|
||||
index_item_source_maps! {
|
||||
strukt; structs_offset[Struct]; generic_item; GenericItemSourceMap<'_>,
|
||||
union; unions_offset[Union]; generic_item; GenericItemSourceMap<'_>,
|
||||
enum_generic; enum_generics_offset[Enum]; non_generic_item; &TypesSourceMap,
|
||||
variant; variants_offset[Variant]; non_generic_item; &TypesSourceMap,
|
||||
konst; consts_offset[Const]; non_generic_item; &TypesSourceMap,
|
||||
statik; statics_offset[Static]; non_generic_item; &TypesSourceMap,
|
||||
trait_generic; trait_generics_offset[Trait]; non_generic_item; &TypesSourceMap,
|
||||
trait_alias_generic; trait_alias_generics_offset[TraitAlias]; non_generic_item; &TypesSourceMap,
|
||||
impl_; impls_offset[Impl]; generic_item; GenericItemSourceMap<'_>,
|
||||
type_alias; type_aliases_offset[TypeAlias]; generic_item; GenericItemSourceMap<'_>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub enum AttrOwner {
|
||||
/// Attributes on an item.
|
||||
|
|
@ -515,10 +337,8 @@ pub enum AttrOwner {
|
|||
TopLevel,
|
||||
|
||||
Variant(FileItemTreeId<Variant>),
|
||||
// while not relevant to early name resolution, fields can contain visibility
|
||||
Field(FieldParent, ItemTreeFieldId),
|
||||
Param(FileItemTreeId<Function>, ItemTreeParamId),
|
||||
TypeOrConstParamData(GenericModItem, LocalTypeOrConstParamId),
|
||||
LifetimeParamData(GenericModItem, LocalLifetimeParamId),
|
||||
}
|
||||
|
||||
impl AttrOwner {
|
||||
|
|
@ -534,7 +354,6 @@ pub enum FieldParent {
|
|||
EnumVariant(FileItemTreeId<Variant>),
|
||||
}
|
||||
|
||||
pub type ItemTreeParamId = Idx<Param>;
|
||||
pub type ItemTreeFieldId = Idx<Field>;
|
||||
|
||||
macro_rules! from_attrs {
|
||||
|
|
@ -561,9 +380,6 @@ pub trait ItemTreeNode: Clone {
|
|||
fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self;
|
||||
fn attr_owner(id: FileItemTreeId<Self>) -> AttrOwner;
|
||||
}
|
||||
pub trait GenericsItemTreeNode: ItemTreeNode {
|
||||
fn generic_params(&self) -> &Arc<GenericParams>;
|
||||
}
|
||||
|
||||
pub struct FileItemTreeId<N>(Idx<N>);
|
||||
|
||||
|
|
@ -616,7 +432,7 @@ pub struct TreeId {
|
|||
}
|
||||
|
||||
impl TreeId {
|
||||
pub(crate) fn new(file: HirFileId, block: Option<BlockId>) -> Self {
|
||||
pub fn new(file: HirFileId, block: Option<BlockId>) -> Self {
|
||||
Self { file, block }
|
||||
}
|
||||
|
||||
|
|
@ -627,16 +443,6 @@ impl TreeId {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn item_tree_with_source_map(
|
||||
&self,
|
||||
db: &dyn DefDatabase,
|
||||
) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
|
||||
match self.block {
|
||||
Some(block) => db.block_item_tree_with_source_map(block),
|
||||
None => db.file_item_tree_with_source_map(self.file),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn file_id(self) -> HirFileId {
|
||||
self.file
|
||||
}
|
||||
|
|
@ -669,13 +475,6 @@ impl<N> ItemTreeId<N> {
|
|||
self.tree.item_tree(db)
|
||||
}
|
||||
|
||||
pub fn item_tree_with_source_map(
|
||||
self,
|
||||
db: &dyn DefDatabase,
|
||||
) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
|
||||
self.tree.item_tree_with_source_map(db)
|
||||
}
|
||||
|
||||
pub fn resolved<R>(self, db: &dyn DefDatabase, cb: impl FnOnce(&N) -> R) -> R
|
||||
where
|
||||
ItemTree: Index<FileItemTreeId<N>, Output = N>,
|
||||
|
|
@ -707,7 +506,7 @@ impl<N> Hash for ItemTreeId<N> {
|
|||
}
|
||||
|
||||
macro_rules! mod_items {
|
||||
( $( $typ:ident $(<$generic_params:ident>)? in $fld:ident -> $ast:ty ),+ $(,)? ) => {
|
||||
( $( $typ:ident in $fld:ident -> $ast:ty ),+ $(,)? ) => {
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum ModItem {
|
||||
$(
|
||||
|
|
@ -715,16 +514,6 @@ macro_rules! mod_items {
|
|||
)+
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum GenericModItem {
|
||||
$(
|
||||
$(
|
||||
#[cfg_attr(ignore_fragment, $generic_params)]
|
||||
$typ(FileItemTreeId<$typ>),
|
||||
)?
|
||||
)+
|
||||
}
|
||||
|
||||
impl ModItem {
|
||||
pub fn ast_id(&self, tree: &ItemTree) -> FileAstId<ast::Item> {
|
||||
match self {
|
||||
|
|
@ -733,52 +522,12 @@ macro_rules! mod_items {
|
|||
}
|
||||
}
|
||||
|
||||
impl GenericModItem {
|
||||
pub fn ast_id(&self, tree: &ItemTree) -> FileAstId<ast::AnyHasGenericParams> {
|
||||
match self {
|
||||
$(
|
||||
$(
|
||||
#[cfg_attr(ignore_fragment, $generic_params)]
|
||||
GenericModItem::$typ(it) => tree[it.index()].ast_id().upcast(),
|
||||
)?
|
||||
)+
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GenericModItem> for ModItem {
|
||||
fn from(id: GenericModItem) -> ModItem {
|
||||
match id {
|
||||
$(
|
||||
$(
|
||||
#[cfg_attr(ignore_fragment, $generic_params)]
|
||||
GenericModItem::$typ(id) => ModItem::$typ(id),
|
||||
)?
|
||||
)+
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GenericModItem> for AttrOwner {
|
||||
fn from(t: GenericModItem) -> AttrOwner {
|
||||
AttrOwner::ModItem(t.into())
|
||||
}
|
||||
}
|
||||
|
||||
$(
|
||||
impl From<FileItemTreeId<$typ>> for ModItem {
|
||||
fn from(id: FileItemTreeId<$typ>) -> ModItem {
|
||||
ModItem::$typ(id)
|
||||
}
|
||||
}
|
||||
$(
|
||||
#[cfg_attr(ignore_fragment, $generic_params)]
|
||||
impl From<FileItemTreeId<$typ>> for GenericModItem {
|
||||
fn from(id: FileItemTreeId<$typ>) -> GenericModItem {
|
||||
GenericModItem::$typ(id)
|
||||
}
|
||||
}
|
||||
)?
|
||||
)+
|
||||
|
||||
$(
|
||||
|
|
@ -805,14 +554,6 @@ macro_rules! mod_items {
|
|||
&self.data().$fld[index]
|
||||
}
|
||||
}
|
||||
|
||||
$(
|
||||
impl GenericsItemTreeNode for $typ {
|
||||
fn generic_params(&self) -> &Arc<GenericParams> {
|
||||
&self.$generic_params
|
||||
}
|
||||
}
|
||||
)?
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
|
@ -821,16 +562,16 @@ mod_items! {
|
|||
Use in uses -> ast::Use,
|
||||
ExternCrate in extern_crates -> ast::ExternCrate,
|
||||
ExternBlock in extern_blocks -> ast::ExternBlock,
|
||||
Function<explicit_generic_params> in functions -> ast::Fn,
|
||||
Struct<generic_params> in structs -> ast::Struct,
|
||||
Union<generic_params> in unions -> ast::Union,
|
||||
Enum<generic_params> in enums -> ast::Enum,
|
||||
Function in functions -> ast::Fn,
|
||||
Struct in structs -> ast::Struct,
|
||||
Union in unions -> ast::Union,
|
||||
Enum in enums -> ast::Enum,
|
||||
Const in consts -> ast::Const,
|
||||
Static in statics -> ast::Static,
|
||||
Trait<generic_params> in traits -> ast::Trait,
|
||||
TraitAlias<generic_params> in trait_aliases -> ast::TraitAlias,
|
||||
Impl<generic_params> in impls -> ast::Impl,
|
||||
TypeAlias<generic_params> in type_aliases -> ast::TypeAlias,
|
||||
Trait in traits -> ast::Trait,
|
||||
TraitAlias in trait_aliases -> ast::TraitAlias,
|
||||
Impl in impls -> ast::Impl,
|
||||
TypeAlias in type_aliases -> ast::TypeAlias,
|
||||
Mod in mods -> ast::Module,
|
||||
MacroCall in macro_calls -> ast::MacroCall,
|
||||
MacroRules in macro_rules -> ast::MacroRules,
|
||||
|
|
@ -906,6 +647,34 @@ pub struct UseTree {
|
|||
kind: UseTreeKind,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ImportAlias {
|
||||
/// Unnamed alias, as in `use Foo as _;`
|
||||
Underscore,
|
||||
/// Named alias
|
||||
Alias(Name),
|
||||
}
|
||||
|
||||
impl ImportAlias {
|
||||
pub fn display(&self, edition: Edition) -> impl fmt::Display + '_ {
|
||||
ImportAliasDisplay { value: self, edition }
|
||||
}
|
||||
}
|
||||
|
||||
struct ImportAliasDisplay<'a> {
|
||||
value: &'a ImportAlias,
|
||||
edition: Edition,
|
||||
}
|
||||
|
||||
impl fmt::Display for ImportAliasDisplay<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.value {
|
||||
ImportAlias::Underscore => f.write_str("_"),
|
||||
ImportAlias::Alias(name) => fmt::Display::fmt(&name.display_no_db(self.edition), f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub enum UseTreeKind {
|
||||
/// ```ignore
|
||||
|
|
@ -946,67 +715,30 @@ pub struct ExternBlock {
|
|||
pub struct Function {
|
||||
pub name: Name,
|
||||
pub visibility: RawVisibilityId,
|
||||
pub explicit_generic_params: Arc<GenericParams>,
|
||||
pub abi: Option<Symbol>,
|
||||
pub params: Box<[Param]>,
|
||||
pub ret_type: TypeRefId,
|
||||
pub ast_id: FileAstId<ast::Fn>,
|
||||
pub types_map: Arc<TypesMap>,
|
||||
pub(crate) flags: FnFlags,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Param {
|
||||
pub type_ref: Option<TypeRefId>,
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
|
||||
pub struct FnFlags: u16 {
|
||||
const HAS_SELF_PARAM = 1 << 0;
|
||||
const HAS_BODY = 1 << 1;
|
||||
const HAS_DEFAULT_KW = 1 << 2;
|
||||
const HAS_CONST_KW = 1 << 3;
|
||||
const HAS_ASYNC_KW = 1 << 4;
|
||||
const HAS_UNSAFE_KW = 1 << 5;
|
||||
const IS_VARARGS = 1 << 6;
|
||||
const HAS_SAFE_KW = 1 << 7;
|
||||
/// The `#[target_feature]` attribute is necessary to check safety (with RFC 2396),
|
||||
/// but keeping it for all functions will consume a lot of memory when there are
|
||||
/// only very few functions with it. So we only encode its existence here, and lookup
|
||||
/// it if needed.
|
||||
const HAS_TARGET_FEATURE = 1 << 8;
|
||||
const DEPRECATED_SAFE_2024 = 1 << 9;
|
||||
const RUSTC_ALLOW_INCOHERENT_IMPL = 1 << 10;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Struct {
|
||||
pub name: Name,
|
||||
pub visibility: RawVisibilityId,
|
||||
pub generic_params: Arc<GenericParams>,
|
||||
pub fields: Box<[Field]>,
|
||||
pub shape: FieldsShape,
|
||||
pub ast_id: FileAstId<ast::Struct>,
|
||||
pub types_map: Arc<TypesMap>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Union {
|
||||
pub name: Name,
|
||||
pub visibility: RawVisibilityId,
|
||||
pub generic_params: Arc<GenericParams>,
|
||||
pub fields: Box<[Field]>,
|
||||
pub ast_id: FileAstId<ast::Union>,
|
||||
pub types_map: Arc<TypesMap>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Enum {
|
||||
pub name: Name,
|
||||
pub visibility: RawVisibilityId,
|
||||
pub generic_params: Arc<GenericParams>,
|
||||
pub variants: Range<FileItemTreeId<Variant>>,
|
||||
pub ast_id: FileAstId<ast::Enum>,
|
||||
}
|
||||
|
|
@ -1017,7 +749,6 @@ pub struct Variant {
|
|||
pub fields: Box<[Field]>,
|
||||
pub shape: FieldsShape,
|
||||
pub ast_id: FileAstId<ast::Variant>,
|
||||
pub types_map: Arc<TypesMap>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
|
|
@ -1027,12 +758,37 @@ pub enum FieldsShape {
|
|||
Unit,
|
||||
}
|
||||
|
||||
/// Visibility of an item, not yet resolved.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum RawVisibility {
|
||||
/// `pub(in module)`, `pub(crate)` or `pub(super)`. Also private, which is
|
||||
/// equivalent to `pub(self)`.
|
||||
Module(Interned<ModPath>, VisibilityExplicitness),
|
||||
/// `pub`.
|
||||
Public,
|
||||
}
|
||||
|
||||
/// Whether the item was imported through an explicit `pub(crate) use` or just a `use` without
|
||||
/// visibility.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum VisibilityExplicitness {
|
||||
Explicit,
|
||||
Implicit,
|
||||
}
|
||||
|
||||
impl VisibilityExplicitness {
|
||||
pub fn is_explicit(&self) -> bool {
|
||||
matches!(self, Self::Explicit)
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Remove this from item tree?
|
||||
/// A single field of an enum variant or struct
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Field {
|
||||
pub name: Name,
|
||||
pub type_ref: TypeRefId,
|
||||
pub visibility: RawVisibilityId,
|
||||
// FIXME: Not an item tree property
|
||||
pub is_unsafe: bool,
|
||||
}
|
||||
|
||||
|
|
@ -1041,39 +797,20 @@ pub struct Const {
|
|||
/// `None` for `const _: () = ();`
|
||||
pub name: Option<Name>,
|
||||
pub visibility: RawVisibilityId,
|
||||
pub type_ref: TypeRefId,
|
||||
pub ast_id: FileAstId<ast::Const>,
|
||||
pub has_body: bool,
|
||||
pub types_map: Arc<TypesMap>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Static {
|
||||
pub name: Name,
|
||||
pub visibility: RawVisibilityId,
|
||||
pub flags: StaticFlags,
|
||||
pub type_ref: TypeRefId,
|
||||
pub ast_id: FileAstId<ast::Static>,
|
||||
pub types_map: Arc<TypesMap>,
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct StaticFlags: u8 {
|
||||
const MUTABLE = 1 << 0;
|
||||
const IS_EXTERN = 1 << 1;
|
||||
const HAS_SAFE_KW = 1 << 2;
|
||||
const HAS_UNSAFE_KW = 1 << 3;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Trait {
|
||||
pub name: Name,
|
||||
pub visibility: RawVisibilityId,
|
||||
pub generic_params: Arc<GenericParams>,
|
||||
pub is_auto: bool,
|
||||
pub is_unsafe: bool,
|
||||
pub items: Box<[AssocItem]>,
|
||||
pub ast_id: FileAstId<ast::Trait>,
|
||||
}
|
||||
|
|
@ -1082,32 +819,20 @@ pub struct Trait {
|
|||
pub struct TraitAlias {
|
||||
pub name: Name,
|
||||
pub visibility: RawVisibilityId,
|
||||
pub generic_params: Arc<GenericParams>,
|
||||
pub ast_id: FileAstId<ast::TraitAlias>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Impl {
|
||||
pub generic_params: Arc<GenericParams>,
|
||||
pub target_trait: Option<TraitRef>,
|
||||
pub self_ty: TypeRefId,
|
||||
pub is_negative: bool,
|
||||
pub is_unsafe: bool,
|
||||
pub items: Box<[AssocItem]>,
|
||||
pub ast_id: FileAstId<ast::Impl>,
|
||||
pub types_map: Arc<TypesMap>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct TypeAlias {
|
||||
pub name: Name,
|
||||
pub visibility: RawVisibilityId,
|
||||
/// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`.
|
||||
pub bounds: Box<[TypeBound]>,
|
||||
pub generic_params: Arc<GenericParams>,
|
||||
pub type_ref: Option<TypeRefId>,
|
||||
pub ast_id: FileAstId<ast::TypeAlias>,
|
||||
pub types_map: Arc<TypesMap>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
|
|
|
|||
|
|
@ -4,41 +4,28 @@ use std::{cell::OnceCell, collections::hash_map::Entry};
|
|||
|
||||
use hir_expand::{
|
||||
HirFileId,
|
||||
mod_path::path,
|
||||
mod_path::PathKind,
|
||||
name::AsName,
|
||||
span_map::{SpanMap, SpanMapRef},
|
||||
};
|
||||
use intern::{Symbol, sym};
|
||||
use la_arena::Arena;
|
||||
use rustc_hash::FxHashMap;
|
||||
use span::{AstIdMap, SyntaxContext};
|
||||
use syntax::{
|
||||
AstNode,
|
||||
ast::{self, HasModuleItem, HasName, HasTypeBounds, IsString},
|
||||
ast::{self, HasModuleItem, HasName, IsString},
|
||||
};
|
||||
use thin_vec::ThinVec;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
LocalLifetimeParamId, LocalTypeOrConstParamId,
|
||||
db::DefDatabase,
|
||||
generics::{GenericParams, GenericParamsCollector},
|
||||
item_tree::{
|
||||
AssocItem, AttrOwner, Const, Either, Enum, ExternBlock, ExternCrate, Field, FieldParent,
|
||||
FieldsShape, FileItemTreeId, FnFlags, Function, GenericArgs, GenericItemSourceMapBuilder,
|
||||
GenericModItem, Idx, Impl, ImportAlias, Interned, ItemTree, ItemTreeData,
|
||||
ItemTreeSourceMaps, ItemTreeSourceMapsBuilder, Macro2, MacroCall, MacroRules, Mod, ModItem,
|
||||
ModKind, ModPath, Mutability, Name, Param, Path, Range, RawAttrs, RawIdx, RawVisibilityId,
|
||||
Static, StaticFlags, Struct, StructKind, Trait, TraitAlias, TypeAlias, Union, Use, UseTree,
|
||||
UseTreeKind, Variant,
|
||||
AssocItem, AttrOwner, Const, Enum, ExternBlock, ExternCrate, Field, FieldParent,
|
||||
FieldsShape, FileItemTreeId, Function, Idx, Impl, ImportAlias, Interned, ItemTree,
|
||||
ItemTreeData, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, ModPath, Name, Range,
|
||||
RawAttrs, RawIdx, RawVisibility, RawVisibilityId, Static, Struct, StructKind, Trait,
|
||||
TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind, Variant, VisibilityExplicitness,
|
||||
},
|
||||
lower::LowerCtx,
|
||||
path::AssociatedTypeBinding,
|
||||
type_ref::{
|
||||
LifetimeRef, PathId, RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId,
|
||||
TypesMap, TypesSourceMap,
|
||||
},
|
||||
visibility::RawVisibility,
|
||||
};
|
||||
|
||||
fn id<N>(index: Idx<N>) -> FileItemTreeId<N> {
|
||||
|
|
@ -49,11 +36,8 @@ pub(super) struct Ctx<'a> {
|
|||
db: &'a dyn DefDatabase,
|
||||
tree: ItemTree,
|
||||
source_ast_id_map: Arc<AstIdMap>,
|
||||
generic_param_attr_buffer:
|
||||
FxHashMap<Either<LocalTypeOrConstParamId, LocalLifetimeParamId>, RawAttrs>,
|
||||
span_map: OnceCell<SpanMap>,
|
||||
file: HirFileId,
|
||||
source_maps: ItemTreeSourceMapsBuilder,
|
||||
}
|
||||
|
||||
impl<'a> Ctx<'a> {
|
||||
|
|
@ -61,11 +45,9 @@ impl<'a> Ctx<'a> {
|
|||
Self {
|
||||
db,
|
||||
tree: ItemTree::default(),
|
||||
generic_param_attr_buffer: FxHashMap::default(),
|
||||
source_ast_id_map: db.ast_id_map(file),
|
||||
file,
|
||||
span_map: OnceCell::new(),
|
||||
source_maps: ItemTreeSourceMapsBuilder::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -73,39 +55,13 @@ impl<'a> Ctx<'a> {
|
|||
self.span_map.get_or_init(|| self.db.span_map(self.file)).as_ref()
|
||||
}
|
||||
|
||||
fn body_ctx<'b, 'c>(
|
||||
&self,
|
||||
types_map: &'b mut TypesMap,
|
||||
types_source_map: &'b mut TypesSourceMap,
|
||||
) -> LowerCtx<'c>
|
||||
where
|
||||
'a: 'c,
|
||||
'b: 'c,
|
||||
{
|
||||
// FIXME: This seems a bit wasteful that if `LowerCtx` will initialize the span map we won't benefit.
|
||||
LowerCtx::with_span_map_cell(
|
||||
self.db,
|
||||
self.file,
|
||||
self.span_map.clone(),
|
||||
types_map,
|
||||
types_source_map,
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn lower_module_items(
|
||||
mut self,
|
||||
item_owner: &dyn HasModuleItem,
|
||||
) -> (ItemTree, ItemTreeSourceMaps) {
|
||||
pub(super) fn lower_module_items(mut self, item_owner: &dyn HasModuleItem) -> ItemTree {
|
||||
self.tree.top_level =
|
||||
item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect();
|
||||
assert!(self.generic_param_attr_buffer.is_empty());
|
||||
(self.tree, self.source_maps.build())
|
||||
self.tree
|
||||
}
|
||||
|
||||
pub(super) fn lower_macro_stmts(
|
||||
mut self,
|
||||
stmts: ast::MacroStmts,
|
||||
) -> (ItemTree, ItemTreeSourceMaps) {
|
||||
pub(super) fn lower_macro_stmts(mut self, stmts: ast::MacroStmts) -> ItemTree {
|
||||
self.tree.top_level = stmts
|
||||
.statements()
|
||||
.filter_map(|stmt| {
|
||||
|
|
@ -135,11 +91,10 @@ impl<'a> Ctx<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
assert!(self.generic_param_attr_buffer.is_empty());
|
||||
(self.tree, self.source_maps.build())
|
||||
self.tree
|
||||
}
|
||||
|
||||
pub(super) fn lower_block(mut self, block: &ast::BlockExpr) -> (ItemTree, ItemTreeSourceMaps) {
|
||||
pub(super) fn lower_block(mut self, block: &ast::BlockExpr) -> ItemTree {
|
||||
self.tree
|
||||
.attrs
|
||||
.insert(AttrOwner::TopLevel, RawAttrs::new(self.db.upcast(), block, self.span_map()));
|
||||
|
|
@ -164,8 +119,7 @@ impl<'a> Ctx<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
assert!(self.generic_param_attr_buffer.is_empty());
|
||||
(self.tree, self.source_maps.build())
|
||||
self.tree
|
||||
}
|
||||
|
||||
fn data(&mut self) -> &mut ItemTreeData {
|
||||
|
|
@ -232,31 +186,13 @@ impl<'a> Ctx<'a> {
|
|||
}
|
||||
|
||||
fn lower_struct(&mut self, strukt: &ast::Struct) -> Option<FileItemTreeId<Struct>> {
|
||||
let (mut types_map, mut types_source_map) =
|
||||
(TypesMap::default(), TypesSourceMap::default());
|
||||
let mut body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
|
||||
let visibility = self.lower_visibility(strukt);
|
||||
let name = strukt.name()?.as_name();
|
||||
let ast_id = self.source_ast_id_map.ast_id(strukt);
|
||||
let (fields, kind, attrs) = self.lower_fields(&strukt.kind(), &mut body_ctx);
|
||||
let (generic_params, generics_source_map) =
|
||||
self.lower_generic_params(HasImplicitSelf::No, strukt);
|
||||
types_map.shrink_to_fit();
|
||||
types_source_map.shrink_to_fit();
|
||||
let res = Struct {
|
||||
name,
|
||||
visibility,
|
||||
generic_params,
|
||||
fields,
|
||||
shape: kind,
|
||||
ast_id,
|
||||
types_map: Arc::new(types_map),
|
||||
};
|
||||
let (fields, kind, attrs) = self.lower_fields(&strukt.kind());
|
||||
let res = Struct { name, visibility, fields, shape: kind, ast_id };
|
||||
let id = id(self.data().structs.alloc(res));
|
||||
self.source_maps.structs.push(GenericItemSourceMapBuilder {
|
||||
item: types_source_map,
|
||||
generics: generics_source_map,
|
||||
});
|
||||
|
||||
for (idx, attr) in attrs {
|
||||
self.add_attrs(
|
||||
AttrOwner::Field(
|
||||
|
|
@ -266,14 +202,12 @@ impl<'a> Ctx<'a> {
|
|||
attr,
|
||||
);
|
||||
}
|
||||
self.write_generic_params_attributes(id.into());
|
||||
Some(id)
|
||||
}
|
||||
|
||||
fn lower_fields(
|
||||
&mut self,
|
||||
strukt_kind: &ast::StructKind,
|
||||
body_ctx: &mut LowerCtx<'_>,
|
||||
) -> (Box<[Field]>, FieldsShape, Vec<(usize, RawAttrs)>) {
|
||||
match strukt_kind {
|
||||
ast::StructKind::Record(it) => {
|
||||
|
|
@ -281,7 +215,7 @@ impl<'a> Ctx<'a> {
|
|||
let mut attrs = vec![];
|
||||
|
||||
for (i, field) in it.fields().enumerate() {
|
||||
let data = self.lower_record_field(&field, body_ctx);
|
||||
let data = self.lower_record_field(&field);
|
||||
fields.push(data);
|
||||
let attr = RawAttrs::new(self.db.upcast(), &field, self.span_map());
|
||||
if !attr.is_empty() {
|
||||
|
|
@ -295,7 +229,7 @@ impl<'a> Ctx<'a> {
|
|||
let mut attrs = vec![];
|
||||
|
||||
for (i, field) in it.fields().enumerate() {
|
||||
let data = self.lower_tuple_field(i, &field, body_ctx);
|
||||
let data = self.lower_tuple_field(i, &field);
|
||||
fields.push(data);
|
||||
let attr = RawAttrs::new(self.db.upcast(), &field, self.span_map());
|
||||
if !attr.is_empty() {
|
||||
|
|
@ -308,63 +242,32 @@ impl<'a> Ctx<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn lower_record_field(
|
||||
&mut self,
|
||||
field: &ast::RecordField,
|
||||
body_ctx: &mut LowerCtx<'_>,
|
||||
) -> Field {
|
||||
fn lower_record_field(&mut self, field: &ast::RecordField) -> Field {
|
||||
let name = match field.name() {
|
||||
Some(name) => name.as_name(),
|
||||
None => Name::missing(),
|
||||
};
|
||||
let visibility = self.lower_visibility(field);
|
||||
let type_ref = TypeRef::from_ast_opt(body_ctx, field.ty());
|
||||
|
||||
Field { name, type_ref, visibility, is_unsafe: field.unsafe_token().is_some() }
|
||||
Field { name, visibility, is_unsafe: field.unsafe_token().is_some() }
|
||||
}
|
||||
|
||||
fn lower_tuple_field(
|
||||
&mut self,
|
||||
idx: usize,
|
||||
field: &ast::TupleField,
|
||||
body_ctx: &mut LowerCtx<'_>,
|
||||
) -> Field {
|
||||
fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleField) -> Field {
|
||||
let name = Name::new_tuple_field(idx);
|
||||
let visibility = self.lower_visibility(field);
|
||||
let type_ref = TypeRef::from_ast_opt(body_ctx, field.ty());
|
||||
Field { name, type_ref, visibility, is_unsafe: false }
|
||||
Field { name, visibility, is_unsafe: false }
|
||||
}
|
||||
|
||||
fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {
|
||||
let (mut types_map, mut types_source_map) =
|
||||
(TypesMap::default(), TypesSourceMap::default());
|
||||
let mut body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
|
||||
let visibility = self.lower_visibility(union);
|
||||
let name = union.name()?.as_name();
|
||||
let ast_id = self.source_ast_id_map.ast_id(union);
|
||||
let (fields, _, attrs) = match union.record_field_list() {
|
||||
Some(record_field_list) => {
|
||||
self.lower_fields(&StructKind::Record(record_field_list), &mut body_ctx)
|
||||
}
|
||||
Some(record_field_list) => self.lower_fields(&StructKind::Record(record_field_list)),
|
||||
None => (Box::default(), FieldsShape::Record, Vec::default()),
|
||||
};
|
||||
let (generic_params, generics_source_map) =
|
||||
self.lower_generic_params(HasImplicitSelf::No, union);
|
||||
types_map.shrink_to_fit();
|
||||
types_source_map.shrink_to_fit();
|
||||
let res = Union {
|
||||
name,
|
||||
visibility,
|
||||
generic_params,
|
||||
fields,
|
||||
ast_id,
|
||||
types_map: Arc::new(types_map),
|
||||
};
|
||||
let res = Union { name, visibility, fields, ast_id };
|
||||
let id = id(self.data().unions.alloc(res));
|
||||
self.source_maps.unions.push(GenericItemSourceMapBuilder {
|
||||
item: types_source_map,
|
||||
generics: generics_source_map,
|
||||
});
|
||||
for (idx, attr) in attrs {
|
||||
self.add_attrs(
|
||||
AttrOwner::Field(
|
||||
|
|
@ -374,7 +277,6 @@ impl<'a> Ctx<'a> {
|
|||
attr,
|
||||
);
|
||||
}
|
||||
self.write_generic_params_attributes(id.into());
|
||||
Some(id)
|
||||
}
|
||||
|
||||
|
|
@ -388,12 +290,8 @@ impl<'a> Ctx<'a> {
|
|||
FileItemTreeId(self.next_variant_idx())..FileItemTreeId(self.next_variant_idx())
|
||||
}
|
||||
};
|
||||
let (generic_params, generics_source_map) =
|
||||
self.lower_generic_params(HasImplicitSelf::No, enum_);
|
||||
let res = Enum { name, visibility, generic_params, variants, ast_id };
|
||||
let res = Enum { name, visibility, variants, ast_id };
|
||||
let id = id(self.data().enums.alloc(res));
|
||||
self.source_maps.enum_generics.push(generics_source_map);
|
||||
self.write_generic_params_attributes(id.into());
|
||||
Some(id)
|
||||
}
|
||||
|
||||
|
|
@ -411,20 +309,14 @@ impl<'a> Ctx<'a> {
|
|||
}
|
||||
|
||||
fn lower_variant(&mut self, variant: &ast::Variant) -> Idx<Variant> {
|
||||
let (mut types_map, mut types_source_map) =
|
||||
(TypesMap::default(), TypesSourceMap::default());
|
||||
let mut body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
|
||||
let name = match variant.name() {
|
||||
Some(name) => name.as_name(),
|
||||
None => Name::missing(),
|
||||
};
|
||||
let (fields, kind, attrs) = self.lower_fields(&variant.kind(), &mut body_ctx);
|
||||
let (fields, kind, attrs) = self.lower_fields(&variant.kind());
|
||||
let ast_id = self.source_ast_id_map.ast_id(variant);
|
||||
types_map.shrink_to_fit();
|
||||
types_source_map.shrink_to_fit();
|
||||
let res = Variant { name, fields, shape: kind, ast_id, types_map: Arc::new(types_map) };
|
||||
let res = Variant { name, fields, shape: kind, ast_id };
|
||||
let id = self.data().variants.alloc(res);
|
||||
self.source_maps.variants.push(types_source_map);
|
||||
for (idx, attr) in attrs {
|
||||
self.add_attrs(
|
||||
AttrOwner::Field(
|
||||
|
|
@ -438,144 +330,14 @@ impl<'a> Ctx<'a> {
|
|||
}
|
||||
|
||||
fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>> {
|
||||
let (mut types_map, mut types_source_map) =
|
||||
(TypesMap::default(), TypesSourceMap::default());
|
||||
let mut body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
|
||||
|
||||
let visibility = self.lower_visibility(func);
|
||||
let name = func.name()?.as_name();
|
||||
|
||||
let mut has_self_param = false;
|
||||
let mut has_var_args = false;
|
||||
let mut params = vec![];
|
||||
let mut attrs = vec![];
|
||||
let mut push_attr = |idx, attr: RawAttrs| {
|
||||
if !attr.is_empty() {
|
||||
attrs.push((idx, attr))
|
||||
}
|
||||
};
|
||||
if let Some(param_list) = func.param_list() {
|
||||
if let Some(self_param) = param_list.self_param() {
|
||||
push_attr(
|
||||
params.len(),
|
||||
RawAttrs::new(self.db.upcast(), &self_param, self.span_map()),
|
||||
);
|
||||
let self_type = match self_param.ty() {
|
||||
Some(type_ref) => TypeRef::from_ast(&mut body_ctx, type_ref),
|
||||
None => {
|
||||
let self_type = body_ctx.alloc_type_ref_desugared(TypeRef::Path(
|
||||
Name::new_symbol_root(sym::Self_.clone()).into(),
|
||||
));
|
||||
match self_param.kind() {
|
||||
ast::SelfParamKind::Owned => self_type,
|
||||
ast::SelfParamKind::Ref => body_ctx.alloc_type_ref_desugared(
|
||||
TypeRef::Reference(Box::new(RefType {
|
||||
ty: self_type,
|
||||
lifetime: self_param.lifetime().as_ref().map(LifetimeRef::new),
|
||||
mutability: Mutability::Shared,
|
||||
})),
|
||||
),
|
||||
ast::SelfParamKind::MutRef => body_ctx.alloc_type_ref_desugared(
|
||||
TypeRef::Reference(Box::new(RefType {
|
||||
ty: self_type,
|
||||
lifetime: self_param.lifetime().as_ref().map(LifetimeRef::new),
|
||||
mutability: Mutability::Mut,
|
||||
})),
|
||||
),
|
||||
}
|
||||
}
|
||||
};
|
||||
params.push(Param { type_ref: Some(self_type) });
|
||||
has_self_param = true;
|
||||
}
|
||||
for param in param_list.params() {
|
||||
push_attr(params.len(), RawAttrs::new(self.db.upcast(), ¶m, self.span_map()));
|
||||
let param = match param.dotdotdot_token() {
|
||||
Some(_) => {
|
||||
has_var_args = true;
|
||||
Param { type_ref: None }
|
||||
}
|
||||
None => {
|
||||
let type_ref = TypeRef::from_ast_opt(&mut body_ctx, param.ty());
|
||||
Param { type_ref: Some(type_ref) }
|
||||
}
|
||||
};
|
||||
params.push(param);
|
||||
}
|
||||
}
|
||||
|
||||
let ret_type = match func.ret_type() {
|
||||
Some(rt) => match rt.ty() {
|
||||
Some(type_ref) => TypeRef::from_ast(&mut body_ctx, type_ref),
|
||||
None if rt.thin_arrow_token().is_some() => body_ctx.alloc_error_type(),
|
||||
None => body_ctx.alloc_type_ref_desugared(TypeRef::unit()),
|
||||
},
|
||||
None => body_ctx.alloc_type_ref_desugared(TypeRef::unit()),
|
||||
};
|
||||
|
||||
let ret_type = if func.async_token().is_some() {
|
||||
let future_impl = desugar_future_path(&mut body_ctx, ret_type);
|
||||
let ty_bound = TypeBound::Path(future_impl, TraitBoundModifier::None);
|
||||
body_ctx.alloc_type_ref_desugared(TypeRef::ImplTrait(ThinVec::from_iter([ty_bound])))
|
||||
} else {
|
||||
ret_type
|
||||
};
|
||||
|
||||
let abi = func.abi().map(lower_abi);
|
||||
|
||||
let ast_id = self.source_ast_id_map.ast_id(func);
|
||||
|
||||
let mut flags = FnFlags::default();
|
||||
if func.body().is_some() {
|
||||
flags |= FnFlags::HAS_BODY;
|
||||
}
|
||||
if has_self_param {
|
||||
flags |= FnFlags::HAS_SELF_PARAM;
|
||||
}
|
||||
if func.default_token().is_some() {
|
||||
flags |= FnFlags::HAS_DEFAULT_KW;
|
||||
}
|
||||
if func.const_token().is_some() {
|
||||
flags |= FnFlags::HAS_CONST_KW;
|
||||
}
|
||||
if func.async_token().is_some() {
|
||||
flags |= FnFlags::HAS_ASYNC_KW;
|
||||
}
|
||||
if func.unsafe_token().is_some() {
|
||||
flags |= FnFlags::HAS_UNSAFE_KW;
|
||||
}
|
||||
if func.safe_token().is_some() {
|
||||
flags |= FnFlags::HAS_SAFE_KW;
|
||||
}
|
||||
if has_var_args {
|
||||
flags |= FnFlags::IS_VARARGS;
|
||||
}
|
||||
|
||||
types_map.shrink_to_fit();
|
||||
types_source_map.shrink_to_fit();
|
||||
let (generic_params, generics_source_map) =
|
||||
self.lower_generic_params(HasImplicitSelf::No, func);
|
||||
let res = Function {
|
||||
name,
|
||||
visibility,
|
||||
explicit_generic_params: generic_params,
|
||||
abi,
|
||||
params: params.into_boxed_slice(),
|
||||
ret_type,
|
||||
ast_id,
|
||||
types_map: Arc::new(types_map),
|
||||
flags,
|
||||
};
|
||||
let res = Function { name, visibility, ast_id };
|
||||
|
||||
let id = id(self.data().functions.alloc(res));
|
||||
self.source_maps.functions.push(GenericItemSourceMapBuilder {
|
||||
item: types_source_map,
|
||||
generics: generics_source_map,
|
||||
});
|
||||
for (idx, attr) in attrs {
|
||||
self.add_attrs(AttrOwner::Param(id, Idx::from_raw(RawIdx::from_u32(idx as u32))), attr);
|
||||
}
|
||||
self.write_generic_params_attributes(id.into());
|
||||
Some(id)
|
||||
}
|
||||
|
||||
|
|
@ -583,83 +345,27 @@ impl<'a> Ctx<'a> {
|
|||
&mut self,
|
||||
type_alias: &ast::TypeAlias,
|
||||
) -> Option<FileItemTreeId<TypeAlias>> {
|
||||
let (mut types_map, mut types_source_map) =
|
||||
(TypesMap::default(), TypesSourceMap::default());
|
||||
let mut body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
|
||||
let name = type_alias.name()?.as_name();
|
||||
let type_ref = type_alias.ty().map(|it| TypeRef::from_ast(&mut body_ctx, it));
|
||||
let visibility = self.lower_visibility(type_alias);
|
||||
let bounds = self.lower_type_bounds(type_alias, &mut body_ctx);
|
||||
let ast_id = self.source_ast_id_map.ast_id(type_alias);
|
||||
let (generic_params, generics_source_map) =
|
||||
self.lower_generic_params(HasImplicitSelf::No, type_alias);
|
||||
types_map.shrink_to_fit();
|
||||
types_source_map.shrink_to_fit();
|
||||
let res = TypeAlias {
|
||||
name,
|
||||
visibility,
|
||||
bounds,
|
||||
generic_params,
|
||||
type_ref,
|
||||
ast_id,
|
||||
types_map: Arc::new(types_map),
|
||||
};
|
||||
let res = TypeAlias { name, visibility, ast_id };
|
||||
let id = id(self.data().type_aliases.alloc(res));
|
||||
self.source_maps.type_aliases.push(GenericItemSourceMapBuilder {
|
||||
item: types_source_map,
|
||||
generics: generics_source_map,
|
||||
});
|
||||
self.write_generic_params_attributes(id.into());
|
||||
Some(id)
|
||||
}
|
||||
|
||||
fn lower_static(&mut self, static_: &ast::Static) -> Option<FileItemTreeId<Static>> {
|
||||
let (mut types_map, mut types_source_map) =
|
||||
(TypesMap::default(), TypesSourceMap::default());
|
||||
let mut body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
|
||||
let name = static_.name()?.as_name();
|
||||
let type_ref = TypeRef::from_ast_opt(&mut body_ctx, static_.ty());
|
||||
let visibility = self.lower_visibility(static_);
|
||||
|
||||
let mut flags = StaticFlags::empty();
|
||||
if static_.mut_token().is_some() {
|
||||
flags |= StaticFlags::MUTABLE;
|
||||
}
|
||||
if static_.safe_token().is_some() {
|
||||
flags |= StaticFlags::HAS_SAFE_KW;
|
||||
}
|
||||
if static_.unsafe_token().is_some() {
|
||||
flags |= StaticFlags::HAS_UNSAFE_KW;
|
||||
}
|
||||
|
||||
let ast_id = self.source_ast_id_map.ast_id(static_);
|
||||
types_map.shrink_to_fit();
|
||||
types_source_map.shrink_to_fit();
|
||||
let res =
|
||||
Static { name, visibility, type_ref, ast_id, flags, types_map: Arc::new(types_map) };
|
||||
self.source_maps.statics.push(types_source_map);
|
||||
let res = Static { name, visibility, ast_id };
|
||||
Some(id(self.data().statics.alloc(res)))
|
||||
}
|
||||
|
||||
fn lower_const(&mut self, konst: &ast::Const) -> FileItemTreeId<Const> {
|
||||
let (mut types_map, mut types_source_map) =
|
||||
(TypesMap::default(), TypesSourceMap::default());
|
||||
let mut body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
|
||||
let name = konst.name().map(|it| it.as_name());
|
||||
let type_ref = TypeRef::from_ast_opt(&mut body_ctx, konst.ty());
|
||||
let visibility = self.lower_visibility(konst);
|
||||
let ast_id = self.source_ast_id_map.ast_id(konst);
|
||||
types_map.shrink_to_fit();
|
||||
types_source_map.shrink_to_fit();
|
||||
let res = Const {
|
||||
name,
|
||||
visibility,
|
||||
type_ref,
|
||||
ast_id,
|
||||
has_body: konst.body().is_some(),
|
||||
types_map: Arc::new(types_map),
|
||||
};
|
||||
self.source_maps.consts.push(types_source_map);
|
||||
let res = Const { name, visibility, ast_id };
|
||||
id(self.data().consts.alloc(res))
|
||||
}
|
||||
|
||||
|
|
@ -688,8 +394,6 @@ impl<'a> Ctx<'a> {
|
|||
let name = trait_def.name()?.as_name();
|
||||
let visibility = self.lower_visibility(trait_def);
|
||||
let ast_id = self.source_ast_id_map.ast_id(trait_def);
|
||||
let is_auto = trait_def.auto_token().is_some();
|
||||
let is_unsafe = trait_def.unsafe_token().is_some();
|
||||
|
||||
let items = trait_def
|
||||
.assoc_item_list()
|
||||
|
|
@ -698,12 +402,8 @@ impl<'a> Ctx<'a> {
|
|||
.filter_map(|item_node| self.lower_assoc_item(&item_node))
|
||||
.collect();
|
||||
|
||||
let (generic_params, generics_source_map) =
|
||||
self.lower_generic_params(HasImplicitSelf::Yes(trait_def.type_bound_list()), trait_def);
|
||||
let def = Trait { name, visibility, generic_params, is_auto, is_unsafe, items, ast_id };
|
||||
let def = Trait { name, visibility, items, ast_id };
|
||||
let id = id(self.data().traits.alloc(def));
|
||||
self.source_maps.trait_generics.push(generics_source_map);
|
||||
self.write_generic_params_attributes(id.into());
|
||||
Some(id)
|
||||
}
|
||||
|
||||
|
|
@ -714,32 +414,14 @@ impl<'a> Ctx<'a> {
|
|||
let name = trait_alias_def.name()?.as_name();
|
||||
let visibility = self.lower_visibility(trait_alias_def);
|
||||
let ast_id = self.source_ast_id_map.ast_id(trait_alias_def);
|
||||
let (generic_params, generics_source_map) = self.lower_generic_params(
|
||||
HasImplicitSelf::Yes(trait_alias_def.type_bound_list()),
|
||||
trait_alias_def,
|
||||
);
|
||||
|
||||
let alias = TraitAlias { name, visibility, generic_params, ast_id };
|
||||
let alias = TraitAlias { name, visibility, ast_id };
|
||||
let id = id(self.data().trait_aliases.alloc(alias));
|
||||
self.source_maps.trait_alias_generics.push(generics_source_map);
|
||||
self.write_generic_params_attributes(id.into());
|
||||
Some(id)
|
||||
}
|
||||
|
||||
fn lower_impl(&mut self, impl_def: &ast::Impl) -> FileItemTreeId<Impl> {
|
||||
let (mut types_map, mut types_source_map) =
|
||||
(TypesMap::default(), TypesSourceMap::default());
|
||||
let mut body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
|
||||
|
||||
let ast_id = self.source_ast_id_map.ast_id(impl_def);
|
||||
// FIXME: If trait lowering fails, due to a non PathType for example, we treat this impl
|
||||
// as if it was an non-trait impl. Ideally we want to create a unique missing ref that only
|
||||
// equals itself.
|
||||
let self_ty = TypeRef::from_ast_opt(&mut body_ctx, impl_def.self_ty());
|
||||
let target_trait = impl_def.trait_().and_then(|tr| TraitRef::from_ast(&mut body_ctx, tr));
|
||||
let is_negative = impl_def.excl_token().is_some();
|
||||
let is_unsafe = impl_def.unsafe_token().is_some();
|
||||
|
||||
// We cannot use `assoc_items()` here as that does not include macro calls.
|
||||
let items = impl_def
|
||||
.assoc_item_list()
|
||||
|
|
@ -749,27 +431,8 @@ impl<'a> Ctx<'a> {
|
|||
.collect();
|
||||
// Note that trait impls don't get implicit `Self` unlike traits, because here they are a
|
||||
// type alias rather than a type parameter, so this is handled by the resolver.
|
||||
let (generic_params, generics_source_map) =
|
||||
self.lower_generic_params(HasImplicitSelf::No, impl_def);
|
||||
types_map.shrink_to_fit();
|
||||
types_source_map.shrink_to_fit();
|
||||
let res = Impl {
|
||||
generic_params,
|
||||
target_trait,
|
||||
self_ty,
|
||||
is_negative,
|
||||
is_unsafe,
|
||||
items,
|
||||
ast_id,
|
||||
types_map: Arc::new(types_map),
|
||||
};
|
||||
let id = id(self.data().impls.alloc(res));
|
||||
self.source_maps.impls.push(GenericItemSourceMapBuilder {
|
||||
item: types_source_map,
|
||||
generics: generics_source_map,
|
||||
});
|
||||
self.write_generic_params_attributes(id.into());
|
||||
id
|
||||
let res = Impl { items, ast_id };
|
||||
id(self.data().impls.alloc(res))
|
||||
}
|
||||
|
||||
fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Use>> {
|
||||
|
|
@ -856,68 +519,8 @@ impl<'a> Ctx<'a> {
|
|||
id(self.data().extern_blocks.alloc(res))
|
||||
}
|
||||
|
||||
fn write_generic_params_attributes(&mut self, parent: GenericModItem) {
|
||||
self.generic_param_attr_buffer.drain().for_each(|(idx, attrs)| {
|
||||
self.tree.attrs.insert(
|
||||
match idx {
|
||||
Either::Left(id) => AttrOwner::TypeOrConstParamData(parent, id),
|
||||
Either::Right(id) => AttrOwner::LifetimeParamData(parent, id),
|
||||
},
|
||||
attrs,
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
fn lower_generic_params(
|
||||
&mut self,
|
||||
has_implicit_self: HasImplicitSelf,
|
||||
node: &dyn ast::HasGenericParams,
|
||||
) -> (Arc<GenericParams>, TypesSourceMap) {
|
||||
let (mut types_map, mut types_source_map) =
|
||||
(TypesMap::default(), TypesSourceMap::default());
|
||||
let mut body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
|
||||
debug_assert!(self.generic_param_attr_buffer.is_empty(),);
|
||||
body_ctx.take_impl_traits_bounds();
|
||||
let mut generics = GenericParamsCollector::default();
|
||||
|
||||
if let HasImplicitSelf::Yes(bounds) = has_implicit_self {
|
||||
// Traits and trait aliases get the Self type as an implicit first type parameter.
|
||||
generics.fill_self_param();
|
||||
// add super traits as bounds on Self
|
||||
// i.e., `trait Foo: Bar` is equivalent to `trait Foo where Self: Bar`
|
||||
let bound_target = Either::Left(body_ctx.alloc_type_ref_desugared(TypeRef::Path(
|
||||
Name::new_symbol_root(sym::Self_.clone()).into(),
|
||||
)));
|
||||
generics.fill_bounds(&mut body_ctx, bounds, bound_target);
|
||||
}
|
||||
|
||||
let span_map = body_ctx.span_map().clone();
|
||||
let add_param_attrs = |item: Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
|
||||
param| {
|
||||
let attrs = RawAttrs::new(self.db.upcast(), ¶m, span_map.as_ref());
|
||||
debug_assert!(self.generic_param_attr_buffer.insert(item, attrs).is_none());
|
||||
};
|
||||
generics.fill(&mut body_ctx, node, add_param_attrs);
|
||||
|
||||
let generics = generics.finish(types_map, &mut types_source_map);
|
||||
(generics, types_source_map)
|
||||
}
|
||||
|
||||
fn lower_type_bounds(
|
||||
&mut self,
|
||||
node: &dyn ast::HasTypeBounds,
|
||||
body_ctx: &mut LowerCtx<'_>,
|
||||
) -> Box<[TypeBound]> {
|
||||
match node.type_bound_list() {
|
||||
Some(bound_list) => {
|
||||
bound_list.bounds().map(|it| TypeBound::from_ast(body_ctx, it)).collect()
|
||||
}
|
||||
None => Box::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_visibility(&mut self, item: &dyn ast::HasVisibility) -> RawVisibilityId {
|
||||
let vis = RawVisibility::from_ast(self.db, item.visibility(), &mut |range| {
|
||||
let vis = visibility_from_ast(self.db, item.visibility(), &mut |range| {
|
||||
self.span_map().span_for_range(range).ctx
|
||||
});
|
||||
self.data().vis.alloc(vis)
|
||||
|
|
@ -930,27 +533,6 @@ impl<'a> Ctx<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn desugar_future_path(ctx: &mut LowerCtx<'_>, orig: TypeRefId) -> PathId {
|
||||
let path = path![core::future::Future];
|
||||
let mut generic_args: Vec<_> = std::iter::repeat_n(None, path.segments().len() - 1).collect();
|
||||
let binding = AssociatedTypeBinding {
|
||||
name: Name::new_symbol_root(sym::Output.clone()),
|
||||
args: None,
|
||||
type_ref: Some(orig),
|
||||
bounds: Box::default(),
|
||||
};
|
||||
generic_args.push(Some(GenericArgs { bindings: Box::new([binding]), ..GenericArgs::empty() }));
|
||||
|
||||
let path = Path::from_known_path(path, generic_args);
|
||||
PathId::from_type_ref_unchecked(ctx.alloc_type_ref_desugared(TypeRef::Path(path)))
|
||||
}
|
||||
|
||||
enum HasImplicitSelf {
|
||||
/// Inner list is a type bound list for the implicit `Self`.
|
||||
Yes(Option<ast::TypeBoundList>),
|
||||
No,
|
||||
}
|
||||
|
||||
fn lower_abi(abi: ast::Abi) -> Symbol {
|
||||
match abi.abi_string() {
|
||||
Some(tok) => Symbol::intern(tok.text_without_quotes()),
|
||||
|
|
@ -1041,3 +623,32 @@ pub(crate) fn lower_use_tree(
|
|||
let tree = lowering.lower_use_tree(tree, span_for_range)?;
|
||||
Some((tree, lowering.mapping))
|
||||
}
|
||||
|
||||
fn private_vis() -> RawVisibility {
|
||||
RawVisibility::Module(
|
||||
Interned::new(ModPath::from_kind(PathKind::SELF)),
|
||||
VisibilityExplicitness::Implicit,
|
||||
)
|
||||
}
|
||||
|
||||
fn visibility_from_ast(
|
||||
db: &dyn DefDatabase,
|
||||
node: Option<ast::Visibility>,
|
||||
span_for_range: &mut dyn FnMut(::tt::TextRange) -> SyntaxContext,
|
||||
) -> RawVisibility {
|
||||
let Some(node) = node else { return private_vis() };
|
||||
let path = match node.kind() {
|
||||
ast::VisibilityKind::In(path) => {
|
||||
let path = ModPath::from_src(db.upcast(), path, span_for_range);
|
||||
match path {
|
||||
None => return private_vis(),
|
||||
Some(path) => path,
|
||||
}
|
||||
}
|
||||
ast::VisibilityKind::PubCrate => ModPath::from_kind(PathKind::Crate),
|
||||
ast::VisibilityKind::PubSuper => ModPath::from_kind(PathKind::Super(1)),
|
||||
ast::VisibilityKind::PubSelf => ModPath::from_kind(PathKind::SELF),
|
||||
ast::VisibilityKind::Pub => return RawVisibility::Public,
|
||||
};
|
||||
RawVisibility::Module(Interned::new(path), VisibilityExplicitness::Explicit)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,16 +6,12 @@ use la_arena::{Idx, RawIdx};
|
|||
use span::{Edition, ErasedFileAstId};
|
||||
|
||||
use crate::{
|
||||
generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget},
|
||||
item_tree::{
|
||||
AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, Field, FieldParent,
|
||||
FieldsShape, FileItemTreeId, FnFlags, Function, GenericModItem, GenericParams, Impl,
|
||||
ItemTree, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, Param, Path, RawAttrs,
|
||||
RawVisibilityId, Static, StaticFlags, Struct, Trait, TraitAlias, TypeAlias, TypeBound,
|
||||
FieldsShape, FileItemTreeId, Function, Impl, ItemTree, Macro2, MacroCall, MacroRules, Mod,
|
||||
ModItem, ModKind, RawAttrs, RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias,
|
||||
Union, Use, UseTree, UseTreeKind, Variant,
|
||||
},
|
||||
pretty::{print_path, print_type_bounds, print_type_ref},
|
||||
type_ref::{TypeRefId, TypesMap},
|
||||
visibility::RawVisibility,
|
||||
};
|
||||
|
||||
|
|
@ -122,22 +118,14 @@ impl Printer<'_> {
|
|||
};
|
||||
}
|
||||
|
||||
fn print_fields(
|
||||
&mut self,
|
||||
parent: FieldParent,
|
||||
kind: FieldsShape,
|
||||
fields: &[Field],
|
||||
map: &TypesMap,
|
||||
) {
|
||||
fn print_fields(&mut self, parent: FieldParent, kind: FieldsShape, fields: &[Field]) {
|
||||
let edition = self.edition;
|
||||
match kind {
|
||||
FieldsShape::Record => {
|
||||
self.whitespace();
|
||||
w!(self, "{{");
|
||||
self.indented(|this| {
|
||||
for (idx, Field { name, type_ref, visibility, is_unsafe }) in
|
||||
fields.iter().enumerate()
|
||||
{
|
||||
for (idx, Field { name, visibility, is_unsafe }) in fields.iter().enumerate() {
|
||||
this.print_attrs_of(
|
||||
AttrOwner::Field(parent, Idx::from_raw(RawIdx::from(idx as u32))),
|
||||
"\n",
|
||||
|
|
@ -146,9 +134,8 @@ impl Printer<'_> {
|
|||
if *is_unsafe {
|
||||
w!(this, "unsafe ");
|
||||
}
|
||||
w!(this, "{}: ", name.display(self.db.upcast(), edition));
|
||||
this.print_type_ref(*type_ref, map);
|
||||
wln!(this, ",");
|
||||
|
||||
wln!(this, "{},", name.display(self.db.upcast(), edition));
|
||||
}
|
||||
});
|
||||
w!(self, "}}");
|
||||
|
|
@ -156,9 +143,7 @@ impl Printer<'_> {
|
|||
FieldsShape::Tuple => {
|
||||
w!(self, "(");
|
||||
self.indented(|this| {
|
||||
for (idx, Field { name, type_ref, visibility, is_unsafe }) in
|
||||
fields.iter().enumerate()
|
||||
{
|
||||
for (idx, Field { name, visibility, is_unsafe }) in fields.iter().enumerate() {
|
||||
this.print_attrs_of(
|
||||
AttrOwner::Field(parent, Idx::from_raw(RawIdx::from(idx as u32))),
|
||||
"\n",
|
||||
|
|
@ -167,9 +152,7 @@ impl Printer<'_> {
|
|||
if *is_unsafe {
|
||||
w!(this, "unsafe ");
|
||||
}
|
||||
w!(this, "{}: ", name.display(self.db.upcast(), edition));
|
||||
this.print_type_ref(*type_ref, map);
|
||||
wln!(this, ",");
|
||||
wln!(this, "{},", name.display(self.db.upcast(), edition));
|
||||
}
|
||||
});
|
||||
w!(self, ")");
|
||||
|
|
@ -178,32 +161,6 @@ impl Printer<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
fn print_fields_and_where_clause(
|
||||
&mut self,
|
||||
parent: FieldParent,
|
||||
kind: FieldsShape,
|
||||
fields: &[Field],
|
||||
params: &GenericParams,
|
||||
map: &TypesMap,
|
||||
) {
|
||||
match kind {
|
||||
FieldsShape::Record => {
|
||||
if self.print_where_clause(params) {
|
||||
wln!(self);
|
||||
}
|
||||
self.print_fields(parent, kind, fields, map);
|
||||
}
|
||||
FieldsShape::Unit => {
|
||||
self.print_where_clause(params);
|
||||
self.print_fields(parent, kind, fields, map);
|
||||
}
|
||||
FieldsShape::Tuple => {
|
||||
self.print_fields(parent, kind, fields, map);
|
||||
self.print_where_clause(params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn print_use_tree(&mut self, use_tree: &UseTree) {
|
||||
match &use_tree.kind {
|
||||
UseTreeKind::Single { path, alias } => {
|
||||
|
|
@ -272,89 +229,17 @@ impl Printer<'_> {
|
|||
wln!(self, "}}");
|
||||
}
|
||||
ModItem::Function(it) => {
|
||||
let Function {
|
||||
name,
|
||||
visibility,
|
||||
explicit_generic_params,
|
||||
abi,
|
||||
params,
|
||||
ret_type,
|
||||
ast_id,
|
||||
types_map,
|
||||
flags,
|
||||
} = &self.tree[it];
|
||||
let Function { name, visibility, ast_id } = &self.tree[it];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
if flags.contains(FnFlags::HAS_DEFAULT_KW) {
|
||||
w!(self, "default ");
|
||||
}
|
||||
if flags.contains(FnFlags::HAS_CONST_KW) {
|
||||
w!(self, "const ");
|
||||
}
|
||||
if flags.contains(FnFlags::HAS_ASYNC_KW) {
|
||||
w!(self, "async ");
|
||||
}
|
||||
if flags.contains(FnFlags::HAS_UNSAFE_KW) {
|
||||
w!(self, "unsafe ");
|
||||
}
|
||||
if flags.contains(FnFlags::HAS_SAFE_KW) {
|
||||
w!(self, "safe ");
|
||||
}
|
||||
if let Some(abi) = abi {
|
||||
w!(self, "extern \"{}\" ", abi);
|
||||
}
|
||||
w!(self, "fn {}", name.display(self.db.upcast(), self.edition));
|
||||
self.print_generic_params(explicit_generic_params, it.into());
|
||||
w!(self, "(");
|
||||
if !params.is_empty() {
|
||||
self.indented(|this| {
|
||||
for (idx, Param { type_ref }) in params.iter().enumerate() {
|
||||
this.print_attrs_of(
|
||||
AttrOwner::Param(it, Idx::from_raw(RawIdx::from(idx as u32))),
|
||||
"\n",
|
||||
);
|
||||
if idx == 0 && flags.contains(FnFlags::HAS_SELF_PARAM) {
|
||||
w!(this, "self: ");
|
||||
}
|
||||
if let Some(type_ref) = type_ref {
|
||||
this.print_type_ref(*type_ref, types_map);
|
||||
} else {
|
||||
wln!(this, "...");
|
||||
}
|
||||
wln!(this, ",");
|
||||
}
|
||||
});
|
||||
}
|
||||
w!(self, ") -> ");
|
||||
self.print_type_ref(*ret_type, types_map);
|
||||
self.print_where_clause(explicit_generic_params);
|
||||
if flags.contains(FnFlags::HAS_BODY) {
|
||||
wln!(self, " {{ ... }}");
|
||||
} else {
|
||||
wln!(self, ";");
|
||||
}
|
||||
wln!(self, "fn {};", name.display(self.db.upcast(), self.edition));
|
||||
}
|
||||
ModItem::Struct(it) => {
|
||||
let Struct {
|
||||
visibility,
|
||||
name,
|
||||
fields,
|
||||
shape: kind,
|
||||
generic_params,
|
||||
ast_id,
|
||||
types_map,
|
||||
} = &self.tree[it];
|
||||
let Struct { visibility, name, fields, shape: kind, ast_id } = &self.tree[it];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
w!(self, "struct {}", name.display(self.db.upcast(), self.edition));
|
||||
self.print_generic_params(generic_params, it.into());
|
||||
self.print_fields_and_where_clause(
|
||||
FieldParent::Struct(it),
|
||||
*kind,
|
||||
fields,
|
||||
generic_params,
|
||||
types_map,
|
||||
);
|
||||
self.print_fields(FieldParent::Struct(it), *kind, fields);
|
||||
if matches!(kind, FieldsShape::Record) {
|
||||
wln!(self);
|
||||
} else {
|
||||
|
|
@ -362,50 +247,33 @@ impl Printer<'_> {
|
|||
}
|
||||
}
|
||||
ModItem::Union(it) => {
|
||||
let Union { name, visibility, fields, generic_params, ast_id, types_map } =
|
||||
&self.tree[it];
|
||||
let Union { name, visibility, fields, ast_id } = &self.tree[it];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
w!(self, "union {}", name.display(self.db.upcast(), self.edition));
|
||||
self.print_generic_params(generic_params, it.into());
|
||||
self.print_fields_and_where_clause(
|
||||
FieldParent::Union(it),
|
||||
FieldsShape::Record,
|
||||
fields,
|
||||
generic_params,
|
||||
types_map,
|
||||
);
|
||||
self.print_fields(FieldParent::Union(it), FieldsShape::Record, fields);
|
||||
wln!(self);
|
||||
}
|
||||
ModItem::Enum(it) => {
|
||||
let Enum { name, visibility, variants, generic_params, ast_id } = &self.tree[it];
|
||||
let Enum { name, visibility, variants, ast_id } = &self.tree[it];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
w!(self, "enum {}", name.display(self.db.upcast(), self.edition));
|
||||
self.print_generic_params(generic_params, it.into());
|
||||
self.print_where_clause_and_opening_brace(generic_params);
|
||||
let edition = self.edition;
|
||||
self.indented(|this| {
|
||||
for variant in FileItemTreeId::range_iter(variants.clone()) {
|
||||
let Variant { name, fields, shape: kind, ast_id, types_map } =
|
||||
&this.tree[variant];
|
||||
let Variant { name, fields, shape: kind, ast_id } = &this.tree[variant];
|
||||
this.print_ast_id(ast_id.erase());
|
||||
this.print_attrs_of(variant, "\n");
|
||||
w!(this, "{}", name.display(self.db.upcast(), edition));
|
||||
this.print_fields(
|
||||
FieldParent::EnumVariant(variant),
|
||||
*kind,
|
||||
fields,
|
||||
types_map,
|
||||
);
|
||||
this.print_fields(FieldParent::EnumVariant(variant), *kind, fields);
|
||||
wln!(this, ",");
|
||||
}
|
||||
});
|
||||
wln!(self, "}}");
|
||||
}
|
||||
ModItem::Const(it) => {
|
||||
let Const { name, visibility, type_ref, ast_id, has_body: _, types_map } =
|
||||
&self.tree[it];
|
||||
let Const { name, visibility, ast_id } = &self.tree[it];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
w!(self, "const ");
|
||||
|
|
@ -413,44 +281,22 @@ impl Printer<'_> {
|
|||
Some(name) => w!(self, "{}", name.display(self.db.upcast(), self.edition)),
|
||||
None => w!(self, "_"),
|
||||
}
|
||||
w!(self, ": ");
|
||||
self.print_type_ref(*type_ref, types_map);
|
||||
wln!(self, " = _;");
|
||||
}
|
||||
ModItem::Static(it) => {
|
||||
let Static { name, visibility, type_ref, ast_id, types_map, flags } =
|
||||
&self.tree[it];
|
||||
let Static { name, visibility, ast_id } = &self.tree[it];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
if flags.contains(StaticFlags::HAS_SAFE_KW) {
|
||||
w!(self, "safe ");
|
||||
}
|
||||
if flags.contains(StaticFlags::HAS_UNSAFE_KW) {
|
||||
w!(self, "unsafe ");
|
||||
}
|
||||
w!(self, "static ");
|
||||
if flags.contains(StaticFlags::MUTABLE) {
|
||||
w!(self, "mut ");
|
||||
}
|
||||
w!(self, "{}: ", name.display(self.db.upcast(), self.edition));
|
||||
self.print_type_ref(*type_ref, types_map);
|
||||
w!(self, "{}", name.display(self.db.upcast(), self.edition));
|
||||
w!(self, " = _;");
|
||||
wln!(self);
|
||||
}
|
||||
ModItem::Trait(it) => {
|
||||
let Trait { name, visibility, is_auto, is_unsafe, items, generic_params, ast_id } =
|
||||
&self.tree[it];
|
||||
let Trait { name, visibility, items, ast_id } = &self.tree[it];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
if *is_unsafe {
|
||||
w!(self, "unsafe ");
|
||||
}
|
||||
if *is_auto {
|
||||
w!(self, "auto ");
|
||||
}
|
||||
w!(self, "trait {}", name.display(self.db.upcast(), self.edition));
|
||||
self.print_generic_params(generic_params, it.into());
|
||||
self.print_where_clause_and_opening_brace(generic_params);
|
||||
w!(self, "trait {} {{", name.display(self.db.upcast(), self.edition));
|
||||
self.indented(|this| {
|
||||
for item in &**items {
|
||||
this.print_mod_item((*item).into());
|
||||
|
|
@ -459,43 +305,15 @@ impl Printer<'_> {
|
|||
wln!(self, "}}");
|
||||
}
|
||||
ModItem::TraitAlias(it) => {
|
||||
let TraitAlias { name, visibility, generic_params, ast_id } = &self.tree[it];
|
||||
let TraitAlias { name, visibility, ast_id } = &self.tree[it];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
w!(self, "trait {}", name.display(self.db.upcast(), self.edition));
|
||||
self.print_generic_params(generic_params, it.into());
|
||||
w!(self, " = ");
|
||||
self.print_where_clause(generic_params);
|
||||
w!(self, ";");
|
||||
wln!(self);
|
||||
wln!(self, "trait {} = ..;", name.display(self.db.upcast(), self.edition));
|
||||
}
|
||||
ModItem::Impl(it) => {
|
||||
let Impl {
|
||||
target_trait,
|
||||
self_ty,
|
||||
is_negative,
|
||||
is_unsafe,
|
||||
items,
|
||||
generic_params,
|
||||
ast_id,
|
||||
types_map,
|
||||
} = &self.tree[it];
|
||||
let Impl { items, ast_id } = &self.tree[it];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
if *is_unsafe {
|
||||
w!(self, "unsafe");
|
||||
}
|
||||
w!(self, "impl");
|
||||
self.print_generic_params(generic_params, it.into());
|
||||
w!(self, " ");
|
||||
if *is_negative {
|
||||
w!(self, "!");
|
||||
}
|
||||
if let Some(tr) = target_trait {
|
||||
self.print_path(&types_map[tr.path], types_map);
|
||||
w!(self, " for ");
|
||||
}
|
||||
self.print_type_ref(*self_ty, types_map);
|
||||
self.print_where_clause_and_opening_brace(generic_params);
|
||||
w!(self, "impl {{");
|
||||
self.indented(|this| {
|
||||
for item in &**items {
|
||||
this.print_mod_item((*item).into());
|
||||
|
|
@ -504,28 +322,10 @@ impl Printer<'_> {
|
|||
wln!(self, "}}");
|
||||
}
|
||||
ModItem::TypeAlias(it) => {
|
||||
let TypeAlias {
|
||||
name,
|
||||
visibility,
|
||||
bounds,
|
||||
type_ref,
|
||||
generic_params,
|
||||
ast_id,
|
||||
types_map,
|
||||
} = &self.tree[it];
|
||||
let TypeAlias { name, visibility, ast_id } = &self.tree[it];
|
||||
self.print_ast_id(ast_id.erase());
|
||||
self.print_visibility(*visibility);
|
||||
w!(self, "type {}", name.display(self.db.upcast(), self.edition));
|
||||
self.print_generic_params(generic_params, it.into());
|
||||
if !bounds.is_empty() {
|
||||
w!(self, ": ");
|
||||
self.print_type_bounds(bounds, types_map);
|
||||
}
|
||||
if let Some(ty) = type_ref {
|
||||
w!(self, " = ");
|
||||
self.print_type_ref(*ty, types_map);
|
||||
}
|
||||
self.print_where_clause(generic_params);
|
||||
w!(self, ";");
|
||||
wln!(self);
|
||||
}
|
||||
|
|
@ -580,118 +380,6 @@ impl Printer<'_> {
|
|||
self.blank();
|
||||
}
|
||||
|
||||
fn print_type_ref(&mut self, type_ref: TypeRefId, map: &TypesMap) {
|
||||
let edition = self.edition;
|
||||
print_type_ref(self.db, type_ref, map, self, edition).unwrap();
|
||||
}
|
||||
|
||||
fn print_type_bounds(&mut self, bounds: &[TypeBound], map: &TypesMap) {
|
||||
let edition = self.edition;
|
||||
print_type_bounds(self.db, bounds, map, self, edition).unwrap();
|
||||
}
|
||||
|
||||
fn print_path(&mut self, path: &Path, map: &TypesMap) {
|
||||
let edition = self.edition;
|
||||
print_path(self.db, path, map, self, edition).unwrap();
|
||||
}
|
||||
|
||||
fn print_generic_params(&mut self, params: &GenericParams, parent: GenericModItem) {
|
||||
if params.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
w!(self, "<");
|
||||
let mut first = true;
|
||||
for (idx, lt) in params.iter_lt() {
|
||||
if !first {
|
||||
w!(self, ", ");
|
||||
}
|
||||
first = false;
|
||||
self.print_attrs_of(AttrOwner::LifetimeParamData(parent, idx), " ");
|
||||
w!(self, "{}", lt.name.display(self.db.upcast(), self.edition));
|
||||
}
|
||||
for (idx, x) in params.iter_type_or_consts() {
|
||||
if !first {
|
||||
w!(self, ", ");
|
||||
}
|
||||
first = false;
|
||||
self.print_attrs_of(AttrOwner::TypeOrConstParamData(parent, idx), " ");
|
||||
match x {
|
||||
TypeOrConstParamData::TypeParamData(ty) => match &ty.name {
|
||||
Some(name) => w!(self, "{}", name.display(self.db.upcast(), self.edition)),
|
||||
None => w!(self, "_anon_{}", idx.into_raw()),
|
||||
},
|
||||
TypeOrConstParamData::ConstParamData(konst) => {
|
||||
w!(self, "const {}: ", konst.name.display(self.db.upcast(), self.edition));
|
||||
self.print_type_ref(konst.ty, ¶ms.types_map);
|
||||
}
|
||||
}
|
||||
}
|
||||
w!(self, ">");
|
||||
}
|
||||
|
||||
fn print_where_clause_and_opening_brace(&mut self, params: &GenericParams) {
|
||||
if self.print_where_clause(params) {
|
||||
w!(self, "\n{{");
|
||||
} else {
|
||||
self.whitespace();
|
||||
w!(self, "{{");
|
||||
}
|
||||
}
|
||||
|
||||
fn print_where_clause(&mut self, params: &GenericParams) -> bool {
|
||||
if params.where_predicates().next().is_none() {
|
||||
return false;
|
||||
}
|
||||
|
||||
w!(self, "\nwhere");
|
||||
let edition = self.edition;
|
||||
self.indented(|this| {
|
||||
for (i, pred) in params.where_predicates().enumerate() {
|
||||
if i != 0 {
|
||||
wln!(this, ",");
|
||||
}
|
||||
|
||||
let (target, bound) = match pred {
|
||||
WherePredicate::TypeBound { target, bound } => (target, bound),
|
||||
WherePredicate::Lifetime { target, bound } => {
|
||||
w!(
|
||||
this,
|
||||
"{}: {}",
|
||||
target.name.display(self.db.upcast(), edition),
|
||||
bound.name.display(self.db.upcast(), edition)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
WherePredicate::ForLifetime { lifetimes, target, bound } => {
|
||||
w!(this, "for<");
|
||||
for (i, lt) in lifetimes.iter().enumerate() {
|
||||
if i != 0 {
|
||||
w!(this, ", ");
|
||||
}
|
||||
w!(this, "{}", lt.display(self.db.upcast(), edition));
|
||||
}
|
||||
w!(this, "> ");
|
||||
(target, bound)
|
||||
}
|
||||
};
|
||||
|
||||
match target {
|
||||
WherePredicateTypeTarget::TypeRef(ty) => {
|
||||
this.print_type_ref(*ty, ¶ms.types_map)
|
||||
}
|
||||
WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() {
|
||||
Some(name) => w!(this, "{}", name.display(self.db.upcast(), edition)),
|
||||
None => w!(this, "_anon_{}", id.into_raw()),
|
||||
},
|
||||
}
|
||||
w!(this, ": ");
|
||||
this.print_type_bounds(std::slice::from_ref(bound), ¶ms.types_map);
|
||||
}
|
||||
});
|
||||
true
|
||||
}
|
||||
|
||||
fn print_ast_id(&mut self, ast_id: ErasedFileAstId) {
|
||||
wln!(self, "// AstId: {:?}", ast_id.into_raw());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,11 +83,11 @@ extern "C" {
|
|||
|
||||
#[on_extern_static]
|
||||
// AstId: 3
|
||||
pub(self) static EX_STATIC: u8 = _;
|
||||
pub(self) static EX_STATIC = _;
|
||||
|
||||
#[on_extern_fn]
|
||||
// AstId: 4
|
||||
pub(self) fn ex_fn() -> ();
|
||||
pub(self) fn ex_fn;
|
||||
}
|
||||
"##]],
|
||||
);
|
||||
|
|
@ -131,35 +131,35 @@ enum E {
|
|||
// AstId: 2
|
||||
pub(self) struct Struct {
|
||||
#[doc = " fld docs"]
|
||||
pub(self) fld: (),
|
||||
pub(self) fld,
|
||||
}
|
||||
|
||||
// AstId: 3
|
||||
pub(self) struct Tuple(
|
||||
#[attr]
|
||||
pub(self) 0: u8,
|
||||
pub(self) 0,
|
||||
);
|
||||
|
||||
// AstId: 4
|
||||
pub(self) union Ize {
|
||||
pub(self) a: (),
|
||||
pub(self) b: (),
|
||||
pub(self) a,
|
||||
pub(self) b,
|
||||
}
|
||||
|
||||
// AstId: 5
|
||||
pub(self) enum E {
|
||||
pub(self) enum E
|
||||
// AstId: 6
|
||||
#[doc = " comment on Unit"]
|
||||
Unit,
|
||||
// AstId: 7
|
||||
#[doc = " comment on Tuple"]
|
||||
Tuple(
|
||||
pub(self) 0: u8,
|
||||
pub(self) 0,
|
||||
),
|
||||
// AstId: 8
|
||||
Struct {
|
||||
#[doc = " comment on a: u8"]
|
||||
pub(self) a: u8,
|
||||
pub(self) a,
|
||||
},
|
||||
}
|
||||
"#]],
|
||||
|
|
@ -186,33 +186,23 @@ trait Tr: SuperTrait + 'lifetime {
|
|||
"#,
|
||||
expect![[r#"
|
||||
// AstId: 1
|
||||
pub static mut ST: () = _;
|
||||
pub static ST = _;
|
||||
|
||||
// AstId: 2
|
||||
pub(self) const _: Anon = _;
|
||||
pub(self) const _ = _;
|
||||
|
||||
#[attr]
|
||||
#[inner_attr_in_fn]
|
||||
// AstId: 3
|
||||
pub(self) fn f(
|
||||
#[attr]
|
||||
u8,
|
||||
(),
|
||||
) -> () { ... }
|
||||
pub(self) fn f;
|
||||
|
||||
// AstId: 4
|
||||
pub(self) trait Tr<Self>
|
||||
where
|
||||
Self: SuperTrait,
|
||||
Self: 'lifetime
|
||||
{
|
||||
pub(self) trait Tr {
|
||||
// AstId: 6
|
||||
pub(self) type Assoc: AssocBound = Default;
|
||||
pub(self) type Assoc;
|
||||
|
||||
// AstId: 7
|
||||
pub(self) fn method(
|
||||
self: &Self,
|
||||
) -> ();
|
||||
pub(self) fn method;
|
||||
}
|
||||
"#]],
|
||||
);
|
||||
|
|
@ -242,7 +232,7 @@ mod outline;
|
|||
pub(self) use super::*;
|
||||
|
||||
// AstId: 4
|
||||
pub(self) fn fn_in_module() -> () { ... }
|
||||
pub(self) fn fn_in_module;
|
||||
}
|
||||
|
||||
// AstId: 2
|
||||
|
|
@ -276,153 +266,6 @@ m!();
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mod_paths() {
|
||||
check(
|
||||
r#"
|
||||
struct S {
|
||||
a: self::Ty,
|
||||
b: super::SuperTy,
|
||||
c: super::super::SuperSuperTy,
|
||||
d: ::abs::Path,
|
||||
e: crate::Crate,
|
||||
f: plain::path::Ty,
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
// AstId: 1
|
||||
pub(self) struct S {
|
||||
pub(self) a: self::Ty,
|
||||
pub(self) b: super::SuperTy,
|
||||
pub(self) c: super::super::SuperSuperTy,
|
||||
pub(self) d: ::abs::Path,
|
||||
pub(self) e: crate::Crate,
|
||||
pub(self) f: plain::path::Ty,
|
||||
}
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn types() {
|
||||
check(
|
||||
r#"
|
||||
struct S {
|
||||
a: Mixed<'a, T, Item=(), OtherItem=u8>,
|
||||
b: <Fully as Qualified>::Syntax,
|
||||
c: <TypeAnchored>::Path::<'a>,
|
||||
d: dyn for<'a> Trait<'a>,
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
// AstId: 1
|
||||
pub(self) struct S {
|
||||
pub(self) a: Mixed::<'a, T, Item = (), OtherItem = u8>,
|
||||
pub(self) b: Qualified::<Self=Fully>::Syntax,
|
||||
pub(self) c: <TypeAnchored>::Path::<'a>,
|
||||
pub(self) d: dyn for<'a> Trait::<'a>,
|
||||
}
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generics() {
|
||||
check(
|
||||
r#"
|
||||
struct S<'a, 'b: 'a, T: Copy + 'a + 'b, const K: u8 = 0> {
|
||||
field: &'a &'b T,
|
||||
}
|
||||
|
||||
struct Tuple<T: Copy, U: ?Sized>(T, U);
|
||||
|
||||
impl<'a, 'b: 'a, T: Copy + 'a + 'b, const K: u8 = 0> S<'a, 'b, T, K> {
|
||||
fn f<G: 'a>(arg: impl Copy) -> impl Copy {}
|
||||
}
|
||||
|
||||
enum Enum<'a, T, const U: u8> {}
|
||||
union Union<'a, T, const U: u8> {}
|
||||
|
||||
trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
// AstId: 1
|
||||
pub(self) struct S<'a, 'b, T, const K: u8>
|
||||
where
|
||||
T: Copy,
|
||||
T: 'a,
|
||||
T: 'b,
|
||||
'b: 'a
|
||||
{
|
||||
pub(self) field: &'a &'b T,
|
||||
}
|
||||
|
||||
// AstId: 2
|
||||
pub(self) struct Tuple<T, U>(
|
||||
pub(self) 0: T,
|
||||
pub(self) 1: U,
|
||||
)
|
||||
where
|
||||
T: Copy,
|
||||
U: ?Sized;
|
||||
|
||||
// AstId: 3
|
||||
impl<'a, 'b, T, const K: u8> S::<'a, 'b, T, K>
|
||||
where
|
||||
T: Copy,
|
||||
T: 'a,
|
||||
T: 'b,
|
||||
'b: 'a
|
||||
{
|
||||
// AstId: 9
|
||||
pub(self) fn f<G>(
|
||||
impl Copy,
|
||||
) -> impl Copy
|
||||
where
|
||||
G: 'a { ... }
|
||||
}
|
||||
|
||||
// AstId: 4
|
||||
pub(self) enum Enum<'a, T, const U: u8> {
|
||||
}
|
||||
|
||||
// AstId: 5
|
||||
pub(self) union Union<'a, T, const U: u8> {
|
||||
}
|
||||
|
||||
// AstId: 6
|
||||
pub(self) trait Tr<'a, Self, T>
|
||||
where
|
||||
Self: Super,
|
||||
T: 'a,
|
||||
Self: for<'a> Tr::<'a, T>
|
||||
{
|
||||
}
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generics_with_attributes() {
|
||||
check(
|
||||
r#"
|
||||
struct S<#[cfg(never)] T>;
|
||||
struct S<A, B, #[cfg(never)] C>;
|
||||
struct S<A, #[cfg(never)] B, C>;
|
||||
"#,
|
||||
expect![[r#"
|
||||
// AstId: 1
|
||||
pub(self) struct S<#[cfg(never)] T>;
|
||||
|
||||
// AstId: 2
|
||||
pub(self) struct S<A, B, #[cfg(never)] C>;
|
||||
|
||||
// AstId: 3
|
||||
pub(self) struct S<A, #[cfg(never)] B, C>;
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pub_self() {
|
||||
check(
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use triomphe::Arc;
|
|||
|
||||
use crate::{
|
||||
AdtId, AssocItemId, AttrDefId, Crate, EnumId, EnumVariantId, FunctionId, ImplId, ModuleDefId,
|
||||
StaticId, StructId, TraitId, TypeAliasId, UnionId, db::DefDatabase, path::Path,
|
||||
StaticId, StructId, TraitId, TypeAliasId, UnionId, db::DefDatabase, expr_store::path::Path,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
|
|
@ -140,7 +140,7 @@ impl LangItems {
|
|||
}
|
||||
ModuleDefId::AdtId(AdtId::EnumId(e)) => {
|
||||
lang_items.collect_lang_item(db, e, LangItemTarget::EnumId);
|
||||
crate_def_map.enum_definitions[&e].iter().for_each(|&id| {
|
||||
db.enum_variants(e).variants.iter().for_each(|&(id, _)| {
|
||||
lang_items.collect_lang_item(db, id, LangItemTarget::EnumVariant);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,18 +26,14 @@ pub mod db;
|
|||
pub mod attr;
|
||||
pub mod builtin_type;
|
||||
pub mod item_scope;
|
||||
pub mod path;
|
||||
pub mod per_ns;
|
||||
|
||||
pub mod expander;
|
||||
pub mod lower;
|
||||
pub mod signatures;
|
||||
|
||||
pub mod dyn_map;
|
||||
|
||||
pub mod item_tree;
|
||||
|
||||
pub mod data;
|
||||
pub mod generics;
|
||||
pub mod lang_item;
|
||||
|
||||
pub mod hir;
|
||||
|
|
@ -57,9 +53,10 @@ use intern::{Interned, sym};
|
|||
pub use rustc_abi as layout;
|
||||
use triomphe::Arc;
|
||||
|
||||
pub use crate::signatures::LocalFieldId;
|
||||
|
||||
#[cfg(test)]
|
||||
mod macro_expansion_tests;
|
||||
mod pretty;
|
||||
#[cfg(test)]
|
||||
mod test_db;
|
||||
|
||||
|
|
@ -73,6 +70,7 @@ use hir_expand::{
|
|||
db::ExpandDatabase,
|
||||
eager::expand_eager_macro_input,
|
||||
impl_intern_lookup,
|
||||
mod_path::ModPath,
|
||||
name::Name,
|
||||
proc_macro::{CustomProcMacroExpander, ProcMacroKind},
|
||||
};
|
||||
|
|
@ -88,13 +86,14 @@ pub use hir_expand::{Intern, Lookup, tt};
|
|||
use crate::{
|
||||
attr::Attrs,
|
||||
builtin_type::BuiltinType,
|
||||
data::adt::VariantData,
|
||||
db::DefDatabase,
|
||||
hir::generics::{LocalLifetimeParamId, LocalTypeOrConstParamId},
|
||||
item_tree::{
|
||||
Const, Enum, ExternCrate, Function, Impl, ItemTreeId, ItemTreeNode, Macro2, MacroRules,
|
||||
Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use, Variant,
|
||||
},
|
||||
nameres::LocalDefMap,
|
||||
signatures::VariantFields,
|
||||
};
|
||||
|
||||
type FxIndexMap<K, V> = indexmap::IndexMap<K, V, rustc_hash::FxBuildHasher>;
|
||||
|
|
@ -318,18 +317,6 @@ pub struct BlockLoc {
|
|||
}
|
||||
impl_intern!(BlockId, BlockLoc, intern_block, lookup_intern_block);
|
||||
|
||||
// Id of the anonymous const block expression and patterns. This is very similar to `ClosureId` and
|
||||
// shouldn't be a `DefWithBodyId` since its type inference is dependent on its parent.
|
||||
impl_intern!(ConstBlockId, ConstBlockLoc, intern_anonymous_const, lookup_intern_anonymous_const);
|
||||
|
||||
#[derive(Debug, Hash, PartialEq, Eq, Clone)]
|
||||
pub struct ConstBlockLoc {
|
||||
/// The parent of the anonymous const block.
|
||||
pub parent: DefWithBodyId,
|
||||
/// The root expression of this const block in the parent body.
|
||||
pub root: hir::ExprId,
|
||||
}
|
||||
|
||||
/// A `ModuleId` that is always a crate's root module.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct CrateRootModuleId {
|
||||
|
|
@ -484,8 +471,6 @@ pub struct FieldId {
|
|||
pub local_id: LocalFieldId,
|
||||
}
|
||||
|
||||
pub type LocalFieldId = Idx<data::adt::FieldData>;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct TupleId(pub u32);
|
||||
|
||||
|
|
@ -553,14 +538,11 @@ impl From<ConstParamId> for TypeOrConstParamId {
|
|||
}
|
||||
}
|
||||
|
||||
pub type LocalTypeOrConstParamId = Idx<generics::TypeOrConstParamData>;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct LifetimeParamId {
|
||||
pub parent: GenericDefId,
|
||||
pub local_id: LocalLifetimeParamId,
|
||||
}
|
||||
pub type LocalLifetimeParamId = Idx<generics::LifetimeParamData>;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum ItemContainerId {
|
||||
|
|
@ -635,217 +617,59 @@ impl_from!(
|
|||
for ModuleDefId
|
||||
);
|
||||
|
||||
/// Something that holds types, required for the current const arg lowering implementation as they
|
||||
/// need to be able to query where they are defined.
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||
pub enum TypeOwnerId {
|
||||
FunctionId(FunctionId),
|
||||
StaticId(StaticId),
|
||||
ConstId(ConstId),
|
||||
InTypeConstId(InTypeConstId),
|
||||
AdtId(AdtId),
|
||||
TraitId(TraitId),
|
||||
TraitAliasId(TraitAliasId),
|
||||
TypeAliasId(TypeAliasId),
|
||||
ImplId(ImplId),
|
||||
EnumVariantId(EnumVariantId),
|
||||
}
|
||||
|
||||
impl TypeOwnerId {
|
||||
fn as_generic_def_id(self, db: &dyn DefDatabase) -> Option<GenericDefId> {
|
||||
Some(match self {
|
||||
TypeOwnerId::FunctionId(it) => GenericDefId::FunctionId(it),
|
||||
TypeOwnerId::ConstId(it) => GenericDefId::ConstId(it),
|
||||
TypeOwnerId::StaticId(it) => GenericDefId::StaticId(it),
|
||||
TypeOwnerId::AdtId(it) => GenericDefId::AdtId(it),
|
||||
TypeOwnerId::TraitId(it) => GenericDefId::TraitId(it),
|
||||
TypeOwnerId::TraitAliasId(it) => GenericDefId::TraitAliasId(it),
|
||||
TypeOwnerId::TypeAliasId(it) => GenericDefId::TypeAliasId(it),
|
||||
TypeOwnerId::ImplId(it) => GenericDefId::ImplId(it),
|
||||
TypeOwnerId::EnumVariantId(it) => {
|
||||
GenericDefId::AdtId(AdtId::EnumId(it.lookup(db).parent))
|
||||
}
|
||||
TypeOwnerId::InTypeConstId(_) => return None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl_from!(
|
||||
FunctionId,
|
||||
StaticId,
|
||||
ConstId,
|
||||
InTypeConstId,
|
||||
AdtId,
|
||||
TraitId,
|
||||
TraitAliasId,
|
||||
TypeAliasId,
|
||||
ImplId,
|
||||
EnumVariantId
|
||||
for TypeOwnerId
|
||||
);
|
||||
|
||||
// Every `DefWithBodyId` is a type owner, since bodies can contain type (e.g. `{ let it: Type = _; }`)
|
||||
impl From<DefWithBodyId> for TypeOwnerId {
|
||||
fn from(value: DefWithBodyId) -> Self {
|
||||
match value {
|
||||
DefWithBodyId::FunctionId(it) => it.into(),
|
||||
DefWithBodyId::StaticId(it) => it.into(),
|
||||
DefWithBodyId::ConstId(it) => it.into(),
|
||||
DefWithBodyId::InTypeConstId(it) => it.into(),
|
||||
DefWithBodyId::VariantId(it) => it.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GenericDefId> for TypeOwnerId {
|
||||
fn from(value: GenericDefId) -> Self {
|
||||
match value {
|
||||
GenericDefId::FunctionId(it) => it.into(),
|
||||
GenericDefId::AdtId(it) => it.into(),
|
||||
GenericDefId::TraitId(it) => it.into(),
|
||||
GenericDefId::TraitAliasId(it) => it.into(),
|
||||
GenericDefId::TypeAliasId(it) => it.into(),
|
||||
GenericDefId::ImplId(it) => it.into(),
|
||||
GenericDefId::ConstId(it) => it.into(),
|
||||
GenericDefId::StaticId(it) => it.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: This should not be a thing
|
||||
/// A thing that we want to store in interned ids, but we don't know its type in `hir-def`. This is
|
||||
/// currently only used in `InTypeConstId` for storing the type (which has type `Ty` defined in
|
||||
/// the `hir-ty` crate) of the constant in its id, which is a temporary hack so we may want
|
||||
/// to remove this after removing that.
|
||||
pub trait OpaqueInternableThing: std::any::Any + std::fmt::Debug + Sync + Send {
|
||||
fn as_any(&self) -> &dyn std::any::Any;
|
||||
fn box_any(&self) -> Box<dyn std::any::Any>;
|
||||
fn dyn_hash(&self, state: &mut dyn Hasher);
|
||||
fn dyn_eq(&self, other: &dyn OpaqueInternableThing) -> bool;
|
||||
fn dyn_clone(&self) -> Box<dyn OpaqueInternableThing>;
|
||||
}
|
||||
|
||||
impl Hash for dyn OpaqueInternableThing {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.dyn_hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for dyn OpaqueInternableThing {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.dyn_eq(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for dyn OpaqueInternableThing {}
|
||||
|
||||
impl Clone for Box<dyn OpaqueInternableThing> {
|
||||
fn clone(&self) -> Self {
|
||||
self.dyn_clone()
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(const-generic-body): Use an stable id for in type consts.
|
||||
//
|
||||
// The current id uses `AstId<ast::ConstArg>` which will be changed by every change in the code. Ideally
|
||||
// we should use an id which is relative to the type owner, so that every change will only invalidate the
|
||||
// id if it happens inside of the type owner.
|
||||
//
|
||||
// The solution probably is to have some query on `TypeOwnerId` to traverse its constant children and store
|
||||
// their `AstId` in a list (vector or arena), and use the index of that list in the id here. That query probably
|
||||
// needs name resolution, and might go far and handles the whole path lowering or type lowering for a `TypeOwnerId`.
|
||||
//
|
||||
// Whatever path the solution takes, it should answer 3 questions at the same time:
|
||||
// * Is the id stable enough?
|
||||
// * How to find a constant id using an ast node / position in the source code? This is needed when we want to
|
||||
// provide ide functionalities inside an in type const (which we currently don't support) e.g. go to definition
|
||||
// for a local defined there. A complex id might have some trouble in this reverse mapping.
|
||||
// * How to find the return type of a constant using its id? We have this data when we are doing type lowering
|
||||
// and the name of the struct that contains this constant is resolved, so a query that only traverses the
|
||||
// type owner by its syntax tree might have a hard time here.
|
||||
|
||||
// A constant in a type as a substitution for const generics (like `Foo<{ 2 + 2 }>`) or as an array
|
||||
// length (like `[u8; 2 + 2]`). These constants are body owner and are a variant of `DefWithBodyId`. These
|
||||
// are not called `AnonymousConstId` to prevent confusion with [`ConstBlockId`].
|
||||
impl_intern!(InTypeConstId, InTypeConstLoc, intern_in_type_const, lookup_intern_in_type_const);
|
||||
|
||||
// We would like to set `derive(PartialEq)`
|
||||
// but the compiler complains about that `.expected_ty` does not implement the `Copy` trait.
|
||||
#[allow(clippy::derived_hash_with_manual_eq)]
|
||||
#[derive(Debug, Hash, Eq, Clone)]
|
||||
pub struct InTypeConstLoc {
|
||||
pub id: AstId<ast::ConstArg>,
|
||||
/// The thing this const arg appears in
|
||||
pub owner: TypeOwnerId,
|
||||
// FIXME(const-generic-body): The expected type should not be
|
||||
pub expected_ty: Box<dyn OpaqueInternableThing>,
|
||||
}
|
||||
|
||||
impl PartialEq for InTypeConstLoc {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id == other.id && self.owner == other.owner && *self.expected_ty == *other.expected_ty
|
||||
}
|
||||
}
|
||||
|
||||
impl InTypeConstId {
|
||||
pub fn source(&self, db: &dyn DefDatabase) -> ast::ConstArg {
|
||||
let src = self.lookup(db).id;
|
||||
let file_id = src.file_id;
|
||||
let root = db.parse_or_expand(file_id);
|
||||
db.ast_id_map(file_id).get(src.value).to_node(&root)
|
||||
}
|
||||
}
|
||||
|
||||
/// A constant, which might appears as a const item, an anonymous const block in expressions
|
||||
/// or patterns, or as a constant in types with const generics.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum GeneralConstId {
|
||||
ConstId(ConstId),
|
||||
StaticId(StaticId),
|
||||
ConstBlockId(ConstBlockId),
|
||||
InTypeConstId(InTypeConstId),
|
||||
}
|
||||
|
||||
impl_from!(ConstId, StaticId, ConstBlockId, InTypeConstId for GeneralConstId);
|
||||
impl_from!(ConstId, StaticId for GeneralConstId);
|
||||
|
||||
impl GeneralConstId {
|
||||
pub fn generic_def(self, db: &dyn DefDatabase) -> Option<GenericDefId> {
|
||||
pub fn generic_def(self, _db: &dyn DefDatabase) -> Option<GenericDefId> {
|
||||
match self {
|
||||
GeneralConstId::ConstId(it) => Some(it.into()),
|
||||
GeneralConstId::StaticId(it) => Some(it.into()),
|
||||
GeneralConstId::ConstBlockId(it) => it.lookup(db).parent.as_generic_def_id(db),
|
||||
GeneralConstId::InTypeConstId(it) => it.lookup(db).owner.as_generic_def_id(db),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(self, db: &dyn DefDatabase) -> String {
|
||||
match self {
|
||||
GeneralConstId::StaticId(it) => {
|
||||
db.static_data(it).name.display(db.upcast(), Edition::CURRENT).to_string()
|
||||
let loc = it.lookup(db);
|
||||
let tree = loc.item_tree_id().item_tree(db);
|
||||
let name = tree[loc.id.value].name.display(db.upcast(), Edition::CURRENT);
|
||||
name.to_string()
|
||||
}
|
||||
GeneralConstId::ConstId(const_id) => {
|
||||
let loc = const_id.lookup(db);
|
||||
let tree = loc.item_tree_id().item_tree(db);
|
||||
tree[loc.id.value].name.as_ref().map_or_else(
|
||||
|| "_".to_owned(),
|
||||
|name| name.display(db.upcast(), Edition::CURRENT).to_string(),
|
||||
)
|
||||
}
|
||||
GeneralConstId::ConstId(const_id) => db
|
||||
.const_data(const_id)
|
||||
.name
|
||||
.as_ref()
|
||||
.map(|it| it.as_str())
|
||||
.unwrap_or("_")
|
||||
.to_owned(),
|
||||
GeneralConstId::ConstBlockId(id) => format!("{{anonymous const {id:?}}}"),
|
||||
GeneralConstId::InTypeConstId(id) => format!("{{in type const {id:?}}}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The defs which have a body.
|
||||
/// The defs which have a body (have root expressions for type inference).
|
||||
#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)]
|
||||
pub enum DefWithBodyId {
|
||||
FunctionId(FunctionId),
|
||||
StaticId(StaticId),
|
||||
ConstId(ConstId),
|
||||
InTypeConstId(InTypeConstId),
|
||||
VariantId(EnumVariantId),
|
||||
// /// All fields of a variant are inference roots
|
||||
// VariantId(VariantId),
|
||||
// /// The signature can contain inference roots in a bunch of places
|
||||
// /// like const parameters or const arguments in paths
|
||||
// This should likely be kept on its own with a separate query
|
||||
// GenericDefId(GenericDefId),
|
||||
}
|
||||
impl_from!(FunctionId, ConstId, StaticId, InTypeConstId for DefWithBodyId);
|
||||
impl_from!(FunctionId, ConstId, StaticId for DefWithBodyId);
|
||||
|
||||
impl From<EnumVariantId> for DefWithBodyId {
|
||||
fn from(id: EnumVariantId) -> Self {
|
||||
|
|
@ -860,9 +684,6 @@ impl DefWithBodyId {
|
|||
DefWithBodyId::StaticId(s) => Some(s.into()),
|
||||
DefWithBodyId::ConstId(c) => Some(c.into()),
|
||||
DefWithBodyId::VariantId(c) => Some(c.lookup(db).parent.into()),
|
||||
// FIXME: stable rust doesn't allow generics in constants, but we should
|
||||
// use `TypeOwnerId::as_generic_def_id` when it does.
|
||||
DefWithBodyId::InTypeConstId(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1094,8 +915,8 @@ pub enum VariantId {
|
|||
impl_from!(EnumVariantId, StructId, UnionId for VariantId);
|
||||
|
||||
impl VariantId {
|
||||
pub fn variant_data(self, db: &dyn DefDatabase) -> Arc<VariantData> {
|
||||
db.variant_data(self)
|
||||
pub fn variant_data(self, db: &dyn DefDatabase) -> Arc<VariantFields> {
|
||||
db.variant_fields(self)
|
||||
}
|
||||
|
||||
pub fn file_id(self, db: &dyn DefDatabase) -> HirFileId {
|
||||
|
|
@ -1271,23 +1092,6 @@ impl HasModule for MacroId {
|
|||
}
|
||||
}
|
||||
|
||||
impl HasModule for TypeOwnerId {
|
||||
fn module(&self, db: &dyn DefDatabase) -> ModuleId {
|
||||
match *self {
|
||||
TypeOwnerId::FunctionId(it) => it.module(db),
|
||||
TypeOwnerId::StaticId(it) => it.module(db),
|
||||
TypeOwnerId::ConstId(it) => it.module(db),
|
||||
TypeOwnerId::AdtId(it) => it.module(db),
|
||||
TypeOwnerId::TraitId(it) => it.module(db),
|
||||
TypeOwnerId::TraitAliasId(it) => it.module(db),
|
||||
TypeOwnerId::TypeAliasId(it) => it.module(db),
|
||||
TypeOwnerId::ImplId(it) => it.module(db),
|
||||
TypeOwnerId::EnumVariantId(it) => it.module(db),
|
||||
TypeOwnerId::InTypeConstId(it) => it.lookup(db).owner.module(db),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HasModule for DefWithBodyId {
|
||||
fn module(&self, db: &dyn DefDatabase) -> ModuleId {
|
||||
match self {
|
||||
|
|
@ -1295,7 +1099,6 @@ impl HasModule for DefWithBodyId {
|
|||
DefWithBodyId::StaticId(it) => it.module(db),
|
||||
DefWithBodyId::ConstId(it) => it.module(db),
|
||||
DefWithBodyId::VariantId(it) => it.module(db),
|
||||
DefWithBodyId::InTypeConstId(it) => it.lookup(db).owner.module(db),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1364,22 +1167,18 @@ impl ModuleDefId {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: Replace this with a plain function, it only has one impl
|
||||
/// A helper trait for converting to MacroCallId
|
||||
pub trait AsMacroCall {
|
||||
fn as_call_id(
|
||||
&self,
|
||||
db: &dyn ExpandDatabase,
|
||||
krate: Crate,
|
||||
resolver: impl Fn(&path::ModPath) -> Option<MacroDefId> + Copy,
|
||||
) -> Option<MacroCallId> {
|
||||
self.as_call_id_with_errors(db, krate, resolver).ok()?.value
|
||||
}
|
||||
|
||||
trait AsMacroCall {
|
||||
fn as_call_id_with_errors(
|
||||
&self,
|
||||
db: &dyn ExpandDatabase,
|
||||
krate: Crate,
|
||||
resolver: impl Fn(&path::ModPath) -> Option<MacroDefId> + Copy,
|
||||
resolver: impl Fn(&ModPath) -> Option<MacroDefId> + Copy,
|
||||
eager_callback: &mut dyn FnMut(
|
||||
InFile<(syntax::AstPtr<ast::MacroCall>, span::FileAstId<ast::MacroCall>)>,
|
||||
MacroCallId,
|
||||
),
|
||||
) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro>;
|
||||
}
|
||||
|
||||
|
|
@ -1388,14 +1187,18 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
|
|||
&self,
|
||||
db: &dyn ExpandDatabase,
|
||||
krate: Crate,
|
||||
resolver: impl Fn(&path::ModPath) -> Option<MacroDefId> + Copy,
|
||||
resolver: impl Fn(&ModPath) -> Option<MacroDefId> + Copy,
|
||||
eager_callback: &mut dyn FnMut(
|
||||
InFile<(syntax::AstPtr<ast::MacroCall>, span::FileAstId<ast::MacroCall>)>,
|
||||
MacroCallId,
|
||||
),
|
||||
) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro> {
|
||||
let expands_to = hir_expand::ExpandTo::from_call_site(self.value);
|
||||
let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value));
|
||||
let span_map = db.span_map(self.file_id);
|
||||
let path = self.value.path().and_then(|path| {
|
||||
let range = path.syntax().text_range();
|
||||
let mod_path = path::ModPath::from_src(db, path, &mut |range| {
|
||||
let mod_path = ModPath::from_src(db, path, &mut |range| {
|
||||
span_map.as_ref().span_for_range(range).ctx
|
||||
})?;
|
||||
let call_site = span_map.span_for_range(range);
|
||||
|
|
@ -1418,6 +1221,7 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
|
|||
krate,
|
||||
resolver,
|
||||
resolver,
|
||||
eager_callback,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1426,15 +1230,11 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
|
|||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
struct AstIdWithPath<T: AstIdNode> {
|
||||
ast_id: AstId<T>,
|
||||
path: Interned<path::ModPath>,
|
||||
path: Interned<ModPath>,
|
||||
}
|
||||
|
||||
impl<T: AstIdNode> AstIdWithPath<T> {
|
||||
fn new(
|
||||
file_id: HirFileId,
|
||||
ast_id: FileAstId<T>,
|
||||
path: Interned<path::ModPath>,
|
||||
) -> AstIdWithPath<T> {
|
||||
fn new(file_id: HirFileId, ast_id: FileAstId<T>, path: Interned<ModPath>) -> AstIdWithPath<T> {
|
||||
AstIdWithPath { ast_id: AstId::new(file_id, ast_id), path }
|
||||
}
|
||||
}
|
||||
|
|
@ -1445,7 +1245,11 @@ fn macro_call_as_call_id(
|
|||
call_site: SyntaxContext,
|
||||
expand_to: ExpandTo,
|
||||
krate: Crate,
|
||||
resolver: impl Fn(&path::ModPath) -> Option<MacroDefId> + Copy,
|
||||
resolver: impl Fn(&ModPath) -> Option<MacroDefId> + Copy,
|
||||
eager_callback: &mut dyn FnMut(
|
||||
InFile<(syntax::AstPtr<ast::MacroCall>, span::FileAstId<ast::MacroCall>)>,
|
||||
MacroCallId,
|
||||
),
|
||||
) -> Result<Option<MacroCallId>, UnresolvedMacro> {
|
||||
macro_call_as_call_id_with_eager(
|
||||
db,
|
||||
|
|
@ -1456,6 +1260,7 @@ fn macro_call_as_call_id(
|
|||
krate,
|
||||
resolver,
|
||||
resolver,
|
||||
eager_callback,
|
||||
)
|
||||
.map(|res| res.value)
|
||||
}
|
||||
|
|
@ -1463,12 +1268,16 @@ fn macro_call_as_call_id(
|
|||
fn macro_call_as_call_id_with_eager(
|
||||
db: &dyn ExpandDatabase,
|
||||
ast_id: AstId<ast::MacroCall>,
|
||||
path: &path::ModPath,
|
||||
path: &ModPath,
|
||||
call_site: SyntaxContext,
|
||||
expand_to: ExpandTo,
|
||||
krate: Crate,
|
||||
resolver: impl FnOnce(&path::ModPath) -> Option<MacroDefId>,
|
||||
eager_resolver: impl Fn(&path::ModPath) -> Option<MacroDefId>,
|
||||
resolver: impl FnOnce(&ModPath) -> Option<MacroDefId>,
|
||||
eager_resolver: impl Fn(&ModPath) -> Option<MacroDefId>,
|
||||
eager_callback: &mut dyn FnMut(
|
||||
InFile<(syntax::AstPtr<ast::MacroCall>, span::FileAstId<ast::MacroCall>)>,
|
||||
MacroCallId,
|
||||
),
|
||||
) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro> {
|
||||
let def = resolver(path).ok_or_else(|| UnresolvedMacro { path: path.clone() })?;
|
||||
|
||||
|
|
@ -1481,6 +1290,7 @@ fn macro_call_as_call_id_with_eager(
|
|||
def,
|
||||
call_site,
|
||||
&|path| eager_resolver(path).filter(MacroDefId::is_fn_like),
|
||||
eager_callback,
|
||||
),
|
||||
_ if def.is_fn_like() => ExpandResult {
|
||||
value: Some(def.make_call(
|
||||
|
|
@ -1498,7 +1308,7 @@ fn macro_call_as_call_id_with_eager(
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct UnresolvedMacro {
|
||||
pub path: hir_expand::mod_path::ModPath,
|
||||
pub path: ModPath,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Eq, PartialEq, Clone, Copy)]
|
||||
|
|
|
|||
|
|
@ -1,149 +0,0 @@
|
|||
//! Context for lowering paths.
|
||||
use std::{cell::OnceCell, mem};
|
||||
|
||||
use hir_expand::{AstId, HirFileId, InFile, span_map::SpanMap};
|
||||
use span::{AstIdMap, AstIdNode, Edition, EditionedFileId, FileId, RealSpanMap};
|
||||
use syntax::ast;
|
||||
use thin_vec::ThinVec;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
db::DefDatabase,
|
||||
path::Path,
|
||||
type_ref::{PathId, TypeBound, TypePtr, TypeRef, TypeRefId, TypesMap, TypesSourceMap},
|
||||
};
|
||||
|
||||
pub struct LowerCtx<'a> {
|
||||
pub db: &'a dyn DefDatabase,
|
||||
file_id: HirFileId,
|
||||
span_map: OnceCell<SpanMap>,
|
||||
ast_id_map: OnceCell<Arc<AstIdMap>>,
|
||||
impl_trait_bounds: Vec<ThinVec<TypeBound>>,
|
||||
// Prevent nested impl traits like `impl Foo<impl Bar>`.
|
||||
outer_impl_trait: bool,
|
||||
types_map: &'a mut TypesMap,
|
||||
types_source_map: &'a mut TypesSourceMap,
|
||||
}
|
||||
|
||||
impl<'a> LowerCtx<'a> {
|
||||
pub fn new(
|
||||
db: &'a dyn DefDatabase,
|
||||
file_id: HirFileId,
|
||||
types_map: &'a mut TypesMap,
|
||||
types_source_map: &'a mut TypesSourceMap,
|
||||
) -> Self {
|
||||
LowerCtx {
|
||||
db,
|
||||
file_id,
|
||||
span_map: OnceCell::new(),
|
||||
ast_id_map: OnceCell::new(),
|
||||
impl_trait_bounds: Vec::new(),
|
||||
outer_impl_trait: false,
|
||||
types_map,
|
||||
types_source_map,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_span_map_cell(
|
||||
db: &'a dyn DefDatabase,
|
||||
file_id: HirFileId,
|
||||
span_map: OnceCell<SpanMap>,
|
||||
types_map: &'a mut TypesMap,
|
||||
types_source_map: &'a mut TypesSourceMap,
|
||||
) -> Self {
|
||||
LowerCtx {
|
||||
db,
|
||||
file_id,
|
||||
span_map,
|
||||
ast_id_map: OnceCell::new(),
|
||||
impl_trait_bounds: Vec::new(),
|
||||
outer_impl_trait: false,
|
||||
types_map,
|
||||
types_source_map,
|
||||
}
|
||||
}
|
||||
|
||||
/// Prepares a `LowerCtx` for synthetic AST that needs to be lowered. This is intended for IDE things.
|
||||
pub fn for_synthetic_ast(
|
||||
db: &'a dyn DefDatabase,
|
||||
ast_id_map: Arc<AstIdMap>,
|
||||
types_map: &'a mut TypesMap,
|
||||
types_source_map: &'a mut TypesSourceMap,
|
||||
) -> Self {
|
||||
let file_id = EditionedFileId::new(
|
||||
FileId::from_raw(EditionedFileId::MAX_FILE_ID),
|
||||
Edition::Edition2015,
|
||||
);
|
||||
LowerCtx {
|
||||
db,
|
||||
// Make up an invalid file id, so that if we will try to actually access it salsa will panic.
|
||||
file_id: file_id.into(),
|
||||
span_map: SpanMap::RealSpanMap(Arc::new(RealSpanMap::absolute(file_id))).into(),
|
||||
ast_id_map: ast_id_map.into(),
|
||||
impl_trait_bounds: Vec::new(),
|
||||
outer_impl_trait: false,
|
||||
types_map,
|
||||
types_source_map,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn span_map(&self) -> &SpanMap {
|
||||
self.span_map.get_or_init(|| self.db.span_map(self.file_id))
|
||||
}
|
||||
|
||||
pub(crate) fn lower_path(&mut self, ast: ast::Path) -> Option<Path> {
|
||||
Path::from_src(self, ast)
|
||||
}
|
||||
|
||||
pub(crate) fn ast_id<N: AstIdNode>(&self, item: &N) -> AstId<N> {
|
||||
InFile::new(
|
||||
self.file_id,
|
||||
self.ast_id_map.get_or_init(|| self.db.ast_id_map(self.file_id)).ast_id(item),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn update_impl_traits_bounds_from_type_ref(&mut self, type_ref: TypeRefId) {
|
||||
TypeRef::walk(type_ref, self.types_map, &mut |tr| {
|
||||
if let TypeRef::ImplTrait(bounds) = tr {
|
||||
self.impl_trait_bounds.push(bounds.clone());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn take_impl_traits_bounds(&mut self) -> Vec<ThinVec<TypeBound>> {
|
||||
mem::take(&mut self.impl_trait_bounds)
|
||||
}
|
||||
|
||||
pub(crate) fn outer_impl_trait(&self) -> bool {
|
||||
self.outer_impl_trait
|
||||
}
|
||||
|
||||
pub(crate) fn with_outer_impl_trait_scope<R>(
|
||||
&mut self,
|
||||
impl_trait: bool,
|
||||
f: impl FnOnce(&mut Self) -> R,
|
||||
) -> R {
|
||||
let old = mem::replace(&mut self.outer_impl_trait, impl_trait);
|
||||
let result = f(self);
|
||||
self.outer_impl_trait = old;
|
||||
result
|
||||
}
|
||||
|
||||
pub(crate) fn alloc_type_ref(&mut self, type_ref: TypeRef, node: TypePtr) -> TypeRefId {
|
||||
let id = self.types_map.types.alloc(type_ref);
|
||||
self.types_source_map.types_map_back.insert(id, InFile::new(self.file_id, node));
|
||||
id
|
||||
}
|
||||
|
||||
pub(crate) fn alloc_type_ref_desugared(&mut self, type_ref: TypeRef) -> TypeRefId {
|
||||
self.types_map.types.alloc(type_ref)
|
||||
}
|
||||
|
||||
pub(crate) fn alloc_error_type(&mut self) -> TypeRefId {
|
||||
self.types_map.types.alloc(TypeRef::Error)
|
||||
}
|
||||
|
||||
pub(crate) fn alloc_path(&mut self, path: Path, node: TypePtr) -> PathId {
|
||||
PathId::from_type_ref_unchecked(self.alloc_type_ref(TypeRef::Path(path), node))
|
||||
}
|
||||
}
|
||||
|
|
@ -35,9 +35,9 @@ macro_rules! f {
|
|||
};
|
||||
}
|
||||
|
||||
struct#0:1@58..64#20480# MyTraitMap2#0:2@31..42#ROOT2024# {#0:1@72..73#20480#
|
||||
map#0:1@86..89#20480#:#0:1@89..90#20480# #0:1@89..90#20480#::#0:1@91..93#20480#std#0:1@93..96#20480#::#0:1@96..98#20480#collections#0:1@98..109#20480#::#0:1@109..111#20480#HashSet#0:1@111..118#20480#<#0:1@118..119#20480#(#0:1@119..120#20480#)#0:1@120..121#20480#>#0:1@121..122#20480#,#0:1@122..123#20480#
|
||||
}#0:1@132..133#20480#
|
||||
struct#0:1@58..64#19456# MyTraitMap2#0:2@31..42#ROOT2024# {#0:1@72..73#19456#
|
||||
map#0:1@86..89#19456#:#0:1@89..90#19456# #0:1@89..90#19456#::#0:1@91..93#19456#std#0:1@93..96#19456#::#0:1@96..98#19456#collections#0:1@98..109#19456#::#0:1@109..111#19456#HashSet#0:1@111..118#19456#<#0:1@118..119#19456#(#0:1@119..120#19456#)#0:1@120..121#19456#>#0:1@121..122#19456#,#0:1@122..123#19456#
|
||||
}#0:1@132..133#19456#
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
@ -197,7 +197,7 @@ macro_rules! mk_struct {
|
|||
#[macro_use]
|
||||
mod foo;
|
||||
|
||||
struct#1:1@59..65#20480# Foo#0:2@32..35#ROOT2024#(#1:1@70..71#20480#u32#0:2@41..44#ROOT2024#)#1:1@74..75#20480#;#1:1@75..76#20480#
|
||||
struct#1:1@59..65#19456# Foo#0:2@32..35#ROOT2024#(#1:1@70..71#19456#u32#0:2@41..44#ROOT2024#)#1:1@74..75#19456#;#1:1@75..76#19456#
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
@ -423,10 +423,10 @@ m! { foo, bar }
|
|||
macro_rules! m {
|
||||
($($i:ident),*) => ( impl Bar { $(fn $i() {})* } );
|
||||
}
|
||||
impl#\20480# Bar#\20480# {#\20480#
|
||||
fn#\20480# foo#\ROOT2024#(#\20480#)#\20480# {#\20480#}#\20480#
|
||||
fn#\20480# bar#\ROOT2024#(#\20480#)#\20480# {#\20480#}#\20480#
|
||||
}#\20480#
|
||||
impl#\19456# Bar#\19456# {#\19456#
|
||||
fn#\19456# foo#\ROOT2024#(#\19456#)#\19456# {#\19456#}#\19456#
|
||||
fn#\19456# bar#\ROOT2024#(#\19456#)#\19456# {#\19456#}#\19456#
|
||||
}#\19456#
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,11 +131,16 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
|
|||
for macro_call in source_file.syntax().descendants().filter_map(ast::MacroCall::cast) {
|
||||
let macro_call = InFile::new(source.file_id, ¯o_call);
|
||||
let res = macro_call
|
||||
.as_call_id_with_errors(&db, krate, |path| {
|
||||
.as_call_id_with_errors(
|
||||
&db,
|
||||
krate,
|
||||
|path| {
|
||||
resolver
|
||||
.resolve_path_as_macro(&db, path, Some(MacroSubNs::Bang))
|
||||
.map(|(it, _)| db.macro_def(it))
|
||||
})
|
||||
},
|
||||
&mut |_, _| (),
|
||||
)
|
||||
.unwrap();
|
||||
let macro_call_id = res.value.unwrap();
|
||||
let macro_file = MacroFileId { macro_call_id };
|
||||
|
|
|
|||
|
|
@ -62,7 +62,8 @@ use std::ops::Deref;
|
|||
|
||||
use base_db::Crate;
|
||||
use hir_expand::{
|
||||
ErasedAstId, HirFileId, InFile, MacroCallId, MacroDefId, name::Name, proc_macro::ProcMacroKind,
|
||||
ErasedAstId, HirFileId, InFile, MacroCallId, MacroDefId, mod_path::ModPath, name::Name,
|
||||
proc_macro::ProcMacroKind,
|
||||
};
|
||||
use intern::Symbol;
|
||||
use itertools::Itertools;
|
||||
|
|
@ -75,13 +76,12 @@ use triomphe::Arc;
|
|||
use tt::TextRange;
|
||||
|
||||
use crate::{
|
||||
AstId, BlockId, BlockLoc, CrateRootModuleId, EnumId, EnumVariantId, ExternCrateId, FunctionId,
|
||||
FxIndexMap, LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, ProcMacroId, UseId,
|
||||
AstId, BlockId, BlockLoc, CrateRootModuleId, ExternCrateId, FunctionId, FxIndexMap,
|
||||
LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, ProcMacroId, UseId,
|
||||
db::DefDatabase,
|
||||
item_scope::{BuiltinShadowMode, ItemScope},
|
||||
item_tree::{ItemTreeId, Mod, TreeId},
|
||||
nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode},
|
||||
path::ModPath,
|
||||
per_ns::PerNs,
|
||||
visibility::{Visibility, VisibilityExplicitness},
|
||||
};
|
||||
|
|
@ -158,12 +158,15 @@ pub struct DefMap {
|
|||
/// this contains all kinds of macro, not just `macro_rules!` macro.
|
||||
/// ExternCrateId being None implies it being imported from the general prelude import.
|
||||
macro_use_prelude: FxHashMap<Name, (MacroId, Option<ExternCrateId>)>,
|
||||
pub(crate) enum_definitions: FxHashMap<EnumId, Box<[EnumVariantId]>>,
|
||||
|
||||
// FIXME: AstId's are fairly unstable
|
||||
/// Tracks which custom derives are in scope for an item, to allow resolution of derive helper
|
||||
/// attributes.
|
||||
// FIXME: Figure out a better way for the IDE layer to resolve these?
|
||||
derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<(Name, MacroId, MacroCallId)>>,
|
||||
// FIXME: AstId's are fairly unstable
|
||||
/// A mapping from [`hir_expand::MacroDefId`] to [`crate::MacroId`].
|
||||
pub macro_def_to_macro_id: FxHashMap<ErasedAstId, MacroId>,
|
||||
|
||||
/// The diagnostics that need to be emitted for this crate.
|
||||
diagnostics: Vec<DefDiagnostic>,
|
||||
|
|
@ -454,8 +457,8 @@ impl DefMap {
|
|||
macro_use_prelude: FxHashMap::default(),
|
||||
derive_helpers_in_scope: FxHashMap::default(),
|
||||
diagnostics: Vec::new(),
|
||||
enum_definitions: FxHashMap::default(),
|
||||
data: crate_data,
|
||||
macro_def_to_macro_id: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
fn shrink_to_fit(&mut self) {
|
||||
|
|
@ -469,14 +472,14 @@ impl DefMap {
|
|||
krate: _,
|
||||
prelude: _,
|
||||
data: _,
|
||||
enum_definitions,
|
||||
macro_def_to_macro_id,
|
||||
} = self;
|
||||
|
||||
macro_def_to_macro_id.shrink_to_fit();
|
||||
macro_use_prelude.shrink_to_fit();
|
||||
diagnostics.shrink_to_fit();
|
||||
modules.shrink_to_fit();
|
||||
derive_helpers_in_scope.shrink_to_fit();
|
||||
enum_definitions.shrink_to_fit();
|
||||
for (_, module) in modules.iter_mut() {
|
||||
module.children.shrink_to_fit();
|
||||
module.scope.shrink_to_fit();
|
||||
|
|
|
|||
|
|
@ -265,6 +265,9 @@ impl<'a> AssocItemCollector<'a> {
|
|||
expand_to,
|
||||
self.module_id.krate(),
|
||||
resolver,
|
||||
&mut |ptr, call_id| {
|
||||
self.macro_calls.push((ptr.map(|(_, it)| it.upcast()), call_id))
|
||||
},
|
||||
) {
|
||||
Ok(Some(call_id)) => {
|
||||
self.macro_calls
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use hir_expand::{
|
|||
MacroCallId, MacroCallKind, MacroDefId,
|
||||
attrs::{Attr, AttrId, AttrInput},
|
||||
inert_attr_macro::find_builtin_attr_idx,
|
||||
mod_path::{ModPath, PathKind},
|
||||
};
|
||||
use span::SyntaxContext;
|
||||
use syntax::ast;
|
||||
|
|
@ -15,7 +16,6 @@ use crate::{
|
|||
db::DefDatabase,
|
||||
item_scope::BuiltinShadowMode,
|
||||
nameres::{LocalDefMap, path_resolution::ResolveMode},
|
||||
path::{self, ModPath, PathKind},
|
||||
};
|
||||
|
||||
use super::{DefMap, MacroSubNs};
|
||||
|
|
@ -139,7 +139,7 @@ pub(super) fn derive_macro_as_call_id(
|
|||
derive_pos: u32,
|
||||
call_site: SyntaxContext,
|
||||
krate: Crate,
|
||||
resolver: impl Fn(&path::ModPath) -> Option<(MacroId, MacroDefId)>,
|
||||
resolver: impl Fn(&ModPath) -> Option<(MacroId, MacroDefId)>,
|
||||
derive_macro_id: MacroCallId,
|
||||
) -> Result<(MacroId, MacroDefId, MacroCallId), UnresolvedMacro> {
|
||||
let (macro_id, def_id) = resolver(&item_attr.path)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ use hir_expand::{
|
|||
MacroFileIdExt,
|
||||
attrs::{Attr, AttrId},
|
||||
builtin::{find_builtin_attr, find_builtin_derive, find_builtin_macro},
|
||||
mod_path::{ModPath, PathKind},
|
||||
name::{AsName, Name},
|
||||
proc_macro::CustomProcMacroExpander,
|
||||
};
|
||||
|
|
@ -25,18 +26,18 @@ use syntax::ast;
|
|||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, EnumVariantLoc,
|
||||
ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, ImplLoc, Intern,
|
||||
ItemContainerId, LocalModuleId, Lookup, Macro2Id, Macro2Loc, MacroExpander, MacroId,
|
||||
MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ModuleDefId, ModuleId, ProcMacroId,
|
||||
ProcMacroLoc, StaticLoc, StructLoc, TraitAliasLoc, TraitLoc, TypeAliasLoc, UnionLoc,
|
||||
UnresolvedMacro, UseId, UseLoc,
|
||||
AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, ExternBlockLoc,
|
||||
ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, ImplLoc, Intern, ItemContainerId,
|
||||
LocalModuleId, Lookup, Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId,
|
||||
MacroRulesLoc, MacroRulesLocFlags, ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc,
|
||||
StructLoc, TraitAliasLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, UseId, UseLoc,
|
||||
attr::Attrs,
|
||||
db::DefDatabase,
|
||||
item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports},
|
||||
item_tree::{
|
||||
self, AttrOwner, FieldsShape, FileItemTreeId, ImportKind, ItemTree, ItemTreeId,
|
||||
ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, UseTreeKind,
|
||||
self, AttrOwner, FieldsShape, FileItemTreeId, ImportAlias, ImportKind, ItemTree,
|
||||
ItemTreeId, ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId,
|
||||
UseTreeKind,
|
||||
},
|
||||
macro_call_as_call_id, macro_call_as_call_id_with_eager,
|
||||
nameres::{
|
||||
|
|
@ -48,7 +49,6 @@ use crate::{
|
|||
proc_macro::{ProcMacroDef, ProcMacroKind, parse_macro_name_and_helper_attrs},
|
||||
sub_namespace_match,
|
||||
},
|
||||
path::{ImportAlias, ModPath, PathKind},
|
||||
per_ns::{Item, PerNs},
|
||||
tt,
|
||||
visibility::{RawVisibility, Visibility},
|
||||
|
|
@ -580,6 +580,7 @@ impl DefCollector<'_> {
|
|||
&mut self,
|
||||
def: ProcMacroDef,
|
||||
id: ItemTreeId<item_tree::Function>,
|
||||
ast_id: AstId<ast::Fn>,
|
||||
fn_id: FunctionId,
|
||||
) {
|
||||
let kind = def.kind.to_basedb_kind();
|
||||
|
|
@ -603,6 +604,8 @@ impl DefCollector<'_> {
|
|||
edition: self.def_map.data.edition,
|
||||
}
|
||||
.intern(self.db);
|
||||
|
||||
self.def_map.macro_def_to_macro_id.insert(ast_id.erase(), proc_macro_id.into());
|
||||
self.define_proc_macro(def.name.clone(), proc_macro_id);
|
||||
let crate_data = Arc::get_mut(&mut self.def_map.data).unwrap();
|
||||
if let ProcMacroKind::Derive { helpers } = def.kind {
|
||||
|
|
@ -967,25 +970,14 @@ impl DefCollector<'_> {
|
|||
Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => {
|
||||
cov_mark::hit!(glob_enum);
|
||||
// glob import from enum => just import all the variants
|
||||
|
||||
// We need to check if the def map the enum is from is us, if it is we can't
|
||||
// call the def-map query since we are currently constructing it!
|
||||
let loc = e.lookup(self.db);
|
||||
let tree = loc.id.item_tree(self.db);
|
||||
let current_def_map = self.def_map.krate == loc.container.krate
|
||||
&& self.def_map.block_id() == loc.container.block;
|
||||
let def_map;
|
||||
let resolutions = if current_def_map {
|
||||
&self.def_map.enum_definitions[&e]
|
||||
} else {
|
||||
def_map = loc.container.def_map(self.db);
|
||||
&def_map.enum_definitions[&e]
|
||||
}
|
||||
let resolutions = self
|
||||
.db
|
||||
.enum_variants(e)
|
||||
.variants
|
||||
.iter()
|
||||
.map(|&variant| {
|
||||
let name = tree[variant.lookup(self.db).id.value].name.clone();
|
||||
.map(|&(variant, ref name)| {
|
||||
let res = PerNs::both(variant.into(), variant.into(), vis, None);
|
||||
(Some(name), res)
|
||||
(Some(name.clone()), res)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
self.update(
|
||||
|
|
@ -1237,6 +1229,7 @@ impl DefCollector<'_> {
|
|||
No,
|
||||
}
|
||||
|
||||
let mut eager_callback_buffer = vec![];
|
||||
let mut res = ReachedFixedPoint::Yes;
|
||||
// Retain unresolved macros after this round of resolution.
|
||||
let mut retain = |directive: &MacroDirective| {
|
||||
|
|
@ -1269,6 +1262,9 @@ impl DefCollector<'_> {
|
|||
*expand_to,
|
||||
self.def_map.krate,
|
||||
resolver_def_id,
|
||||
&mut |ptr, call_id| {
|
||||
eager_callback_buffer.push((directive.module_id, ptr, call_id));
|
||||
},
|
||||
);
|
||||
if let Ok(Some(call_id)) = call_id {
|
||||
self.def_map.modules[directive.module_id]
|
||||
|
|
@ -1494,6 +1490,10 @@ impl DefCollector<'_> {
|
|||
macros.extend(mem::take(&mut self.unresolved_macros));
|
||||
self.unresolved_macros = macros;
|
||||
|
||||
for (module_id, ptr, call_id) in eager_callback_buffer {
|
||||
self.def_map.modules[module_id].scope.add_macro_invoc(ptr.map(|(_, it)| it), call_id);
|
||||
}
|
||||
|
||||
for (module_id, depth, container, macro_call_id) in resolved {
|
||||
self.collect_macro_expansion(module_id, macro_call_id, depth, container);
|
||||
}
|
||||
|
|
@ -1560,6 +1560,7 @@ impl DefCollector<'_> {
|
|||
);
|
||||
resolved_res.resolved_def.take_macros().map(|it| self.db.macro_def(it))
|
||||
},
|
||||
&mut |_, _| (),
|
||||
);
|
||||
if let Err(UnresolvedMacro { path }) = macro_call_as_call_id {
|
||||
self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
|
||||
|
|
@ -1839,6 +1840,7 @@ impl ModCollector<'_, '_> {
|
|||
self.def_collector.export_proc_macro(
|
||||
proc_macro,
|
||||
ItemTreeId::new(self.tree_id, id),
|
||||
InFile::new(self.file_id(), self.item_tree[id].ast_id()),
|
||||
fn_id,
|
||||
);
|
||||
}
|
||||
|
|
@ -1882,39 +1884,6 @@ impl ModCollector<'_, '_> {
|
|||
|
||||
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
|
||||
update_def(self.def_collector, enum_.into(), &it.name, vis, false);
|
||||
|
||||
let mut index = 0;
|
||||
let variants = FileItemTreeId::range_iter(it.variants.clone())
|
||||
.filter_map(|variant| {
|
||||
let is_enabled = self
|
||||
.item_tree
|
||||
.attrs(db, krate, variant.into())
|
||||
.cfg()
|
||||
.and_then(|cfg| self.is_cfg_enabled(&cfg).not().then_some(cfg))
|
||||
.map_or(Ok(()), Err);
|
||||
match is_enabled {
|
||||
Err(cfg) => {
|
||||
self.emit_unconfigured_diagnostic(
|
||||
self.tree_id,
|
||||
variant.into(),
|
||||
&cfg,
|
||||
);
|
||||
None
|
||||
}
|
||||
Ok(()) => Some({
|
||||
let loc = EnumVariantLoc {
|
||||
id: ItemTreeId::new(self.tree_id, variant),
|
||||
parent: enum_,
|
||||
index,
|
||||
}
|
||||
.intern(db);
|
||||
index += 1;
|
||||
loc
|
||||
}),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
self.def_collector.def_map.enum_definitions.insert(enum_, variants);
|
||||
}
|
||||
ModItem::Const(id) => {
|
||||
let it = &self.item_tree[id];
|
||||
|
|
@ -2352,6 +2321,10 @@ impl ModCollector<'_, '_> {
|
|||
edition: self.def_collector.def_map.data.edition,
|
||||
}
|
||||
.intern(self.def_collector.db);
|
||||
self.def_collector.def_map.macro_def_to_macro_id.insert(
|
||||
InFile::new(self.file_id(), self.item_tree[id].ast_id()).erase(),
|
||||
macro_id.into(),
|
||||
);
|
||||
self.def_collector.define_macro_rules(
|
||||
self.module_id,
|
||||
mac.name.clone(),
|
||||
|
|
@ -2416,6 +2389,10 @@ impl ModCollector<'_, '_> {
|
|||
edition: self.def_collector.def_map.data.edition,
|
||||
}
|
||||
.intern(self.def_collector.db);
|
||||
self.def_collector.def_map.macro_def_to_macro_id.insert(
|
||||
InFile::new(self.file_id(), self.item_tree[id].ast_id()).erase(),
|
||||
macro_id.into(),
|
||||
);
|
||||
self.def_collector.define_macro_def(
|
||||
self.module_id,
|
||||
mac.name.clone(),
|
||||
|
|
@ -2444,6 +2421,7 @@ impl ModCollector<'_, '_> {
|
|||
// new legacy macros that create textual scopes. We need a way to resolve names in textual
|
||||
// scopes without eager expansion.
|
||||
|
||||
let mut eager_callback_buffer = vec![];
|
||||
// Case 1: try to resolve macro calls with single-segment name and expand macro_rules
|
||||
if let Ok(res) = macro_call_as_call_id_with_eager(
|
||||
db.upcast(),
|
||||
|
|
@ -2485,7 +2463,13 @@ impl ModCollector<'_, '_> {
|
|||
);
|
||||
resolved_res.resolved_def.take_macros().map(|it| db.macro_def(it))
|
||||
},
|
||||
&mut |ptr, call_id| eager_callback_buffer.push((ptr, call_id)),
|
||||
) {
|
||||
for (ptr, call_id) in eager_callback_buffer {
|
||||
self.def_collector.def_map.modules[self.module_id]
|
||||
.scope
|
||||
.add_macro_invoc(ptr.map(|(_, it)| it), call_id);
|
||||
}
|
||||
// FIXME: if there were errors, this might've been in the eager expansion from an
|
||||
// unresolved macro, so we need to push this into late macro resolution. see fixme above
|
||||
if res.err.is_none() {
|
||||
|
|
@ -2648,7 +2632,7 @@ foo!(KABOOM);
|
|||
// the release mode. That's why the argument is not an ra_fixture --
|
||||
// otherwise injection highlighting gets stuck.
|
||||
//
|
||||
// We need to find a way to fail this faster.
|
||||
// We need to find a way to fail this faster!
|
||||
do_resolve(
|
||||
r#"
|
||||
macro_rules! foo {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
use std::ops::Not;
|
||||
|
||||
use cfg::{CfgExpr, CfgOptions};
|
||||
use hir_expand::{ExpandErrorKind, MacroCallKind, attrs::AttrId};
|
||||
use hir_expand::{ExpandErrorKind, MacroCallKind, attrs::AttrId, mod_path::ModPath};
|
||||
use la_arena::Idx;
|
||||
use syntax::ast;
|
||||
|
||||
|
|
@ -11,7 +11,6 @@ use crate::{
|
|||
AstId,
|
||||
item_tree::{self, AttrOwner, ItemTreeId, TreeId},
|
||||
nameres::LocalModuleId,
|
||||
path::ModPath,
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
|
|
|
|||
|
|
@ -11,7 +11,11 @@
|
|||
//! `ReachedFixedPoint` signals about this.
|
||||
|
||||
use either::Either;
|
||||
use hir_expand::{Lookup, name::Name};
|
||||
use hir_expand::{
|
||||
Lookup,
|
||||
mod_path::{ModPath, PathKind},
|
||||
name::Name,
|
||||
};
|
||||
use span::Edition;
|
||||
use triomphe::Arc;
|
||||
|
||||
|
|
@ -21,7 +25,6 @@ use crate::{
|
|||
item_scope::{BUILTIN_SCOPE, ImportOrExternCrate},
|
||||
item_tree::FieldsShape,
|
||||
nameres::{BlockInfo, BuiltinShadowMode, DefMap, LocalDefMap, MacroSubNs, sub_namespace_match},
|
||||
path::{ModPath, PathKind},
|
||||
per_ns::PerNs,
|
||||
visibility::{RawVisibility, Visibility},
|
||||
};
|
||||
|
|
@ -506,22 +509,12 @@ impl DefMap {
|
|||
ModuleDefId::AdtId(AdtId::EnumId(e)) => {
|
||||
// enum variant
|
||||
cov_mark::hit!(can_import_enum_variant);
|
||||
let def_map;
|
||||
|
||||
let loc = e.lookup(db);
|
||||
let tree = loc.id.item_tree(db);
|
||||
let current_def_map =
|
||||
self.krate == loc.container.krate && self.block_id() == loc.container.block;
|
||||
let res = if current_def_map {
|
||||
&self.enum_definitions[&e]
|
||||
} else {
|
||||
def_map = loc.container.def_map(db);
|
||||
&def_map.enum_definitions[&e]
|
||||
}
|
||||
.iter()
|
||||
.find_map(|&variant| {
|
||||
let variant_data = &tree[variant.lookup(db).id.value];
|
||||
(variant_data.name == *segment).then(|| match variant_data.shape {
|
||||
let res =
|
||||
db.enum_variants(e).variants.iter().find(|(_, name)| name == segment).map(
|
||||
|&(variant, _)| {
|
||||
let item_tree_id = variant.lookup(db).id;
|
||||
match item_tree_id.item_tree(db)[item_tree_id.value].shape {
|
||||
FieldsShape::Record => {
|
||||
PerNs::types(variant.into(), Visibility::Public, None)
|
||||
}
|
||||
|
|
@ -531,8 +524,9 @@ impl DefMap {
|
|||
Visibility::Public,
|
||||
None,
|
||||
),
|
||||
})
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
// FIXME: Need to filter visibility here and below? Not sure.
|
||||
return match res {
|
||||
Some(res) => {
|
||||
|
|
|
|||
|
|
@ -30,26 +30,36 @@ impl ProcMacroKind {
|
|||
}
|
||||
|
||||
impl Attrs {
|
||||
#[rustfmt::skip]
|
||||
pub fn parse_proc_macro_decl(&self, func_name: &Name) -> Option<ProcMacroDef> {
|
||||
if self.is_proc_macro() {
|
||||
Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::Bang })
|
||||
} else if self.is_proc_macro_attribute() {
|
||||
Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::Attr })
|
||||
} else if self.by_key(&sym::proc_macro_derive).exists() {
|
||||
let derive = self.by_key(&sym::proc_macro_derive).tt_values().next()?;
|
||||
let def = parse_macro_name_and_helper_attrs(derive)
|
||||
.map(|(name, helpers)| ProcMacroDef { name, kind: ProcMacroKind::Derive { helpers } });
|
||||
|
||||
if def.is_none() {
|
||||
tracing::trace!("malformed `#[proc_macro_derive]`: {}", derive);
|
||||
let derive = self.parse_proc_macro_derive();
|
||||
Some(match derive {
|
||||
Some((name, helpers)) => {
|
||||
ProcMacroDef { name, kind: ProcMacroKind::Derive { helpers } }
|
||||
}
|
||||
|
||||
def
|
||||
None => ProcMacroDef {
|
||||
name: func_name.clone(),
|
||||
kind: ProcMacroKind::Derive { helpers: Box::default() },
|
||||
},
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_proc_macro_derive(&self) -> Option<(Name, Box<[Name]>)> {
|
||||
let derive = self.by_key(&sym::proc_macro_derive).tt_values().next()?;
|
||||
parse_macro_name_and_helper_attrs(derive)
|
||||
}
|
||||
|
||||
pub fn parse_rustc_builtin_macro(&self) -> Option<(Name, Box<[Name]>)> {
|
||||
let derive = self.by_key(&sym::rustc_builtin_macro).tt_values().next()?;
|
||||
parse_macro_name_and_helper_attrs(derive)
|
||||
}
|
||||
}
|
||||
|
||||
// This fn is intended for `#[proc_macro_derive(..)]` and `#[rustc_builtin_macro(..)]`, which have
|
||||
|
|
|
|||
|
|
@ -358,7 +358,7 @@ m!(Z);
|
|||
});
|
||||
let n_recalculated_item_trees =
|
||||
events.iter().filter(|it| it.contains("file_item_tree_shim")).count();
|
||||
assert_eq!(n_recalculated_item_trees, 0);
|
||||
assert_eq!(n_recalculated_item_trees, 1, "{events:#?}");
|
||||
let n_reparsed_macros =
|
||||
events.iter().filter(|it| it.contains("parse_macro_expansion_shim")).count();
|
||||
assert_eq!(n_reparsed_macros, 0);
|
||||
|
|
@ -409,22 +409,22 @@ pub type Ty = ();
|
|||
assert_eq!(module_data.scope.impls().count(), 1);
|
||||
|
||||
for imp in module_data.scope.impls() {
|
||||
db.impl_data(imp);
|
||||
db.impl_signature(imp);
|
||||
}
|
||||
|
||||
for (_, res) in module_data.scope.resolutions() {
|
||||
match res.values.map(|it| it.def).or(res.types.map(|it| it.def)).unwrap() {
|
||||
ModuleDefId::FunctionId(f) => _ = db.function_data(f),
|
||||
ModuleDefId::FunctionId(f) => _ = db.function_signature(f),
|
||||
ModuleDefId::AdtId(adt) => match adt {
|
||||
AdtId::StructId(it) => _ = db.struct_data(it),
|
||||
AdtId::UnionId(it) => _ = db.union_data(it),
|
||||
AdtId::EnumId(it) => _ = db.enum_data(it),
|
||||
AdtId::StructId(it) => _ = db.struct_signature(it),
|
||||
AdtId::UnionId(it) => _ = db.union_signature(it),
|
||||
AdtId::EnumId(it) => _ = db.enum_signature(it),
|
||||
},
|
||||
ModuleDefId::ConstId(it) => _ = db.const_data(it),
|
||||
ModuleDefId::StaticId(it) => _ = db.static_data(it),
|
||||
ModuleDefId::TraitId(it) => _ = db.trait_data(it),
|
||||
ModuleDefId::TraitAliasId(it) => _ = db.trait_alias_data(it),
|
||||
ModuleDefId::TypeAliasId(it) => _ = db.type_alias_data(it),
|
||||
ModuleDefId::ConstId(it) => _ = db.const_signature(it),
|
||||
ModuleDefId::StaticId(it) => _ = db.static_signature(it),
|
||||
ModuleDefId::TraitId(it) => _ = db.trait_signature(it),
|
||||
ModuleDefId::TraitAliasId(it) => _ = db.trait_alias_signature(it),
|
||||
ModuleDefId::TypeAliasId(it) => _ = db.type_alias_signature(it),
|
||||
ModuleDefId::EnumVariantId(_)
|
||||
| ModuleDefId::ModuleId(_)
|
||||
| ModuleDefId::MacroId(_)
|
||||
|
|
|
|||
|
|
@ -1,315 +0,0 @@
|
|||
//! Display and pretty printing routines.
|
||||
|
||||
use std::{
|
||||
fmt::{self, Write},
|
||||
mem,
|
||||
};
|
||||
|
||||
use hir_expand::mod_path::PathKind;
|
||||
use itertools::Itertools;
|
||||
use span::Edition;
|
||||
|
||||
use crate::{
|
||||
db::DefDatabase,
|
||||
lang_item::LangItemTarget,
|
||||
path::{GenericArg, GenericArgs, Path},
|
||||
type_ref::{
|
||||
Mutability, TraitBoundModifier, TypeBound, TypeRef, TypeRefId, TypesMap, UseArgRef,
|
||||
},
|
||||
};
|
||||
|
||||
pub(crate) fn print_path(
|
||||
db: &dyn DefDatabase,
|
||||
path: &Path,
|
||||
map: &TypesMap,
|
||||
buf: &mut dyn Write,
|
||||
edition: Edition,
|
||||
) -> fmt::Result {
|
||||
if let Path::LangItem(it, s) = path {
|
||||
write!(buf, "builtin#lang(")?;
|
||||
match *it {
|
||||
LangItemTarget::ImplDef(it) => write!(buf, "{it:?}")?,
|
||||
LangItemTarget::EnumId(it) => {
|
||||
write!(buf, "{}", db.enum_data(it).name.display(db.upcast(), edition))?
|
||||
}
|
||||
LangItemTarget::Function(it) => {
|
||||
write!(buf, "{}", db.function_data(it).name.display(db.upcast(), edition))?
|
||||
}
|
||||
LangItemTarget::Static(it) => {
|
||||
write!(buf, "{}", db.static_data(it).name.display(db.upcast(), edition))?
|
||||
}
|
||||
LangItemTarget::Struct(it) => {
|
||||
write!(buf, "{}", db.struct_data(it).name.display(db.upcast(), edition))?
|
||||
}
|
||||
LangItemTarget::Union(it) => {
|
||||
write!(buf, "{}", db.union_data(it).name.display(db.upcast(), edition))?
|
||||
}
|
||||
LangItemTarget::TypeAlias(it) => {
|
||||
write!(buf, "{}", db.type_alias_data(it).name.display(db.upcast(), edition))?
|
||||
}
|
||||
LangItemTarget::Trait(it) => {
|
||||
write!(buf, "{}", db.trait_data(it).name.display(db.upcast(), edition))?
|
||||
}
|
||||
LangItemTarget::EnumVariant(it) => {
|
||||
write!(buf, "{}", db.enum_variant_data(it).name.display(db.upcast(), edition))?
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(s) = s {
|
||||
write!(buf, "::{}", s.display(db.upcast(), edition))?;
|
||||
}
|
||||
return write!(buf, ")");
|
||||
}
|
||||
match path.type_anchor() {
|
||||
Some(anchor) => {
|
||||
write!(buf, "<")?;
|
||||
print_type_ref(db, anchor, map, buf, edition)?;
|
||||
write!(buf, ">::")?;
|
||||
}
|
||||
None => match path.kind() {
|
||||
PathKind::Plain => {}
|
||||
&PathKind::SELF => write!(buf, "self")?,
|
||||
PathKind::Super(n) => {
|
||||
for i in 0..*n {
|
||||
if i == 0 {
|
||||
buf.write_str("super")?;
|
||||
} else {
|
||||
buf.write_str("::super")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
PathKind::Crate => write!(buf, "crate")?,
|
||||
PathKind::Abs => {}
|
||||
PathKind::DollarCrate(krate) => write!(
|
||||
buf,
|
||||
"{}",
|
||||
krate
|
||||
.extra_data(db)
|
||||
.display_name
|
||||
.as_ref()
|
||||
.map(|it| it.crate_name().symbol().as_str())
|
||||
.unwrap_or("$crate")
|
||||
)?,
|
||||
},
|
||||
}
|
||||
|
||||
for (i, segment) in path.segments().iter().enumerate() {
|
||||
if i != 0 || !matches!(path.kind(), PathKind::Plain) {
|
||||
write!(buf, "::")?;
|
||||
}
|
||||
|
||||
write!(buf, "{}", segment.name.display(db.upcast(), edition))?;
|
||||
if let Some(generics) = segment.args_and_bindings {
|
||||
write!(buf, "::<")?;
|
||||
print_generic_args(db, generics, map, buf, edition)?;
|
||||
|
||||
write!(buf, ">")?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn print_generic_args(
|
||||
db: &dyn DefDatabase,
|
||||
generics: &GenericArgs,
|
||||
map: &TypesMap,
|
||||
buf: &mut dyn Write,
|
||||
edition: Edition,
|
||||
) -> fmt::Result {
|
||||
let mut first = true;
|
||||
let args = if generics.has_self_type {
|
||||
let (self_ty, args) = generics.args.split_first().unwrap();
|
||||
write!(buf, "Self=")?;
|
||||
print_generic_arg(db, self_ty, map, buf, edition)?;
|
||||
first = false;
|
||||
args
|
||||
} else {
|
||||
&generics.args
|
||||
};
|
||||
for arg in args {
|
||||
if !first {
|
||||
write!(buf, ", ")?;
|
||||
}
|
||||
first = false;
|
||||
print_generic_arg(db, arg, map, buf, edition)?;
|
||||
}
|
||||
for binding in generics.bindings.iter() {
|
||||
if !first {
|
||||
write!(buf, ", ")?;
|
||||
}
|
||||
first = false;
|
||||
write!(buf, "{}", binding.name.display(db.upcast(), edition))?;
|
||||
if !binding.bounds.is_empty() {
|
||||
write!(buf, ": ")?;
|
||||
print_type_bounds(db, &binding.bounds, map, buf, edition)?;
|
||||
}
|
||||
if let Some(ty) = binding.type_ref {
|
||||
write!(buf, " = ")?;
|
||||
print_type_ref(db, ty, map, buf, edition)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn print_generic_arg(
|
||||
db: &dyn DefDatabase,
|
||||
arg: &GenericArg,
|
||||
map: &TypesMap,
|
||||
buf: &mut dyn Write,
|
||||
edition: Edition,
|
||||
) -> fmt::Result {
|
||||
match arg {
|
||||
GenericArg::Type(ty) => print_type_ref(db, *ty, map, buf, edition),
|
||||
GenericArg::Const(c) => write!(buf, "{}", c.display(db.upcast(), edition)),
|
||||
GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn print_type_ref(
|
||||
db: &dyn DefDatabase,
|
||||
type_ref: TypeRefId,
|
||||
map: &TypesMap,
|
||||
buf: &mut dyn Write,
|
||||
edition: Edition,
|
||||
) -> fmt::Result {
|
||||
// FIXME: deduplicate with `HirDisplay` impl
|
||||
match &map[type_ref] {
|
||||
TypeRef::Never => write!(buf, "!")?,
|
||||
TypeRef::Placeholder => write!(buf, "_")?,
|
||||
TypeRef::Tuple(fields) => {
|
||||
write!(buf, "(")?;
|
||||
for (i, field) in fields.iter().enumerate() {
|
||||
if i != 0 {
|
||||
write!(buf, ", ")?;
|
||||
}
|
||||
print_type_ref(db, *field, map, buf, edition)?;
|
||||
}
|
||||
write!(buf, ")")?;
|
||||
}
|
||||
TypeRef::Path(path) => print_path(db, path, map, buf, edition)?,
|
||||
TypeRef::RawPtr(pointee, mtbl) => {
|
||||
let mtbl = match mtbl {
|
||||
Mutability::Shared => "*const",
|
||||
Mutability::Mut => "*mut",
|
||||
};
|
||||
write!(buf, "{mtbl} ")?;
|
||||
print_type_ref(db, *pointee, map, buf, edition)?;
|
||||
}
|
||||
TypeRef::Reference(ref_) => {
|
||||
let mtbl = match ref_.mutability {
|
||||
Mutability::Shared => "",
|
||||
Mutability::Mut => "mut ",
|
||||
};
|
||||
write!(buf, "&")?;
|
||||
if let Some(lt) = &ref_.lifetime {
|
||||
write!(buf, "{} ", lt.name.display(db.upcast(), edition))?;
|
||||
}
|
||||
write!(buf, "{mtbl}")?;
|
||||
print_type_ref(db, ref_.ty, map, buf, edition)?;
|
||||
}
|
||||
TypeRef::Array(array) => {
|
||||
write!(buf, "[")?;
|
||||
print_type_ref(db, array.ty, map, buf, edition)?;
|
||||
write!(buf, "; {}]", array.len.display(db.upcast(), edition))?;
|
||||
}
|
||||
TypeRef::Slice(elem) => {
|
||||
write!(buf, "[")?;
|
||||
print_type_ref(db, *elem, map, buf, edition)?;
|
||||
write!(buf, "]")?;
|
||||
}
|
||||
TypeRef::Fn(fn_) => {
|
||||
let ((_, return_type), args) =
|
||||
fn_.params.split_last().expect("TypeRef::Fn is missing return type");
|
||||
if fn_.is_unsafe {
|
||||
write!(buf, "unsafe ")?;
|
||||
}
|
||||
if let Some(abi) = &fn_.abi {
|
||||
buf.write_str("extern ")?;
|
||||
buf.write_str(abi.as_str())?;
|
||||
buf.write_char(' ')?;
|
||||
}
|
||||
write!(buf, "fn(")?;
|
||||
for (i, (_, typeref)) in args.iter().enumerate() {
|
||||
if i != 0 {
|
||||
write!(buf, ", ")?;
|
||||
}
|
||||
print_type_ref(db, *typeref, map, buf, edition)?;
|
||||
}
|
||||
if fn_.is_varargs {
|
||||
if !args.is_empty() {
|
||||
write!(buf, ", ")?;
|
||||
}
|
||||
write!(buf, "...")?;
|
||||
}
|
||||
write!(buf, ") -> ")?;
|
||||
print_type_ref(db, *return_type, map, buf, edition)?;
|
||||
}
|
||||
TypeRef::Macro(_ast_id) => {
|
||||
write!(buf, "<macro>")?;
|
||||
}
|
||||
TypeRef::Error => write!(buf, "{{unknown}}")?,
|
||||
TypeRef::ImplTrait(bounds) => {
|
||||
write!(buf, "impl ")?;
|
||||
print_type_bounds(db, bounds, map, buf, edition)?;
|
||||
}
|
||||
TypeRef::DynTrait(bounds) => {
|
||||
write!(buf, "dyn ")?;
|
||||
print_type_bounds(db, bounds, map, buf, edition)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn print_type_bounds(
|
||||
db: &dyn DefDatabase,
|
||||
bounds: &[TypeBound],
|
||||
map: &TypesMap,
|
||||
buf: &mut dyn Write,
|
||||
edition: Edition,
|
||||
) -> fmt::Result {
|
||||
for (i, bound) in bounds.iter().enumerate() {
|
||||
if i != 0 {
|
||||
write!(buf, " + ")?;
|
||||
}
|
||||
|
||||
match bound {
|
||||
TypeBound::Path(path, modifier) => {
|
||||
match modifier {
|
||||
TraitBoundModifier::None => (),
|
||||
TraitBoundModifier::Maybe => write!(buf, "?")?,
|
||||
}
|
||||
print_path(db, &map[*path], map, buf, edition)?;
|
||||
}
|
||||
TypeBound::ForLifetime(lifetimes, path) => {
|
||||
write!(
|
||||
buf,
|
||||
"for<{}> ",
|
||||
lifetimes.iter().map(|it| it.display(db.upcast(), edition)).format(", ")
|
||||
)?;
|
||||
print_path(db, &map[*path], map, buf, edition)?;
|
||||
}
|
||||
TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition))?,
|
||||
TypeBound::Use(args) => {
|
||||
write!(buf, "use<")?;
|
||||
let mut first = true;
|
||||
for arg in args {
|
||||
if !mem::take(&mut first) {
|
||||
write!(buf, ", ")?;
|
||||
}
|
||||
match arg {
|
||||
UseArgRef::Name(it) => write!(buf, "{}", it.display(db.upcast(), edition))?,
|
||||
UseArgRef::Lifetime(it) => {
|
||||
write!(buf, "{}", it.name.display(db.upcast(), edition))?
|
||||
}
|
||||
}
|
||||
}
|
||||
write!(buf, ">")?
|
||||
}
|
||||
TypeBound::Error => write!(buf, "{{unknown}}")?,
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1,8 +1,12 @@
|
|||
//! Name resolution façade.
|
||||
use std::{fmt, iter, mem};
|
||||
use std::{fmt, mem};
|
||||
|
||||
use base_db::Crate;
|
||||
use hir_expand::{MacroDefId, name::Name};
|
||||
use hir_expand::{
|
||||
MacroDefId,
|
||||
mod_path::{ModPath, PathKind},
|
||||
name::Name,
|
||||
};
|
||||
use intern::{Symbol, sym};
|
||||
use itertools::Itertools as _;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
|
@ -15,22 +19,24 @@ use crate::{
|
|||
ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, GenericParamId, HasModule,
|
||||
ImplId, ItemContainerId, ItemTreeLoc, LifetimeParamId, LocalModuleId, Lookup, Macro2Id,
|
||||
MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, TraitAliasId,
|
||||
TraitId, TypeAliasId, TypeOrConstParamId, TypeOwnerId, TypeParamId, UseId, VariantId,
|
||||
TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UseId, VariantId,
|
||||
builtin_type::BuiltinType,
|
||||
data::ExternCrateDeclData,
|
||||
db::DefDatabase,
|
||||
expr_store::{
|
||||
HygieneId,
|
||||
path::Path,
|
||||
scope::{ExprScopes, ScopeId},
|
||||
},
|
||||
hir::{
|
||||
BindingId, ExprId, LabelId,
|
||||
generics::{GenericParams, TypeOrConstParamData},
|
||||
hir::{BindingId, ExprId, LabelId},
|
||||
item_scope::{BUILTIN_SCOPE, BuiltinShadowMode, ImportOrExternCrate, ImportOrGlob},
|
||||
},
|
||||
item_scope::{BUILTIN_SCOPE, BuiltinShadowMode, ImportOrExternCrate, ImportOrGlob, ItemScope},
|
||||
item_tree::ImportAlias,
|
||||
lang_item::LangItemTarget,
|
||||
nameres::{DefMap, LocalDefMap, MacroSubNs, ResolvePathResultPrefixInfo},
|
||||
path::{ModPath, Path, PathKind},
|
||||
per_ns::PerNs,
|
||||
type_ref::{LifetimeRef, TypesMap},
|
||||
type_ref::LifetimeRef,
|
||||
visibility::{RawVisibility, Visibility},
|
||||
};
|
||||
|
||||
|
|
@ -77,16 +83,13 @@ impl fmt::Debug for ExprScope {
|
|||
enum Scope {
|
||||
/// All the items and imported names of a module
|
||||
BlockScope(ModuleItemMap),
|
||||
/// Brings the generic parameters of an item into scope
|
||||
/// Brings the generic parameters of an item into scope as well as the `Self` type alias /
|
||||
/// generic for ADTs and impls.
|
||||
GenericParams { def: GenericDefId, params: Arc<GenericParams> },
|
||||
/// Brings `Self` in `impl` block into scope
|
||||
ImplDefScope(ImplId),
|
||||
/// Brings `Self` in enum, struct and union definitions into scope
|
||||
AdtScope(AdtId),
|
||||
/// Local bindings
|
||||
ExprScope(ExprScope),
|
||||
/// Macro definition inside bodies that affects all paths after it in the same block.
|
||||
MacroDefScope(Box<MacroDefId>),
|
||||
MacroDefScope(MacroDefId),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
|
|
@ -216,16 +219,7 @@ impl Resolver {
|
|||
match scope {
|
||||
Scope::ExprScope(_) | Scope::MacroDefScope(_) => continue,
|
||||
Scope::GenericParams { params, def } => {
|
||||
if let Some(id) = params.find_type_by_name(first_name, *def) {
|
||||
return Some((
|
||||
TypeNs::GenericParam(id),
|
||||
remaining_idx(),
|
||||
None,
|
||||
ResolvePathResultPrefixInfo::default(),
|
||||
));
|
||||
}
|
||||
}
|
||||
&Scope::ImplDefScope(impl_) => {
|
||||
if let &GenericDefId::ImplId(impl_) = def {
|
||||
if *first_name == sym::Self_.clone() {
|
||||
return Some((
|
||||
TypeNs::SelfType(impl_),
|
||||
|
|
@ -234,8 +228,7 @@ impl Resolver {
|
|||
ResolvePathResultPrefixInfo::default(),
|
||||
));
|
||||
}
|
||||
}
|
||||
&Scope::AdtScope(adt) => {
|
||||
} else if let &GenericDefId::AdtId(adt) = def {
|
||||
if *first_name == sym::Self_.clone() {
|
||||
return Some((
|
||||
TypeNs::AdtSelfType(adt),
|
||||
|
|
@ -245,6 +238,15 @@ impl Resolver {
|
|||
));
|
||||
}
|
||||
}
|
||||
if let Some(id) = params.find_type_by_name(first_name, *def) {
|
||||
return Some((
|
||||
TypeNs::GenericParam(id),
|
||||
remaining_idx(),
|
||||
None,
|
||||
ResolvePathResultPrefixInfo::default(),
|
||||
));
|
||||
}
|
||||
}
|
||||
Scope::BlockScope(m) => {
|
||||
if let Some(res) = m.resolve_path_in_type_ns(db, path) {
|
||||
return Some(res);
|
||||
|
|
@ -274,13 +276,15 @@ impl Resolver {
|
|||
) -> Option<Visibility> {
|
||||
match visibility {
|
||||
RawVisibility::Module(_, _) => {
|
||||
let (item_map, item_local_map, module) = self.item_scope();
|
||||
let (item_map, item_local_map, module) = self.item_scope_();
|
||||
item_map.resolve_visibility(
|
||||
item_local_map,
|
||||
db,
|
||||
module,
|
||||
visibility,
|
||||
self.scopes().any(|scope| matches!(scope, Scope::ImplDefScope(_))),
|
||||
self.scopes().any(|scope| {
|
||||
matches!(scope, Scope::GenericParams { def: GenericDefId::ImplId(_), .. })
|
||||
}),
|
||||
)
|
||||
}
|
||||
RawVisibility::Public => Some(Visibility::Public),
|
||||
|
|
@ -375,6 +379,14 @@ impl Resolver {
|
|||
handle_macro_def_scope(db, &mut hygiene_id, &mut hygiene_info, macro_id)
|
||||
}
|
||||
Scope::GenericParams { params, def } => {
|
||||
if let &GenericDefId::ImplId(impl_) = def {
|
||||
if *first_name == sym::Self_.clone() {
|
||||
return Some((
|
||||
ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_), None),
|
||||
ResolvePathResultPrefixInfo::default(),
|
||||
));
|
||||
}
|
||||
}
|
||||
if let Some(id) = params.find_const_by_name(first_name, *def) {
|
||||
let val = ValueNs::GenericParam(id);
|
||||
return Some((
|
||||
|
|
@ -383,16 +395,6 @@ impl Resolver {
|
|||
));
|
||||
}
|
||||
}
|
||||
&Scope::ImplDefScope(impl_) => {
|
||||
if *first_name == sym::Self_.clone() {
|
||||
return Some((
|
||||
ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_), None),
|
||||
ResolvePathResultPrefixInfo::default(),
|
||||
));
|
||||
}
|
||||
}
|
||||
// bare `Self` doesn't work in the value namespace in a struct/enum definition
|
||||
Scope::AdtScope(_) => continue,
|
||||
Scope::BlockScope(m) => {
|
||||
if let Some(def) = m.resolve_path_in_value_ns(db, path) {
|
||||
return Some(def);
|
||||
|
|
@ -405,25 +407,24 @@ impl Resolver {
|
|||
match scope {
|
||||
Scope::ExprScope(_) | Scope::MacroDefScope(_) => continue,
|
||||
Scope::GenericParams { params, def } => {
|
||||
if let Some(id) = params.find_type_by_name(first_name, *def) {
|
||||
let ty = TypeNs::GenericParam(id);
|
||||
return Some((
|
||||
ResolveValueResult::Partial(ty, 1, None),
|
||||
ResolvePathResultPrefixInfo::default(),
|
||||
));
|
||||
}
|
||||
}
|
||||
&Scope::ImplDefScope(impl_) => {
|
||||
if let &GenericDefId::ImplId(impl_) = def {
|
||||
if *first_name == sym::Self_.clone() {
|
||||
return Some((
|
||||
ResolveValueResult::Partial(TypeNs::SelfType(impl_), 1, None),
|
||||
ResolvePathResultPrefixInfo::default(),
|
||||
));
|
||||
}
|
||||
}
|
||||
Scope::AdtScope(adt) => {
|
||||
} else if let &GenericDefId::AdtId(adt) = def {
|
||||
if *first_name == sym::Self_.clone() {
|
||||
let ty = TypeNs::AdtSelfType(*adt);
|
||||
let ty = TypeNs::AdtSelfType(adt);
|
||||
return Some((
|
||||
ResolveValueResult::Partial(ty, 1, None),
|
||||
ResolvePathResultPrefixInfo::default(),
|
||||
));
|
||||
}
|
||||
}
|
||||
if let Some(id) = params.find_type_by_name(first_name, *def) {
|
||||
let ty = TypeNs::GenericParam(id);
|
||||
return Some((
|
||||
ResolveValueResult::Partial(ty, 1, None),
|
||||
ResolvePathResultPrefixInfo::default(),
|
||||
|
|
@ -476,7 +477,7 @@ impl Resolver {
|
|||
path: &ModPath,
|
||||
expected_macro_kind: Option<MacroSubNs>,
|
||||
) -> Option<(MacroId, Option<ImportOrGlob>)> {
|
||||
let (item_map, item_local_map, module) = self.item_scope();
|
||||
let (item_map, item_local_map, module) = self.item_scope_();
|
||||
item_map
|
||||
.resolve_path(
|
||||
item_local_map,
|
||||
|
|
@ -596,6 +597,7 @@ impl Resolver {
|
|||
res.map
|
||||
}
|
||||
|
||||
/// Note: Not to be used directly within hir-def/hir-ty
|
||||
pub fn extern_crate_decls_in_scope<'a>(
|
||||
&'a self,
|
||||
db: &'a dyn DefDatabase,
|
||||
|
|
@ -603,7 +605,17 @@ impl Resolver {
|
|||
self.module_scope.def_map[self.module_scope.module_id]
|
||||
.scope
|
||||
.extern_crate_decls()
|
||||
.map(|id| ExternCrateDeclData::extern_crate_decl_data_query(db, id).name.clone())
|
||||
.filter_map(|id| {
|
||||
let loc = id.lookup(db);
|
||||
let tree = loc.item_tree_id().item_tree(db);
|
||||
match &tree[loc.id.value].alias {
|
||||
Some(alias) => match alias {
|
||||
ImportAlias::Underscore => None,
|
||||
ImportAlias::Alias(name) => Some(name.clone()),
|
||||
},
|
||||
None => Some(tree[loc.id.value].name.clone()),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn extern_crates_in_scope(&self) -> impl Iterator<Item = (Name, ModuleId)> + '_ {
|
||||
|
|
@ -621,13 +633,12 @@ impl Resolver {
|
|||
for scope in self.scopes() {
|
||||
match scope {
|
||||
Scope::BlockScope(m) => traits.extend(m.def_map[m.module_id].scope.traits()),
|
||||
&Scope::ImplDefScope(impl_) => {
|
||||
let impl_data = db.impl_data(impl_);
|
||||
&Scope::GenericParams { def: GenericDefId::ImplId(impl_), .. } => {
|
||||
let impl_data = db.impl_signature(impl_);
|
||||
if let Some(target_trait) = impl_data.target_trait {
|
||||
if let Some(TypeNs::TraitId(trait_)) = self.resolve_path_in_type_ns_fully(
|
||||
db,
|
||||
&impl_data.types_map[target_trait.path],
|
||||
) {
|
||||
if let Some(TypeNs::TraitId(trait_)) = self
|
||||
.resolve_path_in_type_ns_fully(db, &impl_data.store[target_trait.path])
|
||||
{
|
||||
traits.insert(trait_);
|
||||
}
|
||||
}
|
||||
|
|
@ -656,29 +667,21 @@ impl Resolver {
|
|||
}
|
||||
|
||||
pub fn module(&self) -> ModuleId {
|
||||
let (def_map, _, local_id) = self.item_scope();
|
||||
let (def_map, _, local_id) = self.item_scope_();
|
||||
def_map.module_id(local_id)
|
||||
}
|
||||
|
||||
pub fn item_scope(&self) -> &ItemScope {
|
||||
let (def_map, _, local_id) = self.item_scope_();
|
||||
&def_map[local_id].scope
|
||||
}
|
||||
|
||||
pub fn krate(&self) -> Crate {
|
||||
self.module_scope.def_map.krate()
|
||||
}
|
||||
|
||||
pub fn def_map(&self) -> &DefMap {
|
||||
self.item_scope().0
|
||||
}
|
||||
|
||||
pub fn where_predicates_in_scope(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (&crate::generics::WherePredicate, (&GenericDefId, &TypesMap))> {
|
||||
self.scopes()
|
||||
.filter_map(|scope| match scope {
|
||||
Scope::GenericParams { params, def } => Some((params, def)),
|
||||
_ => None,
|
||||
})
|
||||
.flat_map(|(params, def)| {
|
||||
params.where_predicates().zip(iter::repeat((def, ¶ms.types_map)))
|
||||
})
|
||||
self.item_scope_().0
|
||||
}
|
||||
|
||||
pub fn generic_def(&self) -> Option<GenericDefId> {
|
||||
|
|
@ -709,19 +712,9 @@ impl Resolver {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn type_owner(&self) -> Option<TypeOwnerId> {
|
||||
self.scopes().find_map(|scope| match scope {
|
||||
Scope::BlockScope(_) | Scope::MacroDefScope(_) => None,
|
||||
&Scope::GenericParams { def, .. } => Some(def.into()),
|
||||
&Scope::ImplDefScope(id) => Some(id.into()),
|
||||
&Scope::AdtScope(adt) => Some(adt.into()),
|
||||
Scope::ExprScope(it) => Some(it.owner.into()),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn impl_def(&self) -> Option<ImplId> {
|
||||
self.scopes().find_map(|scope| match scope {
|
||||
Scope::ImplDefScope(def) => Some(*def),
|
||||
&Scope::GenericParams { def: GenericDefId::ImplId(def), .. } => Some(def),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
|
@ -763,7 +756,6 @@ impl Resolver {
|
|||
return None;
|
||||
}
|
||||
}
|
||||
Scope::AdtScope(_) | Scope::ImplDefScope(_) => continue,
|
||||
Scope::BlockScope(m) => {
|
||||
if m.resolve_path_in_value_ns(db, current_name_as_path).is_some() {
|
||||
// It does not resolve to our renamed variable.
|
||||
|
|
@ -816,7 +808,6 @@ impl Resolver {
|
|||
return None;
|
||||
}
|
||||
}
|
||||
Scope::AdtScope(_) | Scope::ImplDefScope(_) => continue,
|
||||
Scope::BlockScope(m) => {
|
||||
if m.resolve_path_in_value_ns(db, name_as_path).is_some() {
|
||||
return None;
|
||||
|
|
@ -844,7 +835,7 @@ impl Resolver {
|
|||
scope_id: ScopeId,
|
||||
) {
|
||||
if let Some(macro_id) = expr_scopes.macro_def(scope_id) {
|
||||
resolver.scopes.push(Scope::MacroDefScope(macro_id.clone()));
|
||||
resolver.scopes.push(Scope::MacroDefScope(**macro_id));
|
||||
}
|
||||
resolver.scopes.push(Scope::ExprScope(ExprScope {
|
||||
owner,
|
||||
|
|
@ -945,7 +936,7 @@ impl Resolver {
|
|||
path: &ModPath,
|
||||
shadow: BuiltinShadowMode,
|
||||
) -> PerNs {
|
||||
let (item_map, item_local_map, module) = self.item_scope();
|
||||
let (item_map, item_local_map, module) = self.item_scope_();
|
||||
// This method resolves `path` just like import paths, so no expected macro subns is given.
|
||||
let (module_res, segment_index) =
|
||||
item_map.resolve_path(item_local_map, db, module, path, shadow, None);
|
||||
|
|
@ -956,7 +947,7 @@ impl Resolver {
|
|||
}
|
||||
|
||||
/// The innermost block scope that contains items or the module scope that contains this resolver.
|
||||
fn item_scope(&self) -> (&DefMap, &LocalDefMap, LocalModuleId) {
|
||||
fn item_scope_(&self) -> (&DefMap, &LocalDefMap, LocalModuleId) {
|
||||
self.scopes()
|
||||
.find_map(|scope| match scope {
|
||||
Scope::BlockScope(m) => Some((&*m.def_map, &*m.local_def_map, m.module_id)),
|
||||
|
|
@ -994,8 +985,16 @@ impl Scope {
|
|||
})
|
||||
});
|
||||
}
|
||||
Scope::GenericParams { params, def: parent } => {
|
||||
let parent = *parent;
|
||||
&Scope::GenericParams { ref params, def: parent } => {
|
||||
if let GenericDefId::ImplId(impl_) = parent {
|
||||
acc.add(
|
||||
&Name::new_symbol_root(sym::Self_.clone()),
|
||||
ScopeDef::ImplSelfType(impl_),
|
||||
);
|
||||
} else if let GenericDefId::AdtId(adt) = parent {
|
||||
acc.add(&Name::new_symbol_root(sym::Self_.clone()), ScopeDef::AdtSelfType(adt));
|
||||
}
|
||||
|
||||
for (local_id, param) in params.iter_type_or_consts() {
|
||||
if let Some(name) = ¶m.name() {
|
||||
let id = TypeOrConstParamId { parent, local_id };
|
||||
|
|
@ -1018,12 +1017,6 @@ impl Scope {
|
|||
acc.add(¶m.name, ScopeDef::GenericParam(id.into()))
|
||||
}
|
||||
}
|
||||
Scope::ImplDefScope(i) => {
|
||||
acc.add(&Name::new_symbol_root(sym::Self_.clone()), ScopeDef::ImplSelfType(*i));
|
||||
}
|
||||
Scope::AdtScope(i) => {
|
||||
acc.add(&Name::new_symbol_root(sym::Self_.clone()), ScopeDef::AdtSelfType(*i));
|
||||
}
|
||||
Scope::ExprScope(scope) => {
|
||||
if let Some((label, name)) = scope.expr_scopes.label(scope.scope_id) {
|
||||
acc.add(&name, ScopeDef::Label(label))
|
||||
|
|
@ -1074,7 +1067,7 @@ fn resolver_for_scope_(
|
|||
// innermost module scope instead?
|
||||
}
|
||||
if let Some(macro_id) = scopes.macro_def(scope) {
|
||||
r = r.push_scope(Scope::MacroDefScope(macro_id.clone()));
|
||||
r = r.push_scope(Scope::MacroDefScope(**macro_id));
|
||||
}
|
||||
|
||||
r = r.push_expr_scope(owner, Arc::clone(&scopes), scope);
|
||||
|
|
@ -1093,10 +1086,6 @@ impl Resolver {
|
|||
self.push_scope(Scope::GenericParams { def, params })
|
||||
}
|
||||
|
||||
fn push_impl_def_scope(self, impl_def: ImplId) -> Resolver {
|
||||
self.push_scope(Scope::ImplDefScope(impl_def))
|
||||
}
|
||||
|
||||
fn push_block_scope(self, def_map: Arc<DefMap>, local_def_map: Arc<LocalDefMap>) -> Resolver {
|
||||
self.push_scope(Scope::BlockScope(ModuleItemMap {
|
||||
def_map,
|
||||
|
|
@ -1320,10 +1309,7 @@ impl HasResolver for TraitAliasId {
|
|||
impl<T: Into<AdtId> + Copy> HasResolver for T {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
let def = self.into();
|
||||
def.module(db)
|
||||
.resolver(db)
|
||||
.push_generic_params_scope(db, def.into())
|
||||
.push_scope(Scope::AdtScope(def))
|
||||
def.module(db).resolver(db).push_generic_params_scope(db, def.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1353,11 +1339,7 @@ impl HasResolver for TypeAliasId {
|
|||
|
||||
impl HasResolver for ImplId {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
self.lookup(db)
|
||||
.container
|
||||
.resolver(db)
|
||||
.push_generic_params_scope(db, self.into())
|
||||
.push_impl_def_scope(self)
|
||||
self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1380,23 +1362,6 @@ impl HasResolver for UseId {
|
|||
}
|
||||
}
|
||||
|
||||
impl HasResolver for TypeOwnerId {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
match self {
|
||||
TypeOwnerId::FunctionId(it) => it.resolver(db),
|
||||
TypeOwnerId::StaticId(it) => it.resolver(db),
|
||||
TypeOwnerId::ConstId(it) => it.resolver(db),
|
||||
TypeOwnerId::InTypeConstId(it) => it.lookup(db).owner.resolver(db),
|
||||
TypeOwnerId::AdtId(it) => it.resolver(db),
|
||||
TypeOwnerId::TraitId(it) => it.resolver(db),
|
||||
TypeOwnerId::TraitAliasId(it) => it.resolver(db),
|
||||
TypeOwnerId::TypeAliasId(it) => it.resolver(db),
|
||||
TypeOwnerId::ImplId(it) => it.resolver(db),
|
||||
TypeOwnerId::EnumVariantId(it) => it.resolver(db),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HasResolver for DefWithBodyId {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
match self {
|
||||
|
|
@ -1404,7 +1369,6 @@ impl HasResolver for DefWithBodyId {
|
|||
DefWithBodyId::FunctionId(f) => f.resolver(db),
|
||||
DefWithBodyId::StaticId(s) => s.resolver(db),
|
||||
DefWithBodyId::VariantId(v) => v.resolver(db),
|
||||
DefWithBodyId::InTypeConstId(c) => c.lookup(db).owner.resolver(db),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
972
crates/hir-def/src/signatures.rs
Normal file
972
crates/hir-def/src/signatures.rs
Normal file
|
|
@ -0,0 +1,972 @@
|
|||
//! Item signature IR definitions
|
||||
|
||||
use std::ops::Not as _;
|
||||
|
||||
use bitflags::bitflags;
|
||||
use cfg::{CfgExpr, CfgOptions};
|
||||
use either::Either;
|
||||
use hir_expand::{InFile, Intern, Lookup, name::Name};
|
||||
use intern::{Symbol, sym};
|
||||
use la_arena::{Arena, Idx};
|
||||
use rustc_abi::{IntegerType, ReprOptions};
|
||||
use syntax::{
|
||||
AstNode, SyntaxNodePtr,
|
||||
ast::{self, HasGenericParams, IsString},
|
||||
};
|
||||
use thin_vec::ThinVec;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
ConstId, EnumId, EnumVariantId, EnumVariantLoc, FunctionId, HasModule, ImplId, ItemContainerId,
|
||||
ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, UnionId, VariantId,
|
||||
db::DefDatabase,
|
||||
expr_store::{
|
||||
ExpressionStore, ExpressionStoreSourceMap,
|
||||
lower::{
|
||||
ExprCollector, lower_function, lower_generic_params, lower_trait, lower_trait_alias,
|
||||
lower_type_alias,
|
||||
},
|
||||
},
|
||||
hir::{ExprId, PatId, generics::GenericParams},
|
||||
item_tree::{
|
||||
AttrOwner, Field, FieldParent, FieldsShape, FileItemTreeId, ItemTree, ItemTreeId, ModItem,
|
||||
RawVisibility, RawVisibilityId,
|
||||
},
|
||||
lang_item::LangItem,
|
||||
src::HasSource,
|
||||
type_ref::{TraitRef, TypeBound, TypeRef, TypeRefId},
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct StructSignature {
|
||||
pub name: Name,
|
||||
pub generic_params: Arc<GenericParams>,
|
||||
pub store: Arc<ExpressionStore>,
|
||||
pub flags: StructFlags,
|
||||
pub shape: FieldsShape,
|
||||
pub repr: Option<ReprOptions>,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct StructFlags: u8 {
|
||||
/// Indicates whether the struct is `PhantomData`.
|
||||
const IS_PHANTOM_DATA = 1 << 2;
|
||||
/// Indicates whether the struct has a `#[fundamental]` attribute.
|
||||
const IS_FUNDAMENTAL = 1 << 3;
|
||||
/// Indicates whether the struct has a `#[rustc_has_incoherent_inherent_impls]` attribute.
|
||||
const IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPLS = 1 << 4;
|
||||
/// Indicates whether this struct is `Box`.
|
||||
const IS_BOX = 1 << 5;
|
||||
/// Indicates whether this struct is `ManuallyDrop`.
|
||||
const IS_MANUALLY_DROP = 1 << 6;
|
||||
/// Indicates whether this struct is `UnsafeCell`.
|
||||
const IS_UNSAFE_CELL = 1 << 7;
|
||||
}
|
||||
}
|
||||
|
||||
impl StructSignature {
|
||||
pub fn query(db: &dyn DefDatabase, id: StructId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into());
|
||||
|
||||
let mut flags = StructFlags::empty();
|
||||
if attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists() {
|
||||
flags |= StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPLS;
|
||||
}
|
||||
if attrs.by_key(&sym::fundamental).exists() {
|
||||
flags |= StructFlags::IS_FUNDAMENTAL;
|
||||
}
|
||||
if let Some(lang) = attrs.lang_item() {
|
||||
match lang {
|
||||
LangItem::PhantomData => flags |= StructFlags::IS_PHANTOM_DATA,
|
||||
LangItem::OwnedBox => flags |= StructFlags::IS_BOX,
|
||||
LangItem::ManuallyDrop => flags |= StructFlags::IS_MANUALLY_DROP,
|
||||
LangItem::UnsafeCell => flags |= StructFlags::IS_UNSAFE_CELL,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
let repr = attrs.repr();
|
||||
|
||||
let hir_expand::files::InFileWrapper { file_id, value } = loc.source(db);
|
||||
let (store, generic_params, source_map) = lower_generic_params(
|
||||
db,
|
||||
loc.container,
|
||||
id.into(),
|
||||
file_id,
|
||||
value.generic_param_list(),
|
||||
value.where_clause(),
|
||||
);
|
||||
(
|
||||
Arc::new(StructSignature {
|
||||
generic_params,
|
||||
store,
|
||||
flags,
|
||||
shape: item_tree[loc.id.value].shape,
|
||||
name: item_tree[loc.id.value].name.clone(),
|
||||
repr,
|
||||
}),
|
||||
Arc::new(source_map),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct UnionSignature {
|
||||
pub name: Name,
|
||||
pub generic_params: Arc<GenericParams>,
|
||||
pub store: Arc<ExpressionStore>,
|
||||
pub flags: StructFlags,
|
||||
pub repr: Option<ReprOptions>,
|
||||
}
|
||||
|
||||
impl UnionSignature {
|
||||
pub fn query(db: &dyn DefDatabase, id: UnionId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
|
||||
let loc = id.lookup(db);
|
||||
let krate = loc.container.krate;
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into());
|
||||
let mut flags = StructFlags::empty();
|
||||
if attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists() {
|
||||
flags |= StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPLS;
|
||||
}
|
||||
if attrs.by_key(&sym::fundamental).exists() {
|
||||
flags |= StructFlags::IS_FUNDAMENTAL;
|
||||
}
|
||||
|
||||
let repr = attrs.repr();
|
||||
|
||||
let hir_expand::files::InFileWrapper { file_id, value } = loc.source(db);
|
||||
let (store, generic_params, source_map) = lower_generic_params(
|
||||
db,
|
||||
loc.container,
|
||||
id.into(),
|
||||
file_id,
|
||||
value.generic_param_list(),
|
||||
value.where_clause(),
|
||||
);
|
||||
(
|
||||
Arc::new(UnionSignature {
|
||||
generic_params,
|
||||
store,
|
||||
flags,
|
||||
repr,
|
||||
name: item_tree[loc.id.value].name.clone(),
|
||||
}),
|
||||
Arc::new(source_map),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct EnumFlags: u8 {
|
||||
const IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPLS = 1 << 4;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct EnumSignature {
|
||||
pub name: Name,
|
||||
pub generic_params: Arc<GenericParams>,
|
||||
pub store: Arc<ExpressionStore>,
|
||||
pub flags: EnumFlags,
|
||||
pub repr: Option<ReprOptions>,
|
||||
}
|
||||
|
||||
impl EnumSignature {
|
||||
pub fn query(db: &dyn DefDatabase, id: EnumId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into());
|
||||
let mut flags = EnumFlags::empty();
|
||||
if attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists() {
|
||||
flags |= EnumFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPLS;
|
||||
}
|
||||
|
||||
let repr = attrs.repr();
|
||||
|
||||
let hir_expand::files::InFileWrapper { file_id, value } = loc.source(db);
|
||||
let (store, generic_params, source_map) = lower_generic_params(
|
||||
db,
|
||||
loc.container,
|
||||
id.into(),
|
||||
file_id,
|
||||
value.generic_param_list(),
|
||||
value.where_clause(),
|
||||
);
|
||||
|
||||
(
|
||||
Arc::new(EnumSignature {
|
||||
generic_params,
|
||||
store,
|
||||
flags,
|
||||
repr,
|
||||
name: item_tree[loc.id.value].name.clone(),
|
||||
}),
|
||||
Arc::new(source_map),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn variant_body_type(&self) -> IntegerType {
|
||||
match self.repr {
|
||||
Some(ReprOptions { int: Some(builtin), .. }) => builtin,
|
||||
_ => IntegerType::Pointer(true),
|
||||
}
|
||||
}
|
||||
}
|
||||
bitflags::bitflags! {
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
|
||||
pub struct ConstFlags: u8 {
|
||||
const HAS_BODY = 1 << 0;
|
||||
const RUSTC_ALLOW_INCOHERENT_IMPL = 1 << 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct ConstSignature {
|
||||
pub name: Option<Name>,
|
||||
// generic_params: Arc<GenericParams>,
|
||||
pub store: Arc<ExpressionStore>,
|
||||
pub type_ref: TypeRefId,
|
||||
pub flags: ConstFlags,
|
||||
}
|
||||
|
||||
impl ConstSignature {
|
||||
pub fn query(db: &dyn DefDatabase, id: ConstId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
|
||||
let module = loc.container.module(db);
|
||||
let attrs = item_tree.attrs(db, module.krate, ModItem::from(loc.id.value).into());
|
||||
let mut flags = ConstFlags::empty();
|
||||
if attrs.by_key(&sym::rustc_allow_incoherent_impl).exists() {
|
||||
flags |= ConstFlags::RUSTC_ALLOW_INCOHERENT_IMPL;
|
||||
}
|
||||
let source = loc.source(db);
|
||||
if source.value.body().is_some() {
|
||||
flags.insert(ConstFlags::HAS_BODY);
|
||||
}
|
||||
|
||||
let (store, source_map, type_ref) =
|
||||
crate::expr_store::lower::lower_type_ref(db, module, source.map(|it| it.ty()));
|
||||
|
||||
(
|
||||
Arc::new(ConstSignature {
|
||||
store: Arc::new(store),
|
||||
type_ref,
|
||||
flags,
|
||||
name: item_tree[loc.id.value].name.clone(),
|
||||
}),
|
||||
Arc::new(source_map),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn has_body(&self) -> bool {
|
||||
self.flags.contains(ConstFlags::HAS_BODY)
|
||||
}
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
|
||||
pub struct StaticFlags: u8 {
|
||||
const HAS_BODY = 1 << 0;
|
||||
const RUSTC_ALLOW_INCOHERENT_IMPL = 1 << 1;
|
||||
const MUTABLE = 1 << 2;
|
||||
const HAS_UNSAFE = 1 << 3;
|
||||
const HAS_SAFE = 1 << 4;
|
||||
const IS_EXTERN = 1 << 5;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct StaticSignature {
|
||||
pub name: Name,
|
||||
|
||||
// generic_params: Arc<GenericParams>,
|
||||
pub store: Arc<ExpressionStore>,
|
||||
pub type_ref: TypeRefId,
|
||||
pub flags: StaticFlags,
|
||||
}
|
||||
impl StaticSignature {
|
||||
pub fn query(db: &dyn DefDatabase, id: StaticId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
|
||||
let module = loc.container.module(db);
|
||||
let attrs = item_tree.attrs(db, module.krate, ModItem::from(loc.id.value).into());
|
||||
let mut flags = StaticFlags::empty();
|
||||
if attrs.by_key(&sym::rustc_allow_incoherent_impl).exists() {
|
||||
flags |= StaticFlags::RUSTC_ALLOW_INCOHERENT_IMPL;
|
||||
}
|
||||
|
||||
if matches!(loc.container, ItemContainerId::ExternBlockId(_)) {
|
||||
flags.insert(StaticFlags::IS_EXTERN);
|
||||
}
|
||||
|
||||
let source = loc.source(db);
|
||||
if source.value.body().is_some() {
|
||||
flags.insert(StaticFlags::HAS_BODY);
|
||||
}
|
||||
if source.value.mut_token().is_some() {
|
||||
flags.insert(StaticFlags::MUTABLE);
|
||||
}
|
||||
if source.value.unsafe_token().is_some() {
|
||||
flags.insert(StaticFlags::HAS_UNSAFE);
|
||||
}
|
||||
if source.value.safe_token().is_some() {
|
||||
flags.insert(StaticFlags::HAS_SAFE);
|
||||
}
|
||||
|
||||
let (store, source_map, type_ref) =
|
||||
crate::expr_store::lower::lower_type_ref(db, module, source.map(|it| it.ty()));
|
||||
|
||||
(
|
||||
Arc::new(StaticSignature {
|
||||
store: Arc::new(store),
|
||||
type_ref,
|
||||
flags,
|
||||
name: item_tree[loc.id.value].name.clone(),
|
||||
}),
|
||||
Arc::new(source_map),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
|
||||
pub struct ImplFlags: u8 {
|
||||
const IS_NEGATIVE = 1 << 0;
|
||||
const IS_UNSAFE = 1 << 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct ImplSignature {
|
||||
pub generic_params: Arc<GenericParams>,
|
||||
pub store: Arc<ExpressionStore>,
|
||||
pub self_ty: TypeRefId,
|
||||
pub target_trait: Option<TraitRef>,
|
||||
pub flags: ImplFlags,
|
||||
}
|
||||
|
||||
impl ImplSignature {
|
||||
pub fn query(db: &dyn DefDatabase, id: ImplId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
|
||||
let loc = id.lookup(db);
|
||||
|
||||
let mut flags = ImplFlags::empty();
|
||||
let src = loc.source(db);
|
||||
if src.value.unsafe_token().is_some() {
|
||||
flags.insert(ImplFlags::IS_UNSAFE);
|
||||
}
|
||||
if src.value.excl_token().is_some() {
|
||||
flags.insert(ImplFlags::IS_NEGATIVE);
|
||||
}
|
||||
|
||||
let (store, source_map, self_ty, target_trait, generic_params) =
|
||||
crate::expr_store::lower::lower_impl(db, loc.container, src, id);
|
||||
|
||||
(
|
||||
Arc::new(ImplSignature {
|
||||
store: Arc::new(store),
|
||||
generic_params,
|
||||
self_ty,
|
||||
target_trait,
|
||||
flags,
|
||||
}),
|
||||
Arc::new(source_map),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
|
||||
pub struct TraitFlags: u8 {
|
||||
const IS_AUTO = 1 << 0;
|
||||
const IS_UNSAFE = 1 << 1;
|
||||
const IS_FUNDAMENTAL = 1 << 2;
|
||||
const RUSTC_HAS_INCOHERENT_INHERENT_IMPLS = 1 << 3;
|
||||
const SKIP_ARRAY_DURING_METHOD_DISPATCH = 1 << 4;
|
||||
const SKIP_BOXED_SLICE_DURING_METHOD_DISPATCH = 1 << 5;
|
||||
const RUSTC_PAREN_SUGAR = 1 << 6;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct TraitSignature {
|
||||
pub name: Name,
|
||||
pub generic_params: Arc<GenericParams>,
|
||||
pub store: Arc<ExpressionStore>,
|
||||
pub flags: TraitFlags,
|
||||
}
|
||||
|
||||
impl TraitSignature {
|
||||
pub fn query(db: &dyn DefDatabase, id: TraitId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
|
||||
let mut flags = TraitFlags::empty();
|
||||
let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into());
|
||||
let source = loc.source(db);
|
||||
if source.value.auto_token().is_some() {
|
||||
flags.insert(TraitFlags::IS_AUTO);
|
||||
}
|
||||
if source.value.unsafe_token().is_some() {
|
||||
flags.insert(TraitFlags::IS_UNSAFE);
|
||||
}
|
||||
if attrs.by_key(&sym::fundamental).exists() {
|
||||
flags |= TraitFlags::IS_FUNDAMENTAL;
|
||||
}
|
||||
if attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists() {
|
||||
flags |= TraitFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS;
|
||||
}
|
||||
if attrs.by_key(&sym::rustc_paren_sugar).exists() {
|
||||
flags |= TraitFlags::RUSTC_PAREN_SUGAR;
|
||||
}
|
||||
let mut skip_array_during_method_dispatch =
|
||||
attrs.by_key(&sym::rustc_skip_array_during_method_dispatch).exists();
|
||||
let mut skip_boxed_slice_during_method_dispatch = false;
|
||||
for tt in attrs.by_key(&sym::rustc_skip_during_method_dispatch).tt_values() {
|
||||
for tt in tt.iter() {
|
||||
if let tt::iter::TtElement::Leaf(tt::Leaf::Ident(ident)) = tt {
|
||||
skip_array_during_method_dispatch |= ident.sym == sym::array;
|
||||
skip_boxed_slice_during_method_dispatch |= ident.sym == sym::boxed_slice;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if skip_array_during_method_dispatch {
|
||||
flags |= TraitFlags::SKIP_ARRAY_DURING_METHOD_DISPATCH;
|
||||
}
|
||||
if skip_boxed_slice_during_method_dispatch {
|
||||
flags |= TraitFlags::SKIP_BOXED_SLICE_DURING_METHOD_DISPATCH;
|
||||
}
|
||||
|
||||
let (store, source_map, generic_params) = lower_trait(db, loc.container, source, id);
|
||||
|
||||
(
|
||||
Arc::new(TraitSignature {
|
||||
store: Arc::new(store),
|
||||
generic_params,
|
||||
flags,
|
||||
name: item_tree[loc.id.value].name.clone(),
|
||||
}),
|
||||
Arc::new(source_map),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct TraitAliasSignature {
|
||||
pub name: Name,
|
||||
pub generic_params: Arc<GenericParams>,
|
||||
pub store: Arc<ExpressionStore>,
|
||||
}
|
||||
|
||||
impl TraitAliasSignature {
|
||||
pub fn query(
|
||||
db: &dyn DefDatabase,
|
||||
id: TraitAliasId,
|
||||
) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
|
||||
let source = loc.source(db);
|
||||
let (store, source_map, generic_params) = lower_trait_alias(db, loc.container, source, id);
|
||||
|
||||
(
|
||||
Arc::new(TraitAliasSignature {
|
||||
generic_params,
|
||||
store: Arc::new(store),
|
||||
name: item_tree[loc.id.value].name.clone(),
|
||||
}),
|
||||
Arc::new(source_map),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
|
||||
pub struct FnFlags: u16 {
|
||||
const HAS_SELF_PARAM = 1 << 0;
|
||||
const HAS_BODY = 1 << 1;
|
||||
const HAS_DEFAULT_KW = 1 << 2;
|
||||
const HAS_CONST_KW = 1 << 3;
|
||||
const HAS_ASYNC_KW = 1 << 4;
|
||||
const HAS_UNSAFE_KW = 1 << 5;
|
||||
const IS_VARARGS = 1 << 6;
|
||||
const HAS_SAFE_KW = 1 << 7;
|
||||
/// The `#[target_feature]` attribute is necessary to check safety (with RFC 2396),
|
||||
/// but keeping it for all functions will consume a lot of memory when there are
|
||||
/// only very few functions with it. So we only encode its existence here, and lookup
|
||||
/// it if needed.
|
||||
const HAS_TARGET_FEATURE = 1 << 8;
|
||||
const DEPRECATED_SAFE_2024 = 1 << 9;
|
||||
const RUSTC_ALLOW_INCOHERENT_IMPLS = 1 << 9;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct FunctionSignature {
|
||||
pub name: Name,
|
||||
pub generic_params: Arc<GenericParams>,
|
||||
pub store: Arc<ExpressionStore>,
|
||||
pub params: Box<[TypeRefId]>,
|
||||
pub ret_type: Option<TypeRefId>,
|
||||
pub abi: Option<Symbol>,
|
||||
pub flags: FnFlags,
|
||||
// FIXME: we should put this behind a fn flags + query to avoid bloating the struct
|
||||
pub legacy_const_generics_indices: Option<Box<Box<[u32]>>>,
|
||||
}
|
||||
|
||||
impl FunctionSignature {
|
||||
pub fn query(
|
||||
db: &dyn DefDatabase,
|
||||
id: FunctionId,
|
||||
) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
|
||||
let loc = id.lookup(db);
|
||||
let module = loc.container.module(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
|
||||
let mut flags = FnFlags::empty();
|
||||
let attrs = item_tree.attrs(db, module.krate, ModItem::from(loc.id.value).into());
|
||||
if attrs.by_key(&sym::rustc_allow_incoherent_impl).exists() {
|
||||
flags.insert(FnFlags::RUSTC_ALLOW_INCOHERENT_IMPLS);
|
||||
}
|
||||
|
||||
if attrs.by_key(&sym::target_feature).exists() {
|
||||
flags.insert(FnFlags::HAS_TARGET_FEATURE);
|
||||
}
|
||||
let legacy_const_generics_indices = attrs.rustc_legacy_const_generics();
|
||||
|
||||
let source = loc.source(db);
|
||||
|
||||
if source.value.unsafe_token().is_some() {
|
||||
if attrs.by_key(&sym::rustc_deprecated_safe_2024).exists() {
|
||||
flags.insert(FnFlags::DEPRECATED_SAFE_2024);
|
||||
} else {
|
||||
flags.insert(FnFlags::HAS_UNSAFE_KW);
|
||||
}
|
||||
}
|
||||
if source.value.async_token().is_some() {
|
||||
flags.insert(FnFlags::HAS_ASYNC_KW);
|
||||
}
|
||||
if source.value.const_token().is_some() {
|
||||
flags.insert(FnFlags::HAS_CONST_KW);
|
||||
}
|
||||
if source.value.default_token().is_some() {
|
||||
flags.insert(FnFlags::HAS_DEFAULT_KW);
|
||||
}
|
||||
if source.value.safe_token().is_some() {
|
||||
flags.insert(FnFlags::HAS_SAFE_KW);
|
||||
}
|
||||
if source.value.body().is_some() {
|
||||
flags.insert(FnFlags::HAS_BODY);
|
||||
}
|
||||
|
||||
let abi = source.value.abi().map(|abi| {
|
||||
abi.abi_string()
|
||||
.map_or_else(|| sym::C.clone(), |it| Symbol::intern(it.text_without_quotes()))
|
||||
});
|
||||
let (store, source_map, generic_params, params, ret_type, self_param, variadic) =
|
||||
lower_function(db, module, source, id);
|
||||
if self_param {
|
||||
flags.insert(FnFlags::HAS_SELF_PARAM);
|
||||
}
|
||||
if variadic {
|
||||
flags.insert(FnFlags::IS_VARARGS);
|
||||
}
|
||||
(
|
||||
Arc::new(FunctionSignature {
|
||||
generic_params,
|
||||
store: Arc::new(store),
|
||||
params,
|
||||
ret_type,
|
||||
abi,
|
||||
flags,
|
||||
legacy_const_generics_indices,
|
||||
name: item_tree[loc.id.value].name.clone(),
|
||||
}),
|
||||
Arc::new(source_map),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn has_body(&self) -> bool {
|
||||
self.flags.contains(FnFlags::HAS_BODY)
|
||||
}
|
||||
|
||||
/// True if the first param is `self`. This is relevant to decide whether this
|
||||
/// can be called as a method.
|
||||
pub fn has_self_param(&self) -> bool {
|
||||
self.flags.contains(FnFlags::HAS_SELF_PARAM)
|
||||
}
|
||||
|
||||
pub fn is_default(&self) -> bool {
|
||||
self.flags.contains(FnFlags::HAS_DEFAULT_KW)
|
||||
}
|
||||
|
||||
pub fn is_const(&self) -> bool {
|
||||
self.flags.contains(FnFlags::HAS_CONST_KW)
|
||||
}
|
||||
|
||||
pub fn is_async(&self) -> bool {
|
||||
self.flags.contains(FnFlags::HAS_ASYNC_KW)
|
||||
}
|
||||
|
||||
pub fn is_unsafe(&self) -> bool {
|
||||
self.flags.contains(FnFlags::HAS_UNSAFE_KW)
|
||||
}
|
||||
|
||||
pub fn is_deprecated_safe_2024(&self) -> bool {
|
||||
self.flags.contains(FnFlags::DEPRECATED_SAFE_2024)
|
||||
}
|
||||
|
||||
pub fn is_safe(&self) -> bool {
|
||||
self.flags.contains(FnFlags::HAS_SAFE_KW)
|
||||
}
|
||||
|
||||
pub fn is_varargs(&self) -> bool {
|
||||
self.flags.contains(FnFlags::IS_VARARGS)
|
||||
}
|
||||
|
||||
pub fn has_target_feature(&self) -> bool {
|
||||
self.flags.contains(FnFlags::HAS_TARGET_FEATURE)
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
|
||||
pub struct TypeAliasFlags: u16 {
|
||||
const IS_EXTERN = 1 << 7;
|
||||
const RUSTC_ALLOW_INCOHERENT_IMPLS = 1 << 8;
|
||||
const RUSTC_HAS_INCOHERENT_INHERENT_IMPLS = 1 << 9;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct TypeAliasSignature {
|
||||
pub name: Name,
|
||||
pub generic_params: Arc<GenericParams>,
|
||||
pub store: Arc<ExpressionStore>,
|
||||
pub bounds: Box<[TypeBound]>,
|
||||
pub ty: Option<TypeRefId>,
|
||||
pub flags: TypeAliasFlags,
|
||||
}
|
||||
|
||||
impl TypeAliasSignature {
|
||||
pub fn query(
|
||||
db: &dyn DefDatabase,
|
||||
id: TypeAliasId,
|
||||
) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
|
||||
let mut flags = TypeAliasFlags::empty();
|
||||
let attrs = item_tree.attrs(
|
||||
db,
|
||||
loc.container.module(db).krate(),
|
||||
ModItem::from(loc.id.value).into(),
|
||||
);
|
||||
if attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists() {
|
||||
flags.insert(TypeAliasFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS);
|
||||
}
|
||||
if attrs.by_key(&sym::rustc_allow_incoherent_impl).exists() {
|
||||
flags.insert(TypeAliasFlags::RUSTC_ALLOW_INCOHERENT_IMPLS);
|
||||
}
|
||||
if matches!(loc.container, ItemContainerId::ExternBlockId(_)) {
|
||||
flags.insert(TypeAliasFlags::IS_EXTERN);
|
||||
}
|
||||
let source = loc.source(db);
|
||||
let (store, source_map, generic_params, bounds, ty) =
|
||||
lower_type_alias(db, loc.container.module(db), source, id);
|
||||
|
||||
(
|
||||
Arc::new(TypeAliasSignature {
|
||||
store: Arc::new(store),
|
||||
generic_params,
|
||||
flags,
|
||||
bounds,
|
||||
name: item_tree[loc.id.value].name.clone(),
|
||||
ty,
|
||||
}),
|
||||
Arc::new(source_map),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct FunctionBody {
|
||||
pub store: Arc<ExpressionStore>,
|
||||
pub parameters: Box<[PatId]>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct SimpleBody {
|
||||
pub store: Arc<ExpressionStore>,
|
||||
}
|
||||
pub type StaticBody = SimpleBody;
|
||||
pub type ConstBody = SimpleBody;
|
||||
pub type EnumVariantBody = SimpleBody;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct VariantFieldsBody {
|
||||
pub store: Arc<ExpressionStore>,
|
||||
pub fields: Box<[Option<ExprId>]>,
|
||||
}
|
||||
|
||||
/// A single field of an enum variant or struct
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct FieldData {
|
||||
pub name: Name,
|
||||
pub type_ref: TypeRefId,
|
||||
pub visibility: RawVisibility,
|
||||
pub is_unsafe: bool,
|
||||
}
|
||||
|
||||
pub type LocalFieldId = Idx<FieldData>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct VariantFields {
|
||||
fields: Arena<FieldData>,
|
||||
pub store: Arc<ExpressionStore>,
|
||||
pub shape: FieldsShape,
|
||||
}
|
||||
impl VariantFields {
|
||||
#[inline]
|
||||
pub(crate) fn query(
|
||||
db: &dyn DefDatabase,
|
||||
id: VariantId,
|
||||
) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
|
||||
let (shape, (fields, store, source_map)) = match id {
|
||||
VariantId::EnumVariantId(id) => {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let parent = loc.parent.lookup(db);
|
||||
let variant = &item_tree[loc.id.value];
|
||||
(
|
||||
variant.shape,
|
||||
lower_fields(
|
||||
db,
|
||||
parent.container,
|
||||
&item_tree,
|
||||
FieldParent::EnumVariant(loc.id.value),
|
||||
loc.source(db).map(|src| {
|
||||
variant.fields.iter().zip(
|
||||
src.field_list()
|
||||
.map(|it| {
|
||||
match it {
|
||||
ast::FieldList::RecordFieldList(record_field_list) => {
|
||||
Either::Left(record_field_list.fields().map(|it| {
|
||||
(SyntaxNodePtr::new(it.syntax()), it.ty())
|
||||
}))
|
||||
}
|
||||
ast::FieldList::TupleFieldList(field_list) => {
|
||||
Either::Right(field_list.fields().map(|it| {
|
||||
(SyntaxNodePtr::new(it.syntax()), it.ty())
|
||||
}))
|
||||
}
|
||||
}
|
||||
.into_iter()
|
||||
})
|
||||
.into_iter()
|
||||
.flatten(),
|
||||
)
|
||||
}),
|
||||
Some(item_tree[parent.id.value].visibility),
|
||||
),
|
||||
)
|
||||
}
|
||||
VariantId::StructId(id) => {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let strukt = &item_tree[loc.id.value];
|
||||
(
|
||||
strukt.shape,
|
||||
lower_fields(
|
||||
db,
|
||||
loc.container,
|
||||
&item_tree,
|
||||
FieldParent::Struct(loc.id.value),
|
||||
loc.source(db).map(|src| {
|
||||
strukt.fields.iter().zip(
|
||||
src.field_list()
|
||||
.map(|it| {
|
||||
match it {
|
||||
ast::FieldList::RecordFieldList(record_field_list) => {
|
||||
Either::Left(record_field_list.fields().map(|it| {
|
||||
(SyntaxNodePtr::new(it.syntax()), it.ty())
|
||||
}))
|
||||
}
|
||||
ast::FieldList::TupleFieldList(field_list) => {
|
||||
Either::Right(field_list.fields().map(|it| {
|
||||
(SyntaxNodePtr::new(it.syntax()), it.ty())
|
||||
}))
|
||||
}
|
||||
}
|
||||
.into_iter()
|
||||
})
|
||||
.into_iter()
|
||||
.flatten(),
|
||||
)
|
||||
}),
|
||||
None,
|
||||
),
|
||||
)
|
||||
}
|
||||
VariantId::UnionId(id) => {
|
||||
let loc = id.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let union = &item_tree[loc.id.value];
|
||||
(
|
||||
FieldsShape::Record,
|
||||
lower_fields(
|
||||
db,
|
||||
loc.container,
|
||||
&item_tree,
|
||||
FieldParent::Union(loc.id.value),
|
||||
loc.source(db).map(|src| {
|
||||
union.fields.iter().zip(
|
||||
src.record_field_list()
|
||||
.map(|it| {
|
||||
it.fields()
|
||||
.map(|it| (SyntaxNodePtr::new(it.syntax()), it.ty()))
|
||||
})
|
||||
.into_iter()
|
||||
.flatten(),
|
||||
)
|
||||
}),
|
||||
None,
|
||||
),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
(Arc::new(VariantFields { fields, store: Arc::new(store), shape }), Arc::new(source_map))
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.fields.len()
|
||||
}
|
||||
|
||||
pub fn fields(&self) -> &Arena<FieldData> {
|
||||
&self.fields
|
||||
}
|
||||
|
||||
pub fn field(&self, name: &Name) -> Option<LocalFieldId> {
|
||||
self.fields().iter().find_map(|(id, data)| if &data.name == name { Some(id) } else { None })
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_fields<'a>(
|
||||
db: &dyn DefDatabase,
|
||||
module: ModuleId,
|
||||
item_tree: &ItemTree,
|
||||
parent: FieldParent,
|
||||
fields: InFile<impl Iterator<Item = (&'a Field, (SyntaxNodePtr, Option<ast::Type>))>>,
|
||||
override_visibility: Option<RawVisibilityId>,
|
||||
) -> (Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap) {
|
||||
let mut arena = Arena::new();
|
||||
let cfg_options = module.krate.cfg_options(db);
|
||||
let mut col = ExprCollector::new(db, module, fields.file_id);
|
||||
for (idx, (field, (ptr, ty))) in fields.value.enumerate() {
|
||||
let attr_owner = AttrOwner::make_field_indexed(parent, idx);
|
||||
let attrs = item_tree.attrs(db, module.krate, attr_owner);
|
||||
if attrs.is_cfg_enabled(cfg_options) {
|
||||
arena.alloc(FieldData {
|
||||
name: field.name.clone(),
|
||||
type_ref: col.lower_type_ref_opt(ty, &mut |_| TypeRef::Error),
|
||||
visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(),
|
||||
is_unsafe: field.is_unsafe,
|
||||
});
|
||||
} else {
|
||||
col.source_map.diagnostics.push(
|
||||
crate::expr_store::ExpressionStoreDiagnostics::InactiveCode {
|
||||
node: InFile::new(fields.file_id, ptr),
|
||||
cfg: attrs.cfg().unwrap(),
|
||||
opts: cfg_options.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
let store = col.store.finish();
|
||||
(arena, store, col.source_map)
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct InactiveEnumVariantCode {
|
||||
pub cfg: CfgExpr,
|
||||
pub opts: CfgOptions,
|
||||
pub ast_id: span::FileAstId<ast::Variant>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct EnumVariants {
|
||||
pub variants: Box<[(EnumVariantId, Name)]>,
|
||||
}
|
||||
|
||||
impl EnumVariants {
|
||||
pub(crate) fn enum_variants_query(
|
||||
db: &dyn DefDatabase,
|
||||
e: EnumId,
|
||||
) -> (Arc<EnumVariants>, Option<Arc<ThinVec<InactiveEnumVariantCode>>>) {
|
||||
let loc = e.lookup(db);
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
|
||||
let mut diagnostics = ThinVec::new();
|
||||
let cfg_options = loc.container.krate.cfg_options(db);
|
||||
let mut index = 0;
|
||||
let variants = FileItemTreeId::range_iter(item_tree[loc.id.value].variants.clone())
|
||||
.filter_map(|variant| {
|
||||
let attrs = item_tree.attrs(db, loc.container.krate, variant.into());
|
||||
if attrs.is_cfg_enabled(cfg_options) {
|
||||
let enum_variant = EnumVariantLoc {
|
||||
id: ItemTreeId::new(loc.id.tree_id(), variant),
|
||||
parent: e,
|
||||
index,
|
||||
}
|
||||
.intern(db);
|
||||
index += 1;
|
||||
Some((enum_variant, item_tree[variant].name.clone()))
|
||||
} else {
|
||||
diagnostics.push(InactiveEnumVariantCode {
|
||||
ast_id: item_tree[variant].ast_id,
|
||||
cfg: attrs.cfg().unwrap(),
|
||||
opts: cfg_options.clone(),
|
||||
});
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
(
|
||||
Arc::new(EnumVariants { variants }),
|
||||
diagnostics.is_empty().not().then(|| Arc::new(diagnostics)),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn variant(&self, name: &Name) -> Option<EnumVariantId> {
|
||||
self.variants.iter().find_map(|(v, n)| if n == name { Some(*v) } else { None })
|
||||
}
|
||||
|
||||
// [Adopted from rustc](https://github.com/rust-lang/rust/blob/bd53aa3bf7a24a70d763182303bd75e5fc51a9af/compiler/rustc_middle/src/ty/adt.rs#L446-L448)
|
||||
pub fn is_payload_free(&self, db: &dyn DefDatabase) -> bool {
|
||||
self.variants.iter().all(|&(v, _)| {
|
||||
// The condition check order is slightly modified from rustc
|
||||
// to improve performance by early returning with relatively fast checks
|
||||
let variant = &db.variant_fields(v.into());
|
||||
if !variant.fields().is_empty() {
|
||||
return false;
|
||||
}
|
||||
// The outer if condition is whether this variant has const ctor or not
|
||||
if !matches!(variant.shape, FieldsShape::Unit) {
|
||||
let body = db.body(v.into());
|
||||
// A variant with explicit discriminant
|
||||
if body.exprs[body.body_expr] != crate::hir::Expr::Missing {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -2,80 +2,19 @@
|
|||
|
||||
use std::iter;
|
||||
|
||||
use intern::Interned;
|
||||
use hir_expand::Lookup;
|
||||
use la_arena::ArenaMap;
|
||||
use span::SyntaxContext;
|
||||
use syntax::ast;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
ConstId, FunctionId, HasModule, LocalFieldId, LocalModuleId, ModuleId, VariantId,
|
||||
ConstId, FunctionId, HasModule, ItemContainerId, ItemLoc, ItemTreeLoc, LocalFieldId,
|
||||
LocalModuleId, ModuleId, TraitId, TypeAliasId, VariantId,
|
||||
db::DefDatabase,
|
||||
nameres::DefMap,
|
||||
path::{ModPath, PathKind},
|
||||
resolver::HasResolver,
|
||||
resolver::{HasResolver, Resolver},
|
||||
};
|
||||
|
||||
/// Visibility of an item, not yet resolved.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum RawVisibility {
|
||||
/// `pub(in module)`, `pub(crate)` or `pub(super)`. Also private, which is
|
||||
/// equivalent to `pub(self)`.
|
||||
Module(Interned<ModPath>, VisibilityExplicitness),
|
||||
/// `pub`.
|
||||
Public,
|
||||
}
|
||||
|
||||
impl RawVisibility {
|
||||
pub(crate) fn private() -> RawVisibility {
|
||||
RawVisibility::Module(
|
||||
Interned::new(ModPath::from_kind(PathKind::SELF)),
|
||||
VisibilityExplicitness::Implicit,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn from_ast(
|
||||
db: &dyn DefDatabase,
|
||||
node: Option<ast::Visibility>,
|
||||
span_for_range: &mut dyn FnMut(::tt::TextRange) -> SyntaxContext,
|
||||
) -> RawVisibility {
|
||||
let node = match node {
|
||||
None => return RawVisibility::private(),
|
||||
Some(node) => node,
|
||||
};
|
||||
Self::from_ast_with_span_map(db, node, span_for_range)
|
||||
}
|
||||
|
||||
fn from_ast_with_span_map(
|
||||
db: &dyn DefDatabase,
|
||||
node: ast::Visibility,
|
||||
span_for_range: &mut dyn FnMut(::tt::TextRange) -> SyntaxContext,
|
||||
) -> RawVisibility {
|
||||
let path = match node.kind() {
|
||||
ast::VisibilityKind::In(path) => {
|
||||
let path = ModPath::from_src(db.upcast(), path, span_for_range);
|
||||
match path {
|
||||
None => return RawVisibility::private(),
|
||||
Some(path) => path,
|
||||
}
|
||||
}
|
||||
ast::VisibilityKind::PubCrate => ModPath::from_kind(PathKind::Crate),
|
||||
ast::VisibilityKind::PubSuper => ModPath::from_kind(PathKind::Super(1)),
|
||||
ast::VisibilityKind::PubSelf => ModPath::from_kind(PathKind::SELF),
|
||||
ast::VisibilityKind::Pub => return RawVisibility::Public,
|
||||
};
|
||||
RawVisibility::Module(Interned::new(path), VisibilityExplicitness::Explicit)
|
||||
}
|
||||
|
||||
pub fn resolve(
|
||||
&self,
|
||||
db: &dyn DefDatabase,
|
||||
resolver: &crate::resolver::Resolver,
|
||||
) -> Visibility {
|
||||
// we fall back to public visibility (i.e. fail open) if the path can't be resolved
|
||||
resolver.resolve_visibility(db, self).unwrap_or(Visibility::Public)
|
||||
}
|
||||
}
|
||||
pub use crate::item_tree::{RawVisibility, VisibilityExplicitness};
|
||||
|
||||
/// Visibility of an item, with the path resolved.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
|
|
@ -87,6 +26,15 @@ pub enum Visibility {
|
|||
}
|
||||
|
||||
impl Visibility {
|
||||
pub fn resolve(
|
||||
db: &dyn DefDatabase,
|
||||
resolver: &crate::resolver::Resolver,
|
||||
raw_vis: &RawVisibility,
|
||||
) -> Self {
|
||||
// we fall back to public visibility (i.e. fail open) if the path can't be resolved
|
||||
resolver.resolve_visibility(db, raw_vis).unwrap_or(Visibility::Public)
|
||||
}
|
||||
|
||||
pub(crate) fn is_visible_from_other_crate(self) -> bool {
|
||||
matches!(self, Visibility::Public)
|
||||
}
|
||||
|
|
@ -254,30 +202,20 @@ impl Visibility {
|
|||
}
|
||||
}
|
||||
|
||||
/// Whether the item was imported through an explicit `pub(crate) use` or just a `use` without
|
||||
/// visibility.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum VisibilityExplicitness {
|
||||
Explicit,
|
||||
Implicit,
|
||||
}
|
||||
|
||||
impl VisibilityExplicitness {
|
||||
pub fn is_explicit(&self) -> bool {
|
||||
matches!(self, Self::Explicit)
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolve visibility of all specific fields of a struct or union variant.
|
||||
pub(crate) fn field_visibilities_query(
|
||||
db: &dyn DefDatabase,
|
||||
variant_id: VariantId,
|
||||
) -> Arc<ArenaMap<LocalFieldId, Visibility>> {
|
||||
let var_data = variant_id.variant_data(db);
|
||||
let variant_fields = db.variant_fields(variant_id);
|
||||
let fields = variant_fields.fields();
|
||||
if fields.is_empty() {
|
||||
return Arc::default();
|
||||
}
|
||||
let resolver = variant_id.module(db).resolver(db);
|
||||
let mut res = ArenaMap::default();
|
||||
for (field_id, field_data) in var_data.fields().iter() {
|
||||
res.insert(field_id, field_data.visibility.resolve(db, &resolver));
|
||||
for (field_id, field_data) in fields.iter() {
|
||||
res.insert(field_id, Visibility::resolve(db, &resolver, &field_data.visibility));
|
||||
}
|
||||
Arc::new(res)
|
||||
}
|
||||
|
|
@ -285,11 +223,43 @@ pub(crate) fn field_visibilities_query(
|
|||
/// Resolve visibility of a function.
|
||||
pub(crate) fn function_visibility_query(db: &dyn DefDatabase, def: FunctionId) -> Visibility {
|
||||
let resolver = def.resolver(db);
|
||||
db.function_data(def).visibility.resolve(db, &resolver)
|
||||
let loc = def.lookup(db);
|
||||
let tree = loc.item_tree_id().item_tree(db);
|
||||
if let ItemContainerId::TraitId(trait_id) = loc.container {
|
||||
trait_vis(db, &resolver, trait_id)
|
||||
} else {
|
||||
Visibility::resolve(db, &resolver, &tree[tree[loc.id.value].visibility])
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolve visibility of a const.
|
||||
pub(crate) fn const_visibility_query(db: &dyn DefDatabase, def: ConstId) -> Visibility {
|
||||
let resolver = def.resolver(db);
|
||||
db.const_data(def).visibility.resolve(db, &resolver)
|
||||
let loc = def.lookup(db);
|
||||
let tree = loc.item_tree_id().item_tree(db);
|
||||
if let ItemContainerId::TraitId(trait_id) = loc.container {
|
||||
trait_vis(db, &resolver, trait_id)
|
||||
} else {
|
||||
Visibility::resolve(db, &resolver, &tree[tree[loc.id.value].visibility])
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolve visibility of a type alias.
|
||||
pub(crate) fn type_alias_visibility_query(db: &dyn DefDatabase, def: TypeAliasId) -> Visibility {
|
||||
let resolver = def.resolver(db);
|
||||
let loc = def.lookup(db);
|
||||
let tree = loc.item_tree_id().item_tree(db);
|
||||
if let ItemContainerId::TraitId(trait_id) = loc.container {
|
||||
trait_vis(db, &resolver, trait_id)
|
||||
} else {
|
||||
Visibility::resolve(db, &resolver, &tree[tree[loc.id.value].visibility])
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn trait_vis(db: &dyn DefDatabase, resolver: &Resolver, trait_id: TraitId) -> Visibility {
|
||||
let ItemLoc { id: tree_id, .. } = trait_id.lookup(db);
|
||||
let item_tree = tree_id.item_tree(db);
|
||||
let tr_def = &item_tree[tree_id.value];
|
||||
Visibility::resolve(db, resolver, &item_tree[tr_def.visibility])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -784,13 +784,13 @@ fn include_str_expand(
|
|||
db: &dyn ExpandDatabase,
|
||||
arg_id: MacroCallId,
|
||||
tt: &tt::TopSubtree,
|
||||
span: Span,
|
||||
call_site: Span,
|
||||
) -> ExpandResult<tt::TopSubtree> {
|
||||
let (path, span) = match parse_string(tt) {
|
||||
let (path, input_span) = match parse_string(tt) {
|
||||
Ok(it) => it,
|
||||
Err(e) => {
|
||||
return ExpandResult::new(
|
||||
tt::TopSubtree::empty(DelimSpan { open: span, close: span }),
|
||||
tt::TopSubtree::empty(DelimSpan { open: call_site, close: call_site }),
|
||||
e,
|
||||
);
|
||||
}
|
||||
|
|
@ -800,17 +800,17 @@ fn include_str_expand(
|
|||
// it's unusual to `include_str!` a Rust file), but we can return an empty string.
|
||||
// Ideally, we'd be able to offer a precise expansion if the user asks for macro
|
||||
// expansion.
|
||||
let file_id = match relative_file(db, arg_id, path.as_str(), true, span) {
|
||||
let file_id = match relative_file(db, arg_id, path.as_str(), true, input_span) {
|
||||
Ok(file_id) => file_id,
|
||||
Err(_) => {
|
||||
return ExpandResult::ok(quote!(span =>""));
|
||||
return ExpandResult::ok(quote!(call_site =>""));
|
||||
}
|
||||
};
|
||||
|
||||
let text = db.file_text(file_id.file_id());
|
||||
let text = &*text.text(db);
|
||||
|
||||
ExpandResult::ok(quote!(span =>#text))
|
||||
ExpandResult::ok(quote!(call_site =>#text))
|
||||
}
|
||||
|
||||
fn get_env_inner(db: &dyn ExpandDatabase, arg_id: MacroCallId, key: &Symbol) -> Option<String> {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
//! See the full discussion : <https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Eager.20expansion.20of.20built-in.20macros>
|
||||
use base_db::Crate;
|
||||
use span::SyntaxContext;
|
||||
use syntax::{Parse, SyntaxElement, SyntaxNode, TextSize, WalkEvent, ted};
|
||||
use syntax::{AstPtr, Parse, SyntaxElement, SyntaxNode, TextSize, WalkEvent, ted};
|
||||
use syntax_bridge::DocCommentDesugarMode;
|
||||
use triomphe::Arc;
|
||||
|
||||
|
|
@ -32,6 +32,11 @@ use crate::{
|
|||
mod_path::ModPath,
|
||||
};
|
||||
|
||||
pub type EagerCallBackFn<'a> = &'a mut dyn FnMut(
|
||||
InFile<(syntax::AstPtr<ast::MacroCall>, span::FileAstId<ast::MacroCall>)>,
|
||||
MacroCallId,
|
||||
);
|
||||
|
||||
pub fn expand_eager_macro_input(
|
||||
db: &dyn ExpandDatabase,
|
||||
krate: Crate,
|
||||
|
|
@ -40,6 +45,7 @@ pub fn expand_eager_macro_input(
|
|||
def: MacroDefId,
|
||||
call_site: SyntaxContext,
|
||||
resolver: &dyn Fn(&ModPath) -> Option<MacroDefId>,
|
||||
eager_callback: EagerCallBackFn<'_>,
|
||||
) -> ExpandResult<Option<MacroCallId>> {
|
||||
let expand_to = ExpandTo::from_call_site(macro_call);
|
||||
|
||||
|
|
@ -71,6 +77,7 @@ pub fn expand_eager_macro_input(
|
|||
krate,
|
||||
call_site,
|
||||
resolver,
|
||||
eager_callback,
|
||||
)
|
||||
};
|
||||
let err = parse_err.or(err);
|
||||
|
|
@ -117,6 +124,7 @@ fn lazy_expand(
|
|||
ast_id: AstId<ast::MacroCall>,
|
||||
krate: Crate,
|
||||
call_site: SyntaxContext,
|
||||
eager_callback: EagerCallBackFn<'_>,
|
||||
) -> ExpandResult<(InFile<Parse<SyntaxNode>>, Arc<ExpansionSpanMap>)> {
|
||||
let expand_to = ExpandTo::from_call_site(macro_call);
|
||||
let id = def.make_call(
|
||||
|
|
@ -125,6 +133,7 @@ fn lazy_expand(
|
|||
MacroCallKind::FnLike { ast_id, expand_to, eager: None },
|
||||
call_site,
|
||||
);
|
||||
eager_callback(ast_id.map(|ast_id| (AstPtr::new(macro_call), ast_id)), id);
|
||||
let macro_file = id.as_macro_file();
|
||||
|
||||
db.parse_macro_expansion(macro_file)
|
||||
|
|
@ -140,6 +149,7 @@ fn eager_macro_recur(
|
|||
krate: Crate,
|
||||
call_site: SyntaxContext,
|
||||
macro_resolver: &dyn Fn(&ModPath) -> Option<MacroDefId>,
|
||||
eager_callback: EagerCallBackFn<'_>,
|
||||
) -> ExpandResult<Option<(SyntaxNode, TextSize)>> {
|
||||
let original = curr.value.clone_for_update();
|
||||
|
||||
|
|
@ -205,9 +215,14 @@ fn eager_macro_recur(
|
|||
def,
|
||||
call_site,
|
||||
macro_resolver,
|
||||
eager_callback,
|
||||
);
|
||||
match value {
|
||||
Some(call_id) => {
|
||||
eager_callback(
|
||||
curr.with_value(ast_id).map(|ast_id| (AstPtr::new(&call), ast_id)),
|
||||
call_id,
|
||||
);
|
||||
let ExpandResult { value: (parse, map), err: err2 } =
|
||||
db.parse_macro_expansion(call_id.as_macro_file());
|
||||
|
||||
|
|
@ -230,8 +245,15 @@ fn eager_macro_recur(
|
|||
| MacroDefKind::BuiltInAttr(..)
|
||||
| MacroDefKind::BuiltInDerive(..)
|
||||
| MacroDefKind::ProcMacro(..) => {
|
||||
let ExpandResult { value: (parse, tm), err } =
|
||||
lazy_expand(db, &def, &call, curr.with_value(ast_id), krate, call_site);
|
||||
let ExpandResult { value: (parse, tm), err } = lazy_expand(
|
||||
db,
|
||||
&def,
|
||||
&call,
|
||||
curr.with_value(ast_id),
|
||||
krate,
|
||||
call_site,
|
||||
eager_callback,
|
||||
);
|
||||
|
||||
// replace macro inside
|
||||
let ExpandResult { value, err: error } = eager_macro_recur(
|
||||
|
|
@ -244,6 +266,7 @@ fn eager_macro_recur(
|
|||
krate,
|
||||
call_site,
|
||||
macro_resolver,
|
||||
eager_callback,
|
||||
);
|
||||
let err = err.or(error);
|
||||
|
||||
|
|
|
|||
|
|
@ -77,6 +77,9 @@ impl<N: AstIdNode> AstId<N> {
|
|||
pub fn to_ptr(&self, db: &dyn ExpandDatabase) -> AstPtr<N> {
|
||||
db.ast_id_map(self.file_id).get(self.value)
|
||||
}
|
||||
pub fn erase(&self) -> ErasedAstId {
|
||||
crate::InFile::new(self.file_id, self.value.erase())
|
||||
}
|
||||
}
|
||||
|
||||
pub type ErasedAstId = crate::InFile<ErasedFileAstId>;
|
||||
|
|
|
|||
|
|
@ -282,6 +282,17 @@ impl MacroDefKind {
|
|||
pub fn is_declarative(&self) -> bool {
|
||||
matches!(self, MacroDefKind::Declarative(..))
|
||||
}
|
||||
|
||||
pub fn erased_ast_id(&self) -> ErasedAstId {
|
||||
match *self {
|
||||
MacroDefKind::ProcMacro(id, ..) => id.erase(),
|
||||
MacroDefKind::BuiltIn(id, _)
|
||||
| MacroDefKind::BuiltInAttr(id, _)
|
||||
| MacroDefKind::BuiltInDerive(id, _)
|
||||
| MacroDefKind::BuiltInEager(id, _)
|
||||
| MacroDefKind::Declarative(id, ..) => id.erase(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ use base_db::Crate;
|
|||
use hir_def::{
|
||||
AssocItemId, BlockId, CallableDefId, GenericDefId, HasModule, ItemContainerId, Lookup,
|
||||
TypeAliasId, VariantId,
|
||||
data::{TraitFlags, adt::StructFlags},
|
||||
hir::Movability,
|
||||
lang_item::{LangItem, LangItemTarget},
|
||||
signatures::{ImplFlags, StructFlags, TraitFlags},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
|
@ -68,7 +68,7 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
|
|||
fn discriminant_type(&self, ty: chalk_ir::Ty<Interner>) -> chalk_ir::Ty<Interner> {
|
||||
if let chalk_ir::TyKind::Adt(id, _) = ty.kind(Interner) {
|
||||
if let hir_def::AdtId::EnumId(e) = id.0 {
|
||||
let enum_data = self.db.enum_data(e);
|
||||
let enum_data = self.db.enum_signature(e);
|
||||
let ty = enum_data.repr.unwrap_or_default().discr_type();
|
||||
return chalk_ir::TyKind::Scalar(match ty {
|
||||
hir_def::layout::IntegerType::Pointer(is_signed) => match is_signed {
|
||||
|
|
@ -144,20 +144,20 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
|
|||
let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db);
|
||||
|
||||
let mut result = vec![];
|
||||
_ =
|
||||
if fps.is_empty() {
|
||||
debug!("Unrestricted search for {:?} impls...", trait_);
|
||||
self.for_trait_impls(trait_, self_ty_fp, |impls| {
|
||||
_ = self.for_trait_impls(trait_, self_ty_fp, |impls| {
|
||||
result.extend(impls.for_trait(trait_).map(id_to_chalk));
|
||||
ControlFlow::Continue(())
|
||||
})
|
||||
});
|
||||
} else {
|
||||
_ =
|
||||
self.for_trait_impls(trait_, self_ty_fp, |impls| {
|
||||
result.extend(fps.iter().flat_map(move |fp| {
|
||||
impls.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk)
|
||||
}));
|
||||
ControlFlow::Continue(())
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
debug!("impls_for_trait returned {} impls", result.len());
|
||||
|
|
@ -426,19 +426,19 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
|
|||
|
||||
fn trait_name(&self, trait_id: chalk_ir::TraitId<Interner>) -> String {
|
||||
let id = from_chalk_trait_id(trait_id);
|
||||
self.db.trait_data(id).name.display(self.db.upcast(), self.edition()).to_string()
|
||||
self.db.trait_signature(id).name.display(self.db.upcast(), self.edition()).to_string()
|
||||
}
|
||||
fn adt_name(&self, chalk_ir::AdtId(adt_id): AdtId) -> String {
|
||||
let edition = self.edition();
|
||||
match adt_id {
|
||||
hir_def::AdtId::StructId(id) => {
|
||||
self.db.struct_data(id).name.display(self.db.upcast(), edition).to_string()
|
||||
self.db.struct_signature(id).name.display(self.db.upcast(), edition).to_string()
|
||||
}
|
||||
hir_def::AdtId::EnumId(id) => {
|
||||
self.db.enum_data(id).name.display(self.db.upcast(), edition).to_string()
|
||||
self.db.enum_signature(id).name.display(self.db.upcast(), edition).to_string()
|
||||
}
|
||||
hir_def::AdtId::UnionId(id) => {
|
||||
self.db.union_data(id).name.display(self.db.upcast(), edition).to_string()
|
||||
self.db.union_signature(id).name.display(self.db.upcast(), edition).to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -448,7 +448,7 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
|
|||
}
|
||||
fn assoc_type_name(&self, assoc_ty_id: chalk_ir::AssocTypeId<Interner>) -> String {
|
||||
let id = self.db.associated_ty_data(from_assoc_type_id(assoc_ty_id)).name;
|
||||
self.db.type_alias_data(id).name.display(self.db.upcast(), self.edition()).to_string()
|
||||
self.db.type_alias_signature(id).name.display(self.db.upcast(), self.edition()).to_string()
|
||||
}
|
||||
fn opaque_type_name(&self, opaque_ty_id: chalk_ir::OpaqueTyId<Interner>) -> String {
|
||||
format!("Opaque_{:?}", opaque_ty_id.0)
|
||||
|
|
@ -611,11 +611,11 @@ pub(crate) fn associated_ty_data_query(
|
|||
};
|
||||
|
||||
// Lower bounds -- we could/should maybe move this to a separate query in `lower`
|
||||
let type_alias_data = db.type_alias_data(type_alias);
|
||||
let type_alias_data = db.type_alias_signature(type_alias);
|
||||
let generic_params = generics(db.upcast(), type_alias.into());
|
||||
let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
|
||||
let mut ctx =
|
||||
crate::TyLoweringContext::new(db, &resolver, &type_alias_data.types_map, type_alias.into())
|
||||
crate::TyLoweringContext::new(db, &resolver, &type_alias_data.store, type_alias.into())
|
||||
.with_type_param_mode(crate::lower::ParamLoweringMode::Variable);
|
||||
|
||||
let trait_subst = TyBuilder::subst_for_def(db, trait_, None)
|
||||
|
|
@ -669,7 +669,7 @@ pub(crate) fn trait_datum_query(
|
|||
) -> Arc<TraitDatum> {
|
||||
debug!("trait_datum {:?}", trait_id);
|
||||
let trait_ = from_chalk_trait_id(trait_id);
|
||||
let trait_data = db.trait_data(trait_);
|
||||
let trait_data = db.trait_signature(trait_);
|
||||
debug!("trait {:?} = {:?}", trait_id, trait_data.name);
|
||||
let generic_params = generics(db.upcast(), trait_.into());
|
||||
let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST);
|
||||
|
|
@ -760,7 +760,7 @@ pub(crate) fn adt_datum_query(
|
|||
|
||||
let (fundamental, phantom_data) = match adt_id {
|
||||
hir_def::AdtId::StructId(s) => {
|
||||
let flags = db.struct_data(s).flags;
|
||||
let flags = db.struct_signature(s).flags;
|
||||
(
|
||||
flags.contains(StructFlags::IS_FUNDAMENTAL),
|
||||
flags.contains(StructFlags::IS_PHANTOM_DATA),
|
||||
|
|
@ -840,7 +840,7 @@ fn impl_def_datum(db: &dyn HirDatabase, krate: Crate, impl_id: hir_def::ImplId)
|
|||
.expect("invalid impl passed to Chalk")
|
||||
.into_value_and_skipped_binders()
|
||||
.0;
|
||||
let impl_data = db.impl_data(impl_id);
|
||||
let impl_data = db.impl_signature(impl_id);
|
||||
|
||||
let generic_params = generics(db.upcast(), impl_id.into());
|
||||
let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST);
|
||||
|
|
@ -851,8 +851,7 @@ fn impl_def_datum(db: &dyn HirDatabase, krate: Crate, impl_id: hir_def::ImplId)
|
|||
rust_ir::ImplType::External
|
||||
};
|
||||
let where_clauses = convert_where_clauses(db, impl_id.into(), &bound_vars);
|
||||
let negative = impl_data.is_negative;
|
||||
|
||||
let negative = impl_data.flags.contains(ImplFlags::IS_NEGATIVE);
|
||||
let polarity = if negative { rust_ir::Polarity::Negative } else { rust_ir::Polarity::Positive };
|
||||
|
||||
let impl_datum_bound = rust_ir::ImplDatumBound { trait_ref, where_clauses };
|
||||
|
|
@ -867,7 +866,7 @@ fn impl_def_datum(db: &dyn HirDatabase, krate: Crate, impl_id: hir_def::ImplId)
|
|||
})
|
||||
.filter(|&type_alias| {
|
||||
// don't include associated types that don't exist in the trait
|
||||
let name = &db.type_alias_data(type_alias).name;
|
||||
let name = &db.type_alias_signature(type_alias).name;
|
||||
trait_data.associated_type_by_name(name).is_some()
|
||||
})
|
||||
.map(|type_alias| TypeAliasAsValue(type_alias).to_chalk(db))
|
||||
|
|
@ -896,7 +895,7 @@ fn type_alias_associated_ty_value(
|
|||
_krate: Crate,
|
||||
type_alias: TypeAliasId,
|
||||
) -> Arc<AssociatedTyValue> {
|
||||
let type_alias_data = db.type_alias_data(type_alias);
|
||||
let type_alias_data = db.type_alias_signature(type_alias);
|
||||
let impl_id = match type_alias.lookup(db.upcast()).container {
|
||||
ItemContainerId::ImplId(it) => it,
|
||||
_ => panic!("assoc ty value should be in impl"),
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use chalk_ir::{
|
|||
use hir_def::{
|
||||
DefWithBodyId, FunctionId, GenericDefId, HasModule, ItemContainerId, Lookup, TraitId,
|
||||
builtin_type::{BuiltinFloat, BuiltinInt, BuiltinType, BuiltinUint},
|
||||
generics::TypeOrConstParamData,
|
||||
hir::generics::{TypeOrConstParamData, TypeParamProvenance},
|
||||
lang_item::LangItem,
|
||||
type_ref::Rawness,
|
||||
};
|
||||
|
|
@ -314,7 +314,7 @@ impl TyExt for Ty {
|
|||
let param_data = &generic_params[id.local_id];
|
||||
match param_data {
|
||||
TypeOrConstParamData::TypeParamData(p) => match p.provenance {
|
||||
hir_def::generics::TypeParamProvenance::ArgumentImplTrait => {
|
||||
TypeParamProvenance::ArgumentImplTrait => {
|
||||
let substs = TyBuilder::placeholder_subst(db, id.parent);
|
||||
let predicates = db
|
||||
.generic_predicates(id.parent)
|
||||
|
|
|
|||
|
|
@ -3,10 +3,9 @@
|
|||
use base_db::Crate;
|
||||
use chalk_ir::{BoundVar, DebruijnIndex, cast::Cast};
|
||||
use hir_def::{
|
||||
ConstBlockLoc, EnumVariantId, GeneralConstId, HasModule as _, StaticId,
|
||||
expr_store::{Body, HygieneId},
|
||||
EnumVariantId, GeneralConstId, HasModule as _, StaticId,
|
||||
expr_store::{Body, HygieneId, path::Path},
|
||||
hir::{Expr, ExprId},
|
||||
path::Path,
|
||||
resolver::{Resolver, ValueNs},
|
||||
type_ref::LiteralConstRef,
|
||||
};
|
||||
|
|
@ -23,7 +22,6 @@ use crate::{
|
|||
generics::Generics,
|
||||
infer::InferenceContext,
|
||||
lower::ParamLoweringMode,
|
||||
mir::monomorphize_mir_body_bad,
|
||||
to_placeholder_idx,
|
||||
};
|
||||
|
||||
|
|
@ -102,7 +100,7 @@ pub(crate) fn path_to_const<'g>(
|
|||
resolver: &Resolver,
|
||||
path: &Path,
|
||||
mode: ParamLoweringMode,
|
||||
args: impl FnOnce() -> Option<&'g Generics>,
|
||||
args: impl FnOnce() -> &'g Generics,
|
||||
debruijn: DebruijnIndex,
|
||||
expected_ty: Ty,
|
||||
) -> Option<Const> {
|
||||
|
|
@ -115,7 +113,7 @@ pub(crate) fn path_to_const<'g>(
|
|||
}
|
||||
ParamLoweringMode::Variable => {
|
||||
let args = args();
|
||||
match args.and_then(|args| args.type_or_const_param_idx(p.into())) {
|
||||
match args.type_or_const_param_idx(p.into()) {
|
||||
Some(it) => ConstValue::BoundVar(BoundVar::new(debruijn, it)),
|
||||
None => {
|
||||
never!(
|
||||
|
|
@ -165,15 +163,15 @@ pub fn intern_const_ref(
|
|||
ty: Ty,
|
||||
krate: Crate,
|
||||
) -> Const {
|
||||
let layout = db.layout_of_ty(ty.clone(), TraitEnvironment::empty(krate));
|
||||
let layout = || db.layout_of_ty(ty.clone(), TraitEnvironment::empty(krate));
|
||||
let bytes = match value {
|
||||
LiteralConstRef::Int(i) => {
|
||||
// FIXME: We should handle failure of layout better.
|
||||
let size = layout.map(|it| it.size.bytes_usize()).unwrap_or(16);
|
||||
let size = layout().map(|it| it.size.bytes_usize()).unwrap_or(16);
|
||||
ConstScalar::Bytes(i.to_le_bytes()[0..size].into(), MemoryMap::default())
|
||||
}
|
||||
LiteralConstRef::UInt(i) => {
|
||||
let size = layout.map(|it| it.size.bytes_usize()).unwrap_or(16);
|
||||
let size = layout().map(|it| it.size.bytes_usize()).unwrap_or(16);
|
||||
ConstScalar::Bytes(i.to_le_bytes()[0..size].into(), MemoryMap::default())
|
||||
}
|
||||
LiteralConstRef::Bool(b) => ConstScalar::Bytes(Box::new([*b as u8]), MemoryMap::default()),
|
||||
|
|
@ -268,18 +266,6 @@ pub(crate) fn const_eval_query(
|
|||
let krate = s.module(db.upcast()).krate();
|
||||
db.monomorphized_mir_body(s.into(), subst, TraitEnvironment::empty(krate))?
|
||||
}
|
||||
GeneralConstId::ConstBlockId(c) => {
|
||||
let ConstBlockLoc { parent, root } = db.lookup_intern_anonymous_const(c);
|
||||
let body = db.body(parent);
|
||||
let infer = db.infer(parent);
|
||||
Arc::new(monomorphize_mir_body_bad(
|
||||
db,
|
||||
lower_to_mir(db, parent, &body, &infer, root)?,
|
||||
subst,
|
||||
db.trait_environment_for_body(parent),
|
||||
)?)
|
||||
}
|
||||
GeneralConstId::InTypeConstId(c) => db.mir_body(c.into())?,
|
||||
};
|
||||
let c = interpret_mir(db, body, false, trait_env)?.0?;
|
||||
Ok(c)
|
||||
|
|
@ -318,7 +304,7 @@ pub(crate) fn const_eval_discriminant_variant(
|
|||
return Ok(value);
|
||||
}
|
||||
|
||||
let repr = db.enum_data(loc.parent).repr;
|
||||
let repr = db.enum_signature(loc.parent).repr;
|
||||
let is_signed = repr.and_then(|repr| repr.int).is_none_or(|int| int.is_signed());
|
||||
|
||||
let mir_body = db.monomorphized_mir_body(
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ fn eval_goal(db: &TestDB, file_id: EditionedFileId) -> Result<Const, ConstEvalEr
|
|||
.declarations()
|
||||
.find_map(|x| match x {
|
||||
hir_def::ModuleDefId::ConstId(x) => {
|
||||
if db.const_data(x).name.as_ref()?.display(db, file_id.edition()).to_string()
|
||||
if db.const_signature(x).name.as_ref()?.display(db, file_id.edition()).to_string()
|
||||
== "GOAL"
|
||||
{
|
||||
Some(x)
|
||||
|
|
@ -2458,6 +2458,8 @@ fn extern_weak_statics() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
// FIXME
|
||||
#[should_panic]
|
||||
fn from_ne_bytes() {
|
||||
check_number(
|
||||
r#"
|
||||
|
|
@ -2534,6 +2536,8 @@ fn const_transfer_memory() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
// FIXME
|
||||
#[should_panic]
|
||||
fn anonymous_const_block() {
|
||||
check_number(
|
||||
r#"
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ use std::fmt;
|
|||
|
||||
use hir_def::{
|
||||
AdtId, ConstId, EnumId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup,
|
||||
ModuleDefId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, data::adt::VariantData,
|
||||
db::DefDatabase, hir::Pat, src::HasSource,
|
||||
ModuleDefId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, db::DefDatabase, hir::Pat,
|
||||
item_tree::FieldsShape, signatures::StaticFlags, src::HasSource,
|
||||
};
|
||||
use hir_expand::{
|
||||
HirFileId, HirFileIdExt,
|
||||
|
|
@ -178,7 +178,7 @@ impl<'a> DeclValidator<'a> {
|
|||
|
||||
fn validate_trait(&mut self, trait_id: TraitId) {
|
||||
// Check the trait name.
|
||||
let data = self.db.trait_data(trait_id);
|
||||
let data = self.db.trait_signature(trait_id);
|
||||
self.create_incorrect_case_diagnostic_for_item_name(
|
||||
trait_id,
|
||||
&data.name,
|
||||
|
|
@ -197,7 +197,7 @@ impl<'a> DeclValidator<'a> {
|
|||
// Check the function name.
|
||||
// Skipped if function is an associated item of a trait implementation.
|
||||
if !self.is_trait_impl_container(container) {
|
||||
let data = self.db.function_data(func);
|
||||
let data = self.db.function_signature(func);
|
||||
|
||||
// Don't run the lint on extern "[not Rust]" fn items with the
|
||||
// #[no_mangle] attribute.
|
||||
|
|
@ -293,7 +293,7 @@ impl<'a> DeclValidator<'a> {
|
|||
|
||||
fn validate_struct(&mut self, struct_id: StructId) {
|
||||
// Check the structure name.
|
||||
let data = self.db.struct_data(struct_id);
|
||||
let data = self.db.struct_signature(struct_id);
|
||||
self.create_incorrect_case_diagnostic_for_item_name(
|
||||
struct_id,
|
||||
&data.name,
|
||||
|
|
@ -307,12 +307,13 @@ impl<'a> DeclValidator<'a> {
|
|||
|
||||
/// Check incorrect names for struct fields.
|
||||
fn validate_struct_fields(&mut self, struct_id: StructId) {
|
||||
let data = self.db.variant_data(struct_id.into());
|
||||
let VariantData::Record { fields, .. } = data.as_ref() else {
|
||||
let data = self.db.variant_fields(struct_id.into());
|
||||
if data.shape != FieldsShape::Record {
|
||||
return;
|
||||
};
|
||||
let edition = self.edition(struct_id);
|
||||
let mut struct_fields_replacements = fields
|
||||
let mut struct_fields_replacements = data
|
||||
.fields()
|
||||
.iter()
|
||||
.filter_map(|(_, field)| {
|
||||
to_lower_snake_case(&field.name.display_no_db(edition).to_smolstr()).map(
|
||||
|
|
@ -378,7 +379,7 @@ impl<'a> DeclValidator<'a> {
|
|||
}
|
||||
|
||||
fn validate_enum(&mut self, enum_id: EnumId) {
|
||||
let data = self.db.enum_data(enum_id);
|
||||
let data = self.db.enum_signature(enum_id);
|
||||
|
||||
// Check the enum name.
|
||||
self.create_incorrect_case_diagnostic_for_item_name(
|
||||
|
|
@ -467,12 +468,13 @@ impl<'a> DeclValidator<'a> {
|
|||
|
||||
/// Check incorrect names for fields of enum variant.
|
||||
fn validate_enum_variant_fields(&mut self, variant_id: EnumVariantId) {
|
||||
let variant_data = self.db.variant_data(variant_id.into());
|
||||
let VariantData::Record { fields, .. } = variant_data.as_ref() else {
|
||||
let variant_data = self.db.variant_fields(variant_id.into());
|
||||
if variant_data.shape != FieldsShape::Record {
|
||||
return;
|
||||
};
|
||||
let edition = self.edition(variant_id);
|
||||
let mut variant_field_replacements = fields
|
||||
let mut variant_field_replacements = variant_data
|
||||
.fields()
|
||||
.iter()
|
||||
.filter_map(|(_, field)| {
|
||||
to_lower_snake_case(&field.name.display_no_db(edition).to_smolstr()).map(
|
||||
|
|
@ -544,7 +546,7 @@ impl<'a> DeclValidator<'a> {
|
|||
return;
|
||||
}
|
||||
|
||||
let data = self.db.const_data(const_id);
|
||||
let data = self.db.const_signature(const_id);
|
||||
let Some(name) = &data.name else {
|
||||
return;
|
||||
};
|
||||
|
|
@ -557,8 +559,8 @@ impl<'a> DeclValidator<'a> {
|
|||
}
|
||||
|
||||
fn validate_static(&mut self, static_id: StaticId) {
|
||||
let data = self.db.static_data(static_id);
|
||||
if data.is_extern() {
|
||||
let data = self.db.static_signature(static_id);
|
||||
if data.flags.contains(StaticFlags::IS_EXTERN) {
|
||||
cov_mark::hit!(extern_static_incorrect_case_ignored);
|
||||
return;
|
||||
}
|
||||
|
|
@ -579,7 +581,7 @@ impl<'a> DeclValidator<'a> {
|
|||
}
|
||||
|
||||
// Check the type alias name.
|
||||
let data = self.db.type_alias_data(type_alias_id);
|
||||
let data = self.db.type_alias_signature(type_alias_id);
|
||||
self.create_incorrect_case_diagnostic_for_item_name(
|
||||
type_alias_id,
|
||||
&data.name,
|
||||
|
|
|
|||
|
|
@ -11,8 +11,10 @@ pub(crate) mod pat_analysis;
|
|||
|
||||
use chalk_ir::Mutability;
|
||||
use hir_def::{
|
||||
AdtId, EnumVariantId, LocalFieldId, VariantId, data::adt::VariantData, expr_store::Body,
|
||||
AdtId, EnumVariantId, LocalFieldId, Lookup, VariantId,
|
||||
expr_store::{Body, path::Path},
|
||||
hir::PatId,
|
||||
item_tree::FieldsShape,
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
use span::Edition;
|
||||
|
|
@ -269,7 +271,7 @@ impl<'a> PatCtxt<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn lower_path(&mut self, pat: PatId, _path: &hir_def::path::Path) -> Pat {
|
||||
fn lower_path(&mut self, pat: PatId, _path: &Path) -> Pat {
|
||||
let ty = &self.infer[pat];
|
||||
|
||||
let pat_from_kind = |kind| Pat { ty: ty.clone(), kind: Box::new(kind) };
|
||||
|
|
@ -322,26 +324,29 @@ impl HirDisplay for Pat {
|
|||
if let Some(variant) = variant {
|
||||
match variant {
|
||||
VariantId::EnumVariantId(v) => {
|
||||
let loc = v.lookup(f.db.upcast());
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
f.db.enum_variant_data(v).name.display(f.db.upcast(), f.edition())
|
||||
f.db.enum_variants(loc.parent).variants[loc.index as usize]
|
||||
.1
|
||||
.display(f.db.upcast(), f.edition())
|
||||
)?;
|
||||
}
|
||||
VariantId::StructId(s) => write!(
|
||||
f,
|
||||
"{}",
|
||||
f.db.struct_data(s).name.display(f.db.upcast(), f.edition())
|
||||
f.db.struct_signature(s).name.display(f.db.upcast(), f.edition())
|
||||
)?,
|
||||
VariantId::UnionId(u) => write!(
|
||||
f,
|
||||
"{}",
|
||||
f.db.union_data(u).name.display(f.db.upcast(), f.edition())
|
||||
f.db.union_signature(u).name.display(f.db.upcast(), f.edition())
|
||||
)?,
|
||||
};
|
||||
|
||||
let variant_data = variant.variant_data(f.db.upcast());
|
||||
if let VariantData::Record { fields: rec_fields, .. } = &*variant_data {
|
||||
if variant_data.shape == FieldsShape::Record {
|
||||
write!(f, " {{ ")?;
|
||||
|
||||
let mut printed = 0;
|
||||
|
|
@ -350,11 +355,11 @@ impl HirDisplay for Pat {
|
|||
.filter(|p| !matches!(*p.pattern.kind, PatKind::Wild))
|
||||
.map(|p| {
|
||||
printed += 1;
|
||||
WriteWith(move |f| {
|
||||
WriteWith(|f| {
|
||||
write!(
|
||||
f,
|
||||
"{}: ",
|
||||
rec_fields[p.field]
|
||||
variant_data.fields()[p.field]
|
||||
.name
|
||||
.display(f.db.upcast(), f.edition())
|
||||
)?;
|
||||
|
|
@ -363,7 +368,7 @@ impl HirDisplay for Pat {
|
|||
});
|
||||
f.write_joined(subpats, ", ")?;
|
||||
|
||||
if printed < rec_fields.len() {
|
||||
if printed < variant_data.fields().len() {
|
||||
write!(f, "{}..", if printed > 0 { ", " } else { "" })?;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@ use std::mem;
|
|||
use either::Either;
|
||||
use hir_def::{
|
||||
AdtId, DefWithBodyId, FieldId, FunctionId, VariantId,
|
||||
expr_store::Body,
|
||||
expr_store::{Body, path::Path},
|
||||
hir::{Expr, ExprId, ExprOrPatId, Pat, PatId, Statement, UnaryOp},
|
||||
path::Path,
|
||||
resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs},
|
||||
signatures::StaticFlags,
|
||||
type_ref::Rawness,
|
||||
};
|
||||
use span::Edition;
|
||||
|
|
@ -31,11 +31,10 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> MissingUnsafe
|
|||
let _p = tracing::info_span!("missing_unsafe").entered();
|
||||
|
||||
let is_unsafe = match def {
|
||||
DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe(),
|
||||
DefWithBodyId::StaticId(_)
|
||||
| DefWithBodyId::ConstId(_)
|
||||
| DefWithBodyId::VariantId(_)
|
||||
| DefWithBodyId::InTypeConstId(_) => false,
|
||||
DefWithBodyId::FunctionId(it) => db.function_signature(it).is_unsafe(),
|
||||
DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) | DefWithBodyId::VariantId(_) => {
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
let mut res = MissingUnsafeResult { fn_is_unsafe: is_unsafe, ..MissingUnsafeResult::default() };
|
||||
|
|
@ -361,10 +360,12 @@ impl<'a> UnsafeVisitor<'a> {
|
|||
let value_or_partial =
|
||||
self.resolver.resolve_path_in_value_ns(self.db.upcast(), path, hygiene);
|
||||
if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial {
|
||||
let static_data = self.db.static_data(id);
|
||||
if static_data.mutable() {
|
||||
let static_data = self.db.static_signature(id);
|
||||
if static_data.flags.contains(StaticFlags::MUTABLE) {
|
||||
self.on_unsafe_op(node, UnsafetyReason::MutableStatic);
|
||||
} else if static_data.is_extern() && !static_data.has_safe_kw() {
|
||||
} else if static_data.flags.contains(StaticFlags::IS_EXTERN)
|
||||
&& !static_data.flags.contains(StaticFlags::HAS_SAFE)
|
||||
{
|
||||
self.on_unsafe_op(node, UnsafetyReason::ExternStatic);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,20 +13,21 @@ use either::Either;
|
|||
use hir_def::{
|
||||
GenericDefId, HasModule, ImportPathConfig, ItemContainerId, LocalFieldId, Lookup, ModuleDefId,
|
||||
ModuleId, TraitId,
|
||||
data::adt::VariantData,
|
||||
db::DefDatabase,
|
||||
expr_store::{ExpressionStore, path::Path},
|
||||
find_path::{self, PrefixKind},
|
||||
generics::{TypeOrConstParamData, TypeParamProvenance},
|
||||
hir::generics::{
|
||||
TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
|
||||
},
|
||||
item_scope::ItemInNs,
|
||||
item_tree::FieldsShape,
|
||||
lang_item::{LangItem, LangItemTarget},
|
||||
nameres::DefMap,
|
||||
path::{Path, PathKind},
|
||||
type_ref::{
|
||||
TraitBoundModifier, TypeBound, TypeRef, TypeRefId, TypesMap, TypesSourceMap, UseArgRef,
|
||||
},
|
||||
signatures::VariantFields,
|
||||
type_ref::{ConstRef, TraitBoundModifier, TypeBound, TypeRef, TypeRefId, UseArgRef},
|
||||
visibility::Visibility,
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
use hir_expand::{mod_path::PathKind, name::Name};
|
||||
use intern::{Internable, Interned, sym};
|
||||
use itertools::Itertools;
|
||||
use la_arena::ArenaMap;
|
||||
|
|
@ -614,7 +615,7 @@ impl HirDisplay for ProjectionTy {
|
|||
write!(
|
||||
f,
|
||||
">::{}",
|
||||
f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id))
|
||||
f.db.type_alias_signature(from_assoc_type_id(self.associated_ty_id))
|
||||
.name
|
||||
.display(f.db.upcast(), f.edition())
|
||||
)?;
|
||||
|
|
@ -786,7 +787,7 @@ fn render_const_scalar(
|
|||
}
|
||||
TyKind::Adt(adt, _) if b.len() == 2 * size_of::<usize>() => match adt.0 {
|
||||
hir_def::AdtId::StructId(s) => {
|
||||
let data = f.db.struct_data(s);
|
||||
let data = f.db.struct_signature(s);
|
||||
write!(f, "&{}", data.name.display(f.db.upcast(), f.edition()))?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -844,11 +845,11 @@ fn render_const_scalar(
|
|||
};
|
||||
match adt.0 {
|
||||
hir_def::AdtId::StructId(s) => {
|
||||
let data = f.db.struct_data(s);
|
||||
let data = f.db.struct_signature(s);
|
||||
write!(f, "{}", data.name.display(f.db.upcast(), f.edition()))?;
|
||||
let field_types = f.db.field_types(s.into());
|
||||
render_variant_after_name(
|
||||
&f.db.variant_data(s.into()),
|
||||
&f.db.variant_fields(s.into()),
|
||||
f,
|
||||
&field_types,
|
||||
f.db.trait_environment(adt.0.into()),
|
||||
|
|
@ -859,7 +860,11 @@ fn render_const_scalar(
|
|||
)
|
||||
}
|
||||
hir_def::AdtId::UnionId(u) => {
|
||||
write!(f, "{}", f.db.union_data(u).name.display(f.db.upcast(), f.edition()))
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
f.db.union_signature(u).name.display(f.db.upcast(), f.edition())
|
||||
)
|
||||
}
|
||||
hir_def::AdtId::EnumId(e) => {
|
||||
let Ok(target_data_layout) = f.db.target_data_layout(trait_env.krate) else {
|
||||
|
|
@ -870,11 +875,17 @@ fn render_const_scalar(
|
|||
else {
|
||||
return f.write_str("<failed-to-detect-variant>");
|
||||
};
|
||||
let data = f.db.enum_variant_data(var_id);
|
||||
write!(f, "{}", data.name.display(f.db.upcast(), f.edition()))?;
|
||||
let loc = var_id.lookup(f.db.upcast());
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
f.db.enum_variants(loc.parent).variants[loc.index as usize]
|
||||
.1
|
||||
.display(f.db.upcast(), f.edition())
|
||||
)?;
|
||||
let field_types = f.db.field_types(var_id.into());
|
||||
render_variant_after_name(
|
||||
&f.db.variant_data(var_id.into()),
|
||||
&f.db.variant_fields(var_id.into()),
|
||||
f,
|
||||
&field_types,
|
||||
f.db.trait_environment(adt.0.into()),
|
||||
|
|
@ -932,7 +943,7 @@ fn render_const_scalar(
|
|||
}
|
||||
|
||||
fn render_variant_after_name(
|
||||
data: &VariantData,
|
||||
data: &VariantFields,
|
||||
f: &mut HirFormatter<'_>,
|
||||
field_types: &ArenaMap<LocalFieldId, Binders<Ty>>,
|
||||
trait_env: Arc<TraitEnvironment>,
|
||||
|
|
@ -941,8 +952,8 @@ fn render_variant_after_name(
|
|||
b: &[u8],
|
||||
memory_map: &MemoryMap,
|
||||
) -> Result<(), HirDisplayError> {
|
||||
match data {
|
||||
VariantData::Record { fields, .. } | VariantData::Tuple { fields, .. } => {
|
||||
match data.shape {
|
||||
FieldsShape::Record | FieldsShape::Tuple => {
|
||||
let render_field = |f: &mut HirFormatter<'_>, id: LocalFieldId| {
|
||||
let offset = layout.fields.offset(u32::from(id.into_raw()) as usize).bytes_usize();
|
||||
let ty = field_types[id].clone().substitute(Interner, subst);
|
||||
|
|
@ -952,8 +963,8 @@ fn render_variant_after_name(
|
|||
let size = layout.size.bytes_usize();
|
||||
render_const_scalar(f, &b[offset..offset + size], memory_map, &ty)
|
||||
};
|
||||
let mut it = fields.iter();
|
||||
if matches!(data, VariantData::Record { .. }) {
|
||||
let mut it = data.fields().iter();
|
||||
if matches!(data.shape, FieldsShape::Record) {
|
||||
write!(f, " {{")?;
|
||||
if let Some((id, data)) = it.next() {
|
||||
write!(f, " {}: ", data.name.display(f.db.upcast(), f.edition()))?;
|
||||
|
|
@ -978,7 +989,7 @@ fn render_variant_after_name(
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
VariantData::Unit => Ok(()),
|
||||
FieldsShape::Unit => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1156,16 +1167,23 @@ impl HirDisplay for Ty {
|
|||
CallableDefId::FunctionId(ff) => write!(
|
||||
f,
|
||||
"{}",
|
||||
db.function_data(ff).name.display(f.db.upcast(), f.edition())
|
||||
db.function_signature(ff).name.display(f.db.upcast(), f.edition())
|
||||
)?,
|
||||
CallableDefId::StructId(s) => {
|
||||
write!(f, "{}", db.struct_data(s).name.display(f.db.upcast(), f.edition()))?
|
||||
}
|
||||
CallableDefId::EnumVariantId(e) => write!(
|
||||
CallableDefId::StructId(s) => write!(
|
||||
f,
|
||||
"{}",
|
||||
db.enum_variant_data(e).name.display(f.db.upcast(), f.edition())
|
||||
db.struct_signature(s).name.display(f.db.upcast(), f.edition())
|
||||
)?,
|
||||
CallableDefId::EnumVariantId(e) => {
|
||||
let loc = e.lookup(db.upcast());
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
db.enum_variants(loc.parent).variants[loc.index as usize]
|
||||
.1
|
||||
.display(db.upcast(), f.edition())
|
||||
)?
|
||||
}
|
||||
};
|
||||
f.end_location_link();
|
||||
|
||||
|
|
@ -1228,9 +1246,9 @@ impl HirDisplay for Ty {
|
|||
match f.display_kind {
|
||||
DisplayKind::Diagnostics | DisplayKind::Test => {
|
||||
let name = match *def_id {
|
||||
hir_def::AdtId::StructId(it) => db.struct_data(it).name.clone(),
|
||||
hir_def::AdtId::UnionId(it) => db.union_data(it).name.clone(),
|
||||
hir_def::AdtId::EnumId(it) => db.enum_data(it).name.clone(),
|
||||
hir_def::AdtId::StructId(it) => db.struct_signature(it).name.clone(),
|
||||
hir_def::AdtId::UnionId(it) => db.union_signature(it).name.clone(),
|
||||
hir_def::AdtId::EnumId(it) => db.enum_signature(it).name.clone(),
|
||||
};
|
||||
write!(f, "{}", name.display(f.db.upcast(), f.edition()))?;
|
||||
}
|
||||
|
|
@ -1269,8 +1287,8 @@ impl HirDisplay for Ty {
|
|||
ItemContainerId::TraitId(it) => it,
|
||||
_ => panic!("not an associated type"),
|
||||
};
|
||||
let trait_data = db.trait_data(trait_);
|
||||
let type_alias_data = db.type_alias_data(type_alias);
|
||||
let trait_data = db.trait_signature(trait_);
|
||||
let type_alias_data = db.type_alias_signature(type_alias);
|
||||
|
||||
// Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
|
||||
if f.display_kind.is_test() {
|
||||
|
|
@ -1296,7 +1314,7 @@ impl HirDisplay for Ty {
|
|||
}
|
||||
TyKind::Foreign(type_alias) => {
|
||||
let alias = from_foreign_def_id(*type_alias);
|
||||
let type_alias = db.type_alias_data(alias);
|
||||
let type_alias = db.type_alias_signature(alias);
|
||||
f.start_location_link(alias.into());
|
||||
write!(f, "{}", type_alias.name.display(f.db.upcast(), f.edition()))?;
|
||||
f.end_location_link();
|
||||
|
|
@ -1789,7 +1807,11 @@ fn write_bounds_like_dyn_trait(
|
|||
// existential) here, which is the only thing that's
|
||||
// possible in actual Rust, and hence don't print it
|
||||
f.start_location_link(trait_.into());
|
||||
write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast(), f.edition()))?;
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
f.db.trait_signature(trait_).name.display(f.db.upcast(), f.edition())
|
||||
)?;
|
||||
f.end_location_link();
|
||||
if is_fn_trait {
|
||||
if let [self_, params @ ..] = trait_ref.substitution.as_slice(Interner) {
|
||||
|
|
@ -1861,7 +1883,7 @@ fn write_bounds_like_dyn_trait(
|
|||
}
|
||||
if let AliasTy::Projection(proj) = alias {
|
||||
let assoc_ty_id = from_assoc_type_id(proj.associated_ty_id);
|
||||
let type_alias = f.db.type_alias_data(assoc_ty_id);
|
||||
let type_alias = f.db.type_alias_signature(assoc_ty_id);
|
||||
f.start_location_link(assoc_ty_id.into());
|
||||
write!(f, "{}", type_alias.name.display(f.db.upcast(), f.edition()))?;
|
||||
f.end_location_link();
|
||||
|
|
@ -1914,7 +1936,7 @@ impl HirDisplay for TraitRef {
|
|||
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
|
||||
let trait_ = self.hir_trait_id();
|
||||
f.start_location_link(trait_.into());
|
||||
write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast(), f.edition()))?;
|
||||
write!(f, "{}", f.db.trait_signature(trait_).name.display(f.db.upcast(), f.edition()))?;
|
||||
f.end_location_link();
|
||||
let substs = self.substitution.as_slice(Interner);
|
||||
hir_fmt_generics(f, &substs[1..], None, substs[0].ty(Interner))
|
||||
|
|
@ -1945,7 +1967,7 @@ impl HirDisplay for WhereClause {
|
|||
write!(
|
||||
f,
|
||||
"{}",
|
||||
f.db.type_alias_data(type_alias).name.display(f.db.upcast(), f.edition()),
|
||||
f.db.type_alias_signature(type_alias).name.display(f.db.upcast(), f.edition()),
|
||||
)?;
|
||||
f.end_location_link();
|
||||
write!(f, " = ")?;
|
||||
|
|
@ -2040,70 +2062,97 @@ pub fn write_visibility(
|
|||
}
|
||||
}
|
||||
|
||||
pub trait HirDisplayWithTypesMap {
|
||||
pub trait HirDisplayWithExpressionStore {
|
||||
fn hir_fmt(
|
||||
&self,
|
||||
f: &mut HirFormatter<'_>,
|
||||
types_map: &TypesMap,
|
||||
store: &ExpressionStore,
|
||||
) -> Result<(), HirDisplayError>;
|
||||
}
|
||||
|
||||
impl<T: ?Sized + HirDisplayWithTypesMap> HirDisplayWithTypesMap for &'_ T {
|
||||
impl<T: ?Sized + HirDisplayWithExpressionStore> HirDisplayWithExpressionStore for &'_ T {
|
||||
fn hir_fmt(
|
||||
&self,
|
||||
f: &mut HirFormatter<'_>,
|
||||
types_map: &TypesMap,
|
||||
store: &ExpressionStore,
|
||||
) -> Result<(), HirDisplayError> {
|
||||
T::hir_fmt(&**self, f, types_map)
|
||||
T::hir_fmt(&**self, f, store)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hir_display_with_types_map<'a, T: HirDisplayWithTypesMap + 'a>(
|
||||
pub fn hir_display_with_store<'a, T: HirDisplayWithExpressionStore + 'a>(
|
||||
value: T,
|
||||
types_map: &'a TypesMap,
|
||||
store: &'a ExpressionStore,
|
||||
) -> impl HirDisplay + 'a {
|
||||
TypesMapAdapter(value, types_map)
|
||||
ExpressionStoreAdapter(value, store)
|
||||
}
|
||||
|
||||
struct TypesMapAdapter<'a, T>(T, &'a TypesMap);
|
||||
struct ExpressionStoreAdapter<'a, T>(T, &'a ExpressionStore);
|
||||
|
||||
impl<'a, T> TypesMapAdapter<'a, T> {
|
||||
fn wrap(types_map: &'a TypesMap) -> impl Fn(T) -> TypesMapAdapter<'a, T> {
|
||||
move |value| TypesMapAdapter(value, types_map)
|
||||
impl<'a, T> ExpressionStoreAdapter<'a, T> {
|
||||
fn wrap(store: &'a ExpressionStore) -> impl Fn(T) -> ExpressionStoreAdapter<'a, T> {
|
||||
move |value| ExpressionStoreAdapter(value, store)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: HirDisplayWithTypesMap> HirDisplay for TypesMapAdapter<'_, T> {
|
||||
impl<T: HirDisplayWithExpressionStore> HirDisplay for ExpressionStoreAdapter<'_, T> {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
|
||||
T::hir_fmt(&self.0, f, self.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplayWithTypesMap for TypeRefId {
|
||||
impl HirDisplayWithExpressionStore for TypeRefId {
|
||||
fn hir_fmt(
|
||||
&self,
|
||||
f: &mut HirFormatter<'_>,
|
||||
types_map: &TypesMap,
|
||||
store: &ExpressionStore,
|
||||
) -> Result<(), HirDisplayError> {
|
||||
match &types_map[*self] {
|
||||
match &store[*self] {
|
||||
TypeRef::Never => write!(f, "!")?,
|
||||
TypeRef::TypeParam(param) => {
|
||||
let generic_params = f.db.generic_params(param.parent());
|
||||
match generic_params[param.local_id()].name() {
|
||||
Some(name) => write!(f, "{}", name.display(f.db.upcast(), f.edition()))?,
|
||||
None => {
|
||||
write!(f, "impl ")?;
|
||||
f.write_joined(
|
||||
generic_params
|
||||
.where_predicates()
|
||||
.filter_map(|it| match it {
|
||||
WherePredicate::TypeBound {
|
||||
target: WherePredicateTypeTarget::TypeOrConstParam(p),
|
||||
bound,
|
||||
}
|
||||
| WherePredicate::ForLifetime {
|
||||
lifetimes: _,
|
||||
target: WherePredicateTypeTarget::TypeOrConstParam(p),
|
||||
bound,
|
||||
} if *p == param.local_id() => Some(bound),
|
||||
_ => None,
|
||||
})
|
||||
.map(ExpressionStoreAdapter::wrap(store)),
|
||||
" + ",
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
TypeRef::Placeholder => write!(f, "_")?,
|
||||
TypeRef::Tuple(elems) => {
|
||||
write!(f, "(")?;
|
||||
f.write_joined(elems.iter().map(TypesMapAdapter::wrap(types_map)), ", ")?;
|
||||
f.write_joined(elems.iter().map(ExpressionStoreAdapter::wrap(store)), ", ")?;
|
||||
if elems.len() == 1 {
|
||||
write!(f, ",")?;
|
||||
}
|
||||
write!(f, ")")?;
|
||||
}
|
||||
TypeRef::Path(path) => path.hir_fmt(f, types_map)?,
|
||||
TypeRef::Path(path) => path.hir_fmt(f, store)?,
|
||||
TypeRef::RawPtr(inner, mutability) => {
|
||||
let mutability = match mutability {
|
||||
hir_def::type_ref::Mutability::Shared => "*const ",
|
||||
hir_def::type_ref::Mutability::Mut => "*mut ",
|
||||
};
|
||||
write!(f, "{mutability}")?;
|
||||
inner.hir_fmt(f, types_map)?;
|
||||
inner.hir_fmt(f, store)?;
|
||||
}
|
||||
TypeRef::Reference(ref_) => {
|
||||
let mutability = match ref_.mutability {
|
||||
|
|
@ -2115,16 +2164,18 @@ impl HirDisplayWithTypesMap for TypeRefId {
|
|||
write!(f, "{} ", lifetime.name.display(f.db.upcast(), f.edition()))?;
|
||||
}
|
||||
write!(f, "{mutability}")?;
|
||||
ref_.ty.hir_fmt(f, types_map)?;
|
||||
ref_.ty.hir_fmt(f, store)?;
|
||||
}
|
||||
TypeRef::Array(array) => {
|
||||
write!(f, "[")?;
|
||||
array.ty.hir_fmt(f, types_map)?;
|
||||
write!(f, "; {}]", array.len.display(f.db.upcast(), f.edition()))?;
|
||||
array.ty.hir_fmt(f, store)?;
|
||||
write!(f, "; ")?;
|
||||
array.len.hir_fmt(f, store)?;
|
||||
write!(f, "]")?;
|
||||
}
|
||||
TypeRef::Slice(inner) => {
|
||||
write!(f, "[")?;
|
||||
inner.hir_fmt(f, types_map)?;
|
||||
inner.hir_fmt(f, store)?;
|
||||
write!(f, "]")?;
|
||||
}
|
||||
TypeRef::Fn(fn_) => {
|
||||
|
|
@ -2144,7 +2195,7 @@ impl HirDisplayWithTypesMap for TypeRefId {
|
|||
write!(f, "{}: ", name.display(f.db.upcast(), f.edition()))?;
|
||||
}
|
||||
|
||||
param_type.hir_fmt(f, types_map)?;
|
||||
param_type.hir_fmt(f, store)?;
|
||||
|
||||
if index != function_parameters.len() - 1 {
|
||||
write!(f, ", ")?;
|
||||
|
|
@ -2154,41 +2205,22 @@ impl HirDisplayWithTypesMap for TypeRefId {
|
|||
write!(f, "{}...", if fn_.params.len() == 1 { "" } else { ", " })?;
|
||||
}
|
||||
write!(f, ")")?;
|
||||
match &types_map[*return_type] {
|
||||
match &store[*return_type] {
|
||||
TypeRef::Tuple(tup) if tup.is_empty() => {}
|
||||
_ => {
|
||||
write!(f, " -> ")?;
|
||||
return_type.hir_fmt(f, types_map)?;
|
||||
return_type.hir_fmt(f, store)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TypeRef::ImplTrait(bounds) => {
|
||||
write!(f, "impl ")?;
|
||||
f.write_joined(bounds.iter().map(TypesMapAdapter::wrap(types_map)), " + ")?;
|
||||
f.write_joined(bounds.iter().map(ExpressionStoreAdapter::wrap(store)), " + ")?;
|
||||
}
|
||||
TypeRef::DynTrait(bounds) => {
|
||||
write!(f, "dyn ")?;
|
||||
f.write_joined(bounds.iter().map(TypesMapAdapter::wrap(types_map)), " + ")?;
|
||||
}
|
||||
TypeRef::Macro(macro_call) => {
|
||||
let (mut types_map, mut types_source_map) =
|
||||
(TypesMap::default(), TypesSourceMap::default());
|
||||
let mut ctx = hir_def::lower::LowerCtx::new(
|
||||
f.db.upcast(),
|
||||
macro_call.file_id,
|
||||
&mut types_map,
|
||||
&mut types_source_map,
|
||||
);
|
||||
let macro_call = macro_call.to_node(f.db.upcast());
|
||||
match macro_call.path() {
|
||||
Some(path) => match Path::from_src(&mut ctx, path) {
|
||||
Some(path) => path.hir_fmt(f, &types_map)?,
|
||||
None => write!(f, "{{macro}}")?,
|
||||
},
|
||||
None => write!(f, "{{macro}}")?,
|
||||
}
|
||||
write!(f, "!(..)")?;
|
||||
f.write_joined(bounds.iter().map(ExpressionStoreAdapter::wrap(store)), " + ")?;
|
||||
}
|
||||
TypeRef::Error => write!(f, "{{error}}")?,
|
||||
}
|
||||
|
|
@ -2196,11 +2228,24 @@ impl HirDisplayWithTypesMap for TypeRefId {
|
|||
}
|
||||
}
|
||||
|
||||
impl HirDisplayWithTypesMap for TypeBound {
|
||||
impl HirDisplayWithExpressionStore for ConstRef {
|
||||
fn hir_fmt(
|
||||
&self,
|
||||
f: &mut HirFormatter<'_>,
|
||||
types_map: &TypesMap,
|
||||
_store: &ExpressionStore,
|
||||
) -> Result<(), HirDisplayError> {
|
||||
// FIXME
|
||||
write!(f, "{{const}}")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplayWithExpressionStore for TypeBound {
|
||||
fn hir_fmt(
|
||||
&self,
|
||||
f: &mut HirFormatter<'_>,
|
||||
store: &ExpressionStore,
|
||||
) -> Result<(), HirDisplayError> {
|
||||
match self {
|
||||
&TypeBound::Path(path, modifier) => {
|
||||
|
|
@ -2208,7 +2253,7 @@ impl HirDisplayWithTypesMap for TypeBound {
|
|||
TraitBoundModifier::None => (),
|
||||
TraitBoundModifier::Maybe => write!(f, "?")?,
|
||||
}
|
||||
types_map[path].hir_fmt(f, types_map)
|
||||
store[path].hir_fmt(f, store)
|
||||
}
|
||||
TypeBound::Lifetime(lifetime) => {
|
||||
write!(f, "{}", lifetime.name.display(f.db.upcast(), f.edition()))
|
||||
|
|
@ -2220,7 +2265,7 @@ impl HirDisplayWithTypesMap for TypeBound {
|
|||
"for<{}> ",
|
||||
lifetimes.iter().map(|it| it.display(f.db.upcast(), edition)).format(", ")
|
||||
)?;
|
||||
types_map[*path].hir_fmt(f, types_map)
|
||||
store[*path].hir_fmt(f, store)
|
||||
}
|
||||
TypeBound::Use(args) => {
|
||||
let edition = f.edition();
|
||||
|
|
@ -2240,16 +2285,16 @@ impl HirDisplayWithTypesMap for TypeBound {
|
|||
}
|
||||
}
|
||||
|
||||
impl HirDisplayWithTypesMap for Path {
|
||||
impl HirDisplayWithExpressionStore for Path {
|
||||
fn hir_fmt(
|
||||
&self,
|
||||
f: &mut HirFormatter<'_>,
|
||||
types_map: &TypesMap,
|
||||
store: &ExpressionStore,
|
||||
) -> Result<(), HirDisplayError> {
|
||||
match (self.type_anchor(), self.kind()) {
|
||||
(Some(anchor), _) => {
|
||||
write!(f, "<")?;
|
||||
anchor.hir_fmt(f, types_map)?;
|
||||
anchor.hir_fmt(f, store)?;
|
||||
write!(f, ">")?;
|
||||
}
|
||||
(_, PathKind::Plain) => {}
|
||||
|
|
@ -2292,7 +2337,7 @@ impl HirDisplayWithTypesMap for Path {
|
|||
});
|
||||
if let Some(ty) = trait_self_ty {
|
||||
write!(f, "<")?;
|
||||
ty.hir_fmt(f, types_map)?;
|
||||
ty.hir_fmt(f, store)?;
|
||||
write!(f, " as ")?;
|
||||
// Now format the path of the trait...
|
||||
}
|
||||
|
|
@ -2306,14 +2351,14 @@ impl HirDisplayWithTypesMap for Path {
|
|||
// We should be in type context, so format as `Foo<Bar>` instead of `Foo::<Bar>`.
|
||||
// Do we actually format expressions?
|
||||
match generic_args.parenthesized {
|
||||
hir_def::path::GenericArgsParentheses::ReturnTypeNotation => {
|
||||
hir_def::expr_store::path::GenericArgsParentheses::ReturnTypeNotation => {
|
||||
write!(f, "(..)")?;
|
||||
}
|
||||
hir_def::path::GenericArgsParentheses::ParenSugar => {
|
||||
hir_def::expr_store::path::GenericArgsParentheses::ParenSugar => {
|
||||
// First argument will be a tuple, which already includes the parentheses.
|
||||
// If the tuple only contains 1 item, write it manually to avoid the trailing `,`.
|
||||
let tuple = match generic_args.args[0] {
|
||||
hir_def::path::GenericArg::Type(ty) => match &types_map[ty] {
|
||||
hir_def::expr_store::path::GenericArg::Type(ty) => match &store[ty] {
|
||||
TypeRef::Tuple(it) => Some(it),
|
||||
_ => None,
|
||||
},
|
||||
|
|
@ -2322,20 +2367,20 @@ impl HirDisplayWithTypesMap for Path {
|
|||
if let Some(v) = tuple {
|
||||
if v.len() == 1 {
|
||||
write!(f, "(")?;
|
||||
v[0].hir_fmt(f, types_map)?;
|
||||
v[0].hir_fmt(f, store)?;
|
||||
write!(f, ")")?;
|
||||
} else {
|
||||
generic_args.args[0].hir_fmt(f, types_map)?;
|
||||
generic_args.args[0].hir_fmt(f, store)?;
|
||||
}
|
||||
}
|
||||
if let Some(ret) = generic_args.bindings[0].type_ref {
|
||||
if !matches!(&types_map[ret], TypeRef::Tuple(v) if v.is_empty()) {
|
||||
if !matches!(&store[ret], TypeRef::Tuple(v) if v.is_empty()) {
|
||||
write!(f, " -> ")?;
|
||||
ret.hir_fmt(f, types_map)?;
|
||||
ret.hir_fmt(f, store)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
hir_def::path::GenericArgsParentheses::No => {
|
||||
hir_def::expr_store::path::GenericArgsParentheses::No => {
|
||||
let mut first = true;
|
||||
// Skip the `Self` bound if exists. It's handled outside the loop.
|
||||
for arg in &generic_args.args[generic_args.has_self_type as usize..] {
|
||||
|
|
@ -2345,7 +2390,7 @@ impl HirDisplayWithTypesMap for Path {
|
|||
} else {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
arg.hir_fmt(f, types_map)?;
|
||||
arg.hir_fmt(f, store)?;
|
||||
}
|
||||
for binding in generic_args.bindings.iter() {
|
||||
if first {
|
||||
|
|
@ -2358,12 +2403,15 @@ impl HirDisplayWithTypesMap for Path {
|
|||
match &binding.type_ref {
|
||||
Some(ty) => {
|
||||
write!(f, " = ")?;
|
||||
ty.hir_fmt(f, types_map)?
|
||||
ty.hir_fmt(f, store)?
|
||||
}
|
||||
None => {
|
||||
write!(f, ": ")?;
|
||||
f.write_joined(
|
||||
binding.bounds.iter().map(TypesMapAdapter::wrap(types_map)),
|
||||
binding
|
||||
.bounds
|
||||
.iter()
|
||||
.map(ExpressionStoreAdapter::wrap(store)),
|
||||
" + ",
|
||||
)?;
|
||||
}
|
||||
|
|
@ -2389,18 +2437,19 @@ impl HirDisplayWithTypesMap for Path {
|
|||
}
|
||||
}
|
||||
|
||||
impl HirDisplayWithTypesMap for hir_def::path::GenericArg {
|
||||
impl HirDisplayWithExpressionStore for hir_def::expr_store::path::GenericArg {
|
||||
fn hir_fmt(
|
||||
&self,
|
||||
f: &mut HirFormatter<'_>,
|
||||
types_map: &TypesMap,
|
||||
store: &ExpressionStore,
|
||||
) -> Result<(), HirDisplayError> {
|
||||
match self {
|
||||
hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f, types_map),
|
||||
hir_def::path::GenericArg::Const(c) => {
|
||||
write!(f, "{}", c.display(f.db.upcast(), f.edition()))
|
||||
hir_def::expr_store::path::GenericArg::Type(ty) => ty.hir_fmt(f, store),
|
||||
hir_def::expr_store::path::GenericArg::Const(_c) => {
|
||||
// write!(f, "{}", c.display(f.db.upcast(), f.edition()))
|
||||
write!(f, "<expr>")
|
||||
}
|
||||
hir_def::path::GenericArg::Lifetime(lifetime) => {
|
||||
hir_def::expr_store::path::GenericArg::Lifetime(lifetime) => {
|
||||
write!(f, "{}", lifetime.name.display(f.db.upcast(), f.edition()))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
use chalk_ir::cast::Cast;
|
||||
use hir_def::AdtId;
|
||||
use hir_def::data::adt::StructFlags;
|
||||
use hir_def::lang_item::LangItem;
|
||||
use hir_def::signatures::StructFlags;
|
||||
use stdx::never;
|
||||
use triomphe::Arc;
|
||||
|
||||
|
|
@ -32,7 +32,6 @@ fn has_destructor(db: &dyn HirDatabase, adt: AdtId) -> bool {
|
|||
},
|
||||
None => db.trait_impls_in_crate(module.krate()),
|
||||
};
|
||||
|
||||
impls.for_trait_and_self_ty(drop_trait, TyFingerprint::Adt(adt)).next().is_some()
|
||||
}
|
||||
|
||||
|
|
@ -55,7 +54,7 @@ pub(crate) fn has_drop_glue(db: &dyn HirDatabase, ty: Ty, env: Arc<TraitEnvironm
|
|||
}
|
||||
match adt.0 {
|
||||
AdtId::StructId(id) => {
|
||||
if db.struct_data(id).flags.contains(StructFlags::IS_MANUALLY_DROP) {
|
||||
if db.struct_signature(id).flags.contains(StructFlags::IS_MANUALLY_DROP) {
|
||||
return DropGlue::None;
|
||||
}
|
||||
db.field_types(id.into())
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use chalk_ir::{
|
|||
use chalk_solve::rust_ir::InlineBound;
|
||||
use hir_def::{
|
||||
AssocItemId, ConstId, FunctionId, GenericDefId, HasModule, TraitId, TypeAliasId,
|
||||
data::TraitFlags, lang_item::LangItem,
|
||||
lang_item::LangItem, signatures::TraitFlags,
|
||||
};
|
||||
use rustc_hash::FxHashSet;
|
||||
use smallvec::SmallVec;
|
||||
|
|
@ -369,7 +369,7 @@ fn virtual_call_violations_for_method<F>(
|
|||
where
|
||||
F: FnMut(MethodViolationCode) -> ControlFlow<()>,
|
||||
{
|
||||
let func_data = db.function_data(func);
|
||||
let func_data = db.function_signature(func);
|
||||
if !func_data.has_self_param() {
|
||||
cb(MethodViolationCode::StaticMethod)?;
|
||||
}
|
||||
|
|
@ -429,7 +429,7 @@ where
|
|||
|
||||
// Allow `impl AutoTrait` predicates
|
||||
if let WhereClause::Implemented(TraitRef { trait_id, substitution }) = pred {
|
||||
let trait_data = db.trait_data(from_chalk_trait_id(*trait_id));
|
||||
let trait_data = db.trait_signature(from_chalk_trait_id(*trait_id));
|
||||
if trait_data.flags.contains(TraitFlags::IS_AUTO)
|
||||
&& substitution
|
||||
.as_slice(Interner)
|
||||
|
|
|
|||
|
|
@ -40,8 +40,11 @@ fn check_dyn_compatibility<'a>(
|
|||
.declarations()
|
||||
.filter_map(|def| {
|
||||
if let hir_def::ModuleDefId::TraitId(trait_id) = def {
|
||||
let name =
|
||||
db.trait_data(trait_id).name.display_no_db(file_id.edition()).to_smolstr();
|
||||
let name = db
|
||||
.trait_signature(trait_id)
|
||||
.name
|
||||
.display_no_db(file_id.edition())
|
||||
.to_smolstr();
|
||||
Some((trait_id, name))
|
||||
} else {
|
||||
None
|
||||
|
|
|
|||
|
|
@ -11,14 +11,14 @@ use std::ops;
|
|||
|
||||
use chalk_ir::{BoundVar, DebruijnIndex, cast::Cast as _};
|
||||
use hir_def::{
|
||||
ConstParamId, GenericDefId, GenericParamId, ItemContainerId, LifetimeParamId,
|
||||
LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
|
||||
ConstParamId, GenericDefId, GenericParamId, ItemContainerId, LifetimeParamId, Lookup,
|
||||
TypeOrConstParamId, TypeParamId,
|
||||
db::DefDatabase,
|
||||
generics::{
|
||||
GenericParamDataRef, GenericParams, LifetimeParamData, TypeOrConstParamData,
|
||||
TypeParamProvenance,
|
||||
expr_store::ExpressionStore,
|
||||
hir::generics::{
|
||||
GenericParamDataRef, GenericParams, LifetimeParamData, LocalLifetimeParamId,
|
||||
LocalTypeOrConstParamId, TypeOrConstParamData, TypeParamProvenance, WherePredicate,
|
||||
},
|
||||
type_ref::TypesMap,
|
||||
};
|
||||
use itertools::chain;
|
||||
use stdx::TupleExt;
|
||||
|
|
@ -28,14 +28,15 @@ use crate::{Interner, Substitution, db::HirDatabase, lt_to_placeholder_idx, to_p
|
|||
|
||||
pub fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
|
||||
let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
|
||||
let params = db.generic_params(def);
|
||||
let (params, store) = db.generic_params_and_store(def);
|
||||
let has_trait_self_param = params.trait_self_param().is_some();
|
||||
Generics { def, params, parent_generics, has_trait_self_param }
|
||||
Generics { def, params, parent_generics, has_trait_self_param, store }
|
||||
}
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Generics {
|
||||
def: GenericDefId,
|
||||
params: Arc<GenericParams>,
|
||||
store: Arc<ExpressionStore>,
|
||||
parent_generics: Option<Box<Generics>>,
|
||||
has_trait_self_param: bool,
|
||||
}
|
||||
|
|
@ -55,8 +56,12 @@ impl Generics {
|
|||
self.def
|
||||
}
|
||||
|
||||
pub(crate) fn self_types_map(&self) -> &TypesMap {
|
||||
&self.params.types_map
|
||||
pub(crate) fn store(&self) -> &ExpressionStore {
|
||||
&self.store
|
||||
}
|
||||
|
||||
pub(crate) fn where_predicates(&self) -> impl Iterator<Item = &WherePredicate> {
|
||||
self.params.where_predicates()
|
||||
}
|
||||
|
||||
pub(crate) fn iter_id(&self) -> impl Iterator<Item = GenericParamId> + '_ {
|
||||
|
|
@ -71,12 +76,6 @@ impl Generics {
|
|||
self.iter_parent().map(|(id, _)| id)
|
||||
}
|
||||
|
||||
pub(crate) fn iter_self_type_or_consts(
|
||||
&self,
|
||||
) -> impl DoubleEndedIterator<Item = (LocalTypeOrConstParamId, &TypeOrConstParamData)> {
|
||||
self.params.iter_type_or_consts()
|
||||
}
|
||||
|
||||
pub(crate) fn iter_self_type_or_consts_id(
|
||||
&self,
|
||||
) -> impl DoubleEndedIterator<Item = GenericParamId> + '_ {
|
||||
|
|
@ -90,14 +89,12 @@ impl Generics {
|
|||
self.iter_self().chain(self.iter_parent())
|
||||
}
|
||||
|
||||
pub(crate) fn iter_parents_with_types_map(
|
||||
pub(crate) fn iter_parents_with_store(
|
||||
&self,
|
||||
) -> impl Iterator<Item = ((GenericParamId, GenericParamDataRef<'_>), &TypesMap)> + '_ {
|
||||
self.iter_parent().zip(
|
||||
self.parent_generics()
|
||||
.into_iter()
|
||||
.flat_map(|it| std::iter::repeat(&it.params.types_map)),
|
||||
)
|
||||
) -> impl Iterator<Item = ((GenericParamId, GenericParamDataRef<'_>), &ExpressionStore)> + '_
|
||||
{
|
||||
self.iter_parent()
|
||||
.zip(self.parent_generics().into_iter().flat_map(|it| std::iter::repeat(&*it.store)))
|
||||
}
|
||||
|
||||
/// Iterate over the params without parent params.
|
||||
|
|
@ -160,7 +157,12 @@ impl Generics {
|
|||
fn find_type_or_const_param(&self, param: TypeOrConstParamId) -> Option<usize> {
|
||||
if param.parent == self.def {
|
||||
let idx = param.local_id.into_raw().into_u32() as usize;
|
||||
debug_assert!(idx <= self.params.len_type_or_consts());
|
||||
debug_assert!(
|
||||
idx <= self.params.len_type_or_consts(),
|
||||
"idx: {} len: {}",
|
||||
idx,
|
||||
self.params.len_type_or_consts()
|
||||
);
|
||||
if self.params.trait_self_param() == Some(param.local_id) {
|
||||
return Some(idx);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,19 +34,18 @@ use chalk_ir::{
|
|||
};
|
||||
use either::Either;
|
||||
use hir_def::{
|
||||
AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, ImplId, ItemContainerId, Lookup,
|
||||
TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId,
|
||||
AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, GenericDefId, ImplId, ItemContainerId,
|
||||
Lookup, TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId,
|
||||
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
|
||||
data::{ConstData, StaticData},
|
||||
expr_store::{Body, HygieneId},
|
||||
expr_store::{Body, ExpressionStore, HygieneId, path::Path},
|
||||
hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId},
|
||||
lang_item::{LangItem, LangItemTarget},
|
||||
layout::Integer,
|
||||
path::{ModPath, Path},
|
||||
resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
|
||||
type_ref::{LifetimeRef, TypeRefId, TypesMap},
|
||||
signatures::{ConstSignature, StaticSignature},
|
||||
type_ref::{ConstRef, LifetimeRef, TypeRefId},
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
use hir_expand::{mod_path::ModPath, name::Name};
|
||||
use indexmap::IndexSet;
|
||||
use intern::sym;
|
||||
use la_arena::{ArenaMap, Entry};
|
||||
|
|
@ -71,7 +70,7 @@ use crate::{
|
|||
mir::MirSpan,
|
||||
to_assoc_type_id,
|
||||
traits::FnTrait,
|
||||
utils::{InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder},
|
||||
utils::UnevaluatedConstEvaluatorFolder,
|
||||
};
|
||||
|
||||
// This lint has a false positive here. See the link below for details.
|
||||
|
|
@ -96,11 +95,11 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer
|
|||
DefWithBodyId::FunctionId(f) => {
|
||||
ctx.collect_fn(f);
|
||||
}
|
||||
DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_data(c)),
|
||||
DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)),
|
||||
DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_signature(c)),
|
||||
DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_signature(s)),
|
||||
DefWithBodyId::VariantId(v) => {
|
||||
ctx.return_ty = TyBuilder::builtin(
|
||||
match db.enum_data(v.lookup(db.upcast()).parent).variant_body_type() {
|
||||
match db.enum_signature(v.lookup(db.upcast()).parent).variant_body_type() {
|
||||
hir_def::layout::IntegerType::Pointer(signed) => match signed {
|
||||
true => BuiltinType::Int(BuiltinInt::Isize),
|
||||
false => BuiltinType::Uint(BuiltinUint::Usize),
|
||||
|
|
@ -124,16 +123,6 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer
|
|||
},
|
||||
);
|
||||
}
|
||||
DefWithBodyId::InTypeConstId(c) => {
|
||||
// FIXME(const-generic-body): We should not get the return type in this way.
|
||||
ctx.return_ty = c
|
||||
.lookup(db.upcast())
|
||||
.expected_ty
|
||||
.box_any()
|
||||
.downcast::<InTypeConstIdMetadata>()
|
||||
.unwrap()
|
||||
.0;
|
||||
}
|
||||
}
|
||||
|
||||
ctx.infer_body();
|
||||
|
|
@ -597,7 +586,8 @@ pub(crate) struct InferenceContext<'a> {
|
|||
/// Generally you should not resolve things via this resolver. Instead create a TyLoweringContext
|
||||
/// and resolve the path via its methods. This will ensure proper error reporting.
|
||||
pub(crate) resolver: Resolver,
|
||||
generics: OnceCell<Option<Generics>>,
|
||||
generic_def: GenericDefId,
|
||||
generics: OnceCell<Generics>,
|
||||
table: unify::InferenceTable<'a>,
|
||||
/// The traits in scope, disregarding block modules. This is used for caching purposes.
|
||||
traits_in_scope: FxHashSet<TraitId>,
|
||||
|
|
@ -708,6 +698,12 @@ impl<'a> InferenceContext<'a> {
|
|||
return_coercion: None,
|
||||
db,
|
||||
owner,
|
||||
generic_def: match owner {
|
||||
DefWithBodyId::FunctionId(it) => it.into(),
|
||||
DefWithBodyId::StaticId(it) => it.into(),
|
||||
DefWithBodyId::ConstId(it) => it.into(),
|
||||
DefWithBodyId::VariantId(it) => it.lookup(db.upcast()).parent.into(),
|
||||
},
|
||||
body,
|
||||
traits_in_scope: resolver.traits_in_scope(db.upcast()),
|
||||
resolver,
|
||||
|
|
@ -724,14 +720,8 @@ impl<'a> InferenceContext<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn generics(&self) -> Option<&Generics> {
|
||||
self.generics
|
||||
.get_or_init(|| {
|
||||
self.resolver
|
||||
.generic_def()
|
||||
.map(|def| crate::generics::generics(self.db.upcast(), def))
|
||||
})
|
||||
.as_ref()
|
||||
pub(crate) fn generics(&self) -> &Generics {
|
||||
self.generics.get_or_init(|| crate::generics::generics(self.db.upcast(), self.generic_def))
|
||||
}
|
||||
|
||||
// FIXME: This function should be private in module. It is currently only used in the consteval, since we need
|
||||
|
|
@ -894,9 +884,9 @@ impl<'a> InferenceContext<'a> {
|
|||
result
|
||||
}
|
||||
|
||||
fn collect_const(&mut self, data: &ConstData) {
|
||||
fn collect_const(&mut self, data: &ConstSignature) {
|
||||
let return_ty =
|
||||
self.make_ty(data.type_ref, &data.types_map, InferenceTyDiagnosticSource::Signature);
|
||||
self.make_ty(data.type_ref, &data.store, InferenceTyDiagnosticSource::Signature);
|
||||
|
||||
// Constants might be defining usage sites of TAITs.
|
||||
self.make_tait_coercion_table(iter::once(&return_ty));
|
||||
|
|
@ -904,9 +894,9 @@ impl<'a> InferenceContext<'a> {
|
|||
self.return_ty = return_ty;
|
||||
}
|
||||
|
||||
fn collect_static(&mut self, data: &StaticData) {
|
||||
fn collect_static(&mut self, data: &StaticSignature) {
|
||||
let return_ty =
|
||||
self.make_ty(data.type_ref, &data.types_map, InferenceTyDiagnosticSource::Signature);
|
||||
self.make_ty(data.type_ref, &data.store, InferenceTyDiagnosticSource::Signature);
|
||||
|
||||
// Statics might be defining usage sites of TAITs.
|
||||
self.make_tait_coercion_table(iter::once(&return_ty));
|
||||
|
|
@ -915,13 +905,13 @@ impl<'a> InferenceContext<'a> {
|
|||
}
|
||||
|
||||
fn collect_fn(&mut self, func: FunctionId) {
|
||||
let data = self.db.function_data(func);
|
||||
let data = self.db.function_signature(func);
|
||||
let mut param_tys =
|
||||
self.with_ty_lowering(&data.types_map, InferenceTyDiagnosticSource::Signature, |ctx| {
|
||||
ctx.type_param_mode(ParamLoweringMode::Placeholder)
|
||||
.impl_trait_mode(ImplTraitLoweringMode::Param);
|
||||
self.with_ty_lowering(&data.store, InferenceTyDiagnosticSource::Signature, |ctx| {
|
||||
ctx.type_param_mode(ParamLoweringMode::Placeholder);
|
||||
data.params.iter().map(|&type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>()
|
||||
});
|
||||
|
||||
// Check if function contains a va_list, if it does then we append it to the parameter types
|
||||
// that are collected from the function data
|
||||
if data.is_varargs() {
|
||||
|
|
@ -956,22 +946,27 @@ impl<'a> InferenceContext<'a> {
|
|||
tait_candidates.insert(ty);
|
||||
}
|
||||
}
|
||||
let return_ty = data.ret_type;
|
||||
|
||||
let return_ty =
|
||||
self.with_ty_lowering(&data.types_map, InferenceTyDiagnosticSource::Signature, |ctx| {
|
||||
let return_ty = match data.ret_type {
|
||||
Some(return_ty) => {
|
||||
let return_ty = self.with_ty_lowering(
|
||||
&data.store,
|
||||
InferenceTyDiagnosticSource::Signature,
|
||||
|ctx| {
|
||||
ctx.type_param_mode(ParamLoweringMode::Placeholder)
|
||||
.impl_trait_mode(ImplTraitLoweringMode::Opaque)
|
||||
.lower_ty(return_ty)
|
||||
});
|
||||
},
|
||||
);
|
||||
let return_ty = self.insert_type_vars(return_ty);
|
||||
|
||||
let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) {
|
||||
if let Some(rpits) = self.db.return_type_impl_traits(func) {
|
||||
// RPIT opaque types use substitution of their parent function.
|
||||
let fn_placeholders = TyBuilder::placeholder_subst(self.db, func);
|
||||
let mut mode = ImplTraitReplacingMode::ReturnPosition(FxHashSet::default());
|
||||
let result =
|
||||
self.insert_inference_vars_for_impl_trait(return_ty, fn_placeholders, &mut mode);
|
||||
let result = self.insert_inference_vars_for_impl_trait(
|
||||
return_ty,
|
||||
fn_placeholders,
|
||||
&mut mode,
|
||||
);
|
||||
if let ImplTraitReplacingMode::ReturnPosition(taits) = mode {
|
||||
tait_candidates.extend(taits);
|
||||
}
|
||||
|
|
@ -985,6 +980,9 @@ impl<'a> InferenceContext<'a> {
|
|||
result
|
||||
} else {
|
||||
return_ty
|
||||
}
|
||||
}
|
||||
None => self.result.standard_types.unit.clone(),
|
||||
};
|
||||
|
||||
self.return_ty = self.normalize_associated_types_in(return_ty);
|
||||
|
|
@ -1287,38 +1285,54 @@ impl<'a> InferenceContext<'a> {
|
|||
|
||||
fn with_ty_lowering<R>(
|
||||
&mut self,
|
||||
types_map: &TypesMap,
|
||||
store: &ExpressionStore,
|
||||
types_source: InferenceTyDiagnosticSource,
|
||||
f: impl FnOnce(&mut TyLoweringContext<'_>) -> R,
|
||||
) -> R {
|
||||
let mut ctx = TyLoweringContext::new(
|
||||
self.db,
|
||||
&self.resolver,
|
||||
types_map,
|
||||
self.owner.into(),
|
||||
store,
|
||||
&self.diagnostics,
|
||||
types_source,
|
||||
self.generic_def,
|
||||
);
|
||||
f(&mut ctx)
|
||||
}
|
||||
|
||||
fn with_body_ty_lowering<R>(&mut self, f: impl FnOnce(&mut TyLoweringContext<'_>) -> R) -> R {
|
||||
self.with_ty_lowering(&self.body.types, InferenceTyDiagnosticSource::Body, f)
|
||||
self.with_ty_lowering(self.body, InferenceTyDiagnosticSource::Body, f)
|
||||
}
|
||||
|
||||
fn make_ty(
|
||||
&mut self,
|
||||
type_ref: TypeRefId,
|
||||
types_map: &TypesMap,
|
||||
store: &ExpressionStore,
|
||||
type_source: InferenceTyDiagnosticSource,
|
||||
) -> Ty {
|
||||
let ty = self.with_ty_lowering(types_map, type_source, |ctx| ctx.lower_ty(type_ref));
|
||||
let ty = self.with_ty_lowering(store, type_source, |ctx| ctx.lower_ty(type_ref));
|
||||
let ty = self.insert_type_vars(ty);
|
||||
self.normalize_associated_types_in(ty)
|
||||
}
|
||||
|
||||
fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty {
|
||||
self.make_ty(type_ref, &self.body.types, InferenceTyDiagnosticSource::Body)
|
||||
self.make_ty(type_ref, self.body, InferenceTyDiagnosticSource::Body)
|
||||
}
|
||||
|
||||
fn make_body_const(&mut self, const_ref: ConstRef, ty: Ty) -> Const {
|
||||
let const_ = self.with_ty_lowering(self.body, InferenceTyDiagnosticSource::Body, |ctx| {
|
||||
ctx.type_param_mode = ParamLoweringMode::Placeholder;
|
||||
ctx.lower_const(&const_ref, ty)
|
||||
});
|
||||
self.insert_type_vars(const_)
|
||||
}
|
||||
|
||||
fn make_path_as_body_const(&mut self, path: &Path, ty: Ty) -> Const {
|
||||
let const_ = self.with_ty_lowering(self.body, InferenceTyDiagnosticSource::Body, |ctx| {
|
||||
ctx.type_param_mode = ParamLoweringMode::Placeholder;
|
||||
ctx.lower_path_as_const(path, ty)
|
||||
});
|
||||
self.insert_type_vars(const_)
|
||||
}
|
||||
|
||||
fn err_ty(&self) -> Ty {
|
||||
|
|
@ -1326,7 +1340,7 @@ impl<'a> InferenceContext<'a> {
|
|||
}
|
||||
|
||||
fn make_body_lifetime(&mut self, lifetime_ref: &LifetimeRef) -> Lifetime {
|
||||
let lt = self.with_ty_lowering(TypesMap::EMPTY, InferenceTyDiagnosticSource::Body, |ctx| {
|
||||
let lt = self.with_ty_lowering(self.body, InferenceTyDiagnosticSource::Body, |ctx| {
|
||||
ctx.lower_lifetime(lifetime_ref)
|
||||
});
|
||||
self.insert_type_vars(lt)
|
||||
|
|
@ -1494,10 +1508,10 @@ impl<'a> InferenceContext<'a> {
|
|||
let mut ctx = TyLoweringContext::new(
|
||||
self.db,
|
||||
&self.resolver,
|
||||
&self.body.types,
|
||||
self.owner.into(),
|
||||
&self.body.store,
|
||||
&self.diagnostics,
|
||||
InferenceTyDiagnosticSource::Body,
|
||||
self.generic_def,
|
||||
);
|
||||
let mut path_ctx = ctx.at_path(path, node);
|
||||
let (resolution, unresolved) = if value_ns {
|
||||
|
|
|
|||
|
|
@ -389,7 +389,7 @@ fn pointer_kind(ty: &Ty, table: &mut InferenceTable<'_>) -> Result<Option<Pointe
|
|||
return Err(());
|
||||
};
|
||||
|
||||
let struct_data = table.db.variant_data(id.into());
|
||||
let struct_data = table.db.variant_fields(id.into());
|
||||
if let Some((last_field, _)) = struct_data.fields().iter().last() {
|
||||
let last_field_ty =
|
||||
table.db.field_types(id.into())[last_field].clone().substitute(Interner, subst);
|
||||
|
|
|
|||
|
|
@ -10,13 +10,13 @@ use chalk_ir::{
|
|||
use either::Either;
|
||||
use hir_def::{
|
||||
DefWithBodyId, FieldId, HasModule, TupleFieldId, TupleId, VariantId,
|
||||
data::adt::VariantData,
|
||||
expr_store::path::Path,
|
||||
hir::{
|
||||
Array, AsmOperand, BinaryOp, BindingId, CaptureBy, Expr, ExprId, ExprOrPatId, Pat, PatId,
|
||||
Statement, UnaryOp,
|
||||
},
|
||||
item_tree::FieldsShape,
|
||||
lang_item::LangItem,
|
||||
path::Path,
|
||||
resolver::ValueNs,
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
|
|
@ -283,18 +283,20 @@ impl CapturedItem {
|
|||
match proj {
|
||||
ProjectionElem::Deref => {}
|
||||
ProjectionElem::Field(Either::Left(f)) => {
|
||||
match &*f.parent.variant_data(db.upcast()) {
|
||||
VariantData::Record { fields, .. } => {
|
||||
let variant_data = f.parent.variant_data(db.upcast());
|
||||
match variant_data.shape {
|
||||
FieldsShape::Record => {
|
||||
result.push('_');
|
||||
result.push_str(fields[f.local_id].name.as_str())
|
||||
result.push_str(variant_data.fields()[f.local_id].name.as_str())
|
||||
}
|
||||
VariantData::Tuple { fields, .. } => {
|
||||
let index = fields.iter().position(|it| it.0 == f.local_id);
|
||||
FieldsShape::Tuple => {
|
||||
let index =
|
||||
variant_data.fields().iter().position(|it| it.0 == f.local_id);
|
||||
if let Some(index) = index {
|
||||
format_to!(result, "_{index}");
|
||||
}
|
||||
}
|
||||
VariantData::Unit => {}
|
||||
FieldsShape::Unit => {}
|
||||
}
|
||||
}
|
||||
ProjectionElem::Field(Either::Right(f)) => format_to!(result, "_{}", f.index),
|
||||
|
|
@ -325,18 +327,22 @@ impl CapturedItem {
|
|||
ProjectionElem::Deref => {}
|
||||
ProjectionElem::Field(Either::Left(f)) => {
|
||||
let variant_data = f.parent.variant_data(db.upcast());
|
||||
match &*variant_data {
|
||||
VariantData::Record { fields, .. } => format_to!(
|
||||
match variant_data.shape {
|
||||
FieldsShape::Record => format_to!(
|
||||
result,
|
||||
".{}",
|
||||
fields[f.local_id].name.display(db.upcast(), edition)
|
||||
variant_data.fields()[f.local_id].name.display(db.upcast(), edition)
|
||||
),
|
||||
VariantData::Tuple { fields, .. } => format_to!(
|
||||
FieldsShape::Tuple => format_to!(
|
||||
result,
|
||||
".{}",
|
||||
fields.iter().position(|it| it.0 == f.local_id).unwrap_or_default()
|
||||
variant_data
|
||||
.fields()
|
||||
.iter()
|
||||
.position(|it| it.0 == f.local_id)
|
||||
.unwrap_or_default()
|
||||
),
|
||||
VariantData::Unit => {}
|
||||
FieldsShape::Unit => {}
|
||||
}
|
||||
}
|
||||
ProjectionElem::Field(Either::Right(f)) => {
|
||||
|
|
@ -383,16 +389,17 @@ impl CapturedItem {
|
|||
result = format!("({result})");
|
||||
}
|
||||
let variant_data = f.parent.variant_data(db.upcast());
|
||||
let field = match &*variant_data {
|
||||
VariantData::Record { fields, .. } => {
|
||||
fields[f.local_id].name.as_str().to_owned()
|
||||
let field = match variant_data.shape {
|
||||
FieldsShape::Record => {
|
||||
variant_data.fields()[f.local_id].name.as_str().to_owned()
|
||||
}
|
||||
VariantData::Tuple { fields, .. } => fields
|
||||
FieldsShape::Tuple => variant_data
|
||||
.fields()
|
||||
.iter()
|
||||
.position(|it| it.0 == f.local_id)
|
||||
.unwrap_or_default()
|
||||
.to_string(),
|
||||
VariantData::Unit => "[missing field]".to_owned(),
|
||||
FieldsShape::Unit => "[missing field]".to_owned(),
|
||||
};
|
||||
result = format!("{result}.{field}");
|
||||
field_need_paren = false;
|
||||
|
|
@ -494,10 +501,7 @@ impl CapturedItemWithoutTy {
|
|||
Ok(BoundVar::new(outer_binder, idx).to_ty(Interner))
|
||||
}
|
||||
}
|
||||
let Some(generics) = ctx.generics() else {
|
||||
return Binders::empty(Interner, ty);
|
||||
};
|
||||
let filler = &mut Filler { db: ctx.db, generics };
|
||||
let filler = &mut Filler { db: ctx.db, generics: ctx.generics() };
|
||||
let result = ty.clone().try_fold_with(filler, DebruijnIndex::INNERMOST).unwrap_or(ty);
|
||||
make_binders(ctx.db, filler.generics, result)
|
||||
}
|
||||
|
|
@ -518,7 +522,6 @@ impl InferenceContext<'_> {
|
|||
return None;
|
||||
}
|
||||
let hygiene = self.body.expr_or_pat_path_hygiene(id);
|
||||
|
||||
self.resolver.resolve_path_in_value_ns_fully(self.db.upcast(), path, hygiene).and_then(
|
||||
|result| match result {
|
||||
ValueNs::LocalBinding(binding) => {
|
||||
|
|
@ -1159,7 +1162,7 @@ impl InferenceContext<'_> {
|
|||
self.consume_place(place)
|
||||
}
|
||||
VariantId::StructId(s) => {
|
||||
let vd = &*self.db.variant_data(s.into());
|
||||
let vd = &*self.db.variant_fields(s.into());
|
||||
for field_pat in args.iter() {
|
||||
let arg = field_pat.pat;
|
||||
let Some(local_id) = vd.field(&field_pat.name) else {
|
||||
|
|
@ -1211,7 +1214,7 @@ impl InferenceContext<'_> {
|
|||
self.consume_place(place)
|
||||
}
|
||||
VariantId::StructId(s) => {
|
||||
let vd = &*self.db.variant_data(s.into());
|
||||
let vd = &*self.db.variant_fields(s.into());
|
||||
let (al, ar) =
|
||||
args.split_at(ellipsis.map_or(args.len(), |it| it as usize));
|
||||
let fields = vd.fields().iter();
|
||||
|
|
|
|||
|
|
@ -6,7 +6,10 @@ use std::cell::RefCell;
|
|||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use either::Either;
|
||||
use hir_def::{TypeOwnerId, hir::ExprOrPatId, path::Path, resolver::Resolver, type_ref::TypesMap};
|
||||
use hir_def::GenericDefId;
|
||||
use hir_def::expr_store::ExpressionStore;
|
||||
use hir_def::expr_store::path::Path;
|
||||
use hir_def::{hir::ExprOrPatId, resolver::Resolver};
|
||||
use la_arena::{Idx, RawIdx};
|
||||
|
||||
use crate::{
|
||||
|
|
@ -58,12 +61,12 @@ impl<'a> InferenceTyLoweringContext<'a> {
|
|||
pub(super) fn new(
|
||||
db: &'a dyn HirDatabase,
|
||||
resolver: &'a Resolver,
|
||||
types_map: &'a TypesMap,
|
||||
owner: TypeOwnerId,
|
||||
store: &'a ExpressionStore,
|
||||
diagnostics: &'a Diagnostics,
|
||||
source: InferenceTyDiagnosticSource,
|
||||
generic_def: GenericDefId,
|
||||
) -> Self {
|
||||
Self { ctx: TyLoweringContext::new(db, resolver, types_map, owner), diagnostics, source }
|
||||
Self { ctx: TyLoweringContext::new(db, resolver, store, generic_def), diagnostics, source }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -9,12 +9,12 @@ use chalk_ir::{DebruijnIndex, Mutability, TyVariableKind, cast::Cast, fold::Shif
|
|||
use either::Either;
|
||||
use hir_def::{
|
||||
BlockId, FieldId, GenericDefId, GenericParamId, ItemContainerId, Lookup, TupleFieldId, TupleId,
|
||||
expr_store::path::{GenericArg, GenericArgs, Path},
|
||||
hir::{
|
||||
ArithOp, Array, AsmOperand, AsmOptions, BinaryOp, ClosureKind, Expr, ExprId, ExprOrPatId,
|
||||
LabelId, Literal, Pat, PatId, Statement, UnaryOp,
|
||||
},
|
||||
lang_item::{LangItem, LangItemTarget},
|
||||
path::{GenericArg, GenericArgs, Path},
|
||||
resolver::ValueNs,
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
|
|
@ -38,9 +38,7 @@ use crate::{
|
|||
pat::contains_explicit_ref_binding,
|
||||
},
|
||||
lang_items::lang_items_for_bin_op,
|
||||
lower::{
|
||||
ParamLoweringMode, const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability,
|
||||
},
|
||||
lower::{ParamLoweringMode, generic_arg_to_chalk, lower_to_chalk_mutability},
|
||||
mapping::{ToChalk, from_chalk},
|
||||
method_resolution::{self, VisibleFromModule},
|
||||
primitive::{self, UintTy},
|
||||
|
|
@ -349,8 +347,7 @@ impl InferenceContext<'_> {
|
|||
}
|
||||
Expr::Const(id) => {
|
||||
self.with_breakable_ctx(BreakableKind::Border, None, None, |this| {
|
||||
let loc = this.db.lookup_intern_anonymous_const(*id);
|
||||
this.infer_expr(loc.root, expected, ExprIsRead::Yes)
|
||||
this.infer_expr(*id, expected, ExprIsRead::Yes)
|
||||
})
|
||||
.1
|
||||
}
|
||||
|
|
@ -920,6 +917,7 @@ impl InferenceContext<'_> {
|
|||
.map_or((self.err_ty(), Vec::new()), |adj| {
|
||||
adj.apply(&mut self.table, base_ty)
|
||||
});
|
||||
|
||||
// mutability will be fixed up in `InferenceContext::infer_mut`;
|
||||
adj.push(Adjustment::borrow(
|
||||
Mutability::Not,
|
||||
|
|
@ -1676,12 +1674,12 @@ impl InferenceContext<'_> {
|
|||
});
|
||||
}
|
||||
&TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), ref parameters) => {
|
||||
let local_id = self.db.variant_data(s.into()).field(name)?;
|
||||
let local_id = self.db.variant_fields(s.into()).field(name)?;
|
||||
let field = FieldId { parent: s.into(), local_id };
|
||||
(field, parameters.clone())
|
||||
}
|
||||
&TyKind::Adt(AdtId(hir_def::AdtId::UnionId(u)), ref parameters) => {
|
||||
let local_id = self.db.variant_data(u.into()).field(name)?;
|
||||
let local_id = self.db.variant_fields(u.into()).field(name)?;
|
||||
let field = FieldId { parent: u.into(), local_id };
|
||||
(field, parameters.clone())
|
||||
}
|
||||
|
|
@ -2212,20 +2210,10 @@ impl InferenceContext<'_> {
|
|||
kind_id,
|
||||
args.next().unwrap(), // `peek()` is `Some(_)`, so guaranteed no panic
|
||||
self,
|
||||
&self.body.types,
|
||||
&self.body.store,
|
||||
|this, type_ref| this.make_body_ty(type_ref),
|
||||
|this, c, ty| {
|
||||
const_or_path_to_chalk(
|
||||
this.db,
|
||||
&this.resolver,
|
||||
this.owner.into(),
|
||||
ty,
|
||||
c,
|
||||
ParamLoweringMode::Placeholder,
|
||||
|| this.generics(),
|
||||
DebruijnIndex::INNERMOST,
|
||||
)
|
||||
},
|
||||
|this, c, ty| this.make_body_const(*c, ty),
|
||||
|this, path, ty| this.make_path_as_body_const(path, ty),
|
||||
|this, lt_ref| this.make_body_lifetime(lt_ref),
|
||||
),
|
||||
};
|
||||
|
|
@ -2305,7 +2293,7 @@ impl InferenceContext<'_> {
|
|||
_ => return Default::default(),
|
||||
};
|
||||
|
||||
let data = self.db.function_data(func);
|
||||
let data = self.db.function_signature(func);
|
||||
let Some(legacy_const_generics_indices) = &data.legacy_const_generics_indices else {
|
||||
return Default::default();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -69,8 +69,7 @@ impl InferenceContext<'_> {
|
|||
}
|
||||
}
|
||||
Expr::Const(id) => {
|
||||
let loc = self.db.lookup_intern_anonymous_const(*id);
|
||||
self.infer_mut_expr(loc.root, Mutability::Not);
|
||||
self.infer_mut_expr(*id, Mutability::Not);
|
||||
}
|
||||
Expr::Let { pat, expr } => self.infer_mut_expr(*expr, self.pat_bound_mutability(*pat)),
|
||||
Expr::Block { id: _, statements, tail, label: _ }
|
||||
|
|
|
|||
|
|
@ -4,9 +4,8 @@ use std::iter::repeat_with;
|
|||
|
||||
use hir_def::{
|
||||
HasModule,
|
||||
expr_store::Body,
|
||||
expr_store::{Body, path::Path},
|
||||
hir::{Binding, BindingAnnotation, BindingId, Expr, ExprId, Literal, Pat, PatId},
|
||||
path::Path,
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
use stdx::TupleExt;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
use chalk_ir::cast::Cast;
|
||||
use hir_def::{
|
||||
AdtId, AssocItemId, GenericDefId, ItemContainerId, Lookup,
|
||||
path::{Path, PathSegment},
|
||||
expr_store::path::{Path, PathSegment},
|
||||
resolver::{ResolveValueResult, TypeNs, ValueNs},
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
|
|
@ -159,10 +159,10 @@ impl InferenceContext<'_> {
|
|||
let mut ctx = TyLoweringContext::new(
|
||||
self.db,
|
||||
&self.resolver,
|
||||
&self.body.types,
|
||||
self.owner.into(),
|
||||
self.body,
|
||||
&self.diagnostics,
|
||||
InferenceTyDiagnosticSource::Body,
|
||||
self.generic_def,
|
||||
);
|
||||
let mut path_ctx = if no_diagnostics {
|
||||
ctx.at_path_forget_diagnostics(path)
|
||||
|
|
@ -281,7 +281,7 @@ impl InferenceContext<'_> {
|
|||
self.db.trait_items(trait_).items.iter().map(|(_name, id)| *id).find_map(|item| {
|
||||
match item {
|
||||
AssocItemId::FunctionId(func) => {
|
||||
if segment.name == &self.db.function_data(func).name {
|
||||
if segment.name == &self.db.function_signature(func).name {
|
||||
Some(AssocItemId::FunctionId(func))
|
||||
} else {
|
||||
None
|
||||
|
|
@ -289,7 +289,7 @@ impl InferenceContext<'_> {
|
|||
}
|
||||
|
||||
AssocItemId::ConstId(konst) => {
|
||||
if self.db.const_data(konst).name.as_ref() == Some(segment.name) {
|
||||
if self.db.const_signature(konst).name.as_ref() == Some(segment.name) {
|
||||
Some(AssocItemId::ConstId(konst))
|
||||
} else {
|
||||
None
|
||||
|
|
|
|||
|
|
@ -924,7 +924,7 @@ impl<'a> InferenceTable<'a> {
|
|||
// Must use a loop here and not recursion because otherwise users will conduct completely
|
||||
// artificial examples of structs that have themselves as the tail field and complain r-a crashes.
|
||||
while let Some((AdtId::StructId(id), subst)) = ty.as_adt() {
|
||||
let struct_data = self.db.variant_data(id.into());
|
||||
let struct_data = self.db.variant_fields(id.into());
|
||||
if let Some((last_field, _)) = struct_data.fields().iter().next_back() {
|
||||
let last_field_ty = self.db.field_types(id.into())[last_field]
|
||||
.clone()
|
||||
|
|
@ -1027,7 +1027,6 @@ mod resolve {
|
|||
.assert_ty_ref(Interner)
|
||||
.clone();
|
||||
}
|
||||
|
||||
if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
|
||||
// known_ty may contain other variables that are known by now
|
||||
self.var_stack.push(var);
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ impl UninhabitedFrom<'_> {
|
|||
variant: VariantId,
|
||||
subst: &Substitution,
|
||||
) -> ControlFlow<VisiblyUninhabited> {
|
||||
let variant_data = self.db.variant_data(variant);
|
||||
let variant_data = self.db.variant_fields(variant);
|
||||
let fields = variant_data.fields();
|
||||
if fields.is_empty() {
|
||||
return CONTINUE_OPAQUELY_INHABITED;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Functions to detect special lang items
|
||||
|
||||
use hir_def::{AdtId, data::adt::StructFlags, lang_item::LangItem};
|
||||
use hir_def::{AdtId, lang_item::LangItem, signatures::StructFlags};
|
||||
use hir_expand::name::Name;
|
||||
use intern::sym;
|
||||
|
||||
|
|
@ -8,13 +8,13 @@ use crate::db::HirDatabase;
|
|||
|
||||
pub fn is_box(db: &dyn HirDatabase, adt: AdtId) -> bool {
|
||||
let AdtId::StructId(id) = adt else { return false };
|
||||
db.struct_data(id).flags.contains(StructFlags::IS_BOX)
|
||||
db.struct_signature(id).flags.contains(StructFlags::IS_BOX)
|
||||
}
|
||||
|
||||
pub fn is_unsafe_cell(db: &dyn HirDatabase, adt: AdtId) -> bool {
|
||||
let AdtId::StructId(id) = adt else { return false };
|
||||
|
||||
db.struct_data(id).flags.contains(StructFlags::IS_UNSAFE_CELL)
|
||||
db.struct_signature(id).flags.contains(StructFlags::IS_UNSAFE_CELL)
|
||||
}
|
||||
|
||||
pub fn lang_items_for_bin_op(op: syntax::ast::BinaryOp) -> Option<(Name, LangItem)> {
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ pub fn layout_of_ty_query(
|
|||
let result = match kind {
|
||||
TyKind::Adt(AdtId(def), subst) => {
|
||||
if let hir_def::AdtId::StructId(s) = def {
|
||||
let data = db.struct_data(*s);
|
||||
let data = db.struct_signature(*s);
|
||||
let repr = data.repr.unwrap_or_default();
|
||||
if repr.simd() {
|
||||
return layout_of_simd_ty(db, *s, repr.packed(), subst, trait_env, &target);
|
||||
|
|
@ -378,7 +378,7 @@ pub(crate) fn layout_of_ty_recover(
|
|||
fn struct_tail_erasing_lifetimes(db: &dyn HirDatabase, pointee: Ty) -> Ty {
|
||||
match pointee.kind(Interner) {
|
||||
&TyKind::Adt(AdtId(hir_def::AdtId::StructId(i)), ref subst) => {
|
||||
let data = db.variant_data(i.into());
|
||||
let data = db.variant_fields(i.into());
|
||||
let mut it = data.fields().iter().rev();
|
||||
match it.next() {
|
||||
Some((f, _)) => {
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ use std::{cmp, ops::Bound};
|
|||
|
||||
use hir_def::{
|
||||
AdtId, VariantId,
|
||||
data::adt::VariantData,
|
||||
layout::{Integer, ReprOptions, TargetDataLayout},
|
||||
signatures::VariantFields,
|
||||
};
|
||||
use intern::sym;
|
||||
use rustc_index::IndexVec;
|
||||
|
|
@ -34,7 +34,7 @@ pub fn layout_of_adt_query(
|
|||
};
|
||||
let dl = &*target;
|
||||
let cx = LayoutCx::new(dl);
|
||||
let handle_variant = |def: VariantId, var: &VariantData| {
|
||||
let handle_variant = |def: VariantId, var: &VariantFields| {
|
||||
var.fields()
|
||||
.iter()
|
||||
.map(|(fd, _)| db.layout_of_ty(field_ty(db, def, fd, &subst), trait_env.clone()))
|
||||
|
|
@ -42,15 +42,15 @@ pub fn layout_of_adt_query(
|
|||
};
|
||||
let (variants, repr) = match def {
|
||||
AdtId::StructId(s) => {
|
||||
let data = db.struct_data(s);
|
||||
let data = db.struct_signature(s);
|
||||
let mut r = SmallVec::<[_; 1]>::new();
|
||||
r.push(handle_variant(s.into(), &db.variant_data(s.into()))?);
|
||||
r.push(handle_variant(s.into(), &db.variant_fields(s.into()))?);
|
||||
(r, data.repr.unwrap_or_default())
|
||||
}
|
||||
AdtId::UnionId(id) => {
|
||||
let data = db.union_data(id);
|
||||
let data = db.union_signature(id);
|
||||
let mut r = SmallVec::new();
|
||||
r.push(handle_variant(id.into(), &db.variant_data(id.into()))?);
|
||||
r.push(handle_variant(id.into(), &db.variant_fields(id.into()))?);
|
||||
(r, data.repr.unwrap_or_default())
|
||||
}
|
||||
AdtId::EnumId(e) => {
|
||||
|
|
@ -58,9 +58,9 @@ pub fn layout_of_adt_query(
|
|||
let r = variants
|
||||
.variants
|
||||
.iter()
|
||||
.map(|&(v, _)| handle_variant(v.into(), &db.variant_data(v.into())))
|
||||
.map(|&(v, _)| handle_variant(v.into(), &db.variant_fields(v.into())))
|
||||
.collect::<Result<SmallVec<_>, _>>()?;
|
||||
(r, db.enum_data(e).repr.unwrap_or_default())
|
||||
(r, db.enum_signature(e).repr.unwrap_or_default())
|
||||
}
|
||||
};
|
||||
let variants = variants
|
||||
|
|
|
|||
|
|
@ -44,21 +44,26 @@ fn eval_goal(
|
|||
let adt_or_type_alias_id = scope.declarations().find_map(|x| match x {
|
||||
hir_def::ModuleDefId::AdtId(x) => {
|
||||
let name = match x {
|
||||
hir_def::AdtId::StructId(x) => {
|
||||
db.struct_data(x).name.display_no_db(file_id.edition()).to_smolstr()
|
||||
}
|
||||
hir_def::AdtId::StructId(x) => db
|
||||
.struct_signature(x)
|
||||
.name
|
||||
.display_no_db(file_id.edition())
|
||||
.to_smolstr(),
|
||||
hir_def::AdtId::UnionId(x) => {
|
||||
db.union_data(x).name.display_no_db(file_id.edition()).to_smolstr()
|
||||
db.union_signature(x).name.display_no_db(file_id.edition()).to_smolstr()
|
||||
}
|
||||
hir_def::AdtId::EnumId(x) => {
|
||||
db.enum_data(x).name.display_no_db(file_id.edition()).to_smolstr()
|
||||
db.enum_signature(x).name.display_no_db(file_id.edition()).to_smolstr()
|
||||
}
|
||||
};
|
||||
(name == "Goal").then_some(Either::Left(x))
|
||||
}
|
||||
hir_def::ModuleDefId::TypeAliasId(x) => {
|
||||
let name =
|
||||
db.type_alias_data(x).name.display_no_db(file_id.edition()).to_smolstr();
|
||||
let name = db
|
||||
.type_alias_signature(x)
|
||||
.name
|
||||
.display_no_db(file_id.edition())
|
||||
.to_smolstr();
|
||||
(name == "Goal").then_some(Either::Right(x))
|
||||
}
|
||||
_ => None,
|
||||
|
|
@ -101,7 +106,8 @@ fn eval_expr(
|
|||
.declarations()
|
||||
.find_map(|x| match x {
|
||||
hir_def::ModuleDefId::FunctionId(x) => {
|
||||
let name = db.function_data(x).name.display_no_db(file_id.edition()).to_smolstr();
|
||||
let name =
|
||||
db.function_signature(x).name.display_no_db(file_id.edition()).to_smolstr();
|
||||
(name == "main").then_some(x)
|
||||
}
|
||||
_ => None,
|
||||
|
|
@ -512,10 +518,7 @@ fn niche_optimization() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn const_eval() {
|
||||
size_and_align! {
|
||||
struct Goal([i32; 2 + 2]);
|
||||
}
|
||||
fn const_eval_simple() {
|
||||
size_and_align! {
|
||||
const X: usize = 5;
|
||||
struct Goal([i32; X]);
|
||||
|
|
@ -527,6 +530,15 @@ fn const_eval() {
|
|||
struct Ar<T>([T; foo::BAR]);
|
||||
struct Goal(Ar<Ar<i32>>);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
// FIXME
|
||||
#[should_panic]
|
||||
fn const_eval_complex() {
|
||||
size_and_align! {
|
||||
struct Goal([i32; 2 + 2]);
|
||||
}
|
||||
size_and_align! {
|
||||
type Goal = [u8; 2 + 2];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1022,15 +1022,6 @@ pub fn known_const_to_ast(
|
|||
db: &dyn HirDatabase,
|
||||
display_target: DisplayTarget,
|
||||
) -> Option<ConstArg> {
|
||||
if let ConstValue::Concrete(c) = &konst.interned().value {
|
||||
match c.interned {
|
||||
ConstScalar::UnevaluatedConst(GeneralConstId::InTypeConstId(cid), _) => {
|
||||
return Some(cid.source(db.upcast()));
|
||||
}
|
||||
ConstScalar::Unknown => return None,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
Some(make::expr_const_value(konst.display(db, display_target).to_string().as_str()))
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,13 +1,10 @@
|
|||
//! This files contains the declaration of diagnostics kinds for ty and path lowering.
|
||||
|
||||
use either::Either;
|
||||
use hir_def::type_ref::TypeRefId;
|
||||
|
||||
type TypeSource = Either<TypeRefId, hir_def::type_ref::TypeSource>;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub struct TyLoweringDiagnostic {
|
||||
pub source: TypeSource,
|
||||
pub source: TypeRefId,
|
||||
pub kind: TyLoweringDiagnosticKind,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,12 +6,13 @@ use chalk_ir::{BoundVar, cast::Cast, fold::Shift};
|
|||
use either::Either;
|
||||
use hir_def::{
|
||||
GenericDefId, GenericParamId, ItemContainerId, Lookup, TraitId,
|
||||
data::TraitFlags,
|
||||
expr_store::HygieneId,
|
||||
generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
|
||||
expr_store::{
|
||||
HygieneId,
|
||||
path::{GenericArg, GenericArgs, GenericArgsParentheses, Path, PathSegment, PathSegments},
|
||||
},
|
||||
resolver::{ResolveValueResult, TypeNs, ValueNs},
|
||||
type_ref::{TypeBound, TypeRef, TypesMap},
|
||||
signatures::TraitFlags,
|
||||
type_ref::TypeRef,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
use stdx::never;
|
||||
|
|
@ -23,9 +24,7 @@ use crate::{
|
|||
consteval::unknown_const_as_generic,
|
||||
error_lifetime,
|
||||
generics::generics,
|
||||
lower::{
|
||||
ImplTraitLoweringState, generic_arg_to_chalk, named_associated_type_shorthand_candidates,
|
||||
},
|
||||
lower::{generic_arg_to_chalk, named_associated_type_shorthand_candidates},
|
||||
to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
|
||||
utils::associated_type_by_name_including_super_traits,
|
||||
};
|
||||
|
|
@ -228,12 +227,7 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
|
|||
TyKind::Placeholder(to_placeholder_idx(self.ctx.db, param_id.into()))
|
||||
}
|
||||
ParamLoweringMode::Variable => {
|
||||
let idx = match self
|
||||
.ctx
|
||||
.generics()
|
||||
.expect("generics in scope")
|
||||
.type_or_const_param_idx(param_id.into())
|
||||
{
|
||||
let idx = match self.ctx.generics().type_or_const_param_idx(param_id.into()) {
|
||||
None => {
|
||||
never!("no matching generics");
|
||||
return (TyKind::Error.intern(Interner), None);
|
||||
|
|
@ -246,7 +240,7 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
|
|||
}
|
||||
.intern(Interner),
|
||||
TypeNs::SelfType(impl_id) => {
|
||||
let generics = self.ctx.generics().expect("impl should have generic param scope");
|
||||
let generics = self.ctx.generics();
|
||||
|
||||
match self.ctx.type_param_mode {
|
||||
ParamLoweringMode::Placeholder => {
|
||||
|
|
@ -480,21 +474,20 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
|
|||
}
|
||||
|
||||
fn select_associated_type(&mut self, res: Option<TypeNs>) -> Ty {
|
||||
let Some((generics, res)) = self.ctx.generics().zip(res) else {
|
||||
let Some(res) = res else {
|
||||
return TyKind::Error.intern(Interner);
|
||||
};
|
||||
let segment = self.current_or_prev_segment;
|
||||
let ty = named_associated_type_shorthand_candidates(
|
||||
self.ctx.db,
|
||||
generics.def(),
|
||||
self.ctx.def,
|
||||
res,
|
||||
Some(segment.name.clone()),
|
||||
move |name, t, associated_ty| {
|
||||
let generics = self.ctx.generics().unwrap();
|
||||
|
||||
if name != segment.name {
|
||||
return None;
|
||||
}
|
||||
let generics = self.ctx.generics();
|
||||
|
||||
let parent_subst = t.substitution.clone();
|
||||
let parent_subst = match self.ctx.type_param_mode {
|
||||
|
|
@ -612,8 +605,12 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
|
|||
self.current_or_prev_segment.args_and_bindings.is_some_and(|generics| {
|
||||
generics.parenthesized == GenericArgsParentheses::ReturnTypeNotation
|
||||
});
|
||||
let is_fn_trait =
|
||||
!self.ctx.db.trait_data(trait_).flags.contains(TraitFlags::RUSTC_PAREN_SUGAR);
|
||||
let is_fn_trait = !self
|
||||
.ctx
|
||||
.db
|
||||
.trait_signature(trait_)
|
||||
.flags
|
||||
.contains(TraitFlags::RUSTC_PAREN_SUGAR);
|
||||
is_rtn || is_fn_trait
|
||||
}
|
||||
_ => true,
|
||||
|
|
@ -719,9 +716,10 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
|
|||
id,
|
||||
arg,
|
||||
self.ctx,
|
||||
self.ctx.types_map,
|
||||
self.ctx.store,
|
||||
|ctx, type_ref| ctx.lower_ty(type_ref),
|
||||
|ctx, const_ref, ty| ctx.lower_const(const_ref, ty),
|
||||
|ctx, path, ty| ctx.lower_path_as_const(path, ty),
|
||||
|ctx, lifetime_ref| ctx.lower_lifetime(lifetime_ref),
|
||||
);
|
||||
substs.push(arg);
|
||||
|
|
@ -795,7 +793,6 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
|
|||
|
||||
pub(super) fn assoc_type_bindings_from_type_bound<'c>(
|
||||
mut self,
|
||||
bound: &'c TypeBound,
|
||||
trait_ref: TraitRef,
|
||||
) -> Option<impl Iterator<Item = QuantifiedWhereClause> + use<'a, 'b, 'c>> {
|
||||
self.current_or_prev_segment.args_and_bindings.map(|args_and_bindings| {
|
||||
|
|
@ -819,7 +816,8 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
|
|||
false, // this is not relevant
|
||||
Some(super_trait_ref.self_type_parameter(Interner)),
|
||||
);
|
||||
let self_params = generics(self.ctx.db.upcast(), associated_ty.into()).len_self();
|
||||
let generics = generics(self.ctx.db.upcast(), associated_ty.into());
|
||||
let self_params = generics.len_self();
|
||||
let substitution = Substitution::from_iter(
|
||||
Interner,
|
||||
substitution
|
||||
|
|
@ -835,7 +833,7 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
|
|||
binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
|
||||
);
|
||||
if let Some(type_ref) = binding.type_ref {
|
||||
match (&self.ctx.types_map[type_ref], self.ctx.impl_trait_mode.mode) {
|
||||
match (&self.ctx.store[type_ref], self.ctx.impl_trait_mode.mode) {
|
||||
(TypeRef::ImplTrait(_), ImplTraitLoweringMode::Disallowed) => (),
|
||||
(_, ImplTraitLoweringMode::Disallowed | ImplTraitLoweringMode::Opaque) => {
|
||||
let ty = self.ctx.lower_ty(type_ref);
|
||||
|
|
@ -844,72 +842,6 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
|
|||
predicates
|
||||
.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
|
||||
}
|
||||
(_, ImplTraitLoweringMode::Param | ImplTraitLoweringMode::Variable) => {
|
||||
// Find the generic index for the target of our `bound`
|
||||
let target_param_idx =
|
||||
self.ctx.resolver.where_predicates_in_scope().find_map(
|
||||
|(p, (_, types_map))| match p {
|
||||
WherePredicate::TypeBound {
|
||||
target: WherePredicateTypeTarget::TypeOrConstParam(idx),
|
||||
bound: b,
|
||||
} if std::ptr::eq::<TypesMap>(
|
||||
self.ctx.types_map,
|
||||
types_map,
|
||||
) && bound == b =>
|
||||
{
|
||||
Some(idx)
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
);
|
||||
let ty = if let Some(target_param_idx) = target_param_idx {
|
||||
let mut counter = 0;
|
||||
let generics = self.ctx.generics().expect("generics in scope");
|
||||
for (idx, data) in generics.iter_self_type_or_consts() {
|
||||
// Count the number of `impl Trait` things that appear before
|
||||
// the target of our `bound`.
|
||||
// Our counter within `impl_trait_mode` should be that number
|
||||
// to properly lower each types within `type_ref`
|
||||
if data.type_param().is_some_and(|p| {
|
||||
p.provenance == TypeParamProvenance::ArgumentImplTrait
|
||||
}) {
|
||||
counter += 1;
|
||||
}
|
||||
if idx == *target_param_idx {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let mut ext = TyLoweringContext::new_maybe_unowned(
|
||||
self.ctx.db,
|
||||
self.ctx.resolver,
|
||||
self.ctx.types_map,
|
||||
self.ctx.types_source_map,
|
||||
self.ctx.owner,
|
||||
)
|
||||
.with_type_param_mode(self.ctx.type_param_mode);
|
||||
match self.ctx.impl_trait_mode.mode {
|
||||
ImplTraitLoweringMode::Param => {
|
||||
ext.impl_trait_mode =
|
||||
ImplTraitLoweringState::param(counter);
|
||||
}
|
||||
ImplTraitLoweringMode::Variable => {
|
||||
ext.impl_trait_mode =
|
||||
ImplTraitLoweringState::variable(counter);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
let ty = ext.lower_ty(type_ref);
|
||||
self.ctx.diagnostics.extend(ext.diagnostics);
|
||||
ty
|
||||
} else {
|
||||
self.ctx.lower_ty(type_ref)
|
||||
};
|
||||
|
||||
let alias_eq =
|
||||
AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
|
||||
predicates
|
||||
.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
|
||||
}
|
||||
}
|
||||
}
|
||||
for bound in binding.bounds.iter() {
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ use chalk_ir::{UniverseIndex, WithKind, cast::Cast};
|
|||
use hir_def::{
|
||||
AssocItemId, BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup,
|
||||
ModuleId, TraitId,
|
||||
data::{TraitFlags, adt::StructFlags},
|
||||
nameres::{DefMap, assoc::ImplItems},
|
||||
signatures::{ConstFlags, EnumFlags, FnFlags, StructFlags, TraitFlags, TypeAliasFlags},
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
use intern::sym;
|
||||
|
|
@ -313,7 +313,7 @@ impl InherentImpls {
|
|||
fn collect_def_map(&mut self, db: &dyn HirDatabase, def_map: &DefMap) {
|
||||
for (_module_id, module_data) in def_map.modules() {
|
||||
for impl_id in module_data.scope.impls() {
|
||||
let data = db.impl_data(impl_id);
|
||||
let data = db.impl_signature(impl_id);
|
||||
if data.target_trait.is_some() {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -384,14 +384,17 @@ pub fn def_crates(db: &dyn HirDatabase, ty: &Ty, cur_crate: Crate) -> Option<Sma
|
|||
&TyKind::Adt(AdtId(def_id), _) => {
|
||||
let rustc_has_incoherent_inherent_impls = match def_id {
|
||||
hir_def::AdtId::StructId(id) => db
|
||||
.struct_data(id)
|
||||
.struct_signature(id)
|
||||
.flags
|
||||
.contains(StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL),
|
||||
.contains(StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPLS),
|
||||
hir_def::AdtId::UnionId(id) => db
|
||||
.union_data(id)
|
||||
.union_signature(id)
|
||||
.flags
|
||||
.contains(StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL),
|
||||
hir_def::AdtId::EnumId(id) => db.enum_data(id).rustc_has_incoherent_inherent_impls,
|
||||
.contains(StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPLS),
|
||||
hir_def::AdtId::EnumId(id) => db
|
||||
.enum_signature(id)
|
||||
.flags
|
||||
.contains(EnumFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPLS),
|
||||
};
|
||||
Some(if rustc_has_incoherent_inherent_impls {
|
||||
db.incoherent_inherent_impl_crates(cur_crate, TyFingerprint::Adt(def_id))
|
||||
|
|
@ -401,17 +404,23 @@ pub fn def_crates(db: &dyn HirDatabase, ty: &Ty, cur_crate: Crate) -> Option<Sma
|
|||
}
|
||||
&TyKind::Foreign(id) => {
|
||||
let alias = from_foreign_def_id(id);
|
||||
Some(if db.type_alias_data(alias).rustc_has_incoherent_inherent_impls() {
|
||||
Some(
|
||||
if db
|
||||
.type_alias_signature(alias)
|
||||
.flags
|
||||
.contains(TypeAliasFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS)
|
||||
{
|
||||
db.incoherent_inherent_impl_crates(cur_crate, TyFingerprint::ForeignType(id))
|
||||
} else {
|
||||
smallvec![alias.module(db.upcast()).krate()]
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
TyKind::Dyn(_) => {
|
||||
let trait_id = ty.dyn_trait()?;
|
||||
Some(
|
||||
if db
|
||||
.trait_data(trait_id)
|
||||
.trait_signature(trait_id)
|
||||
.flags
|
||||
.contains(TraitFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS)
|
||||
{
|
||||
|
|
@ -618,8 +627,8 @@ pub fn lookup_impl_const(
|
|||
let substitution = Substitution::from_iter(Interner, subs.iter(Interner));
|
||||
let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution };
|
||||
|
||||
let const_data = db.const_data(const_id);
|
||||
let name = match const_data.name.as_ref() {
|
||||
let const_signature = db.const_signature(const_id);
|
||||
let name = match const_signature.name.as_ref() {
|
||||
Some(name) => name,
|
||||
None => return (const_id, subs),
|
||||
};
|
||||
|
|
@ -691,7 +700,7 @@ pub(crate) fn lookup_impl_method_query(
|
|||
substitution: Substitution::from_iter(Interner, fn_subst.iter(Interner).skip(fn_params)),
|
||||
};
|
||||
|
||||
let name = &db.function_data(func).name;
|
||||
let name = &db.function_signature(func).name;
|
||||
let Some((impl_fn, impl_subst)) =
|
||||
lookup_impl_assoc_item_for_trait_ref(trait_ref, db, env, name).and_then(|assoc| {
|
||||
if let (AssocItemId::FunctionId(id), subst) = assoc { Some((id, subst)) } else { None }
|
||||
|
|
@ -822,17 +831,20 @@ fn is_inherent_impl_coherent(
|
|||
|
||||
&TyKind::Adt(AdtId(adt), _) => match adt {
|
||||
hir_def::AdtId::StructId(id) => db
|
||||
.struct_data(id)
|
||||
.struct_signature(id)
|
||||
.flags
|
||||
.contains(StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL),
|
||||
.contains(StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPLS),
|
||||
hir_def::AdtId::UnionId(id) => db
|
||||
.union_data(id)
|
||||
.union_signature(id)
|
||||
.flags
|
||||
.contains(StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL),
|
||||
hir_def::AdtId::EnumId(it) => db.enum_data(it).rustc_has_incoherent_inherent_impls,
|
||||
.contains(StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPLS),
|
||||
hir_def::AdtId::EnumId(it) => db
|
||||
.enum_signature(it)
|
||||
.flags
|
||||
.contains(EnumFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPLS),
|
||||
},
|
||||
TyKind::Dyn(it) => it.principal_id().is_some_and(|trait_id| {
|
||||
db.trait_data(from_chalk_trait_id(trait_id))
|
||||
db.trait_signature(from_chalk_trait_id(trait_id))
|
||||
.flags
|
||||
.contains(TraitFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS)
|
||||
}),
|
||||
|
|
@ -843,11 +855,16 @@ fn is_inherent_impl_coherent(
|
|||
rustc_has_incoherent_inherent_impls
|
||||
&& !items.items.is_empty()
|
||||
&& items.items.iter().all(|&(_, assoc)| match assoc {
|
||||
AssocItemId::FunctionId(it) => db.function_data(it).rustc_allow_incoherent_impl(),
|
||||
AssocItemId::ConstId(it) => db.const_data(it).rustc_allow_incoherent_impl(),
|
||||
AssocItemId::TypeAliasId(it) => {
|
||||
db.type_alias_data(it).rustc_allow_incoherent_impl()
|
||||
AssocItemId::FunctionId(it) => {
|
||||
db.function_signature(it).flags.contains(FnFlags::RUSTC_ALLOW_INCOHERENT_IMPLS)
|
||||
}
|
||||
AssocItemId::ConstId(it) => {
|
||||
db.const_signature(it).flags.contains(ConstFlags::RUSTC_ALLOW_INCOHERENT_IMPL)
|
||||
}
|
||||
AssocItemId::TypeAliasId(it) => db
|
||||
.type_alias_signature(it)
|
||||
.flags
|
||||
.contains(TypeAliasFlags::RUSTC_ALLOW_INCOHERENT_IMPLS),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -882,8 +899,8 @@ pub fn check_orphan_rules(db: &dyn HirDatabase, impl_: ImplId) -> bool {
|
|||
match ty.kind(Interner) {
|
||||
TyKind::Ref(_, _, referenced) => ty = referenced.clone(),
|
||||
&TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), ref subs) => {
|
||||
let struct_data = db.struct_data(s);
|
||||
if struct_data.flags.contains(StructFlags::IS_FUNDAMENTAL) {
|
||||
let struct_signature = db.struct_signature(s);
|
||||
if struct_signature.flags.contains(StructFlags::IS_FUNDAMENTAL) {
|
||||
let next = subs.type_parameters(Interner).next();
|
||||
match next {
|
||||
Some(it) => ty = it,
|
||||
|
|
@ -901,7 +918,7 @@ pub fn check_orphan_rules(db: &dyn HirDatabase, impl_: ImplId) -> bool {
|
|||
|
||||
// FIXME: param coverage
|
||||
// - No uncovered type parameters `P1..=Pn` may appear in `T0..Ti`` (excluding `Ti`)
|
||||
trait_ref.substitution.type_parameters(Interner).any(|ty| {
|
||||
let is_not_orphan = trait_ref.substitution.type_parameters(Interner).any(|ty| {
|
||||
match unwrap_fundamental(ty).kind(Interner) {
|
||||
&TyKind::Adt(AdtId(id), _) => is_local(id.module(db.upcast()).krate()),
|
||||
TyKind::Error => true,
|
||||
|
|
@ -910,7 +927,9 @@ pub fn check_orphan_rules(db: &dyn HirDatabase, impl_: ImplId) -> bool {
|
|||
}),
|
||||
_ => false,
|
||||
}
|
||||
})
|
||||
});
|
||||
#[allow(clippy::let_and_return)]
|
||||
is_not_orphan
|
||||
}
|
||||
|
||||
pub fn iterate_path_candidates(
|
||||
|
|
@ -1206,7 +1225,7 @@ fn iterate_trait_method_candidates(
|
|||
let TraitEnvironment { krate, block, .. } = *table.trait_env;
|
||||
|
||||
'traits: for &t in traits_in_scope {
|
||||
let data = db.trait_data(t);
|
||||
let data = db.trait_signature(t);
|
||||
|
||||
// Traits annotated with `#[rustc_skip_during_method_dispatch]` are skipped during
|
||||
// method resolution, if the receiver is an array, and we're compiling for editions before
|
||||
|
|
@ -1521,7 +1540,7 @@ fn is_valid_trait_method_candidate(
|
|||
let db = table.db;
|
||||
match item {
|
||||
AssocItemId::FunctionId(fn_id) => {
|
||||
let data = db.function_data(fn_id);
|
||||
let data = db.function_signature(fn_id);
|
||||
|
||||
check_that!(name.is_none_or(|n| n == &data.name));
|
||||
|
||||
|
|
@ -1552,7 +1571,7 @@ fn is_valid_trait_method_candidate(
|
|||
}
|
||||
AssocItemId::ConstId(c) => {
|
||||
check_that!(receiver_ty.is_none());
|
||||
check_that!(name.is_none_or(|n| db.const_data(c).name.as_ref() == Some(n)));
|
||||
check_that!(name.is_none_or(|n| db.const_signature(c).name.as_ref() == Some(n)));
|
||||
|
||||
IsValidCandidate::Yes
|
||||
}
|
||||
|
|
@ -1574,7 +1593,7 @@ fn is_valid_impl_fn_candidate(
|
|||
check_that!(name.is_none_or(|n| n == item_name));
|
||||
|
||||
let db = table.db;
|
||||
let data = db.function_data(fn_id);
|
||||
let data = db.function_signature(fn_id);
|
||||
|
||||
if let Some(from_module) = visible_from_module {
|
||||
if !db.function_visibility(fn_id).is_visible_from(db.upcast(), from_module) {
|
||||
|
|
|
|||
|
|
@ -9,11 +9,12 @@ use hir_def::{
|
|||
AdtId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, StaticId,
|
||||
VariantId,
|
||||
builtin_type::BuiltinType,
|
||||
data::adt::{StructFlags, VariantData},
|
||||
expr_store::HygieneId,
|
||||
item_tree::FieldsShape,
|
||||
lang_item::LangItem,
|
||||
layout::{TagEncoding, Variants},
|
||||
resolver::{HasResolver, TypeNs, ValueNs},
|
||||
signatures::{StaticFlags, StructFlags},
|
||||
};
|
||||
use hir_expand::{HirFileIdExt, InFile, mod_path::path, name::Name};
|
||||
use intern::sym;
|
||||
|
|
@ -368,7 +369,7 @@ impl MirEvalError {
|
|||
for (func, span, def) in stack.iter().take(30).rev() {
|
||||
match func {
|
||||
Either::Left(func) => {
|
||||
let function_name = db.function_data(*func);
|
||||
let function_name = db.function_signature(*func);
|
||||
writeln!(
|
||||
f,
|
||||
"In function {} ({:?})",
|
||||
|
|
@ -421,7 +422,7 @@ impl MirEvalError {
|
|||
)?;
|
||||
}
|
||||
MirEvalError::MirLowerError(func, err) => {
|
||||
let function_name = db.function_data(*func);
|
||||
let function_name = db.function_signature(*func);
|
||||
let self_ = match func.lookup(db.upcast()).container {
|
||||
ItemContainerId::ImplId(impl_id) => Some({
|
||||
let generics = crate::generics::generics(db.upcast(), impl_id.into());
|
||||
|
|
@ -432,7 +433,7 @@ impl MirEvalError {
|
|||
.to_string()
|
||||
}),
|
||||
ItemContainerId::TraitId(it) => Some(
|
||||
db.trait_data(it)
|
||||
db.trait_signature(it)
|
||||
.name
|
||||
.display(db.upcast(), display_target.edition)
|
||||
.to_string(),
|
||||
|
|
@ -1761,7 +1762,7 @@ impl Evaluator<'_> {
|
|||
AdtId::EnumId(_) => not_supported!("unsizing enums"),
|
||||
};
|
||||
let Some((last_field, _)) =
|
||||
self.db.variant_data(id.into()).fields().iter().next_back()
|
||||
self.db.variant_fields(id.into()).fields().iter().next_back()
|
||||
else {
|
||||
not_supported!("unsizing struct without field");
|
||||
};
|
||||
|
|
@ -2243,7 +2244,7 @@ impl Evaluator<'_> {
|
|||
}
|
||||
chalk_ir::TyKind::Adt(adt, subst) => match adt.0 {
|
||||
AdtId::StructId(s) => {
|
||||
let data = this.db.variant_data(s.into());
|
||||
let data = this.db.variant_fields(s.into());
|
||||
let layout = this.layout(ty)?;
|
||||
let field_types = this.db.field_types(s.into());
|
||||
for (f, _) in data.fields().iter() {
|
||||
|
|
@ -2272,7 +2273,7 @@ impl Evaluator<'_> {
|
|||
bytes,
|
||||
e,
|
||||
) {
|
||||
let data = &this.db.variant_data(v.into());
|
||||
let data = &this.db.variant_fields(v.into());
|
||||
let field_types = this.db.field_types(v.into());
|
||||
for (f, _) in data.fields().iter() {
|
||||
let offset =
|
||||
|
|
@ -2755,8 +2756,8 @@ impl Evaluator<'_> {
|
|||
if let Some(o) = self.static_locations.get(&st) {
|
||||
return Ok(*o);
|
||||
};
|
||||
let static_data = self.db.static_data(st);
|
||||
let result = if !static_data.is_extern() {
|
||||
let static_data = self.db.static_signature(st);
|
||||
let result = if !static_data.flags.contains(StaticFlags::IS_EXTERN) {
|
||||
let konst = self.db.const_eval_static(st).map_err(|e| {
|
||||
MirEvalError::ConstEvalError(static_data.name.as_str().to_owned(), Box::new(e))
|
||||
})?;
|
||||
|
|
@ -2843,16 +2844,16 @@ impl Evaluator<'_> {
|
|||
TyKind::Adt(id, subst) => {
|
||||
match id.0 {
|
||||
AdtId::StructId(s) => {
|
||||
let data = self.db.struct_data(s);
|
||||
let data = self.db.struct_signature(s);
|
||||
if data.flags.contains(StructFlags::IS_MANUALLY_DROP) {
|
||||
return Ok(());
|
||||
}
|
||||
let layout = self.layout_adt(id.0, subst.clone())?;
|
||||
match self.db.variant_data(s.into()).as_ref() {
|
||||
VariantData::Record { fields, .. }
|
||||
| VariantData::Tuple { fields, .. } => {
|
||||
let variant_fields = self.db.variant_fields(s.into());
|
||||
match variant_fields.shape {
|
||||
FieldsShape::Record | FieldsShape::Tuple => {
|
||||
let field_types = self.db.field_types(s.into());
|
||||
for (field, _) in fields.iter() {
|
||||
for (field, _) in variant_fields.fields().iter() {
|
||||
let offset = layout
|
||||
.fields
|
||||
.offset(u32::from(field.into_raw()) as usize)
|
||||
|
|
@ -2862,7 +2863,7 @@ impl Evaluator<'_> {
|
|||
self.run_drop_glue_deep(ty, locals, addr, &[], span)?;
|
||||
}
|
||||
}
|
||||
VariantData::Unit => (),
|
||||
FieldsShape::Unit => (),
|
||||
}
|
||||
}
|
||||
AdtId::UnionId(_) => (), // union fields don't need drop
|
||||
|
|
@ -2923,7 +2924,7 @@ pub fn render_const_using_debug_impl(
|
|||
let resolver = owner.resolver(db.upcast());
|
||||
let Some(TypeNs::TraitId(debug_trait)) = resolver.resolve_path_in_type_ns_fully(
|
||||
db.upcast(),
|
||||
&hir_def::path::Path::from_known_path_with_no_generic(path![core::fmt::Debug]),
|
||||
&hir_def::expr_store::path::Path::from_known_path_with_no_generic(path![core::fmt::Debug]),
|
||||
) else {
|
||||
not_supported!("core::fmt::Debug not found");
|
||||
};
|
||||
|
|
@ -2954,7 +2955,7 @@ pub fn render_const_using_debug_impl(
|
|||
evaluator.write_memory(a3.offset(3 * evaluator.ptr_size()), &[1])?;
|
||||
let Some(ValueNs::FunctionId(format_fn)) = resolver.resolve_path_in_value_ns_fully(
|
||||
db.upcast(),
|
||||
&hir_def::path::Path::from_known_path_with_no_generic(path![std::fmt::format]),
|
||||
&hir_def::expr_store::path::Path::from_known_path_with_no_generic(path![std::fmt::format]),
|
||||
HygieneId::ROOT,
|
||||
) else {
|
||||
not_supported!("std::fmt::format not found");
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ impl Evaluator<'_> {
|
|||
return Ok(false);
|
||||
}
|
||||
|
||||
let function_data = self.db.function_data(def);
|
||||
let function_data = self.db.function_signature(def);
|
||||
let attrs = self.db.attrs(def.into());
|
||||
let is_intrinsic = attrs.by_key(&sym::rustc_intrinsic).exists()
|
||||
// Keep this around for a bit until extern "rustc-intrinsic" abis are no longer used
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ impl Evaluator<'_> {
|
|||
Some(len) => len,
|
||||
_ => {
|
||||
if let AdtId::StructId(id) = id.0 {
|
||||
let struct_data = self.db.variant_data(id.into());
|
||||
let struct_data = self.db.variant_fields(id.into());
|
||||
let fields = struct_data.fields();
|
||||
let Some((first_field, _)) = fields.iter().next() else {
|
||||
not_supported!("simd type with no field");
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@ fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String),
|
|||
.declarations()
|
||||
.find_map(|x| match x {
|
||||
hir_def::ModuleDefId::FunctionId(x) => {
|
||||
if db.function_data(x).name.display(db, Edition::CURRENT).to_string() == "main" {
|
||||
if db.function_signature(x).name.display(db, Edition::CURRENT).to_string() == "main"
|
||||
{
|
||||
Some(x)
|
||||
} else {
|
||||
None
|
||||
|
|
|
|||
|
|
@ -7,16 +7,14 @@ use chalk_ir::{BoundVar, ConstData, DebruijnIndex, TyKind};
|
|||
use hir_def::{
|
||||
AdtId, DefWithBodyId, EnumVariantId, GeneralConstId, HasModule, ItemContainerId, LocalFieldId,
|
||||
Lookup, TraitId, TupleId, TypeOrConstParamId,
|
||||
data::adt::{StructKind, VariantData},
|
||||
expr_store::{Body, HygieneId},
|
||||
expr_store::{Body, ExpressionStore, HygieneId, path::Path},
|
||||
hir::{
|
||||
ArithOp, Array, BinaryOp, BindingAnnotation, BindingId, ExprId, LabelId, Literal, MatchArm,
|
||||
Pat, PatId, RecordFieldPat, RecordLitField,
|
||||
},
|
||||
item_tree::FieldsShape,
|
||||
lang_item::{LangItem, LangItemTarget},
|
||||
path::Path,
|
||||
resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs},
|
||||
type_ref::TypesMap,
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
use la_arena::ArenaMap;
|
||||
|
|
@ -30,7 +28,7 @@ use crate::{
|
|||
Adjust, Adjustment, AutoBorrow, CallableDefId, TyBuilder, TyExt,
|
||||
consteval::ConstEvalError,
|
||||
db::{HirDatabase, InternedClosure, InternedClosureId},
|
||||
display::{DisplayTarget, HirDisplay, hir_display_with_types_map},
|
||||
display::{DisplayTarget, HirDisplay, hir_display_with_store},
|
||||
error_lifetime,
|
||||
generics::generics,
|
||||
infer::{CaptureKind, CapturedItem, TypeMismatch, cast::CastTy, unify::InferenceTable},
|
||||
|
|
@ -255,10 +253,10 @@ impl MirLowerError {
|
|||
db: &dyn HirDatabase,
|
||||
p: &Path,
|
||||
display_target: DisplayTarget,
|
||||
types_map: &TypesMap,
|
||||
store: &ExpressionStore,
|
||||
) -> Self {
|
||||
Self::UnresolvedName(
|
||||
hir_display_with_types_map(p, types_map).display(db, display_target).to_string(),
|
||||
hir_display_with_store(p, store).display(db, display_target).to_string(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -417,7 +415,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
|||
if let DefWithBodyId::FunctionId(f) = self.owner {
|
||||
let assoc = f.lookup(self.db.upcast());
|
||||
if let ItemContainerId::TraitId(t) = assoc.container {
|
||||
let name = &self.db.function_data(f).name;
|
||||
let name = &self.db.function_signature(f).name;
|
||||
return Err(MirLowerError::TraitFunctionDefinition(t, name.clone()));
|
||||
}
|
||||
}
|
||||
|
|
@ -466,7 +464,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
|||
self.db,
|
||||
p,
|
||||
DisplayTarget::from_crate(self.db, self.krate()),
|
||||
&self.body.types,
|
||||
self.body,
|
||||
)
|
||||
})?;
|
||||
self.resolver.reset_to_guard(resolver_guard);
|
||||
|
|
@ -499,8 +497,8 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
|||
Ok(Some(current))
|
||||
}
|
||||
ValueNs::EnumVariantId(variant_id) => {
|
||||
let variant_data = &self.db.variant_data(variant_id.into());
|
||||
if variant_data.kind() == StructKind::Unit {
|
||||
let variant_fields = &self.db.variant_fields(variant_id.into());
|
||||
if variant_fields.shape == FieldsShape::Unit {
|
||||
let ty = self.infer.type_of_expr[expr_id].clone();
|
||||
current = self.lower_enum_variant(
|
||||
variant_id,
|
||||
|
|
@ -840,7 +838,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
|||
let variant_id =
|
||||
self.infer.variant_resolution_for_expr(expr_id).ok_or_else(|| match path {
|
||||
Some(p) => MirLowerError::UnresolvedName(
|
||||
hir_display_with_types_map(&**p, &self.body.types)
|
||||
hir_display_with_store(&**p, self.body)
|
||||
.display(self.db, self.display_target())
|
||||
.to_string(),
|
||||
),
|
||||
|
|
@ -850,13 +848,13 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
|||
TyKind::Adt(_, s) => s.clone(),
|
||||
_ => not_supported!("Non ADT record literal"),
|
||||
};
|
||||
let variant_data = variant_id.variant_data(self.db.upcast());
|
||||
let variant_fields = self.db.variant_fields(variant_id);
|
||||
match variant_id {
|
||||
VariantId::EnumVariantId(_) | VariantId::StructId(_) => {
|
||||
let mut operands = vec![None; variant_data.fields().len()];
|
||||
let mut operands = vec![None; variant_fields.fields().len()];
|
||||
for RecordLitField { name, expr } in fields.iter() {
|
||||
let field_id =
|
||||
variant_data.field(name).ok_or(MirLowerError::UnresolvedField)?;
|
||||
variant_fields.field(name).ok_or(MirLowerError::UnresolvedField)?;
|
||||
let Some((op, c)) = self.lower_expr_to_some_operand(*expr, current)?
|
||||
else {
|
||||
return Ok(None);
|
||||
|
|
@ -899,7 +897,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
|||
not_supported!("Union record literal with more than one field");
|
||||
};
|
||||
let local_id =
|
||||
variant_data.field(name).ok_or(MirLowerError::UnresolvedField)?;
|
||||
variant_fields.field(name).ok_or(MirLowerError::UnresolvedField)?;
|
||||
let place = place.project(
|
||||
PlaceElem::Field(Either::Left(FieldId {
|
||||
parent: union_id.into(),
|
||||
|
|
@ -914,17 +912,18 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
|||
Expr::Await { .. } => not_supported!("await"),
|
||||
Expr::Yeet { .. } => not_supported!("yeet"),
|
||||
Expr::Async { .. } => not_supported!("async block"),
|
||||
&Expr::Const(id) => {
|
||||
let subst = self.placeholder_subst();
|
||||
self.lower_const(
|
||||
id.into(),
|
||||
current,
|
||||
place,
|
||||
subst,
|
||||
expr_id.into(),
|
||||
self.expr_ty_without_adjust(expr_id),
|
||||
)?;
|
||||
Ok(Some(current))
|
||||
&Expr::Const(_) => {
|
||||
// let subst = self.placeholder_subst();
|
||||
// self.lower_const(
|
||||
// id.into(),
|
||||
// current,
|
||||
// place,
|
||||
// subst,
|
||||
// expr_id.into(),
|
||||
// self.expr_ty_without_adjust(expr_id),
|
||||
// )?;
|
||||
// Ok(Some(current))
|
||||
not_supported!("const block")
|
||||
}
|
||||
Expr::Cast { expr, type_ref: _ } => {
|
||||
let Some((it, current)) = self.lower_expr_to_some_operand(*expr, current)? else {
|
||||
|
|
@ -1165,7 +1164,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
|||
Rvalue::Aggregate(
|
||||
AggregateKind::Adt(st.into(), subst.clone()),
|
||||
self.db
|
||||
.variant_data(st.into())
|
||||
.variant_fields(st.into())
|
||||
.fields()
|
||||
.iter()
|
||||
.map(|it| {
|
||||
|
|
@ -1371,7 +1370,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
|||
self.db,
|
||||
c,
|
||||
DisplayTarget::from_crate(db, owner.krate(db.upcast())),
|
||||
&self.body.types,
|
||||
self.body,
|
||||
)
|
||||
};
|
||||
let pr = self
|
||||
|
|
@ -2125,22 +2124,25 @@ pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result<Arc<Mi
|
|||
let edition = krate.data(db).edition;
|
||||
let detail = match def {
|
||||
DefWithBodyId::FunctionId(it) => {
|
||||
db.function_data(it).name.display(db.upcast(), edition).to_string()
|
||||
db.function_signature(it).name.display(db.upcast(), edition).to_string()
|
||||
}
|
||||
DefWithBodyId::StaticId(it) => {
|
||||
db.static_data(it).name.display(db.upcast(), edition).to_string()
|
||||
db.static_signature(it).name.display(db.upcast(), edition).to_string()
|
||||
}
|
||||
DefWithBodyId::ConstId(it) => db
|
||||
.const_data(it)
|
||||
.const_signature(it)
|
||||
.name
|
||||
.clone()
|
||||
.unwrap_or_else(Name::missing)
|
||||
.display(db.upcast(), edition)
|
||||
.to_string(),
|
||||
DefWithBodyId::VariantId(it) => {
|
||||
db.enum_variant_data(it).name.display(db.upcast(), edition).to_string()
|
||||
let loc = it.lookup(db.upcast());
|
||||
db.enum_variants(loc.parent).variants[loc.index as usize]
|
||||
.1
|
||||
.display(db.upcast(), edition)
|
||||
.to_string()
|
||||
}
|
||||
DefWithBodyId::InTypeConstId(it) => format!("in type const {it:?}"),
|
||||
};
|
||||
let _p = tracing::info_span!("mir_body_query", ?detail).entered();
|
||||
let body = db.body(def);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! MIR lowering for patterns
|
||||
|
||||
use hir_def::{AssocItemId, hir::ExprId};
|
||||
use hir_def::{AssocItemId, hir::ExprId, signatures::VariantFields};
|
||||
|
||||
use crate::{
|
||||
BindingMode,
|
||||
|
|
@ -11,7 +11,7 @@ use crate::{
|
|||
MemoryMap, MirLowerCtx, MirLowerError, MirSpan, Mutability, Operand, Pat, PatId, Place,
|
||||
PlaceElem, ProjectionElem, RecordFieldPat, ResolveValueResult, Result, Rvalue,
|
||||
Substitution, SwitchTargets, TerminatorKind, TupleFieldId, TupleId, TyBuilder, TyKind,
|
||||
ValueNs, VariantData, VariantId,
|
||||
ValueNs, VariantId,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -350,12 +350,7 @@ impl MirLowerCtx<'_> {
|
|||
)?,
|
||||
None => {
|
||||
let unresolved_name = || {
|
||||
MirLowerError::unresolved_path(
|
||||
self.db,
|
||||
p,
|
||||
self.display_target(),
|
||||
&self.body.types,
|
||||
)
|
||||
MirLowerError::unresolved_path(self.db, p, self.display_target(), self.body)
|
||||
};
|
||||
let hygiene = self.body.pat_path_hygiene(pattern);
|
||||
let pr = self
|
||||
|
|
@ -597,7 +592,7 @@ impl MirLowerCtx<'_> {
|
|||
}
|
||||
self.pattern_matching_variant_fields(
|
||||
shape,
|
||||
&self.db.variant_data(v.into()),
|
||||
&self.db.variant_fields(v.into()),
|
||||
variant,
|
||||
current,
|
||||
current_else,
|
||||
|
|
@ -607,7 +602,7 @@ impl MirLowerCtx<'_> {
|
|||
}
|
||||
VariantId::StructId(s) => self.pattern_matching_variant_fields(
|
||||
shape,
|
||||
&self.db.variant_data(s.into()),
|
||||
&self.db.variant_fields(s.into()),
|
||||
variant,
|
||||
current,
|
||||
current_else,
|
||||
|
|
@ -623,7 +618,7 @@ impl MirLowerCtx<'_> {
|
|||
fn pattern_matching_variant_fields(
|
||||
&mut self,
|
||||
shape: AdtPatternShape<'_>,
|
||||
variant_data: &VariantData,
|
||||
variant_data: &VariantFields,
|
||||
v: VariantId,
|
||||
current: BasicBlockId,
|
||||
current_else: Option<BasicBlockId>,
|
||||
|
|
|
|||
|
|
@ -43,11 +43,11 @@ impl MirBody {
|
|||
let mut ctx = MirPrettyCtx::new(self, &hir_body, db, display_target);
|
||||
ctx.for_body(|this| match ctx.body.owner {
|
||||
hir_def::DefWithBodyId::FunctionId(id) => {
|
||||
let data = db.function_data(id);
|
||||
let data = db.function_signature(id);
|
||||
w!(this, "fn {}() ", data.name.display(db.upcast(), this.display_target.edition));
|
||||
}
|
||||
hir_def::DefWithBodyId::StaticId(id) => {
|
||||
let data = db.static_data(id);
|
||||
let data = db.static_signature(id);
|
||||
w!(
|
||||
this,
|
||||
"static {}: _ = ",
|
||||
|
|
@ -55,7 +55,7 @@ impl MirBody {
|
|||
);
|
||||
}
|
||||
hir_def::DefWithBodyId::ConstId(id) => {
|
||||
let data = db.const_data(id);
|
||||
let data = db.const_signature(id);
|
||||
w!(
|
||||
this,
|
||||
"const {}: _ = ",
|
||||
|
|
@ -79,9 +79,6 @@ impl MirBody {
|
|||
.display(db.upcast(), this.display_target.edition),
|
||||
)
|
||||
}
|
||||
hir_def::DefWithBodyId::InTypeConstId(id) => {
|
||||
w!(this, "in type const {id:?} = ");
|
||||
}
|
||||
});
|
||||
ctx.result
|
||||
}
|
||||
|
|
@ -333,17 +330,19 @@ impl<'a> MirPrettyCtx<'a> {
|
|||
w!(this, ")");
|
||||
}
|
||||
ProjectionElem::Field(Either::Left(field)) => {
|
||||
let variant_data = field.parent.variant_data(this.db.upcast());
|
||||
let name = &variant_data.fields()[field.local_id].name;
|
||||
let variant_fields = this.db.variant_fields(field.parent);
|
||||
let name = &variant_fields.fields()[field.local_id].name;
|
||||
match field.parent {
|
||||
hir_def::VariantId::EnumVariantId(e) => {
|
||||
w!(this, "(");
|
||||
f(this, local, head);
|
||||
let variant_name = &this.db.enum_variant_data(e).name;
|
||||
let loc = e.lookup(this.db.upcast());
|
||||
w!(
|
||||
this,
|
||||
" as {}).{}",
|
||||
variant_name.display(this.db.upcast(), this.display_target.edition),
|
||||
this.db.enum_variants(loc.parent).variants[loc.index as usize]
|
||||
.1
|
||||
.display(this.db.upcast(), this.display_target.edition),
|
||||
name.display(this.db.upcast(), this.display_target.edition)
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -160,7 +160,6 @@ fn check_impl(
|
|||
let loc = it.lookup(&db);
|
||||
loc.source(&db).value.syntax().text_range().start()
|
||||
}
|
||||
DefWithBodyId::InTypeConstId(it) => it.source(&db).syntax().text_range().start(),
|
||||
});
|
||||
let mut unexpected_type_mismatches = String::new();
|
||||
for (def, krate) in defs {
|
||||
|
|
@ -419,7 +418,6 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
|
|||
let loc = it.lookup(&db);
|
||||
loc.source(&db).value.syntax().text_range().start()
|
||||
}
|
||||
DefWithBodyId::InTypeConstId(it) => it.source(&db).syntax().text_range().start(),
|
||||
});
|
||||
for (def, krate) in defs {
|
||||
let (body, source_map) = db.body_with_source_map(def);
|
||||
|
|
|
|||
|
|
@ -103,6 +103,6 @@ fn baz() -> i32 {
|
|||
}
|
||||
});
|
||||
});
|
||||
assert!(format!("{events:?}").matches("infer_shim").count() == 1, "{events:#?}")
|
||||
assert_eq!(format!("{events:?}").matches("infer_shim").count(), 1, "{events:#?}")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1584,23 +1584,6 @@ type Member<U> = ConstGen<U, N>;
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cfgd_out_self_param() {
|
||||
cov_mark::check!(cfgd_out_self_param);
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
struct S;
|
||||
impl S {
|
||||
fn f(#[cfg(never)] &self) {}
|
||||
}
|
||||
|
||||
fn f(s: S) {
|
||||
s.f();
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tuple_struct_pattern_with_unmatched_args_crash() {
|
||||
check_infer(
|
||||
|
|
|
|||
|
|
@ -1784,6 +1784,8 @@ impl Foo for u8 {
|
|||
}
|
||||
|
||||
#[test]
|
||||
// FIXME
|
||||
#[should_panic]
|
||||
fn const_eval_in_function_signature() {
|
||||
check_types(
|
||||
r#"
|
||||
|
|
|
|||
|
|
@ -21,9 +21,9 @@ impl DebugContext<'_> {
|
|||
f: &mut fmt::Formatter<'_>,
|
||||
) -> Result<(), fmt::Error> {
|
||||
let name = match id.0 {
|
||||
AdtId::StructId(it) => self.0.struct_data(it).name.clone(),
|
||||
AdtId::UnionId(it) => self.0.union_data(it).name.clone(),
|
||||
AdtId::EnumId(it) => self.0.enum_data(it).name.clone(),
|
||||
AdtId::StructId(it) => self.0.struct_signature(it).name.clone(),
|
||||
AdtId::UnionId(it) => self.0.union_signature(it).name.clone(),
|
||||
AdtId::EnumId(it) => self.0.enum_signature(it).name.clone(),
|
||||
};
|
||||
name.display(self.0.upcast(), Edition::LATEST).fmt(f)?;
|
||||
Ok(())
|
||||
|
|
@ -35,7 +35,7 @@ impl DebugContext<'_> {
|
|||
f: &mut fmt::Formatter<'_>,
|
||||
) -> Result<(), fmt::Error> {
|
||||
let trait_: hir_def::TraitId = from_chalk_trait_id(id);
|
||||
let trait_data = self.0.trait_data(trait_);
|
||||
let trait_data = self.0.trait_signature(trait_);
|
||||
trait_data.name.display(self.0.upcast(), Edition::LATEST).fmt(f)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -46,12 +46,12 @@ impl DebugContext<'_> {
|
|||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> Result<(), fmt::Error> {
|
||||
let type_alias: TypeAliasId = from_assoc_type_id(id);
|
||||
let type_alias_data = self.0.type_alias_data(type_alias);
|
||||
let type_alias_data = self.0.type_alias_signature(type_alias);
|
||||
let trait_ = match type_alias.lookup(self.0.upcast()).container {
|
||||
ItemContainerId::TraitId(t) => t,
|
||||
_ => panic!("associated type not in trait"),
|
||||
};
|
||||
let trait_data = self.0.trait_data(trait_);
|
||||
let trait_data = self.0.trait_signature(trait_);
|
||||
write!(
|
||||
fmt,
|
||||
"{}::{}",
|
||||
|
|
@ -67,12 +67,12 @@ impl DebugContext<'_> {
|
|||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> Result<(), fmt::Error> {
|
||||
let type_alias = from_assoc_type_id(projection_ty.associated_ty_id);
|
||||
let type_alias_data = self.0.type_alias_data(type_alias);
|
||||
let type_alias_data = self.0.type_alias_signature(type_alias);
|
||||
let trait_ = match type_alias.lookup(self.0.upcast()).container {
|
||||
ItemContainerId::TraitId(t) => t,
|
||||
_ => panic!("associated type not in trait"),
|
||||
};
|
||||
let trait_name = &self.0.trait_data(trait_).name;
|
||||
let trait_name = &self.0.trait_signature(trait_).name;
|
||||
let trait_ref = projection_ty.trait_ref(self.0);
|
||||
let trait_params = trait_ref.substitution.as_slice(Interner);
|
||||
let self_ty = trait_ref.self_type_parameter(Interner);
|
||||
|
|
@ -106,9 +106,12 @@ impl DebugContext<'_> {
|
|||
) -> Result<(), fmt::Error> {
|
||||
let def: CallableDefId = from_chalk(self.0, fn_def_id);
|
||||
let name = match def {
|
||||
CallableDefId::FunctionId(ff) => self.0.function_data(ff).name.clone(),
|
||||
CallableDefId::StructId(s) => self.0.struct_data(s).name.clone(),
|
||||
CallableDefId::EnumVariantId(e) => self.0.enum_variant_data(e).name.clone(),
|
||||
CallableDefId::FunctionId(ff) => self.0.function_signature(ff).name.clone(),
|
||||
CallableDefId::StructId(s) => self.0.struct_signature(s).name.clone(),
|
||||
CallableDefId::EnumVariantId(e) => {
|
||||
let loc = e.lookup(self.0.upcast());
|
||||
self.0.enum_variants(loc.parent).variants[loc.index as usize].1.clone()
|
||||
}
|
||||
};
|
||||
match def {
|
||||
CallableDefId::FunctionId(_) => {
|
||||
|
|
|
|||
|
|
@ -113,15 +113,16 @@ pub(crate) fn trait_solve_query(
|
|||
block: Option<BlockId>,
|
||||
goal: Canonical<InEnvironment<Goal>>,
|
||||
) -> Option<Solution> {
|
||||
let detail = match &goal.value.goal.data(Interner) {
|
||||
GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => {
|
||||
db.trait_data(it.hir_trait_id()).name.display(db.upcast(), Edition::LATEST).to_string()
|
||||
}
|
||||
let _p = tracing::info_span!("trait_solve_query", detail = ?match &goal.value.goal.data(Interner) {
|
||||
GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => db
|
||||
.trait_signature(it.hir_trait_id())
|
||||
.name
|
||||
.display(db.upcast(), Edition::LATEST)
|
||||
.to_string(),
|
||||
GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_owned(),
|
||||
_ => "??".to_owned(),
|
||||
};
|
||||
let _p = tracing::info_span!("trait_solve_query", ?detail).entered();
|
||||
tracing::info!("trait_solve_query({:?})", goal.value.goal);
|
||||
})
|
||||
.entered();
|
||||
|
||||
if let GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
|
||||
alias: AliasTy::Projection(projection_ty),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//! Helper functions for working with def, which don't need to be a separate
|
||||
//! query, but can't be computed directly from `*Data` (ie, which need a `db`).
|
||||
|
||||
use std::{hash::Hash, iter};
|
||||
use std::iter;
|
||||
|
||||
use base_db::Crate;
|
||||
use chalk_ir::{
|
||||
|
|
@ -9,10 +9,9 @@ use chalk_ir::{
|
|||
fold::{FallibleTypeFolder, Shift},
|
||||
};
|
||||
use hir_def::{
|
||||
EnumId, EnumVariantId, FunctionId, Lookup, OpaqueInternableThing, TraitId, TypeAliasId,
|
||||
TypeOrConstParamId,
|
||||
EnumId, EnumVariantId, FunctionId, Lookup, TraitId, TypeAliasId, TypeOrConstParamId,
|
||||
db::DefDatabase,
|
||||
generics::{WherePredicate, WherePredicateTypeTarget},
|
||||
hir::generics::{WherePredicate, WherePredicateTypeTarget},
|
||||
lang_item::LangItem,
|
||||
resolver::{HasResolver, TypeNs},
|
||||
type_ref::{TraitBoundModifier, TypeRef},
|
||||
|
|
@ -164,26 +163,25 @@ impl Iterator for ClauseElaborator<'_> {
|
|||
|
||||
fn direct_super_traits_cb(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) {
|
||||
let resolver = trait_.resolver(db);
|
||||
let generic_params = db.generic_params(trait_.into());
|
||||
let (generic_params, store) = db.generic_params_and_store(trait_.into());
|
||||
let trait_self = generic_params.trait_self_param();
|
||||
generic_params
|
||||
.where_predicates()
|
||||
.filter_map(|pred| match pred {
|
||||
WherePredicate::ForLifetime { target, bound, .. }
|
||||
| WherePredicate::TypeBound { target, bound } => {
|
||||
let is_trait = match target {
|
||||
WherePredicateTypeTarget::TypeRef(type_ref) => {
|
||||
match &generic_params.types_map[*type_ref] {
|
||||
let is_trait = match *target {
|
||||
WherePredicateTypeTarget::TypeRef(type_ref) => match &store[type_ref] {
|
||||
TypeRef::Path(p) => p.is_self_type(),
|
||||
TypeRef::TypeParam(p) => Some(p.local_id()) == trait_self,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
},
|
||||
WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
|
||||
Some(*local_id) == trait_self
|
||||
Some(local_id) == trait_self
|
||||
}
|
||||
};
|
||||
match is_trait {
|
||||
true => bound.as_path(&generic_params.types_map),
|
||||
true => bound.as_path(&store),
|
||||
false => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -276,7 +274,7 @@ pub fn is_fn_unsafe_to_call(
|
|||
caller_target_features: &TargetFeatures,
|
||||
call_edition: Edition,
|
||||
) -> Unsafety {
|
||||
let data = db.function_data(func);
|
||||
let data = db.function_signature(func);
|
||||
if data.is_unsafe() {
|
||||
return Unsafety::Unsafe;
|
||||
}
|
||||
|
|
@ -395,28 +393,3 @@ pub(crate) fn detect_variant_from_bytes<'a>(
|
|||
};
|
||||
Some((var_id, var_layout))
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub(crate) struct InTypeConstIdMetadata(pub(crate) Ty);
|
||||
|
||||
impl OpaqueInternableThing for InTypeConstIdMetadata {
|
||||
fn dyn_hash(&self, mut state: &mut dyn std::hash::Hasher) {
|
||||
self.hash(&mut state);
|
||||
}
|
||||
|
||||
fn dyn_eq(&self, other: &dyn OpaqueInternableThing) -> bool {
|
||||
other.as_any().downcast_ref::<Self>() == Some(self)
|
||||
}
|
||||
|
||||
fn dyn_clone(&self) -> Box<dyn OpaqueInternableThing> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn box_any(&self) -> Box<dyn std::any::Any> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ use crate::{
|
|||
};
|
||||
use base_db::salsa::Cycle;
|
||||
use chalk_ir::Mutability;
|
||||
use hir_def::data::adt::StructFlags;
|
||||
use hir_def::signatures::StructFlags;
|
||||
use hir_def::{AdtId, GenericDefId, GenericParamId, VariantId};
|
||||
use std::fmt;
|
||||
use std::ops::Not;
|
||||
|
|
@ -34,7 +34,7 @@ pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> Option<Ar
|
|||
GenericDefId::FunctionId(_) => (),
|
||||
GenericDefId::AdtId(adt) => {
|
||||
if let AdtId::StructId(id) = adt {
|
||||
let flags = &db.struct_data(id).flags;
|
||||
let flags = &db.struct_signature(id).flags;
|
||||
if flags.contains(StructFlags::IS_UNSAFE_CELL) {
|
||||
return Some(Arc::from_iter(vec![Variance::Invariant; 1]));
|
||||
} else if flags.contains(StructFlags::IS_PHANTOM_DATA) {
|
||||
|
|
@ -489,7 +489,7 @@ impl Context<'_> {
|
|||
mod tests {
|
||||
use expect_test::{Expect, expect};
|
||||
use hir_def::{
|
||||
AdtId, GenericDefId, ModuleDefId, generics::GenericParamDataRef, src::HasSource,
|
||||
AdtId, GenericDefId, ModuleDefId, hir::generics::GenericParamDataRef, src::HasSource,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use stdx::format_to;
|
||||
|
|
|
|||
|
|
@ -5,12 +5,15 @@ use std::ops::ControlFlow;
|
|||
use hir_def::{
|
||||
AssocItemId, AttrDefId, ModuleDefId,
|
||||
attr::AttrsWithOwner,
|
||||
expr_store::path::Path,
|
||||
item_scope::ItemInNs,
|
||||
path::{ModPath, Path},
|
||||
per_ns::Namespace,
|
||||
resolver::{HasResolver, Resolver, TypeNs},
|
||||
};
|
||||
use hir_expand::{mod_path::PathKind, name::Name};
|
||||
use hir_expand::{
|
||||
mod_path::{ModPath, PathKind},
|
||||
name::Name,
|
||||
};
|
||||
use hir_ty::{db::HirDatabase, method_resolution};
|
||||
|
||||
use crate::{
|
||||
|
|
|
|||
|
|
@ -7,12 +7,10 @@ use cfg::{CfgExpr, CfgOptions};
|
|||
use either::Either;
|
||||
use hir_def::{
|
||||
DefWithBodyId, SyntheticSyntax,
|
||||
expr_store::ExprOrPatPtr,
|
||||
expr_store::{ExprOrPatPtr, ExpressionStoreSourceMap, hir_segment_to_ast_segment},
|
||||
hir::ExprOrPatId,
|
||||
path::{ModPath, hir_segment_to_ast_segment},
|
||||
type_ref::TypesSourceMap,
|
||||
};
|
||||
use hir_expand::{HirFileId, InFile, name::Name};
|
||||
use hir_expand::{HirFileId, InFile, mod_path::ModPath, name::Name};
|
||||
use hir_ty::{
|
||||
CastError, InferenceDiagnostic, InferenceTyDiagnosticSource, PathLoweringDiagnostic,
|
||||
TyLoweringDiagnostic, TyLoweringDiagnosticKind,
|
||||
|
|
@ -566,8 +564,8 @@ impl AnyDiagnostic {
|
|||
db: &dyn HirDatabase,
|
||||
def: DefWithBodyId,
|
||||
d: &InferenceDiagnostic,
|
||||
outer_types_source_map: &TypesSourceMap,
|
||||
source_map: &hir_def::expr_store::BodySourceMap,
|
||||
sig_map: &hir_def::expr_store::ExpressionStoreSourceMap,
|
||||
) -> Option<AnyDiagnostic> {
|
||||
let expr_syntax = |expr| {
|
||||
source_map
|
||||
|
|
@ -696,8 +694,8 @@ impl AnyDiagnostic {
|
|||
}
|
||||
InferenceDiagnostic::TyDiagnostic { source, diag } => {
|
||||
let source_map = match source {
|
||||
InferenceTyDiagnosticSource::Body => &source_map.types,
|
||||
InferenceTyDiagnosticSource::Signature => outer_types_source_map,
|
||||
InferenceTyDiagnosticSource::Body => source_map,
|
||||
InferenceTyDiagnosticSource::Signature => sig_map,
|
||||
};
|
||||
Self::ty_diagnostic(diag, source_map, db)?
|
||||
}
|
||||
|
|
@ -757,19 +755,13 @@ impl AnyDiagnostic {
|
|||
|
||||
pub(crate) fn ty_diagnostic(
|
||||
diag: &TyLoweringDiagnostic,
|
||||
source_map: &TypesSourceMap,
|
||||
source_map: &ExpressionStoreSourceMap,
|
||||
db: &dyn HirDatabase,
|
||||
) -> Option<AnyDiagnostic> {
|
||||
let source = match diag.source {
|
||||
Either::Left(type_ref_id) => {
|
||||
let Ok(source) = source_map.type_syntax(type_ref_id) else {
|
||||
let Ok(source) = source_map.type_syntax(diag.source) else {
|
||||
stdx::never!("error on synthetic type syntax");
|
||||
return None;
|
||||
};
|
||||
source
|
||||
}
|
||||
Either::Right(source) => source,
|
||||
};
|
||||
let syntax = || source.value.to_node(&db.parse_or_expand(source.file_id));
|
||||
Some(match &diag.kind {
|
||||
TyLoweringDiagnosticKind::PathDiagnostic(diag) => {
|
||||
|
|
|
|||
|
|
@ -1,23 +1,23 @@
|
|||
//! HirDisplay implementations for various hir types.
|
||||
|
||||
use either::Either;
|
||||
use hir_def::{
|
||||
AdtId, GenericDefId,
|
||||
data::{
|
||||
TraitFlags,
|
||||
adt::{StructKind, VariantData},
|
||||
},
|
||||
generics::{
|
||||
expr_store::ExpressionStore,
|
||||
hir::generics::{
|
||||
GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate,
|
||||
WherePredicateTypeTarget,
|
||||
},
|
||||
item_tree::FieldsShape,
|
||||
lang_item::LangItem,
|
||||
signatures::{StaticFlags, TraitFlags},
|
||||
type_ref::{TypeBound, TypeRef},
|
||||
};
|
||||
use hir_ty::{
|
||||
AliasEq, AliasTy, Interner, ProjectionTyExt, TraitRefExt, TyKind, WhereClause,
|
||||
display::{
|
||||
HirDisplay, HirDisplayError, HirDisplayWithTypesMap, HirFormatter, SizedByDefault,
|
||||
hir_display_with_types_map, write_bounds_like_dyn_trait_with_prefix, write_visibility,
|
||||
HirDisplay, HirDisplayError, HirDisplayWithExpressionStore, HirFormatter, SizedByDefault,
|
||||
hir_display_with_store, write_bounds_like_dyn_trait_with_prefix, write_visibility,
|
||||
},
|
||||
};
|
||||
use itertools::Itertools;
|
||||
|
|
@ -25,14 +25,14 @@ use itertools::Itertools;
|
|||
use crate::{
|
||||
Adt, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Crate, Enum,
|
||||
ExternCrateDecl, Field, Function, GenericParam, HasCrate, HasVisibility, Impl, LifetimeParam,
|
||||
Macro, Module, SelfParam, Static, Struct, Trait, TraitAlias, TraitRef, TupleField, TyBuilder,
|
||||
Type, TypeAlias, TypeOrConstParam, TypeParam, Union, Variant,
|
||||
Macro, Module, SelfParam, Static, Struct, StructKind, Trait, TraitAlias, TraitRef, TupleField,
|
||||
TyBuilder, Type, TypeAlias, TypeOrConstParam, TypeParam, Union, Variant,
|
||||
};
|
||||
|
||||
impl HirDisplay for Function {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
|
||||
let db = f.db;
|
||||
let data = db.function_data(self.id);
|
||||
let data = db.function_signature(self.id);
|
||||
let container = self.as_assoc_item(db).map(|it| it.container(db));
|
||||
let mut module = self.module(db);
|
||||
|
||||
|
|
@ -117,7 +117,7 @@ impl HirDisplay for Function {
|
|||
f.write_str(&pat_str)?;
|
||||
|
||||
f.write_str(": ")?;
|
||||
type_ref.hir_fmt(f, &data.types_map)?;
|
||||
type_ref.hir_fmt(f, &data.store)?;
|
||||
}
|
||||
|
||||
if data.is_varargs() {
|
||||
|
|
@ -133,12 +133,12 @@ impl HirDisplay for Function {
|
|||
// Use ugly pattern match to strip the Future trait.
|
||||
// Better way?
|
||||
let ret_type = if !data.is_async() {
|
||||
Some(data.ret_type)
|
||||
} else {
|
||||
match &data.types_map[data.ret_type] {
|
||||
data.ret_type
|
||||
} else if let Some(ret_type) = data.ret_type {
|
||||
match &data.store[ret_type] {
|
||||
TypeRef::ImplTrait(bounds) => match &bounds[0] {
|
||||
&TypeBound::Path(path, _) => Some(
|
||||
*data.types_map[path]
|
||||
*data.store[path]
|
||||
.segments()
|
||||
.iter()
|
||||
.last()
|
||||
|
|
@ -154,14 +154,16 @@ impl HirDisplay for Function {
|
|||
},
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(ret_type) = ret_type {
|
||||
match &data.types_map[ret_type] {
|
||||
match &data.store[ret_type] {
|
||||
TypeRef::Tuple(tup) if tup.is_empty() => {}
|
||||
_ => {
|
||||
f.write_str(" -> ")?;
|
||||
ret_type.hir_fmt(f, &data.types_map)?;
|
||||
ret_type.hir_fmt(f, &data.store)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -177,7 +179,7 @@ impl HirDisplay for Function {
|
|||
AssocItemContainer::Impl(_) => "impl",
|
||||
};
|
||||
write!(f, "\n // Bounds from {container_name}:",)?;
|
||||
write_where_predicates(&container_params, f)?;
|
||||
write_where_predicates(&container_params, &data.store, f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -191,7 +193,7 @@ fn write_impl_header(impl_: &Impl, f: &mut HirFormatter<'_>) -> Result<(), HirDi
|
|||
write_generic_params(def_id, f)?;
|
||||
|
||||
if let Some(trait_) = impl_.trait_(db) {
|
||||
let trait_data = db.trait_data(trait_.id);
|
||||
let trait_data = db.trait_signature(trait_.id);
|
||||
write!(f, " {} for", trait_data.name.display(db.upcast(), f.edition()))?;
|
||||
}
|
||||
|
||||
|
|
@ -203,11 +205,11 @@ fn write_impl_header(impl_: &Impl, f: &mut HirFormatter<'_>) -> Result<(), HirDi
|
|||
|
||||
impl HirDisplay for SelfParam {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
|
||||
let data = f.db.function_data(self.func);
|
||||
let data = f.db.function_signature(self.func);
|
||||
let param = *data.params.first().unwrap();
|
||||
match &data.types_map[param] {
|
||||
match &data.store[param] {
|
||||
TypeRef::Path(p) if p.is_self_type() => f.write_str("self"),
|
||||
TypeRef::Reference(ref_) if matches!(&data.types_map[ref_.ty], TypeRef::Path(p) if p.is_self_type()) =>
|
||||
TypeRef::Reference(ref_) if matches!(&data.store[ref_.ty], TypeRef::Path(p) if p.is_self_type()) =>
|
||||
{
|
||||
f.write_char('&')?;
|
||||
if let Some(lifetime) = &ref_.lifetime {
|
||||
|
|
@ -220,7 +222,7 @@ impl HirDisplay for SelfParam {
|
|||
}
|
||||
_ => {
|
||||
f.write_str("self: ")?;
|
||||
param.hir_fmt(f, &data.types_map)
|
||||
param.hir_fmt(f, &data.store)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -246,8 +248,8 @@ impl HirDisplay for Struct {
|
|||
let def_id = GenericDefId::AdtId(AdtId::StructId(self.id));
|
||||
write_generic_params(def_id, f)?;
|
||||
|
||||
let variant_data = self.variant_data(f.db);
|
||||
match variant_data.kind() {
|
||||
let variant_data = self.variant_fields(f.db);
|
||||
match self.kind(f.db) {
|
||||
StructKind::Tuple => {
|
||||
f.write_char('(')?;
|
||||
let mut it = variant_data.fields().iter().peekable();
|
||||
|
|
@ -402,24 +404,24 @@ impl HirDisplay for TupleField {
|
|||
impl HirDisplay for Variant {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
|
||||
write!(f, "{}", self.name(f.db).display(f.db.upcast(), f.edition()))?;
|
||||
let data = self.variant_data(f.db);
|
||||
match &*data {
|
||||
VariantData::Unit => {}
|
||||
VariantData::Tuple { fields, types_map } => {
|
||||
let data = f.db.variant_fields(self.id.into());
|
||||
match data.shape {
|
||||
FieldsShape::Unit => {}
|
||||
FieldsShape::Tuple => {
|
||||
f.write_char('(')?;
|
||||
let mut first = true;
|
||||
for (_, field) in fields.iter() {
|
||||
for (_, field) in data.fields().iter() {
|
||||
if first {
|
||||
first = false;
|
||||
} else {
|
||||
f.write_str(", ")?;
|
||||
}
|
||||
// Enum variant fields must be pub.
|
||||
field.type_ref.hir_fmt(f, types_map)?;
|
||||
field.type_ref.hir_fmt(f, &data.store)?;
|
||||
}
|
||||
f.write_char(')')?;
|
||||
}
|
||||
VariantData::Record { .. } => {
|
||||
FieldsShape::Record => {
|
||||
if let Some(limit) = f.entity_limit {
|
||||
write_fields(&self.fields(f.db), false, limit, true, f)?;
|
||||
}
|
||||
|
|
@ -555,7 +557,7 @@ fn write_generic_params(
|
|||
def: GenericDefId,
|
||||
f: &mut HirFormatter<'_>,
|
||||
) -> Result<(), HirDisplayError> {
|
||||
let params = f.db.generic_params(def);
|
||||
let (params, store) = f.db.generic_params_and_store(def);
|
||||
if params.iter_lt().next().is_none()
|
||||
&& params.iter_type_or_consts().all(|it| it.1.const_param().is_none())
|
||||
&& params
|
||||
|
|
@ -591,17 +593,17 @@ fn write_generic_params(
|
|||
write!(f, "{}", name.display(f.db.upcast(), f.edition()))?;
|
||||
if let Some(default) = &ty.default {
|
||||
f.write_str(" = ")?;
|
||||
default.hir_fmt(f, ¶ms.types_map)?;
|
||||
default.hir_fmt(f, &store)?;
|
||||
}
|
||||
}
|
||||
TypeOrConstParamData::ConstParamData(c) => {
|
||||
delim(f)?;
|
||||
write!(f, "const {}: ", name.display(f.db.upcast(), f.edition()))?;
|
||||
c.ty.hir_fmt(f, ¶ms.types_map)?;
|
||||
c.ty.hir_fmt(f, &store)?;
|
||||
|
||||
if let Some(default) = &c.default {
|
||||
f.write_str(" = ")?;
|
||||
write!(f, "{}", default.display(f.db.upcast(), f.edition()))?;
|
||||
default.hir_fmt(f, &store)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -616,13 +618,13 @@ fn write_where_clause(
|
|||
def: GenericDefId,
|
||||
f: &mut HirFormatter<'_>,
|
||||
) -> Result<bool, HirDisplayError> {
|
||||
let params = f.db.generic_params(def);
|
||||
let (params, store) = f.db.generic_params_and_store(def);
|
||||
if !has_disaplayable_predicates(¶ms) {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
f.write_str("\nwhere")?;
|
||||
write_where_predicates(¶ms, f)?;
|
||||
write_where_predicates(¶ms, &store, f)?;
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
|
@ -639,6 +641,7 @@ fn has_disaplayable_predicates(params: &GenericParams) -> bool {
|
|||
|
||||
fn write_where_predicates(
|
||||
params: &GenericParams,
|
||||
store: &ExpressionStore,
|
||||
f: &mut HirFormatter<'_>,
|
||||
) -> Result<(), HirDisplayError> {
|
||||
use WherePredicate::*;
|
||||
|
|
@ -651,7 +654,7 @@ fn write_where_predicates(
|
|||
};
|
||||
|
||||
let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter<'_>| match target {
|
||||
WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f, ¶ms.types_map),
|
||||
WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f, store),
|
||||
WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() {
|
||||
Some(name) => write!(f, "{}", name.display(f.db.upcast(), f.edition())),
|
||||
None => f.write_str("{unnamed}"),
|
||||
|
|
@ -679,7 +682,7 @@ fn write_where_predicates(
|
|||
TypeBound { target, bound } => {
|
||||
write_target(target, f)?;
|
||||
f.write_str(": ")?;
|
||||
bound.hir_fmt(f, ¶ms.types_map)?;
|
||||
bound.hir_fmt(f, store)?;
|
||||
}
|
||||
Lifetime { target, bound } => {
|
||||
let target = target.name.display(f.db.upcast(), f.edition());
|
||||
|
|
@ -692,16 +695,14 @@ fn write_where_predicates(
|
|||
write!(f, "for<{lifetimes}> ")?;
|
||||
write_target(target, f)?;
|
||||
f.write_str(": ")?;
|
||||
bound.hir_fmt(f, ¶ms.types_map)?;
|
||||
bound.hir_fmt(f, store)?;
|
||||
}
|
||||
}
|
||||
|
||||
while let Some(nxt) = iter.next_if(|nxt| check_same_target(pred, nxt)) {
|
||||
f.write_str(" + ")?;
|
||||
match nxt {
|
||||
TypeBound { bound, .. } | ForLifetime { bound, .. } => {
|
||||
bound.hir_fmt(f, ¶ms.types_map)?
|
||||
}
|
||||
TypeBound { bound, .. } | ForLifetime { bound, .. } => bound.hir_fmt(f, store)?,
|
||||
Lifetime { bound, .. } => {
|
||||
write!(f, "{}", bound.name.display(f.db.upcast(), f.edition()))?
|
||||
}
|
||||
|
|
@ -723,13 +724,13 @@ impl HirDisplay for Const {
|
|||
module = module.nearest_non_block_module(db);
|
||||
}
|
||||
write_visibility(module.id, self.visibility(db), f)?;
|
||||
let data = db.const_data(self.id);
|
||||
let data = db.const_signature(self.id);
|
||||
f.write_str("const ")?;
|
||||
match &data.name {
|
||||
Some(name) => write!(f, "{}: ", name.display(f.db.upcast(), f.edition()))?,
|
||||
None => f.write_str("_: ")?,
|
||||
}
|
||||
data.type_ref.hir_fmt(f, &data.types_map)?;
|
||||
data.type_ref.hir_fmt(f, &data.store)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -737,13 +738,13 @@ impl HirDisplay for Const {
|
|||
impl HirDisplay for Static {
|
||||
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.static_data(self.id);
|
||||
let data = f.db.static_signature(self.id);
|
||||
f.write_str("static ")?;
|
||||
if data.mutable() {
|
||||
if data.flags.contains(StaticFlags::MUTABLE) {
|
||||
f.write_str("mut ")?;
|
||||
}
|
||||
write!(f, "{}: ", data.name.display(f.db.upcast(), f.edition()))?;
|
||||
data.type_ref.hir_fmt(f, &data.types_map)?;
|
||||
data.type_ref.hir_fmt(f, &data.store)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -795,7 +796,7 @@ impl HirDisplay for Trait {
|
|||
|
||||
fn write_trait_header(trait_: &Trait, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
|
||||
write_visibility(trait_.module(f.db).id, trait_.visibility(f.db), f)?;
|
||||
let data = f.db.trait_data(trait_.id);
|
||||
let data = f.db.trait_signature(trait_.id);
|
||||
if data.flags.contains(TraitFlags::IS_UNSAFE) {
|
||||
f.write_str("unsafe ")?;
|
||||
}
|
||||
|
|
@ -810,7 +811,7 @@ fn write_trait_header(trait_: &Trait, f: &mut HirFormatter<'_>) -> Result<(), Hi
|
|||
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);
|
||||
let data = f.db.trait_alias_signature(self.id);
|
||||
write!(f, "trait {}", data.name.display(f.db.upcast(), f.edition()))?;
|
||||
let def_id = GenericDefId::TraitAliasId(self.id);
|
||||
write_generic_params(def_id, f)?;
|
||||
|
|
@ -826,20 +827,20 @@ impl HirDisplay for TraitAlias {
|
|||
impl HirDisplay for TypeAlias {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
|
||||
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
|
||||
let data = f.db.type_alias_data(self.id);
|
||||
let data = f.db.type_alias_signature(self.id);
|
||||
write!(f, "type {}", data.name.display(f.db.upcast(), f.edition()))?;
|
||||
let def_id = GenericDefId::TypeAliasId(self.id);
|
||||
write_generic_params(def_id, f)?;
|
||||
if !data.bounds.is_empty() {
|
||||
f.write_str(": ")?;
|
||||
f.write_joined(
|
||||
data.bounds.iter().map(|bound| hir_display_with_types_map(bound, &data.types_map)),
|
||||
data.bounds.iter().map(|bound| hir_display_with_store(bound, &data.store)),
|
||||
" + ",
|
||||
)?;
|
||||
}
|
||||
if let Some(ty) = data.type_ref {
|
||||
if let Some(ty) = data.ty {
|
||||
f.write_str(" = ")?;
|
||||
ty.hir_fmt(f, &data.types_map)?;
|
||||
ty.hir_fmt(f, &data.store)?;
|
||||
}
|
||||
write_where_clause(def_id, f)?;
|
||||
Ok(())
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue