Merge pull request #18074 from ChayimFriedman2/typeref-source-map

internal: Build source map for `hir_def::TypeRef`s
This commit is contained in:
Lukas Wirth 2024-10-28 11:01:12 +00:00 committed by GitHub
commit 80e9d014be
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
46 changed files with 2511 additions and 929 deletions

View file

@ -30,6 +30,7 @@ use crate::{
nameres::DefMap,
path::{ModPath, Path},
src::HasSource,
type_ref::{TypeRef, TypeRefId, TypesMap, TypesSourceMap},
BlockId, DefWithBodyId, HasModule, Lookup,
};
@ -69,6 +70,7 @@ pub struct Body {
pub self_param: Option<BindingId>,
/// The `ExprId` of the actual body expression.
pub body_expr: ExprId,
pub types: TypesMap,
/// Block expressions in this body that may contain inner items.
block_scopes: Vec<BlockId>,
@ -139,6 +141,8 @@ pub struct BodySourceMap {
field_map_back: FxHashMap<ExprId, FieldSource>,
pat_field_map_back: FxHashMap<PatId, PatFieldSource>,
types: TypesSourceMap,
// FIXME: Make this a sane struct.
template_map: Option<
Box<(
@ -304,6 +308,7 @@ impl Body {
binding_hygiene,
expr_hygiene,
pat_hygiene,
types,
} = self;
block_scopes.shrink_to_fit();
exprs.shrink_to_fit();
@ -314,6 +319,7 @@ impl Body {
binding_hygiene.shrink_to_fit();
expr_hygiene.shrink_to_fit();
pat_hygiene.shrink_to_fit();
types.shrink_to_fit();
}
pub fn walk_bindings_in_pat(&self, pat_id: PatId, mut f: impl FnMut(BindingId)) {
@ -542,6 +548,7 @@ impl Default for Body {
binding_hygiene: Default::default(),
expr_hygiene: Default::default(),
pat_hygiene: Default::default(),
types: Default::default(),
}
}
}
@ -578,6 +585,14 @@ impl Index<BindingId> for Body {
}
}
impl Index<TypeRefId> for Body {
type Output = TypeRef;
fn index(&self, b: TypeRefId) -> &TypeRef {
&self.types[b]
}
}
// FIXME: Change `node_` prefix to something more reasonable.
// Perhaps `expr_syntax` and `expr_id`?
impl BodySourceMap {
@ -691,6 +706,7 @@ impl BodySourceMap {
template_map,
diagnostics,
binding_definitions,
types,
} = self;
if let Some(template_map) = template_map {
template_map.0.shrink_to_fit();
@ -707,5 +723,6 @@ impl BodySourceMap {
expansions.shrink_to_fit();
diagnostics.shrink_to_fit();
binding_definitions.shrink_to_fit();
types.shrink_to_fit();
}
}

View file

@ -12,7 +12,7 @@ use hir_expand::{
span_map::{ExpansionSpanMap, SpanMap},
InFile, MacroDefId,
};
use intern::{sym, Interned, Symbol};
use intern::{sym, Symbol};
use rustc_hash::FxHashMap;
use span::AstIdMap;
use stdx::never;
@ -274,8 +274,8 @@ impl ExprCollector<'_> {
(self.body, self.source_map)
}
fn ctx(&self) -> LowerCtx<'_> {
self.expander.ctx(self.db)
fn ctx(&mut self) -> LowerCtx<'_> {
self.expander.ctx(self.db, &mut self.body.types, &mut self.source_map.types)
}
fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
@ -436,7 +436,7 @@ impl ExprCollector<'_> {
}
ast::Expr::PathExpr(e) => {
let (path, hygiene) = self
.collect_expr_path(&e)
.collect_expr_path(e)
.map(|(path, hygiene)| (Expr::Path(path), hygiene))
.unwrap_or((Expr::Missing, HygieneId::ROOT));
let expr_id = self.alloc_expr(path, syntax_ptr);
@ -486,8 +486,7 @@ impl ExprCollector<'_> {
self.alloc_expr(Expr::Yeet { expr }, syntax_ptr)
}
ast::Expr::RecordExpr(e) => {
let path =
e.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
let path = e.path().and_then(|path| self.parse_path(path)).map(Box::new);
let record_lit = if let Some(nfl) = e.record_expr_field_list() {
let fields = nfl
.fields()
@ -534,7 +533,7 @@ impl ExprCollector<'_> {
ast::Expr::TryExpr(e) => self.collect_try_operator(syntax_ptr, e),
ast::Expr::CastExpr(e) => {
let expr = self.collect_expr_opt(e.expr());
let type_ref = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.ty());
self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
}
ast::Expr::RefExpr(e) => {
@ -573,16 +572,13 @@ impl ExprCollector<'_> {
arg_types.reserve_exact(num_params);
for param in pl.params() {
let pat = this.collect_pat_top(param.pat());
let type_ref =
param.ty().map(|it| Interned::new(TypeRef::from_ast(&this.ctx(), it)));
let type_ref = param.ty().map(|it| TypeRef::from_ast(&this.ctx(), it));
args.push(pat);
arg_types.push(type_ref);
}
}
let ret_type = e
.ret_type()
.and_then(|r| r.ty())
.map(|it| Interned::new(TypeRef::from_ast(&this.ctx(), it)));
let ret_type =
e.ret_type().and_then(|r| r.ty()).map(|it| TypeRef::from_ast(&this.ctx(), it));
let prev_is_lowering_coroutine = mem::take(&mut this.is_lowering_coroutine);
let prev_try_block_label = this.current_try_block_label.take();
@ -709,7 +705,7 @@ impl ExprCollector<'_> {
ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
ast::Expr::AsmExpr(e) => self.lower_inline_asm(e, syntax_ptr),
ast::Expr::OffsetOfExpr(e) => {
let container = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
let container = TypeRef::from_ast_opt(&self.ctx(), e.ty());
let fields = e.fields().map(|it| it.as_name()).collect();
self.alloc_expr(Expr::OffsetOf(OffsetOf { container, fields }), syntax_ptr)
}
@ -717,15 +713,15 @@ impl ExprCollector<'_> {
})
}
fn collect_expr_path(&mut self, e: &ast::PathExpr) -> Option<(Path, HygieneId)> {
fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
self.expander.parse_path(self.db, path, &mut self.body.types, &mut self.source_map.types)
}
fn collect_expr_path(&mut self, e: ast::PathExpr) -> Option<(Path, HygieneId)> {
e.path().and_then(|path| {
let path = self.expander.parse_path(self.db, path)?;
let Path::Normal { type_anchor, mod_path, generic_args } = &path else {
panic!("path parsing produced a non-normal path");
};
let path = self.parse_path(path)?;
// Need to enable `mod_path.len() < 1` for `self`.
let may_be_variable =
type_anchor.is_none() && mod_path.len() <= 1 && generic_args.is_none();
let may_be_variable = matches!(&path, Path::BarePath(mod_path) if mod_path.len() <= 1);
let hygiene = if may_be_variable {
self.hygiene_id_for(e.syntax().text_range().start())
} else {
@ -790,17 +786,14 @@ impl ExprCollector<'_> {
}
ast::Expr::CallExpr(e) => {
let path = collect_path(self, e.expr()?)?;
let path = path
.path()
.and_then(|path| self.expander.parse_path(self.db, path))
.map(Box::new);
let path = path.path().and_then(|path| self.parse_path(path)).map(Box::new);
let (ellipsis, args) = collect_tuple(self, e.arg_list()?.args());
self.alloc_pat_from_expr(Pat::TupleStruct { path, args, ellipsis }, syntax_ptr)
}
ast::Expr::PathExpr(e) => {
let (path, hygiene) = self
.collect_expr_path(e)
.map(|(path, hygiene)| (Pat::Path(Box::new(path)), hygiene))
.collect_expr_path(e.clone())
.map(|(path, hygiene)| (Pat::Path(path), hygiene))
.unwrap_or((Pat::Missing, HygieneId::ROOT));
let pat_id = self.alloc_pat_from_expr(path, syntax_ptr);
if !hygiene.is_root() {
@ -819,8 +812,7 @@ impl ExprCollector<'_> {
id
}
ast::Expr::RecordExpr(e) => {
let path =
e.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
let path = e.path().and_then(|path| self.parse_path(path)).map(Box::new);
let record_field_list = e.record_expr_field_list()?;
let ellipsis = record_field_list.dotdot_token().is_some();
// FIXME: Report an error here if `record_field_list.spread().is_some()`.
@ -1063,7 +1055,7 @@ impl ExprCollector<'_> {
syntax_ptr,
);
let none_arm = MatchArm {
pat: self.alloc_pat_desugared(Pat::Path(Box::new(option_none))),
pat: self.alloc_pat_desugared(Pat::Path(option_none)),
guard: None,
expr: self.alloc_expr(Expr::Break { expr: None, label: None }, syntax_ptr),
};
@ -1325,8 +1317,7 @@ impl ExprCollector<'_> {
return;
}
let pat = self.collect_pat_top(stmt.pat());
let type_ref =
stmt.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
let initializer = stmt.initializer().map(|e| self.collect_expr(e));
let else_branch = stmt
.let_else()
@ -1552,8 +1543,7 @@ impl ExprCollector<'_> {
return pat;
}
ast::Pat::TupleStructPat(p) => {
let path =
p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
let path = p.path().and_then(|path| self.parse_path(path)).map(Box::new);
let (args, ellipsis) = self.collect_tuple_pat(
p.fields(),
comma_follows_token(p.l_paren_token()),
@ -1567,8 +1557,7 @@ impl ExprCollector<'_> {
Pat::Ref { pat, mutability }
}
ast::Pat::PathPat(p) => {
let path =
p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
let path = p.path().and_then(|path| self.parse_path(path));
path.map(Pat::Path).unwrap_or(Pat::Missing)
}
ast::Pat::OrPat(p) => 'b: {
@ -1615,8 +1604,7 @@ impl ExprCollector<'_> {
}
ast::Pat::WildcardPat(_) => Pat::Wild,
ast::Pat::RecordPat(p) => {
let path =
p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
let path = p.path().and_then(|path| self.parse_path(path)).map(Box::new);
let record_pat_field_list =
&p.record_pat_field_list().expect("every struct should have a field list");
let args = record_pat_field_list

View file

@ -158,9 +158,7 @@ impl ExprCollector<'_> {
AsmOperand::Const(self.collect_expr_opt(c.expr()))
}
ast::AsmOperand::AsmSym(s) => {
let Some(path) =
s.path().and_then(|p| self.expander.parse_path(self.db, p))
else {
let Some(path) = s.path().and_then(|p| self.parse_path(p)) else {
continue;
};
AsmOperand::Sym(path)

View file

@ -11,7 +11,6 @@ use crate::{
Statement,
},
pretty::{print_generic_args, print_path, print_type_ref},
type_ref::TypeRef,
};
use super::*;
@ -69,20 +68,20 @@ pub(super) fn print_body_hir(
};
if let DefWithBodyId::FunctionId(it) = owner {
p.buf.push('(');
let function_data = &db.function_data(it);
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);
p.print_type_ref(*ty, &function_data.types_map);
p.buf.push_str(", ");
}
}
body.params.iter().zip(params).for_each(|(&param, ty)| {
p.print_pat(param);
p.buf.push_str(": ");
p.print_type_ref(ty);
p.print_type_ref(*ty, &function_data.types_map);
p.buf.push_str(", ");
});
// remove the last ", " in param list
@ -92,7 +91,7 @@ pub(super) fn print_body_hir(
p.buf.push(')');
// return type
p.buf.push_str(" -> ");
p.print_type_ref(ret_type);
p.print_type_ref(*ret_type, &function_data.types_map);
p.buf.push(' ');
}
p.print_expr(body.body_expr);
@ -242,7 +241,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.print_type_ref(offset_of.container, &self.body.types);
let edition = self.edition;
w!(
self,
@ -296,7 +295,7 @@ impl Printer<'_> {
if let Some(args) = generic_args {
w!(self, "::<");
let edition = self.edition;
print_generic_args(self.db, args, self, edition).unwrap();
print_generic_args(self.db, args, &self.body.types, self, edition).unwrap();
w!(self, ">");
}
w!(self, "(");
@ -405,7 +404,7 @@ impl Printer<'_> {
Expr::Cast { expr, type_ref } => {
self.print_expr(*expr);
w!(self, " as ");
self.print_type_ref(type_ref);
self.print_type_ref(*type_ref, &self.body.types);
}
Expr::Ref { expr, rawness, mutability } => {
w!(self, "&");
@ -493,13 +492,13 @@ impl Printer<'_> {
self.print_pat(*pat);
if let Some(ty) = ty {
w!(self, ": ");
self.print_type_ref(ty);
self.print_type_ref(*ty, &self.body.types);
}
}
w!(self, "|");
if let Some(ret_ty) = ret_type {
w!(self, " -> ");
self.print_type_ref(ret_ty);
self.print_type_ref(*ret_ty, &self.body.types);
}
self.whitespace();
self.print_expr(*body);
@ -734,7 +733,7 @@ impl Printer<'_> {
self.print_pat(*pat);
if let Some(ty) = type_ref {
w!(self, ": ");
self.print_type_ref(ty);
self.print_type_ref(*ty, &self.body.types);
}
if let Some(init) = initializer {
w!(self, " = ");
@ -792,14 +791,14 @@ impl Printer<'_> {
}
}
fn print_type_ref(&mut self, ty: &TypeRef) {
fn print_type_ref(&mut self, ty: TypeRefId, map: &TypesMap) {
let edition = self.edition;
print_type_ref(self.db, ty, self, edition).unwrap();
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, edition).unwrap();
print_path(self.db, path, &self.body.types, self, edition).unwrap();
}
fn print_binding(&mut self, id: BindingId) {

View file

@ -6,7 +6,7 @@ use base_db::CrateId;
use hir_expand::{
name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefKind,
};
use intern::{sym, Interned, Symbol};
use intern::{sym, Symbol};
use la_arena::{Idx, RawIdx};
use smallvec::SmallVec;
use syntax::{ast, Parse};
@ -25,7 +25,7 @@ use crate::{
DefMap, MacroSubNs,
},
path::ImportAlias,
type_ref::{TraitRef, TypeBound, TypeRef},
type_ref::{TraitRef, TypeBound, TypeRefId, TypesMap},
visibility::RawVisibility,
AssocItemId, AstIdWithPath, ConstId, ConstLoc, ExternCrateId, FunctionId, FunctionLoc,
HasModule, ImplId, Intern, ItemContainerId, ItemLoc, Lookup, Macro2Id, MacroRulesId, ModuleId,
@ -35,13 +35,14 @@ use crate::{
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FunctionData {
pub name: Name,
pub params: Box<[Interned<TypeRef>]>,
pub ret_type: Interned<TypeRef>,
pub params: Box<[TypeRefId]>,
pub ret_type: TypeRefId,
pub attrs: Attrs,
pub visibility: RawVisibility,
pub abi: Option<Symbol>,
pub legacy_const_generics_indices: Option<Box<Box<[u32]>>>,
pub rustc_allow_incoherent_impl: bool,
pub types_map: Arc<TypesMap>,
flags: FnFlags,
}
@ -110,13 +111,14 @@ impl FunctionData {
.filter(|&(idx, _)| {
item_tree.attrs(db, krate, attr_owner(idx)).is_cfg_enabled(cfg_options)
})
.filter_map(|(_, param)| param.type_ref.clone())
.filter_map(|(_, param)| param.type_ref)
.collect(),
ret_type: func.ret_type.clone(),
ret_type: func.ret_type,
attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
visibility,
abi: func.abi.clone(),
legacy_const_generics_indices,
types_map: func.types_map.clone(),
flags,
rustc_allow_incoherent_impl,
})
@ -182,13 +184,14 @@ fn parse_rustc_legacy_const_generics(tt: &crate::tt::Subtree) -> Box<[u32]> {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TypeAliasData {
pub name: Name,
pub type_ref: Option<Interned<TypeRef>>,
pub type_ref: Option<TypeRefId>,
pub visibility: RawVisibility,
pub is_extern: bool,
pub rustc_has_incoherent_inherent_impls: bool,
pub rustc_allow_incoherent_impl: bool,
/// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl).
pub bounds: Box<[Interned<TypeBound>]>,
pub bounds: Box<[TypeBound]>,
pub types_map: Arc<TypesMap>,
}
impl TypeAliasData {
@ -216,12 +219,13 @@ impl TypeAliasData {
Arc::new(TypeAliasData {
name: typ.name.clone(),
type_ref: typ.type_ref.clone(),
type_ref: typ.type_ref,
visibility,
is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
rustc_has_incoherent_inherent_impls,
rustc_allow_incoherent_impl,
bounds: typ.bounds.clone(),
types_map: typ.types_map.clone(),
})
}
}
@ -343,13 +347,14 @@ impl TraitAliasData {
#[derive(Debug, PartialEq, Eq)]
pub struct ImplData {
pub target_trait: Option<Interned<TraitRef>>,
pub self_ty: Interned<TypeRef>,
pub target_trait: Option<TraitRef>,
pub self_ty: TypeRefId,
pub items: Box<[AssocItemId]>,
pub is_negative: bool,
pub is_unsafe: bool,
// box it as the vec is usually empty anyways
pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
pub types_map: Arc<TypesMap>,
}
impl ImplData {
@ -368,7 +373,7 @@ impl ImplData {
let item_tree = tree_id.item_tree(db);
let impl_def = &item_tree[tree_id.value];
let target_trait = impl_def.target_trait.clone();
let self_ty = impl_def.self_ty.clone();
let self_ty = impl_def.self_ty;
let is_negative = impl_def.is_negative;
let is_unsafe = impl_def.is_unsafe;
@ -387,6 +392,7 @@ impl ImplData {
is_negative,
is_unsafe,
macro_calls,
types_map: impl_def.types_map.clone(),
}),
DefDiagnostics::new(diagnostics),
)
@ -532,10 +538,11 @@ impl ExternCrateDeclData {
pub struct ConstData {
/// `None` for `const _: () = ();`
pub name: Option<Name>,
pub type_ref: Interned<TypeRef>,
pub type_ref: TypeRefId,
pub visibility: RawVisibility,
pub rustc_allow_incoherent_impl: bool,
pub has_body: bool,
pub types_map: Arc<TypesMap>,
}
impl ConstData {
@ -556,10 +563,11 @@ impl ConstData {
Arc::new(ConstData {
name: konst.name.clone(),
type_ref: konst.type_ref.clone(),
type_ref: konst.type_ref,
visibility,
rustc_allow_incoherent_impl,
has_body: konst.has_body,
types_map: konst.types_map.clone(),
})
}
}
@ -567,12 +575,13 @@ impl ConstData {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StaticData {
pub name: Name,
pub type_ref: Interned<TypeRef>,
pub type_ref: TypeRefId,
pub visibility: RawVisibility,
pub mutable: bool,
pub is_extern: bool,
pub has_safe_kw: bool,
pub has_unsafe_kw: bool,
pub types_map: Arc<TypesMap>,
}
impl StaticData {
@ -583,12 +592,13 @@ impl StaticData {
Arc::new(StaticData {
name: statik.name.clone(),
type_ref: statik.type_ref.clone(),
type_ref: statik.type_ref,
visibility: item_tree[statik.visibility].clone(),
mutable: statik.mutable,
is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
has_safe_kw: statik.has_safe_kw,
has_unsafe_kw: statik.has_unsafe_kw,
types_map: statik.types_map.clone(),
})
}
}

View file

@ -6,7 +6,7 @@ use cfg::CfgOptions;
use either::Either;
use hir_expand::name::Name;
use intern::{sym, Interned};
use intern::sym;
use la_arena::Arena;
use rustc_abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions};
use triomphe::Arc;
@ -21,7 +21,7 @@ use crate::{
lang_item::LangItem,
nameres::diagnostics::{DefDiagnostic, DefDiagnostics},
tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree},
type_ref::TypeRef,
type_ref::{TypeRefId, TypesMap},
visibility::RawVisibility,
EnumId, EnumVariantId, LocalFieldId, LocalModuleId, Lookup, StructId, UnionId, VariantId,
};
@ -73,8 +73,8 @@ pub struct EnumVariantData {
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum VariantData {
Record(Arena<FieldData>),
Tuple(Arena<FieldData>),
Record { fields: Arena<FieldData>, types_map: Arc<TypesMap> },
Tuple { fields: Arena<FieldData>, types_map: Arc<TypesMap> },
Unit,
}
@ -82,7 +82,7 @@ pub enum VariantData {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FieldData {
pub name: Name,
pub type_ref: Interned<TypeRef>,
pub type_ref: TypeRefId,
pub visibility: RawVisibility,
}
@ -208,7 +208,7 @@ impl StructData {
}
let strukt = &item_tree[loc.id.value];
let (data, diagnostics) = lower_fields(
let (fields, diagnostics) = lower_fields(
db,
krate,
loc.container.local_id,
@ -219,12 +219,13 @@ impl StructData {
&strukt.fields,
None,
);
let types_map = strukt.types_map.clone();
(
Arc::new(StructData {
name: strukt.name.clone(),
variant_data: Arc::new(match strukt.shape {
FieldsShape::Record => VariantData::Record(data),
FieldsShape::Tuple => VariantData::Tuple(data),
FieldsShape::Record => VariantData::Record { fields, types_map },
FieldsShape::Tuple => VariantData::Tuple { fields, types_map },
FieldsShape::Unit => VariantData::Unit,
}),
repr,
@ -258,7 +259,7 @@ impl StructData {
}
let union = &item_tree[loc.id.value];
let (data, diagnostics) = lower_fields(
let (fields, diagnostics) = lower_fields(
db,
krate,
loc.container.local_id,
@ -269,10 +270,11 @@ impl StructData {
&union.fields,
None,
);
let types_map = union.types_map.clone();
(
Arc::new(StructData {
name: union.name.clone(),
variant_data: Arc::new(VariantData::Record(data)),
variant_data: Arc::new(VariantData::Record { fields, types_map }),
repr,
visibility: item_tree[union.visibility].clone(),
flags,
@ -360,7 +362,7 @@ impl EnumVariantData {
let item_tree = loc.id.item_tree(db);
let variant = &item_tree[loc.id.value];
let (data, diagnostics) = lower_fields(
let (fields, diagnostics) = lower_fields(
db,
krate,
container.local_id,
@ -371,13 +373,14 @@ impl EnumVariantData {
&variant.fields,
Some(item_tree[loc.parent.lookup(db).id.value].visibility),
);
let types_map = variant.types_map.clone();
(
Arc::new(EnumVariantData {
name: variant.name.clone(),
variant_data: Arc::new(match variant.shape {
FieldsShape::Record => VariantData::Record(data),
FieldsShape::Tuple => VariantData::Tuple(data),
FieldsShape::Record => VariantData::Record { fields, types_map },
FieldsShape::Tuple => VariantData::Tuple { fields, types_map },
FieldsShape::Unit => VariantData::Unit,
}),
}),
@ -390,11 +393,20 @@ impl VariantData {
pub fn fields(&self) -> &Arena<FieldData> {
const EMPTY: &Arena<FieldData> = &Arena::new();
match &self {
VariantData::Record(fields) | VariantData::Tuple(fields) => fields,
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 })
@ -402,8 +414,8 @@ impl VariantData {
pub fn kind(&self) -> StructKind {
match self {
VariantData::Record(_) => StructKind::Record,
VariantData::Tuple(_) => StructKind::Tuple,
VariantData::Record { .. } => StructKind::Record,
VariantData::Tuple { .. } => StructKind::Tuple,
VariantData::Unit => StructKind::Unit,
}
}
@ -463,7 +475,7 @@ fn lower_field(
) -> FieldData {
FieldData {
name: field.name.clone(),
type_ref: field.type_ref.clone(),
type_ref: field.type_ref,
visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(),
}
}

View file

@ -2,7 +2,7 @@
use base_db::{ra_salsa, CrateId, SourceDatabase, Upcast};
use either::Either;
use hir_expand::{db::ExpandDatabase, HirFileId, MacroDefId};
use intern::{sym, Interned};
use intern::sym;
use la_arena::ArenaMap;
use span::{EditionedFileId, MacroCallId};
use syntax::{ast, AstPtr};
@ -18,9 +18,10 @@ use crate::{
},
generics::GenericParams,
import_map::ImportMap,
item_tree::{AttrOwner, ItemTree},
item_tree::{AttrOwner, ItemTree, ItemTreeSourceMaps},
lang_item::{self, LangItem, LangItemTarget, LangItems},
nameres::{diagnostics::DefDiagnostics, DefMap},
type_ref::TypesSourceMap,
visibility::{self, Visibility},
AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstBlockLoc, ConstId, ConstLoc, DefWithBodyId,
EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId,
@ -91,6 +92,18 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
#[ra_salsa::invoke(ItemTree::block_item_tree_query)]
fn block_item_tree(&self, block_id: BlockId) -> Arc<ItemTree>;
#[ra_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>);
#[ra_salsa::invoke(ItemTree::block_item_tree_with_source_map_query)]
fn block_item_tree_with_source_map(
&self,
block_id: BlockId,
) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>);
#[ra_salsa::invoke(DefMap::crate_def_map_query)]
fn crate_def_map(&self, krate: CrateId) -> Arc<DefMap>;
@ -187,7 +200,14 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>;
#[ra_salsa::invoke(GenericParams::generic_params_query)]
fn generic_params(&self, def: GenericDefId) -> Interned<GenericParams>;
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.
#[ra_salsa::invoke(GenericParams::generic_params_with_source_map_query)]
fn generic_params_with_source_map(
&self,
def: GenericDefId,
) -> (Arc<GenericParams>, Option<Arc<TypesSourceMap>>);
// region:attrs

View file

@ -14,6 +14,7 @@ use span::SyntaxContextId;
use syntax::{ast, Parse};
use triomphe::Arc;
use crate::type_ref::{TypesMap, TypesSourceMap};
use crate::{
attr::Attrs, db::DefDatabase, lower::LowerCtx, path::Path, AsMacroCall, MacroId, ModuleId,
UnresolvedMacro,
@ -114,8 +115,19 @@ impl Expander {
mark.bomb.defuse();
}
pub fn ctx<'a>(&self, db: &'a dyn DefDatabase) -> LowerCtx<'a> {
LowerCtx::with_span_map_cell(db, self.current_file_id, self.span_map.clone())
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> {
@ -142,8 +154,20 @@ impl Expander {
self.current_file_id
}
pub(crate) fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option<Path> {
let ctx = LowerCtx::with_span_map_cell(db, self.current_file_id, self.span_map.clone());
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 ctx = LowerCtx::with_span_map_cell(
db,
self.current_file_id,
self.span_map.clone(),
types_map,
types_source_map,
);
Path::from_src(&ctx, path)
}

View file

@ -3,16 +3,18 @@
//! generic parameters. See also the `Generics` type and the `generics_of` query
//! in rustc.
use std::ops;
use std::{ops, sync::LazyLock};
use either::Either;
use hir_expand::{
name::{AsName, Name},
ExpandResult,
};
use intern::Interned;
use la_arena::{Arena, RawIdx};
use stdx::impl_from;
use stdx::{
impl_from,
thin_vec::{EmptyOptimizedThinVec, ThinVec},
};
use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds};
use triomphe::Arc;
@ -22,7 +24,11 @@ use crate::{
item_tree::{AttrOwner, FileItemTreeId, GenericModItem, GenericsItemTreeNode, ItemTree},
lower::LowerCtx,
nameres::{DefMap, MacroSubNs},
type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef},
path::{AssociatedTypeBinding, GenericArg, GenericArgs, NormalPath, Path},
type_ref::{
ArrayType, ConstRef, FnType, LifetimeRef, RefType, TypeBound, TypeRef, TypeRefId, TypesMap,
TypesSourceMap,
},
AdtId, ConstParamId, GenericDefId, HasModule, ItemTreeLoc, LifetimeParamId,
LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
};
@ -37,7 +43,7 @@ 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<Interned<TypeRef>>,
pub default: Option<TypeRefId>,
pub provenance: TypeParamProvenance,
}
@ -51,7 +57,7 @@ pub struct LifetimeParamData {
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct ConstParamData {
pub name: Name,
pub ty: Interned<TypeRef>,
pub ty: TypeRefId,
pub default: Option<ConstRef>,
}
@ -161,6 +167,7 @@ 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 {
@ -183,24 +190,14 @@ impl ops::Index<LocalLifetimeParamId> for GenericParams {
/// associated type bindings like `Iterator<Item = u32>`.
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum WherePredicate {
TypeBound {
target: WherePredicateTypeTarget,
bound: Interned<TypeBound>,
},
Lifetime {
target: LifetimeRef,
bound: LifetimeRef,
},
ForLifetime {
lifetimes: Box<[Name]>,
target: WherePredicateTypeTarget,
bound: Interned<TypeBound>,
},
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(Interned<TypeRef>),
TypeRef(TypeRefId),
/// For desugared where predicates that can directly refer to a type param.
TypeOrConstParam(LocalTypeOrConstParamId),
}
@ -300,7 +297,14 @@ impl GenericParams {
pub(crate) fn generic_params_query(
db: &dyn DefDatabase,
def: GenericDefId,
) -> Interned<GenericParams> {
) -> 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);
@ -309,7 +313,7 @@ impl GenericParams {
// Returns the generic parameters that are enabled under the current `#[cfg]` options
let enabled_params =
|params: &Interned<GenericParams>, item_tree: &ItemTree, parent: GenericModItem| {
|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);
@ -325,7 +329,7 @@ impl GenericParams {
if all_type_or_consts_enabled && all_lifetimes_enabled {
params.clone()
} else {
Interned::new(GenericParams {
Arc::new(GenericParams {
type_or_consts: all_type_or_consts_enabled
.then(|| params.type_or_consts.clone())
.unwrap_or_else(|| {
@ -347,6 +351,7 @@ impl GenericParams {
.collect()
}),
where_predicates: params.where_predicates.clone(),
types_map: params.types_map.clone(),
})
}
};
@ -357,18 +362,18 @@ impl GenericParams {
Data = impl ItemTreeLoc<Id = Id>,
>,
enabled_params: impl Fn(
&Interned<GenericParams>,
&Arc<GenericParams>,
&ItemTree,
GenericModItem,
) -> Interned<GenericParams>,
) -> Interned<GenericParams>
) -> 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())
(enabled_params(item.generic_params(), &tree, id.value.into()), None)
}
match def {
@ -383,28 +388,37 @@ impl GenericParams {
let module = loc.container.module(db);
let func_data = db.function_data(id);
if func_data.params.is_empty() {
enabled_params
(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 param in func_data.params.iter() {
for &param in func_data.params.iter() {
generic_params.fill_implicit_impl_trait_args(
db,
&mut types_map,
&mut types_source_maps,
&mut expander,
&mut || {
(module.def_map(db), Expander::new(db, loc.id.file_id(), module))
},
param,
&item.types_map,
item_source_maps.item(),
);
}
Interned::new(generic_params.finish())
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),
@ -414,11 +428,15 @@ impl GenericParams {
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(_) => Interned::new(GenericParams {
type_or_consts: Default::default(),
lifetimes: Default::default(),
where_predicates: Default::default(),
}),
GenericDefId::ConstId(_) => (
Arc::new(GenericParams {
type_or_consts: Default::default(),
lifetimes: Default::default(),
where_predicates: Default::default(),
types_map: Default::default(),
}),
None,
),
}
}
}
@ -452,7 +470,7 @@ impl GenericParamsCollector {
&mut self,
lower_ctx: &LowerCtx<'_>,
type_bounds: Option<ast::TypeBoundList>,
target: Either<TypeRef, LifetimeRef>,
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());
@ -473,16 +491,15 @@ impl GenericParamsCollector {
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| Interned::new(TypeRef::from_ast(lower_ctx, it)));
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 = TypeRef::Path(name.into());
let type_ref = lower_ctx.alloc_type_ref_desugared(TypeRef::Path(name.into()));
self.fill_bounds(
lower_ctx,
type_param.type_bound_list(),
@ -492,12 +509,10 @@ impl GenericParamsCollector {
}
ast::TypeOrConstParam::Const(const_param) => {
let name = const_param.name().map_or_else(Name::missing, |it| it.as_name());
let ty = const_param
.ty()
.map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it));
let ty = TypeRef::from_ast_opt(lower_ctx, const_param.ty());
let param = ConstParamData {
name,
ty: Interned::new(ty),
ty,
default: ConstRef::from_const_param(lower_ctx, &const_param),
};
let idx = self.type_or_consts.alloc(param.into());
@ -557,7 +572,7 @@ impl GenericParamsCollector {
lower_ctx: &LowerCtx<'_>,
bound: ast::TypeBound,
hrtb_lifetimes: Option<&[Name]>,
target: Either<TypeRef, LifetimeRef>,
target: Either<TypeRefId, LifetimeRef>,
) {
let bound = TypeBound::from_ast(lower_ctx, bound);
self.fill_impl_trait_bounds(lower_ctx.take_impl_traits_bounds());
@ -565,12 +580,12 @@ impl GenericParamsCollector {
(Either::Left(type_ref), bound) => match hrtb_lifetimes {
Some(hrtb_lifetimes) => WherePredicate::ForLifetime {
lifetimes: hrtb_lifetimes.to_vec().into_boxed_slice(),
target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)),
bound: Interned::new(bound),
target: WherePredicateTypeTarget::TypeRef(type_ref),
bound,
},
None => WherePredicate::TypeBound {
target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)),
bound: Interned::new(bound),
target: WherePredicateTypeTarget::TypeRef(type_ref),
bound,
},
},
(Either::Right(lifetime), TypeBound::Lifetime(bound)) => {
@ -581,7 +596,7 @@ impl GenericParamsCollector {
self.where_predicates.push(predicate);
}
fn fill_impl_trait_bounds(&mut self, impl_bounds: Vec<Vec<Interned<TypeBound>>>) {
fn fill_impl_trait_bounds(&mut self, impl_bounds: Vec<ThinVec<TypeBound>>) {
for bounds in impl_bounds {
let param = TypeParamData {
name: None,
@ -589,10 +604,10 @@ impl GenericParamsCollector {
provenance: TypeParamProvenance::ArgumentImplTrait,
};
let param_id = self.type_or_consts.alloc(param.into());
for bound in bounds {
for bound in &bounds {
self.where_predicates.push(WherePredicate::TypeBound {
target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
bound,
bound: bound.clone(),
});
}
}
@ -601,12 +616,16 @@ impl GenericParamsCollector {
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>, Expander)>,
exp_fill: &mut dyn FnMut() -> (Arc<DefMap>, Expander),
type_ref: &TypeRef,
type_ref: TypeRefId,
types_map: &TypesMap,
types_source_map: &TypesSourceMap,
) {
type_ref.walk(&mut |type_ref| {
TypeRef::walk(type_ref, types_map, &mut |type_ref| {
if let TypeRef::ImplTrait(bounds) = type_ref {
let param = TypeParamData {
name: None,
@ -615,12 +634,20 @@ impl GenericParamsCollector {
};
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: bound.clone(),
bound,
});
}
}
if let TypeRef::Macro(mc) = type_ref {
let macro_call = mc.to_node(db.upcast());
let (def_map, expander) = exp.get_or_insert_with(&mut *exp_fill);
@ -641,23 +668,217 @@ impl GenericParamsCollector {
if let Ok(ExpandResult { value: Some((mark, expanded)), .. }) =
expander.enter_expand(db, macro_call, resolver)
{
let ctx = expander.ctx(db);
let (mut macro_types_map, mut macro_types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let ctx = expander.ctx(db, &mut macro_types_map, &mut macro_types_source_map);
let type_ref = TypeRef::from_ast(&ctx, expanded.tree());
self.fill_implicit_impl_trait_args(db, &mut *exp, exp_fill, &type_ref);
self.fill_implicit_impl_trait_args(
db,
generics_types_map,
generics_types_source_map,
&mut *exp,
exp_fill,
type_ref,
&macro_types_map,
&macro_types_source_map,
);
exp.get_or_insert_with(&mut *exp_fill).1.exit(mark);
}
}
});
}
pub(crate) fn finish(self) -> GenericParams {
let Self { mut lifetimes, mut type_or_consts, where_predicates } = self;
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();
GenericParams {
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(FnType::new(fn_.is_varargs(), fn_.is_unsafe(), fn_.abi().clone(), params))
}
TypeRef::Tuple(types) => TypeRef::Tuple(EmptyOptimizedThinVec::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(NormalPath::new(type_anchor, mod_path, generic_args))
}
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,
desugared_from_fn: generic_args.desugared_from_fn,
}
})
}
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 stdx::thin_vec::TrustedLen<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 {
match bound {
TypeBound::Path(path, modifier) => {
TypeBound::Path(copy_path(path, from, from_source_map, to, to_source_map), *modifier)
}
TypeBound::ForLifetime(lifetimes, path) => TypeBound::ForLifetime(
lifetimes.clone(),
copy_path(path, from, from_source_map, to, to_source_map),
),
TypeBound::Lifetime(lifetime) => TypeBound::Lifetime(lifetime.clone()),
TypeBound::Use(use_args) => TypeBound::Use(use_args.clone()),
TypeBound::Error => TypeBound::Error,
}
}

View file

@ -18,15 +18,16 @@ pub mod type_ref;
use std::fmt;
use hir_expand::{name::Name, MacroDefId};
use intern::{Interned, Symbol};
use intern::Symbol;
use la_arena::{Idx, RawIdx};
use rustc_apfloat::ieee::{Half as f16, Quad as f128};
use syntax::ast;
use type_ref::TypeRefId;
use crate::{
builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
path::{GenericArgs, Path},
type_ref::{Mutability, Rawness, TypeRef},
type_ref::{Mutability, Rawness},
BlockId, ConstBlockId,
};
@ -264,7 +265,7 @@ pub enum Expr {
},
Cast {
expr: ExprId,
type_ref: Interned<TypeRef>,
type_ref: TypeRefId,
},
Ref {
expr: ExprId,
@ -300,8 +301,8 @@ pub enum Expr {
},
Closure {
args: Box<[PatId]>,
arg_types: Box<[Option<Interned<TypeRef>>]>,
ret_type: Option<Interned<TypeRef>>,
arg_types: Box<[Option<TypeRefId>]>,
ret_type: Option<TypeRefId>,
body: ExprId,
closure_kind: ClosureKind,
capture_by: CaptureBy,
@ -318,7 +319,7 @@ pub enum Expr {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OffsetOf {
pub container: Interned<TypeRef>,
pub container: TypeRefId,
pub fields: Box<[Name]>,
}
@ -484,7 +485,7 @@ pub struct RecordLitField {
pub enum Statement {
Let {
pat: PatId,
type_ref: Option<Interned<TypeRef>>,
type_ref: Option<TypeRefId>,
initializer: Option<ExprId>,
else_branch: Option<ExprId>,
},
@ -582,7 +583,7 @@ pub enum Pat {
suffix: Box<[PatId]>,
},
/// This might refer to a variable if a single segment path (specifically, on destructuring assignment).
Path(Box<Path>),
Path(Path),
Lit(ExprId),
Bind {
id: BindingId,

View file

@ -2,22 +2,27 @@
//! be directly created from an ast::TypeRef, without further queries.
use core::fmt;
use std::fmt::Write;
use std::{fmt::Write, ops::Index};
use hir_expand::{
db::ExpandDatabase,
name::{AsName, Name},
AstId,
AstId, InFile,
};
use intern::{sym, Interned, Symbol};
use intern::{sym, Symbol};
use la_arena::{Arena, ArenaMap, Idx};
use span::Edition;
use syntax::ast::{self, HasGenericArgs, HasName, IsString};
use stdx::thin_vec::{thin_vec_with_header_struct, EmptyOptimizedThinVec, ThinVec};
use syntax::{
ast::{self, HasGenericArgs, HasName, IsString},
AstPtr,
};
use crate::{
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
hir::Literal,
lower::LowerCtx,
path::Path,
path::{GenericArg, Path},
};
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
@ -104,35 +109,90 @@ impl TraitRef {
}
}
thin_vec_with_header_struct! {
pub new(pub(crate)) struct FnType, FnTypeHeader {
pub params: [(Option<Name>, TypeRefId)],
pub is_varargs: bool,
pub is_unsafe: bool,
pub abi: Option<Symbol>; ref,
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct ArrayType {
pub ty: TypeRefId,
// FIXME: This should be Ast<ConstArg>
pub len: ConstRef,
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct RefType {
pub ty: TypeRefId,
pub lifetime: Option<LifetimeRef>,
pub mutability: Mutability,
}
/// Compare ty::Ty
///
/// Note: Most users of `TypeRef` that end up in the salsa database intern it using
/// `Interned<TypeRef>` to save space. But notably, nested `TypeRef`s are not interned, since that
/// does not seem to save any noticeable amount of memory.
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum TypeRef {
Never,
Placeholder,
Tuple(Vec<TypeRef>),
Tuple(EmptyOptimizedThinVec<TypeRefId>),
Path(Path),
RawPtr(Box<TypeRef>, Mutability),
Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability),
// FIXME: This should be Array(Box<TypeRef>, Ast<ConstArg>),
Array(Box<TypeRef>, ConstRef),
Slice(Box<TypeRef>),
RawPtr(TypeRefId, Mutability),
Reference(Box<RefType>),
Array(Box<ArrayType>),
Slice(TypeRefId),
/// A fn pointer. Last element of the vector is the return type.
Fn(
Box<[(Option<Name>, TypeRef)]>,
bool, /*varargs*/
bool, /*is_unsafe*/
Option<Symbol>, /* abi */
),
ImplTrait(Vec<Interned<TypeBound>>),
DynTrait(Vec<Interned<TypeBound>>),
Fn(FnType),
ImplTrait(ThinVec<TypeBound>),
DynTrait(ThinVec<TypeBound>),
Macro(AstId<ast::MacroCall>),
Error,
}
#[cfg(target_arch = "x86_64")]
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;
fn index(&self, index: TypeRefId) -> &Self::Output {
&self.types[index]
}
}
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(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,
@ -162,7 +222,7 @@ pub enum TypeBound {
}
#[cfg(target_pointer_width = "64")]
const _: [(); 56] = [(); ::std::mem::size_of::<TypeBound>()];
const _: [(); 32] = [(); ::std::mem::size_of::<TypeBound>()];
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum UseArgRef {
@ -172,7 +232,7 @@ pub enum UseArgRef {
/// A modifier on a bound, currently this is only used for `?Sized`, where the
/// modifier is `Maybe`.
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum TraitBoundModifier {
None,
Maybe,
@ -180,12 +240,12 @@ pub enum TraitBoundModifier {
impl TypeRef {
/// Converts an `ast::TypeRef` to a `hir::TypeRef`.
pub fn from_ast(ctx: &LowerCtx<'_>, node: ast::Type) -> Self {
match node {
ast::Type::ParenType(inner) => TypeRef::from_ast_opt(ctx, inner.ty()),
ast::Type::TupleType(inner) => {
TypeRef::Tuple(inner.fields().map(|it| TypeRef::from_ast(ctx, it)).collect())
}
pub fn from_ast(ctx: &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(EmptyOptimizedThinVec::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`
@ -198,20 +258,21 @@ impl TypeRef {
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(Box::new(inner_ty), mutability)
TypeRef::RawPtr(inner_ty, mutability)
}
ast::Type::ArrayType(inner) => {
let len = ConstRef::from_const_arg(ctx, inner.const_arg());
TypeRef::Array(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())), len)
}
ast::Type::SliceType(inner) => {
TypeRef::Slice(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())))
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(&lt));
let mutability = Mutability::from_mutable(inner.mut_token().is_some());
TypeRef::Reference(Box::new(inner_ty), lifetime, mutability)
TypeRef::Reference(Box::new(RefType { ty: inner_ty, lifetime, mutability }))
}
ast::Type::InferType(_inner) => TypeRef::Placeholder,
ast::Type::FnPtrType(inner) => {
@ -219,7 +280,7 @@ impl TypeRef {
.ret_type()
.and_then(|rt| rt.ty())
.map(|it| TypeRef::from_ast(ctx, it))
.unwrap_or_else(|| TypeRef::Tuple(Vec::new()));
.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() {
@ -251,10 +312,10 @@ impl TypeRef {
let abi = inner.abi().map(lower_abi);
params.push((None, ret_ty));
TypeRef::Fn(params.into(), is_varargs, inner.unsafe_token().is_some(), abi)
TypeRef::Fn(FnType::new(is_varargs, inner.unsafe_token().is_some(), abi, params))
}
// for types are close enough for our purposes to the inner type for now...
ast::Type::ForType(inner) => TypeRef::from_ast_opt(ctx, inner.ty()),
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
@ -271,72 +332,72 @@ impl TypeRef {
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: &LowerCtx<'_>, node: Option<ast::Type>) -> Self {
pub(crate) fn from_ast_opt(ctx: &LowerCtx<'_>, node: Option<ast::Type>) -> TypeRefId {
match node {
Some(node) => TypeRef::from_ast(ctx, node),
None => TypeRef::Error,
None => ctx.alloc_error_type(),
}
}
pub(crate) fn unit() -> TypeRef {
TypeRef::Tuple(Vec::new())
TypeRef::Tuple(EmptyOptimizedThinVec::empty())
}
pub fn walk(&self, f: &mut impl FnMut(&TypeRef)) {
go(self, f);
pub fn walk(this: TypeRefId, map: &TypesMap, f: &mut impl FnMut(&TypeRef)) {
go(this, f, map);
fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) {
fn go(type_ref: TypeRefId, f: &mut impl FnMut(&TypeRef), map: &TypesMap) {
let type_ref = &map[type_ref];
f(type_ref);
match type_ref {
TypeRef::Fn(params, _, _, _) => {
params.iter().for_each(|(_, param_type)| go(param_type, f))
TypeRef::Fn(fn_) => {
fn_.params().iter().for_each(|&(_, param_type)| go(param_type, f, map))
}
TypeRef::Tuple(types) => types.iter().for_each(|t| go(t, f)),
TypeRef::RawPtr(type_ref, _)
| TypeRef::Reference(type_ref, ..)
| TypeRef::Array(type_ref, _)
| TypeRef::Slice(type_ref) => go(type_ref, f),
TypeRef::Tuple(types) => types.iter().for_each(|&t| go(t, f, map)),
TypeRef::RawPtr(type_ref, _) | TypeRef::Slice(type_ref) => go(*type_ref, f, map),
TypeRef::Reference(it) => go(it.ty, f, map),
TypeRef::Array(it) => go(it.ty, f, map),
TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
for bound in bounds {
match bound.as_ref() {
match bound {
TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
go_path(path, f)
go_path(path, f, map)
}
TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
}
}
}
TypeRef::Path(path) => go_path(path, f),
TypeRef::Path(path) => go_path(path, f, map),
TypeRef::Never | TypeRef::Placeholder | TypeRef::Macro(_) | TypeRef::Error => {}
};
}
fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef)) {
fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef), map: &TypesMap) {
if let Some(type_ref) = path.type_anchor() {
go(type_ref, f);
go(type_ref, f, map);
}
for segment in path.segments().iter() {
if let Some(args_and_bindings) = segment.args_and_bindings {
for arg in args_and_bindings.args.iter() {
match arg {
crate::path::GenericArg::Type(type_ref) => {
go(type_ref, f);
GenericArg::Type(type_ref) => {
go(*type_ref, f, map);
}
crate::path::GenericArg::Const(_)
| crate::path::GenericArg::Lifetime(_) => {}
GenericArg::Const(_) | GenericArg::Lifetime(_) => {}
}
}
for binding in args_and_bindings.bindings.iter() {
if let Some(type_ref) = &binding.type_ref {
go(type_ref, f);
if let Some(type_ref) = binding.type_ref {
go(type_ref, f, map);
}
for bound in binding.bounds.iter() {
match bound.as_ref() {
match bound {
TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
go_path(path, f)
go_path(path, f, map)
}
TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
}
@ -351,11 +412,13 @@ impl TypeRef {
pub(crate) fn type_bounds_from_ast(
lower_ctx: &LowerCtx<'_>,
type_bounds_opt: Option<ast::TypeBoundList>,
) -> Vec<Interned<TypeBound>> {
) -> ThinVec<TypeBound> {
if let Some(type_bounds) = type_bounds_opt {
type_bounds.bounds().map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it))).collect()
ThinVec::from_iter(Vec::from_iter(
type_bounds.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)),
))
} else {
vec![]
ThinVec::from_iter([])
}
}

View file

@ -61,7 +61,7 @@ use crate::{
db::DefDatabase,
generics::GenericParams,
path::{GenericArgs, ImportAlias, ModPath, Path, PathKind},
type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
type_ref::{Mutability, TraitRef, TypeBound, TypeRefId, TypesMap, TypesSourceMap},
visibility::{RawVisibility, VisibilityExplicitness},
BlockId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup,
};
@ -100,13 +100,20 @@ 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>> = OnceLock::new();
static EMPTY: OnceLock<(Arc<ItemTree>, Arc<ItemTreeSourceMaps>)> = 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 = match_ast! {
let (mut item_tree, source_maps) = match_ast! {
match syntax {
ast::SourceFile(file) => {
top_attrs = Some(RawAttrs::new(db.upcast(), &file, ctx.span_map()));
@ -136,42 +143,55 @@ impl ItemTree {
{
EMPTY
.get_or_init(|| {
Arc::new(ItemTree {
top_level: SmallVec::new_const(),
attrs: FxHashMap::default(),
data: None,
})
(
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(item_tree), Arc::new(source_maps))
}
}
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>> = OnceLock::new();
static EMPTY: OnceLock<(Arc<ItemTree>, Arc<ItemTreeSourceMaps>)> = 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 = ctx.lower_block(&block);
let (mut item_tree, source_maps) = 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::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(item_tree), Arc::new(source_maps))
}
}
@ -308,6 +328,160 @@ struct ItemTreeData {
vis: ItemVisibilities,
}
#[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.
@ -363,7 +537,7 @@ pub trait ItemTreeNode: Clone {
fn attr_owner(id: FileItemTreeId<Self>) -> AttrOwner;
}
pub trait GenericsItemTreeNode: ItemTreeNode {
fn generic_params(&self) -> &Interned<GenericParams>;
fn generic_params(&self) -> &Arc<GenericParams>;
}
pub struct FileItemTreeId<N>(Idx<N>);
@ -428,6 +602,16 @@ 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
}
@ -460,6 +644,13 @@ 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>,
@ -592,7 +783,7 @@ macro_rules! mod_items {
$(
impl GenericsItemTreeNode for $typ {
fn generic_params(&self) -> &Interned<GenericParams> {
fn generic_params(&self) -> &Arc<GenericParams> {
&self.$generic_params
}
}
@ -730,17 +921,18 @@ pub struct ExternBlock {
pub struct Function {
pub name: Name,
pub visibility: RawVisibilityId,
pub explicit_generic_params: Interned<GenericParams>,
pub explicit_generic_params: Arc<GenericParams>,
pub abi: Option<Symbol>,
pub params: Box<[Param]>,
pub ret_type: Interned<TypeRef>,
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<Interned<TypeRef>>,
pub type_ref: Option<TypeRefId>,
}
bitflags::bitflags! {
@ -761,26 +953,28 @@ bitflags::bitflags! {
pub struct Struct {
pub name: Name,
pub visibility: RawVisibilityId,
pub generic_params: Interned<GenericParams>,
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: Interned<GenericParams>,
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: Interned<GenericParams>,
pub generic_params: Arc<GenericParams>,
pub variants: Range<FileItemTreeId<Variant>>,
pub ast_id: FileAstId<ast::Enum>,
}
@ -791,6 +985,7 @@ 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)]
@ -804,7 +999,7 @@ pub enum FieldsShape {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Field {
pub name: Name,
pub type_ref: Interned<TypeRef>,
pub type_ref: TypeRefId,
pub visibility: RawVisibilityId,
}
@ -813,9 +1008,10 @@ pub struct Const {
/// `None` for `const _: () = ();`
pub name: Option<Name>,
pub visibility: RawVisibilityId,
pub type_ref: Interned<TypeRef>,
pub type_ref: TypeRefId,
pub ast_id: FileAstId<ast::Const>,
pub has_body: bool,
pub types_map: Arc<TypesMap>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
@ -826,15 +1022,16 @@ pub struct Static {
pub mutable: bool,
pub has_safe_kw: bool,
pub has_unsafe_kw: bool,
pub type_ref: Interned<TypeRef>,
pub type_ref: TypeRefId,
pub ast_id: FileAstId<ast::Static>,
pub types_map: Arc<TypesMap>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Trait {
pub name: Name,
pub visibility: RawVisibilityId,
pub generic_params: Interned<GenericParams>,
pub generic_params: Arc<GenericParams>,
pub is_auto: bool,
pub is_unsafe: bool,
pub items: Box<[AssocItem]>,
@ -845,19 +1042,20 @@ pub struct Trait {
pub struct TraitAlias {
pub name: Name,
pub visibility: RawVisibilityId,
pub generic_params: Interned<GenericParams>,
pub generic_params: Arc<GenericParams>,
pub ast_id: FileAstId<ast::TraitAlias>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Impl {
pub generic_params: Interned<GenericParams>,
pub target_trait: Option<Interned<TraitRef>>,
pub self_ty: Interned<TypeRef>,
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)]
@ -865,10 +1063,11 @@ 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<[Interned<TypeBound>]>,
pub generic_params: Interned<GenericParams>,
pub type_ref: Option<Interned<TypeRef>>,
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)]

View file

@ -1,12 +1,18 @@
//! AST -> `ItemTree` lowering code.
use std::collections::hash_map::Entry;
use std::{cell::OnceCell, collections::hash_map::Entry};
use hir_expand::{mod_path::path, name::AsName, span_map::SpanMapRef, HirFileId};
use hir_expand::{
mod_path::path,
name::AsName,
span_map::{SpanMap, SpanMapRef},
HirFileId,
};
use intern::{sym, Symbol};
use la_arena::Arena;
use rustc_hash::FxHashMap;
use span::{AstIdMap, SyntaxContextId};
use stdx::thin_vec::ThinVec;
use syntax::{
ast::{self, HasModuleItem, HasName, HasTypeBounds, IsString},
AstNode,
@ -18,14 +24,19 @@ use crate::{
generics::{GenericParams, GenericParamsCollector, TypeParamData, TypeParamProvenance},
item_tree::{
AssocItem, AttrOwner, Const, Either, Enum, ExternBlock, ExternCrate, Field, FieldParent,
FieldsShape, FileItemTreeId, FnFlags, Function, GenericArgs, GenericModItem, Idx, Impl,
ImportAlias, Interned, ItemTree, ItemTreeData, Macro2, MacroCall, MacroRules, Mod, ModItem,
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, Struct, StructKind, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind,
Variant,
},
lower::LowerCtx,
path::AssociatedTypeBinding,
type_ref::{LifetimeRef, TraitBoundModifier, TraitRef, TypeBound, TypeRef},
type_ref::{
LifetimeRef, RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId,
TypesMap, TypesSourceMap,
},
visibility::RawVisibility,
LocalLifetimeParamId, LocalTypeOrConstParamId,
};
@ -40,7 +51,9 @@ pub(super) struct Ctx<'a> {
source_ast_id_map: Arc<AstIdMap>,
generic_param_attr_buffer:
FxHashMap<Either<LocalTypeOrConstParamId, LocalLifetimeParamId>, RawAttrs>,
body_ctx: crate::lower::LowerCtx<'a>,
span_map: OnceCell<SpanMap>,
file: HirFileId,
source_maps: ItemTreeSourceMapsBuilder,
}
impl<'a> Ctx<'a> {
@ -50,22 +63,49 @@ impl<'a> Ctx<'a> {
tree: ItemTree::default(),
generic_param_attr_buffer: FxHashMap::default(),
source_ast_id_map: db.ast_id_map(file),
body_ctx: crate::lower::LowerCtx::new(db, file),
file,
span_map: OnceCell::new(),
source_maps: ItemTreeSourceMapsBuilder::default(),
}
}
pub(super) fn span_map(&self) -> SpanMapRef<'_> {
self.body_ctx.span_map()
self.span_map.get_or_init(|| self.db.span_map(self.file)).as_ref()
}
pub(super) fn lower_module_items(mut self, item_owner: &dyn HasModuleItem) -> ItemTree {
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) {
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.tree, self.source_maps.build())
}
pub(super) fn lower_macro_stmts(mut self, stmts: ast::MacroStmts) -> ItemTree {
pub(super) fn lower_macro_stmts(
mut self,
stmts: ast::MacroStmts,
) -> (ItemTree, ItemTreeSourceMaps) {
self.tree.top_level = stmts
.statements()
.filter_map(|stmt| {
@ -96,10 +136,10 @@ impl<'a> Ctx<'a> {
}
assert!(self.generic_param_attr_buffer.is_empty());
self.tree
(self.tree, self.source_maps.build())
}
pub(super) fn lower_block(mut self, block: &ast::BlockExpr) -> ItemTree {
pub(super) fn lower_block(mut self, block: &ast::BlockExpr) -> (ItemTree, ItemTreeSourceMaps) {
self.tree
.attrs
.insert(AttrOwner::TopLevel, RawAttrs::new(self.db.upcast(), block, self.span_map()));
@ -125,7 +165,7 @@ impl<'a> Ctx<'a> {
}
assert!(self.generic_param_attr_buffer.is_empty());
self.tree
(self.tree, self.source_maps.build())
}
fn data(&mut self) -> &mut ItemTreeData {
@ -144,7 +184,7 @@ impl<'a> Ctx<'a> {
ast::Item::Module(ast) => self.lower_module(ast)?.into(),
ast::Item::Trait(ast) => self.lower_trait(ast)?.into(),
ast::Item::TraitAlias(ast) => self.lower_trait_alias(ast)?.into(),
ast::Item::Impl(ast) => self.lower_impl(ast)?.into(),
ast::Item::Impl(ast) => self.lower_impl(ast).into(),
ast::Item::Use(ast) => self.lower_use(ast)?.into(),
ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast)?.into(),
ast::Item::MacroCall(ast) => self.lower_macro_call(ast)?.into(),
@ -159,12 +199,14 @@ impl<'a> Ctx<'a> {
}
fn add_attrs(&mut self, item: AttrOwner, attrs: RawAttrs) {
match self.tree.attrs.entry(item) {
Entry::Occupied(mut entry) => {
*entry.get_mut() = entry.get().merge(attrs);
}
Entry::Vacant(entry) => {
entry.insert(attrs);
if !attrs.is_empty() {
match self.tree.attrs.entry(item) {
Entry::Occupied(mut entry) => {
*entry.get_mut() = entry.get().merge(attrs);
}
Entry::Vacant(entry) => {
entry.insert(attrs);
}
}
}
}
@ -190,13 +232,31 @@ 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 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());
let generic_params = self.lower_generic_params(HasImplicitSelf::No, strukt);
let res = Struct { name, visibility, generic_params, fields, shape: kind, ast_id };
let (fields, kind, attrs) = self.lower_fields(&strukt.kind(), &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 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(
@ -213,6 +273,7 @@ impl<'a> Ctx<'a> {
fn lower_fields(
&mut self,
strukt_kind: &ast::StructKind,
body_ctx: &LowerCtx<'_>,
) -> (Box<[Field]>, FieldsShape, Vec<(usize, RawAttrs)>) {
match strukt_kind {
ast::StructKind::Record(it) => {
@ -220,7 +281,7 @@ impl<'a> Ctx<'a> {
let mut attrs = vec![];
for (i, field) in it.fields().enumerate() {
let data = self.lower_record_field(&field);
let data = self.lower_record_field(&field, body_ctx);
fields.push(data);
let attr = RawAttrs::new(self.db.upcast(), &field, self.span_map());
if !attr.is_empty() {
@ -234,7 +295,7 @@ impl<'a> Ctx<'a> {
let mut attrs = vec![];
for (i, field) in it.fields().enumerate() {
let data = self.lower_tuple_field(i, &field);
let data = self.lower_tuple_field(i, &field, body_ctx);
fields.push(data);
let attr = RawAttrs::new(self.db.upcast(), &field, self.span_map());
if !attr.is_empty() {
@ -247,35 +308,59 @@ impl<'a> Ctx<'a> {
}
}
fn lower_record_field(&mut self, field: &ast::RecordField) -> Field {
fn lower_record_field(&mut self, field: &ast::RecordField, body_ctx: &LowerCtx<'_>) -> Field {
let name = match field.name() {
Some(name) => name.as_name(),
None => Name::missing(),
};
let visibility = self.lower_visibility(field);
let type_ref = self.lower_type_ref_opt(field.ty());
let type_ref = TypeRef::from_ast_opt(body_ctx, field.ty());
Field { name, type_ref, visibility }
}
fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleField) -> Field {
fn lower_tuple_field(
&mut self,
idx: usize,
field: &ast::TupleField,
body_ctx: &LowerCtx<'_>,
) -> Field {
let name = Name::new_tuple_field(idx);
let visibility = self.lower_visibility(field);
let type_ref = self.lower_type_ref_opt(field.ty());
let type_ref = TypeRef::from_ast_opt(body_ctx, field.ty());
Field { name, type_ref, visibility }
}
fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {
let (mut types_map, mut types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let 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)),
Some(record_field_list) => {
self.lower_fields(&StructKind::Record(record_field_list), &body_ctx)
}
None => (Box::default(), FieldsShape::Record, Vec::default()),
};
let generic_params = self.lower_generic_params(HasImplicitSelf::No, union);
let res = Union { name, visibility, generic_params, fields, ast_id };
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 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(
@ -299,9 +384,11 @@ impl<'a> Ctx<'a> {
FileItemTreeId(self.next_variant_idx())..FileItemTreeId(self.next_variant_idx())
}
};
let generic_params = self.lower_generic_params(HasImplicitSelf::No, enum_);
let (generic_params, generics_source_map) =
self.lower_generic_params(HasImplicitSelf::No, enum_);
let res = Enum { name, visibility, generic_params, 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)
}
@ -320,14 +407,20 @@ 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 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());
let (fields, kind, attrs) = self.lower_fields(&variant.kind(), &body_ctx);
let ast_id = self.source_ast_id_map.ast_id(variant);
let res = Variant { name, fields, shape: kind, ast_id };
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 id = self.data().variants.alloc(res);
self.source_maps.variants.push(types_source_map);
for (idx, attr) in attrs {
self.add_attrs(
AttrOwner::Field(
@ -341,6 +434,10 @@ 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 body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
let visibility = self.lower_visibility(func);
let name = func.name()?.as_name();
@ -360,27 +457,31 @@ impl<'a> Ctx<'a> {
RawAttrs::new(self.db.upcast(), &self_param, self.span_map()),
);
let self_type = match self_param.ty() {
Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
Some(type_ref) => TypeRef::from_ast(&body_ctx, type_ref),
None => {
let self_type =
TypeRef::Path(Name::new_symbol_root(sym::Self_.clone()).into());
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 => TypeRef::Reference(
Box::new(self_type),
self_param.lifetime().as_ref().map(LifetimeRef::new),
Mutability::Shared,
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 => TypeRef::Reference(
Box::new(self_type),
self_param.lifetime().as_ref().map(LifetimeRef::new),
Mutability::Mut,
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,
})),
),
}
}
};
let type_ref = Interned::new(self_type);
params.push(Param { type_ref: Some(type_ref) });
params.push(Param { type_ref: Some(self_type) });
has_self_param = true;
}
for param in param_list.params() {
@ -391,9 +492,8 @@ impl<'a> Ctx<'a> {
Param { type_ref: None }
}
None => {
let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty());
let ty = Interned::new(type_ref);
Param { type_ref: Some(ty) }
let type_ref = TypeRef::from_ast_opt(&body_ctx, param.ty());
Param { type_ref: Some(type_ref) }
}
};
params.push(param);
@ -402,17 +502,17 @@ impl<'a> Ctx<'a> {
let ret_type = match func.ret_type() {
Some(rt) => match rt.ty() {
Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
None if rt.thin_arrow_token().is_some() => TypeRef::Error,
None => TypeRef::unit(),
Some(type_ref) => TypeRef::from_ast(&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 => 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(ret_type);
let ty_bound = Interned::new(TypeBound::Path(future_impl, TraitBoundModifier::None));
TypeRef::ImplTrait(vec![ty_bound])
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
};
@ -447,18 +547,27 @@ impl<'a> Ctx<'a> {
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: self.lower_generic_params(HasImplicitSelf::No, func),
explicit_generic_params: generic_params,
abi,
params: params.into_boxed_slice(),
ret_type: Interned::new(ret_type),
ret_type,
ast_id,
types_map: Arc::new(types_map),
flags,
};
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);
}
@ -470,37 +579,82 @@ 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 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| self.lower_type_ref(&it));
let type_ref = type_alias.ty().map(|it| TypeRef::from_ast(&body_ctx, it));
let visibility = self.lower_visibility(type_alias);
let bounds = self.lower_type_bounds(type_alias);
let bounds = self.lower_type_bounds(type_alias, &body_ctx);
let ast_id = self.source_ast_id_map.ast_id(type_alias);
let generic_params = self.lower_generic_params(HasImplicitSelf::No, type_alias);
let res = TypeAlias { name, visibility, bounds, generic_params, type_ref, ast_id };
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 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 body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
let name = static_.name()?.as_name();
let type_ref = self.lower_type_ref_opt(static_.ty());
let type_ref = TypeRef::from_ast_opt(&body_ctx, static_.ty());
let visibility = self.lower_visibility(static_);
let mutable = static_.mut_token().is_some();
let has_safe_kw = static_.safe_token().is_some();
let has_unsafe_kw = static_.unsafe_token().is_some();
let ast_id = self.source_ast_id_map.ast_id(static_);
let res =
Static { name, visibility, mutable, type_ref, ast_id, has_safe_kw, has_unsafe_kw };
types_map.shrink_to_fit();
types_source_map.shrink_to_fit();
let res = Static {
name,
visibility,
mutable,
type_ref,
ast_id,
has_safe_kw,
has_unsafe_kw,
types_map: Arc::new(types_map),
};
self.source_maps.statics.push(types_source_map);
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 body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
let name = konst.name().map(|it| it.as_name());
let type_ref = self.lower_type_ref_opt(konst.ty());
let type_ref = TypeRef::from_ast_opt(&body_ctx, konst.ty());
let visibility = self.lower_visibility(konst);
let ast_id = self.source_ast_id_map.ast_id(konst);
let res = Const { name, visibility, type_ref, ast_id, has_body: konst.body().is_some() };
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);
id(self.data().consts.alloc(res))
}
@ -539,10 +693,11 @@ impl<'a> Ctx<'a> {
.filter_map(|item_node| self.lower_assoc_item(&item_node))
.collect();
let generic_params =
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 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)
}
@ -554,24 +709,29 @@ 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 = self.lower_generic_params(
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 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) -> Option<FileItemTreeId<Impl>> {
fn lower_impl(&mut self, impl_def: &ast::Impl) -> FileItemTreeId<Impl> {
let (mut types_map, mut types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let 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 = self.lower_type_ref(&impl_def.self_ty()?);
let target_trait = impl_def.trait_().and_then(|tr| self.lower_trait_ref(&tr));
let self_ty = TypeRef::from_ast_opt(&body_ctx, impl_def.self_ty());
let target_trait = impl_def.trait_().and_then(|tr| TraitRef::from_ast(&body_ctx, tr));
let is_negative = impl_def.excl_token().is_some();
let is_unsafe = impl_def.unsafe_token().is_some();
@ -584,12 +744,27 @@ 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 = self.lower_generic_params(HasImplicitSelf::No, impl_def);
let res =
Impl { generic_params, target_trait, self_ty, is_negative, is_unsafe, items, ast_id };
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());
Some(id)
id
}
fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Use>> {
@ -692,14 +867,17 @@ impl<'a> Ctx<'a> {
&mut self,
has_implicit_self: HasImplicitSelf,
node: &dyn ast::HasGenericParams,
) -> Interned<GenericParams> {
) -> (Arc<GenericParams>, TypesSourceMap) {
let (mut types_map, mut types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
debug_assert!(self.generic_param_attr_buffer.is_empty(),);
let add_param_attrs = |item: Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
param| {
let attrs = RawAttrs::new(self.db.upcast(), &param, self.body_ctx.span_map());
let attrs = RawAttrs::new(self.db.upcast(), &param, body_ctx.span_map());
debug_assert!(self.generic_param_attr_buffer.insert(item, attrs).is_none());
};
self.body_ctx.take_impl_traits_bounds();
body_ctx.take_impl_traits_bounds();
let mut generics = GenericParamsCollector::default();
if let HasImplicitSelf::Yes(bounds) = has_implicit_self {
@ -715,23 +893,29 @@ impl<'a> Ctx<'a> {
// add super traits as bounds on Self
// i.e., `trait Foo: Bar` is equivalent to `trait Foo where Self: Bar`
generics.fill_bounds(
&self.body_ctx,
&body_ctx,
bounds,
Either::Left(TypeRef::Path(Name::new_symbol_root(sym::Self_.clone()).into())),
Either::Left(body_ctx.alloc_type_ref_desugared(TypeRef::Path(
Name::new_symbol_root(sym::Self_.clone()).into(),
))),
);
}
generics.fill(&self.body_ctx, node, add_param_attrs);
generics.fill(&body_ctx, node, add_param_attrs);
Interned::new(generics.finish())
let generics = generics.finish(types_map, &mut types_source_map);
(generics, types_source_map)
}
fn lower_type_bounds(&mut self, node: &dyn ast::HasTypeBounds) -> Box<[Interned<TypeBound>]> {
fn lower_type_bounds(
&mut self,
node: &dyn ast::HasTypeBounds,
body_ctx: &LowerCtx<'_>,
) -> Box<[TypeBound]> {
match node.type_bound_list() {
Some(bound_list) => bound_list
.bounds()
.map(|it| Interned::new(TypeBound::from_ast(&self.body_ctx, it)))
.collect(),
Some(bound_list) => {
bound_list.bounds().map(|it| TypeBound::from_ast(body_ctx, it)).collect()
}
None => Box::default(),
}
}
@ -743,23 +927,6 @@ impl<'a> Ctx<'a> {
self.data().vis.alloc(vis)
}
fn lower_trait_ref(&mut self, trait_ref: &ast::Type) -> Option<Interned<TraitRef>> {
let trait_ref = TraitRef::from_ast(&self.body_ctx, trait_ref.clone())?;
Some(Interned::new(trait_ref))
}
fn lower_type_ref(&mut self, type_ref: &ast::Type) -> Interned<TypeRef> {
let tyref = TypeRef::from_ast(&self.body_ctx, type_ref.clone());
Interned::new(tyref)
}
fn lower_type_ref_opt(&mut self, type_ref: Option<ast::Type>) -> Interned<TypeRef> {
match type_ref.map(|ty| self.lower_type_ref(&ty)) {
Some(it) => it,
None => Interned::new(TypeRef::Error),
}
}
fn next_variant_idx(&self) -> Idx<Variant> {
Idx::from_raw(RawIdx::from(
self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32),
@ -767,7 +934,7 @@ impl<'a> Ctx<'a> {
}
}
fn desugar_future_path(orig: TypeRef) -> Path {
fn desugar_future_path(orig: TypeRefId) -> Path {
let path = path![core::future::Future];
let mut generic_args: Vec<_> =
std::iter::repeat(None).take(path.segments().len() - 1).collect();
@ -777,10 +944,7 @@ fn desugar_future_path(orig: TypeRef) -> Path {
type_ref: Some(orig),
bounds: Box::default(),
};
generic_args.push(Some(Interned::new(GenericArgs {
bindings: Box::new([binding]),
..GenericArgs::empty()
})));
generic_args.push(Some(GenericArgs { bindings: Box::new([binding]), ..GenericArgs::empty() }));
Path::from_known_path(path, generic_args)
}

View file

@ -10,11 +10,12 @@ use crate::{
item_tree::{
AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, Field, FieldParent,
FieldsShape, FileItemTreeId, FnFlags, Function, GenericModItem, GenericParams, Impl,
Interned, ItemTree, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, Param, Path,
RawAttrs, RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, TypeBound,
TypeRef, Union, Use, UseTree, UseTreeKind, Variant,
ItemTree, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, Param, Path, RawAttrs,
RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, TypeBound, Union, Use,
UseTree, UseTreeKind, Variant,
},
pretty::{print_path, print_type_bounds, print_type_ref},
type_ref::{TypeRefId, TypesMap},
visibility::RawVisibility,
};
@ -121,7 +122,13 @@ impl Printer<'_> {
};
}
fn print_fields(&mut self, parent: FieldParent, kind: FieldsShape, fields: &[Field]) {
fn print_fields(
&mut self,
parent: FieldParent,
kind: FieldsShape,
fields: &[Field],
map: &TypesMap,
) {
let edition = self.edition;
match kind {
FieldsShape::Record => {
@ -135,7 +142,7 @@ impl Printer<'_> {
);
this.print_visibility(*visibility);
w!(this, "{}: ", name.display(self.db.upcast(), edition));
this.print_type_ref(type_ref);
this.print_type_ref(*type_ref, map);
wln!(this, ",");
}
});
@ -151,7 +158,7 @@ impl Printer<'_> {
);
this.print_visibility(*visibility);
w!(this, "{}: ", name.display(self.db.upcast(), edition));
this.print_type_ref(type_ref);
this.print_type_ref(*type_ref, map);
wln!(this, ",");
}
});
@ -167,20 +174,21 @@ impl Printer<'_> {
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);
self.print_fields(parent, kind, fields, map);
}
FieldsShape::Unit => {
self.print_where_clause(params);
self.print_fields(parent, kind, fields);
self.print_fields(parent, kind, fields, map);
}
FieldsShape::Tuple => {
self.print_fields(parent, kind, fields);
self.print_fields(parent, kind, fields, map);
self.print_where_clause(params);
}
}
@ -262,6 +270,7 @@ impl Printer<'_> {
params,
ret_type,
ast_id,
types_map,
flags,
} = &self.tree[it];
self.print_ast_id(ast_id.erase());
@ -298,7 +307,7 @@ impl Printer<'_> {
w!(this, "self: ");
}
if let Some(type_ref) = type_ref {
this.print_type_ref(type_ref);
this.print_type_ref(*type_ref, types_map);
} else {
wln!(this, "...");
}
@ -307,7 +316,7 @@ impl Printer<'_> {
});
}
w!(self, ") -> ");
self.print_type_ref(ret_type);
self.print_type_ref(*ret_type, types_map);
self.print_where_clause(explicit_generic_params);
if flags.contains(FnFlags::HAS_BODY) {
wln!(self, " {{ ... }}");
@ -316,8 +325,15 @@ impl Printer<'_> {
}
}
ModItem::Struct(it) => {
let Struct { visibility, name, fields, shape: kind, generic_params, ast_id } =
&self.tree[it];
let Struct {
visibility,
name,
fields,
shape: kind,
generic_params,
ast_id,
types_map,
} = &self.tree[it];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "struct {}", name.display(self.db.upcast(), self.edition));
@ -327,6 +343,7 @@ impl Printer<'_> {
*kind,
fields,
generic_params,
types_map,
);
if matches!(kind, FieldsShape::Record) {
wln!(self);
@ -335,7 +352,8 @@ impl Printer<'_> {
}
}
ModItem::Union(it) => {
let Union { name, visibility, fields, generic_params, ast_id } = &self.tree[it];
let Union { name, visibility, fields, generic_params, ast_id, types_map } =
&self.tree[it];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "union {}", name.display(self.db.upcast(), self.edition));
@ -345,6 +363,7 @@ impl Printer<'_> {
FieldsShape::Record,
fields,
generic_params,
types_map,
);
wln!(self);
}
@ -358,18 +377,20 @@ impl Printer<'_> {
let edition = self.edition;
self.indented(|this| {
for variant in FileItemTreeId::range_iter(variants.clone()) {
let Variant { name, fields, shape: kind, ast_id } = &this.tree[variant];
let Variant { name, fields, shape: kind, ast_id, types_map } =
&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::Variant(variant), *kind, fields);
this.print_fields(FieldParent::Variant(variant), *kind, fields, types_map);
wln!(this, ",");
}
});
wln!(self, "}}");
}
ModItem::Const(it) => {
let Const { name, visibility, type_ref, ast_id, has_body: _ } = &self.tree[it];
let Const { name, visibility, type_ref, ast_id, has_body: _, types_map } =
&self.tree[it];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "const ");
@ -378,7 +399,7 @@ impl Printer<'_> {
None => w!(self, "_"),
}
w!(self, ": ");
self.print_type_ref(type_ref);
self.print_type_ref(*type_ref, types_map);
wln!(self, " = _;");
}
ModItem::Static(it) => {
@ -390,6 +411,7 @@ impl Printer<'_> {
ast_id,
has_safe_kw,
has_unsafe_kw,
types_map,
} = &self.tree[it];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
@ -404,7 +426,7 @@ impl Printer<'_> {
w!(self, "mut ");
}
w!(self, "{}: ", name.display(self.db.upcast(), self.edition));
self.print_type_ref(type_ref);
self.print_type_ref(*type_ref, types_map);
w!(self, " = _;");
wln!(self);
}
@ -449,6 +471,7 @@ impl Printer<'_> {
items,
generic_params,
ast_id,
types_map,
} = &self.tree[it];
self.print_ast_id(ast_id.erase());
if *is_unsafe {
@ -461,10 +484,10 @@ impl Printer<'_> {
w!(self, "!");
}
if let Some(tr) = target_trait {
self.print_path(&tr.path);
self.print_path(&tr.path, types_map);
w!(self, " for ");
}
self.print_type_ref(self_ty);
self.print_type_ref(*self_ty, types_map);
self.print_where_clause_and_opening_brace(generic_params);
self.indented(|this| {
for item in &**items {
@ -474,19 +497,26 @@ impl Printer<'_> {
wln!(self, "}}");
}
ModItem::TypeAlias(it) => {
let TypeAlias { name, visibility, bounds, type_ref, generic_params, ast_id } =
&self.tree[it];
let TypeAlias {
name,
visibility,
bounds,
type_ref,
generic_params,
ast_id,
types_map,
} = &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);
self.print_type_bounds(bounds, types_map);
}
if let Some(ty) = type_ref {
w!(self, " = ");
self.print_type_ref(ty);
self.print_type_ref(*ty, types_map);
}
self.print_where_clause(generic_params);
w!(self, ";");
@ -543,19 +573,19 @@ impl Printer<'_> {
self.blank();
}
fn print_type_ref(&mut self, type_ref: &TypeRef) {
fn print_type_ref(&mut self, type_ref: TypeRefId, map: &TypesMap) {
let edition = self.edition;
print_type_ref(self.db, type_ref, self, edition).unwrap();
print_type_ref(self.db, type_ref, map, self, edition).unwrap();
}
fn print_type_bounds(&mut self, bounds: &[Interned<TypeBound>]) {
fn print_type_bounds(&mut self, bounds: &[TypeBound], map: &TypesMap) {
let edition = self.edition;
print_type_bounds(self.db, bounds, self, edition).unwrap();
print_type_bounds(self.db, bounds, map, self, edition).unwrap();
}
fn print_path(&mut self, path: &Path) {
fn print_path(&mut self, path: &Path, map: &TypesMap) {
let edition = self.edition;
print_path(self.db, path, self, edition).unwrap();
print_path(self.db, path, map, self, edition).unwrap();
}
fn print_generic_params(&mut self, params: &GenericParams, parent: GenericModItem) {
@ -586,7 +616,7 @@ impl Printer<'_> {
},
TypeOrConstParamData::ConstParamData(konst) => {
w!(self, "const {}: ", konst.name.display(self.db.upcast(), self.edition));
self.print_type_ref(&konst.ty);
self.print_type_ref(konst.ty, &params.types_map);
}
}
}
@ -640,14 +670,16 @@ impl Printer<'_> {
};
match target {
WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty),
WherePredicateTypeTarget::TypeRef(ty) => {
this.print_type_ref(*ty, &params.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));
this.print_type_bounds(std::slice::from_ref(bound), &params.types_map);
}
});
true

View file

@ -1531,11 +1531,3 @@ fn macro_call_as_call_id_with_eager(
pub struct UnresolvedMacro {
pub path: hir_expand::mod_path::ModPath,
}
intern::impl_internable!(
crate::type_ref::TypeRef,
crate::type_ref::TraitRef,
crate::type_ref::TypeBound,
crate::path::GenericArgs,
generics::GenericParams,
);

View file

@ -5,43 +5,53 @@ use hir_expand::{
span_map::{SpanMap, SpanMapRef},
AstId, HirFileId, InFile,
};
use intern::Interned;
use span::{AstIdMap, AstIdNode};
use stdx::thin_vec::ThinVec;
use syntax::ast;
use triomphe::Arc;
use crate::{db::DefDatabase, path::Path, type_ref::TypeBound};
use crate::{
db::DefDatabase,
path::Path,
type_ref::{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: RefCell<Vec<Vec<Interned<TypeBound>>>>,
impl_trait_bounds: RefCell<Vec<ThinVec<TypeBound>>>,
// Prevent nested impl traits like `impl Foo<impl Bar>`.
outer_impl_trait: RefCell<bool>,
types_map: RefCell<(&'a mut TypesMap, &'a mut TypesSourceMap)>,
}
pub(crate) struct OuterImplTraitGuard<'a> {
ctx: &'a LowerCtx<'a>,
pub(crate) struct OuterImplTraitGuard<'a, 'b> {
ctx: &'a LowerCtx<'b>,
old: bool,
}
impl<'a> OuterImplTraitGuard<'a> {
fn new(ctx: &'a LowerCtx<'a>, impl_trait: bool) -> Self {
impl<'a, 'b> OuterImplTraitGuard<'a, 'b> {
fn new(ctx: &'a LowerCtx<'b>, impl_trait: bool) -> Self {
let old = ctx.outer_impl_trait.replace(impl_trait);
Self { ctx, old }
}
}
impl Drop for OuterImplTraitGuard<'_> {
impl Drop for OuterImplTraitGuard<'_, '_> {
fn drop(&mut self) {
self.ctx.outer_impl_trait.replace(self.old);
}
}
impl<'a> LowerCtx<'a> {
pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self {
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,
@ -49,6 +59,7 @@ impl<'a> LowerCtx<'a> {
ast_id_map: OnceCell::new(),
impl_trait_bounds: RefCell::new(Vec::new()),
outer_impl_trait: RefCell::default(),
types_map: RefCell::new((types_map, types_source_map)),
}
}
@ -56,6 +67,8 @@ impl<'a> LowerCtx<'a> {
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,
@ -64,6 +77,7 @@ impl<'a> LowerCtx<'a> {
ast_id_map: OnceCell::new(),
impl_trait_bounds: RefCell::new(Vec::new()),
outer_impl_trait: RefCell::default(),
types_map: RefCell::new((types_map, types_source_map)),
}
}
@ -82,11 +96,11 @@ impl<'a> LowerCtx<'a> {
)
}
pub fn update_impl_traits_bounds(&self, bounds: Vec<Interned<TypeBound>>) {
pub fn update_impl_traits_bounds(&self, bounds: ThinVec<TypeBound>) {
self.impl_trait_bounds.borrow_mut().push(bounds);
}
pub fn take_impl_traits_bounds(&self) -> Vec<Vec<Interned<TypeBound>>> {
pub fn take_impl_traits_bounds(&self) -> Vec<ThinVec<TypeBound>> {
self.impl_trait_bounds.take()
}
@ -94,7 +108,32 @@ impl<'a> LowerCtx<'a> {
*self.outer_impl_trait.borrow()
}
pub(crate) fn outer_impl_trait_scope(&'a self, impl_trait: bool) -> OuterImplTraitGuard<'a> {
pub(crate) fn outer_impl_trait_scope<'b>(
&'b self,
impl_trait: bool,
) -> OuterImplTraitGuard<'b, 'a> {
OuterImplTraitGuard::new(self, impl_trait)
}
pub(crate) fn alloc_type_ref(&self, type_ref: TypeRef, node: TypePtr) -> TypeRefId {
let mut types_map = self.types_map.borrow_mut();
let (types_map, types_source_map) = &mut *types_map;
let id = types_map.types.alloc(type_ref);
types_source_map.types_map_back.insert(id, InFile::new(self.file_id, node));
id
}
pub(crate) fn alloc_type_ref_desugared(&self, type_ref: TypeRef) -> TypeRefId {
self.types_map.borrow_mut().0.types.alloc(type_ref)
}
pub(crate) fn alloc_error_type(&self) -> TypeRefId {
self.types_map.borrow_mut().0.types.alloc(TypeRef::Error)
}
// FIXME: If we alloc while holding this, well... Bad Things will happen. Need to change this
// to use proper mutability instead of interior mutability.
pub(crate) fn types_map(&self) -> std::cell::Ref<'_, TypesMap> {
std::cell::Ref::map(self.types_map.borrow(), |it| &*it.0)
}
}

View file

@ -253,7 +253,8 @@ m!(Z);
let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
assert_eq!(module_data.scope.resolutions().count(), 4);
});
let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count();
let n_recalculated_item_trees =
events.iter().filter(|it| it.contains("item_tree(")).count();
assert_eq!(n_recalculated_item_trees, 6);
let n_reparsed_macros =
events.iter().filter(|it| it.contains("parse_macro_expansion(")).count();
@ -308,7 +309,7 @@ pub type Ty = ();
let events = db.log_executed(|| {
db.file_item_tree(pos.file_id.into());
});
let n_calculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count();
let n_calculated_item_trees = events.iter().filter(|it| it.contains("item_tree(")).count();
assert_eq!(n_calculated_item_trees, 1);
let n_parsed_files = events.iter().filter(|it| it.contains("parse(")).count();
assert_eq!(n_parsed_files, 1);

View file

@ -9,11 +9,12 @@ use std::{
use crate::{
lang_item::LangItemTarget,
lower::LowerCtx,
type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef},
type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRefId},
};
use hir_expand::name::Name;
use intern::Interned;
use span::Edition;
use stdx::thin_vec::thin_vec_with_header_struct;
use syntax::ast;
pub use hir_expand::mod_path::{path, ModPath, PathKind};
@ -47,20 +48,33 @@ impl Display for ImportAliasDisplay<'_> {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Path {
/// A normal path
Normal {
/// Type based path like `<T>::foo`.
/// Note that paths like `<Type as Trait>::foo` are desugared to `Trait::<Self=Type>::foo`.
type_anchor: Option<Interned<TypeRef>>,
mod_path: Interned<ModPath>,
/// Invariant: the same len as `self.mod_path.segments` or `None` if all segments are `None`.
generic_args: Option<Box<[Option<Interned<GenericArgs>>]>>,
},
/// `BarePath` is used when the path has neither generics nor type anchor, since the vast majority of paths
/// are in this category, and splitting `Path` this way allows it to be more thin. When the path has either generics
/// or type anchor, it is `Path::Normal` with the generics filled with `None` even if there are none (practically
/// this is not a problem since many more paths have generics than a type anchor).
BarePath(Interned<ModPath>),
/// `Path::Normal` may have empty generics and type anchor (but generic args will be filled with `None`).
Normal(NormalPath),
/// A link to a lang item. It is used in desugaring of things like `it?`. We can show these
/// links via a normal path since they might be private and not accessible in the usage place.
LangItem(LangItemTarget, Option<Name>),
}
// This type is being used a lot, make sure it doesn't grow unintentionally.
#[cfg(target_arch = "x86_64")]
const _: () = {
assert!(size_of::<Path>() == 16);
assert!(size_of::<Option<Path>>() == 16);
};
thin_vec_with_header_struct! {
pub new(pub(crate)) struct NormalPath, NormalPathHeader {
pub generic_args: [Option<GenericArgs>],
pub type_anchor: Option<TypeRefId>,
pub mod_path: Interned<ModPath>; ref,
}
}
/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
/// also includes bindings of associated types, like in `Iterator<Item = Foo>`.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -86,20 +100,20 @@ pub struct AssociatedTypeBinding {
pub name: Name,
/// The generic arguments to the associated type. e.g. For `Trait<Assoc<'a, T> = &'a T>`, this
/// would be `['a, T]`.
pub args: Option<Interned<GenericArgs>>,
pub args: Option<GenericArgs>,
/// The type bound to this associated type (in `Item = T`, this would be the
/// `T`). This can be `None` if there are bounds instead.
pub type_ref: Option<TypeRef>,
pub type_ref: Option<TypeRefId>,
/// Bounds for the associated type, like in `Iterator<Item:
/// SomeOtherTrait>`. (This is the unstable `associated_type_bounds`
/// feature.)
pub bounds: Box<[Interned<TypeBound>]>,
pub bounds: Box<[TypeBound]>,
}
/// A single generic argument.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum GenericArg {
Type(TypeRef),
Type(TypeRefId),
Lifetime(LifetimeRef),
Const(ConstRef),
}
@ -112,50 +126,49 @@ impl Path {
}
/// Converts a known mod path to `Path`.
pub fn from_known_path(
path: ModPath,
generic_args: impl Into<Box<[Option<Interned<GenericArgs>>]>>,
) -> Path {
let generic_args = generic_args.into();
assert_eq!(path.len(), generic_args.len());
Path::Normal {
type_anchor: None,
mod_path: Interned::new(path),
generic_args: Some(generic_args),
}
pub fn from_known_path(path: ModPath, generic_args: Vec<Option<GenericArgs>>) -> Path {
Path::Normal(NormalPath::new(None, Interned::new(path), generic_args))
}
/// Converts a known mod path to `Path`.
pub fn from_known_path_with_no_generic(path: ModPath) -> Path {
Path::Normal { type_anchor: None, mod_path: Interned::new(path), generic_args: None }
Path::BarePath(Interned::new(path))
}
#[inline]
pub fn kind(&self) -> &PathKind {
match self {
Path::Normal { mod_path, .. } => &mod_path.kind,
Path::BarePath(mod_path) => &mod_path.kind,
Path::Normal(path) => &path.mod_path().kind,
Path::LangItem(..) => &PathKind::Abs,
}
}
pub fn type_anchor(&self) -> Option<&TypeRef> {
#[inline]
pub fn type_anchor(&self) -> Option<TypeRefId> {
match self {
Path::Normal { type_anchor, .. } => type_anchor.as_deref(),
Path::LangItem(..) => None,
Path::Normal(path) => path.type_anchor(),
Path::LangItem(..) | Path::BarePath(_) => None,
}
}
#[inline]
pub fn generic_args(&self) -> Option<&[Option<GenericArgs>]> {
match self {
Path::Normal(path) => Some(path.generic_args()),
Path::LangItem(..) | Path::BarePath(_) => None,
}
}
pub fn segments(&self) -> PathSegments<'_> {
match self {
Path::Normal { mod_path, generic_args, .. } => {
let s = PathSegments {
segments: mod_path.segments(),
generic_args: generic_args.as_deref(),
};
if let Some(generic_args) = s.generic_args {
assert_eq!(s.segments.len(), generic_args.len());
}
s
Path::BarePath(mod_path) => {
PathSegments { segments: mod_path.segments(), generic_args: None }
}
Path::Normal(path) => PathSegments {
segments: path.mod_path().segments(),
generic_args: Some(path.generic_args()),
},
Path::LangItem(_, seg) => PathSegments {
segments: seg.as_ref().map_or(&[], |seg| std::slice::from_ref(seg)),
generic_args: None,
@ -165,34 +178,55 @@ impl Path {
pub fn mod_path(&self) -> Option<&ModPath> {
match self {
Path::Normal { mod_path, .. } => Some(mod_path),
Path::BarePath(mod_path) => Some(mod_path),
Path::Normal(path) => Some(path.mod_path()),
Path::LangItem(..) => None,
}
}
pub fn qualifier(&self) -> Option<Path> {
let Path::Normal { mod_path, generic_args, type_anchor } = self else {
return None;
};
if mod_path.is_ident() {
return None;
match self {
Path::BarePath(mod_path) => {
if mod_path.is_ident() {
return None;
}
Some(Path::BarePath(Interned::new(ModPath::from_segments(
mod_path.kind,
mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(),
))))
}
Path::Normal(path) => {
let mod_path = path.mod_path();
if mod_path.is_ident() {
return None;
}
let type_anchor = path.type_anchor();
let generic_args = path.generic_args();
let qualifier_mod_path = Interned::new(ModPath::from_segments(
mod_path.kind,
mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(),
));
let qualifier_generic_args = &generic_args[..generic_args.len() - 1];
Some(Path::Normal(NormalPath::new(
type_anchor,
qualifier_mod_path,
qualifier_generic_args.iter().cloned(),
)))
}
Path::LangItem(..) => None,
}
let res = Path::Normal {
type_anchor: type_anchor.clone(),
mod_path: Interned::new(ModPath::from_segments(
mod_path.kind,
mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(),
)),
generic_args: generic_args.as_ref().map(|it| it[..it.len() - 1].to_vec().into()),
};
Some(res)
}
pub fn is_self_type(&self) -> bool {
let Path::Normal { mod_path, generic_args, type_anchor } = self else {
return false;
};
type_anchor.is_none() && generic_args.as_deref().is_none() && mod_path.is_Self()
match self {
Path::BarePath(mod_path) => mod_path.is_Self(),
Path::Normal(path) => {
path.type_anchor().is_none()
&& path.mod_path().is_Self()
&& path.generic_args().iter().all(|args| args.is_none())
}
Path::LangItem(..) => false,
}
}
}
@ -204,7 +238,7 @@ pub struct PathSegment<'a> {
pub struct PathSegments<'a> {
segments: &'a [Name],
generic_args: Option<&'a [Option<Interned<GenericArgs>>]>,
generic_args: Option<&'a [Option<GenericArgs>]>,
}
impl<'a> PathSegments<'a> {
@ -224,7 +258,7 @@ impl<'a> PathSegments<'a> {
pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> {
let res = PathSegment {
name: self.segments.get(idx)?,
args_and_bindings: self.generic_args.and_then(|it| it.get(idx)?.as_deref()),
args_and_bindings: self.generic_args.and_then(|it| it.get(idx)?.as_ref()),
};
Some(res)
}
@ -244,7 +278,7 @@ impl<'a> PathSegments<'a> {
self.segments
.iter()
.zip(self.generic_args.into_iter().flatten().chain(iter::repeat(&None)))
.map(|(name, args)| PathSegment { name, args_and_bindings: args.as_deref() })
.map(|(name, args)| PathSegment { name, args_and_bindings: args.as_ref() })
}
}
@ -268,16 +302,6 @@ impl GenericArgs {
impl From<Name> for Path {
fn from(name: Name) -> Path {
Path::Normal {
type_anchor: None,
mod_path: Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))),
generic_args: None,
}
}
}
impl From<Name> for Box<Path> {
fn from(name: Name) -> Box<Path> {
Box::new(Path::from(name))
Path::BarePath(Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))))
}
}

View file

@ -2,13 +2,14 @@
use std::iter;
use crate::{lower::LowerCtx, type_ref::ConstRef};
use crate::{lower::LowerCtx, path::NormalPath, type_ref::ConstRef};
use hir_expand::{
mod_path::resolve_crate_root,
name::{AsName, Name},
};
use intern::{sym, Interned};
use stdx::thin_vec::EmptyOptimizedThinVec;
use syntax::ast::{self, AstNode, HasGenericArgs, HasTypeBounds};
use crate::{
@ -51,8 +52,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
segment.param_list(),
segment.ret_type(),
)
})
.map(Interned::new);
});
if args.is_some() {
generic_args.resize(segments.len(), None);
generic_args.push(args);
@ -70,16 +70,14 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
match trait_ref {
// <T>::foo
None => {
type_anchor = Some(Interned::new(self_type));
type_anchor = Some(self_type);
kind = PathKind::Plain;
}
// <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
Some(trait_ref) => {
let Path::Normal { mod_path, generic_args: path_generic_args, .. } =
Path::from_src(ctx, trait_ref.path()?)?
else {
return None;
};
let path = Path::from_src(ctx, trait_ref.path()?)?;
let mod_path = path.mod_path()?;
let path_generic_args = path.generic_args();
let num_segments = mod_path.segments().len();
kind = mod_path.kind;
@ -95,7 +93,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
// Insert the type reference (T in the above example) as Self parameter for the trait
let last_segment = generic_args.get_mut(segments.len() - num_segments)?;
*last_segment = Some(Interned::new(match last_segment.take() {
*last_segment = Some(match last_segment.take() {
Some(it) => GenericArgs {
args: iter::once(self_type)
.chain(it.args.iter().cloned())
@ -110,7 +108,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
has_self_type: true,
..GenericArgs::empty()
},
}));
});
}
}
}
@ -137,7 +135,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
};
}
segments.reverse();
if !generic_args.is_empty() {
if !generic_args.is_empty() || type_anchor.is_some() {
generic_args.resize(segments.len(), None);
generic_args.reverse();
}
@ -166,11 +164,11 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
}
let mod_path = Interned::new(ModPath::from_segments(kind, segments));
return Some(Path::Normal {
type_anchor,
mod_path,
generic_args: if generic_args.is_empty() { None } else { Some(generic_args.into()) },
});
if type_anchor.is_none() && generic_args.is_empty() {
return Some(Path::BarePath(mod_path));
} else {
return Some(Path::Normal(NormalPath::new(type_anchor, mod_path, generic_args)));
}
fn qualifier(path: &ast::Path) -> Option<ast::Path> {
if let Some(q) = path.qualifier() {
@ -194,11 +192,13 @@ pub(super) fn lower_generic_args(
match generic_arg {
ast::GenericArg::TypeArg(type_arg) => {
let type_ref = TypeRef::from_ast_opt(lower_ctx, type_arg.ty());
type_ref.walk(&mut |tr| {
let types_map = lower_ctx.types_map();
TypeRef::walk(type_ref, &types_map, &mut |tr| {
if let TypeRef::ImplTrait(bounds) = tr {
lower_ctx.update_impl_traits_bounds(bounds.clone());
}
});
drop(types_map);
args.push(GenericArg::Type(type_ref));
}
ast::GenericArg::AssocTypeArg(assoc_type_arg) => {
@ -212,20 +212,19 @@ pub(super) fn lower_generic_args(
let name = name_ref.as_name();
let args = assoc_type_arg
.generic_arg_list()
.and_then(|args| lower_generic_args(lower_ctx, args))
.map(Interned::new);
.and_then(|args| lower_generic_args(lower_ctx, args));
let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it));
let type_ref = type_ref.inspect(|tr| {
tr.walk(&mut |tr| {
let type_ref = type_ref.inspect(|&tr| {
let types_map = lower_ctx.types_map();
TypeRef::walk(tr, &types_map, &mut |tr| {
if let TypeRef::ImplTrait(bounds) = tr {
lower_ctx.update_impl_traits_bounds(bounds.clone());
}
});
drop(types_map);
});
let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
l.bounds()
.map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it)))
.collect()
l.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect()
} else {
Box::default()
};
@ -269,7 +268,9 @@ fn lower_generic_args_from_fn_path(
let type_ref = TypeRef::from_ast_opt(ctx, param.ty());
param_types.push(type_ref);
}
let args = Box::new([GenericArg::Type(TypeRef::Tuple(param_types))]);
let args = Box::new([GenericArg::Type(
ctx.alloc_type_ref_desugared(TypeRef::Tuple(EmptyOptimizedThinVec::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 {
@ -280,7 +281,7 @@ fn lower_generic_args_from_fn_path(
}])
} else {
// -> ()
let type_ref = TypeRef::Tuple(Vec::new());
let type_ref = ctx.alloc_type_ref_desugared(TypeRef::unit());
Box::new([AssociatedTypeBinding {
name: Name::new_symbol_root(sym::Output.clone()),
args: None,

View file

@ -6,7 +6,6 @@ use std::{
};
use hir_expand::mod_path::PathKind;
use intern::Interned;
use itertools::Itertools;
use span::Edition;
@ -14,12 +13,15 @@ use crate::{
db::DefDatabase,
lang_item::LangItemTarget,
path::{GenericArg, GenericArgs, Path},
type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef, UseArgRef},
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 {
@ -61,7 +63,7 @@ pub(crate) fn print_path(
match path.type_anchor() {
Some(anchor) => {
write!(buf, "<")?;
print_type_ref(db, anchor, buf, edition)?;
print_type_ref(db, anchor, map, buf, edition)?;
write!(buf, ">::")?;
}
None => match path.kind() {
@ -90,7 +92,7 @@ pub(crate) fn print_path(
write!(buf, "{}", segment.name.display(db.upcast(), edition))?;
if let Some(generics) = segment.args_and_bindings {
write!(buf, "::<")?;
print_generic_args(db, generics, buf, edition)?;
print_generic_args(db, generics, map, buf, edition)?;
write!(buf, ">")?;
}
@ -102,6 +104,7 @@ pub(crate) fn print_path(
pub(crate) fn print_generic_args(
db: &dyn DefDatabase,
generics: &GenericArgs,
map: &TypesMap,
buf: &mut dyn Write,
edition: Edition,
) -> fmt::Result {
@ -109,7 +112,7 @@ pub(crate) fn print_generic_args(
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, buf, edition)?;
print_generic_arg(db, self_ty, map, buf, edition)?;
first = false;
args
} else {
@ -120,7 +123,7 @@ pub(crate) fn print_generic_args(
write!(buf, ", ")?;
}
first = false;
print_generic_arg(db, arg, buf, edition)?;
print_generic_arg(db, arg, map, buf, edition)?;
}
for binding in generics.bindings.iter() {
if !first {
@ -130,11 +133,11 @@ pub(crate) fn print_generic_args(
write!(buf, "{}", binding.name.display(db.upcast(), edition))?;
if !binding.bounds.is_empty() {
write!(buf, ": ")?;
print_type_bounds(db, &binding.bounds, buf, edition)?;
print_type_bounds(db, &binding.bounds, map, buf, edition)?;
}
if let Some(ty) = &binding.type_ref {
if let Some(ty) = binding.type_ref {
write!(buf, " = ")?;
print_type_ref(db, ty, buf, edition)?;
print_type_ref(db, ty, map, buf, edition)?;
}
}
Ok(())
@ -143,11 +146,12 @@ pub(crate) fn print_generic_args(
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, buf, edition),
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)),
}
@ -155,12 +159,13 @@ pub(crate) fn print_generic_arg(
pub(crate) fn print_type_ref(
db: &dyn DefDatabase,
type_ref: &TypeRef,
type_ref: TypeRefId,
map: &TypesMap,
buf: &mut dyn Write,
edition: Edition,
) -> fmt::Result {
// FIXME: deduplicate with `HirDisplay` impl
match type_ref {
match &map[type_ref] {
TypeRef::Never => write!(buf, "!")?,
TypeRef::Placeholder => write!(buf, "_")?,
TypeRef::Tuple(fields) => {
@ -169,48 +174,48 @@ pub(crate) fn print_type_ref(
if i != 0 {
write!(buf, ", ")?;
}
print_type_ref(db, field, buf, edition)?;
print_type_ref(db, *field, map, buf, edition)?;
}
write!(buf, ")")?;
}
TypeRef::Path(path) => print_path(db, path, buf, edition)?,
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, buf, edition)?;
print_type_ref(db, *pointee, map, buf, edition)?;
}
TypeRef::Reference(pointee, lt, mtbl) => {
let mtbl = match mtbl {
TypeRef::Reference(ref_) => {
let mtbl = match ref_.mutability {
Mutability::Shared => "",
Mutability::Mut => "mut ",
};
write!(buf, "&")?;
if let Some(lt) = lt {
if let Some(lt) = &ref_.lifetime {
write!(buf, "{} ", lt.name.display(db.upcast(), edition))?;
}
write!(buf, "{mtbl}")?;
print_type_ref(db, pointee, buf, edition)?;
print_type_ref(db, ref_.ty, map, buf, edition)?;
}
TypeRef::Array(elem, len) => {
TypeRef::Array(array) => {
write!(buf, "[")?;
print_type_ref(db, elem, buf, edition)?;
write!(buf, "; {}]", len.display(db.upcast(), edition))?;
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, buf, edition)?;
print_type_ref(db, *elem, map, buf, edition)?;
write!(buf, "]")?;
}
TypeRef::Fn(args_and_ret, varargs, is_unsafe, abi) => {
TypeRef::Fn(fn_) => {
let ((_, return_type), args) =
args_and_ret.split_last().expect("TypeRef::Fn is missing return type");
if *is_unsafe {
fn_.params().split_last().expect("TypeRef::Fn is missing return type");
if fn_.is_unsafe() {
write!(buf, "unsafe ")?;
}
if let Some(abi) = abi {
if let Some(abi) = fn_.abi() {
buf.write_str("extern ")?;
buf.write_str(abi.as_str())?;
buf.write_char(' ')?;
@ -220,16 +225,16 @@ pub(crate) fn print_type_ref(
if i != 0 {
write!(buf, ", ")?;
}
print_type_ref(db, typeref, buf, edition)?;
print_type_ref(db, *typeref, map, buf, edition)?;
}
if *varargs {
if fn_.is_varargs() {
if !args.is_empty() {
write!(buf, ", ")?;
}
write!(buf, "...")?;
}
write!(buf, ") -> ")?;
print_type_ref(db, return_type, buf, edition)?;
print_type_ref(db, *return_type, map, buf, edition)?;
}
TypeRef::Macro(_ast_id) => {
write!(buf, "<macro>")?;
@ -237,11 +242,11 @@ pub(crate) fn print_type_ref(
TypeRef::Error => write!(buf, "{{unknown}}")?,
TypeRef::ImplTrait(bounds) => {
write!(buf, "impl ")?;
print_type_bounds(db, bounds, buf, edition)?;
print_type_bounds(db, bounds, map, buf, edition)?;
}
TypeRef::DynTrait(bounds) => {
write!(buf, "dyn ")?;
print_type_bounds(db, bounds, buf, edition)?;
print_type_bounds(db, bounds, map, buf, edition)?;
}
}
@ -250,7 +255,8 @@ pub(crate) fn print_type_ref(
pub(crate) fn print_type_bounds(
db: &dyn DefDatabase,
bounds: &[Interned<TypeBound>],
bounds: &[TypeBound],
map: &TypesMap,
buf: &mut dyn Write,
edition: Edition,
) -> fmt::Result {
@ -259,13 +265,13 @@ pub(crate) fn print_type_bounds(
write!(buf, " + ")?;
}
match bound.as_ref() {
match bound {
TypeBound::Path(path, modifier) => {
match modifier {
TraitBoundModifier::None => (),
TraitBoundModifier::Maybe => write!(buf, "?")?,
}
print_path(db, path, buf, edition)?;
print_path(db, path, map, buf, edition)?;
}
TypeBound::ForLifetime(lifetimes, path) => {
write!(
@ -273,7 +279,7 @@ pub(crate) fn print_type_bounds(
"for<{}> ",
lifetimes.iter().map(|it| it.display(db.upcast(), edition)).format(", ")
)?;
print_path(db, path, buf, edition)?;
print_path(db, path, map, buf, edition)?;
}
TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition))?,
TypeBound::Use(args) => {

View file

@ -3,7 +3,7 @@ use std::{fmt, iter, mem};
use base_db::CrateId;
use hir_expand::{name::Name, MacroDefId};
use intern::{sym, Interned};
use intern::sym;
use itertools::Itertools as _;
use rustc_hash::FxHashSet;
use smallvec::{smallvec, SmallVec};
@ -24,7 +24,7 @@ use crate::{
nameres::{DefMap, MacroSubNs},
path::{ModPath, Path, PathKind},
per_ns::PerNs,
type_ref::LifetimeRef,
type_ref::{LifetimeRef, TypesMap},
visibility::{RawVisibility, Visibility},
AdtId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId,
ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, GenericParamId, HasModule,
@ -76,7 +76,7 @@ enum Scope {
/// All the items and imported names of a module
BlockScope(ModuleItemMap),
/// Brings the generic parameters of an item into scope
GenericParams { def: GenericDefId, params: Interned<GenericParams> },
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
@ -167,7 +167,8 @@ impl Resolver {
path: &Path,
) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> {
let path = match path {
Path::Normal { mod_path, .. } => mod_path,
Path::BarePath(mod_path) => mod_path,
Path::Normal(it) => it.mod_path(),
Path::LangItem(l, seg) => {
let type_ns = match *l {
LangItemTarget::Union(it) => TypeNs::AdtId(it.into()),
@ -265,7 +266,8 @@ impl Resolver {
mut hygiene_id: HygieneId,
) -> Option<ResolveValueResult> {
let path = match path {
Path::Normal { mod_path, .. } => mod_path,
Path::BarePath(mod_path) => mod_path,
Path::Normal(it) => it.mod_path(),
Path::LangItem(l, None) => {
return Some(ResolveValueResult::ValueNs(
match *l {
@ -620,13 +622,15 @@ impl Resolver {
pub fn where_predicates_in_scope(
&self,
) -> impl Iterator<Item = (&crate::generics::WherePredicate, &GenericDefId)> {
) -> 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)))
.flat_map(|(params, def)| {
params.where_predicates().zip(iter::repeat((def, &params.types_map)))
})
}
pub fn generic_def(&self) -> Option<GenericDefId> {
@ -636,13 +640,20 @@ impl Resolver {
})
}
pub fn generic_params(&self) -> Option<&Interned<GenericParams>> {
pub fn generic_params(&self) -> Option<&Arc<GenericParams>> {
self.scopes().find_map(|scope| match scope {
Scope::GenericParams { params, .. } => Some(params),
_ => None,
})
}
pub fn all_generic_params(&self) -> impl Iterator<Item = (&GenericParams, &GenericDefId)> {
self.scopes().filter_map(|scope| match scope {
Scope::GenericParams { params, def } => Some((&**params, def)),
_ => None,
})
}
pub fn body_owner(&self) -> Option<DefWithBodyId> {
self.scopes().find_map(|scope| match scope {
Scope::ExprScope(it) => Some(it.owner),