Build source map for hir_def::TypeRefs

So that given a `TypeRef` we will be able to trace it back to source code.

This is necessary to be able to provide diagnostics for lowering to chalk tys, since the input to that is `TypeRef`.

This means that `TypeRef`s now have an identity, which means storing them in arena and not interning them, which is an unfortunate (but necessary) loss but also a pretty massive change. Luckily, because of the separation layer we have for IDE and HIR, this change never crosses the IDE boundary.
This commit is contained in:
Chayim Refael Friedman 2024-09-06 16:25:22 +03:00
parent 6a67a4d3cd
commit 89c0ffa6b0
40 changed files with 1712 additions and 778 deletions

View file

@ -30,6 +30,7 @@ use crate::{
nameres::DefMap, nameres::DefMap,
path::{ModPath, Path}, path::{ModPath, Path},
src::HasSource, src::HasSource,
type_ref::{TypeRef, TypeRefId, TypesMap, TypesSourceMap},
BlockId, DefWithBodyId, HasModule, Lookup, BlockId, DefWithBodyId, HasModule, Lookup,
}; };
@ -69,6 +70,7 @@ pub struct Body {
pub self_param: Option<BindingId>, pub self_param: Option<BindingId>,
/// The `ExprId` of the actual body expression. /// The `ExprId` of the actual body expression.
pub body_expr: ExprId, pub body_expr: ExprId,
pub types: TypesMap,
/// Block expressions in this body that may contain inner items. /// Block expressions in this body that may contain inner items.
block_scopes: Vec<BlockId>, block_scopes: Vec<BlockId>,
@ -139,6 +141,8 @@ pub struct BodySourceMap {
field_map_back: FxHashMap<ExprId, FieldSource>, field_map_back: FxHashMap<ExprId, FieldSource>,
pat_field_map_back: FxHashMap<PatId, PatFieldSource>, pat_field_map_back: FxHashMap<PatId, PatFieldSource>,
types: TypesSourceMap,
// FIXME: Make this a sane struct. // FIXME: Make this a sane struct.
template_map: Option< template_map: Option<
Box<( Box<(
@ -304,6 +308,7 @@ impl Body {
binding_hygiene, binding_hygiene,
expr_hygiene, expr_hygiene,
pat_hygiene, pat_hygiene,
types,
} = self; } = self;
block_scopes.shrink_to_fit(); block_scopes.shrink_to_fit();
exprs.shrink_to_fit(); exprs.shrink_to_fit();
@ -314,6 +319,7 @@ impl Body {
binding_hygiene.shrink_to_fit(); binding_hygiene.shrink_to_fit();
expr_hygiene.shrink_to_fit(); expr_hygiene.shrink_to_fit();
pat_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)) { 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(), binding_hygiene: Default::default(),
expr_hygiene: Default::default(), expr_hygiene: Default::default(),
pat_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. // FIXME: Change `node_` prefix to something more reasonable.
// Perhaps `expr_syntax` and `expr_id`? // Perhaps `expr_syntax` and `expr_id`?
impl BodySourceMap { impl BodySourceMap {
@ -691,6 +706,7 @@ impl BodySourceMap {
template_map, template_map,
diagnostics, diagnostics,
binding_definitions, binding_definitions,
types,
} = self; } = self;
if let Some(template_map) = template_map { if let Some(template_map) = template_map {
template_map.0.shrink_to_fit(); template_map.0.shrink_to_fit();
@ -707,5 +723,6 @@ impl BodySourceMap {
expansions.shrink_to_fit(); expansions.shrink_to_fit();
diagnostics.shrink_to_fit(); diagnostics.shrink_to_fit();
binding_definitions.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}, span_map::{ExpansionSpanMap, SpanMap},
InFile, MacroDefId, InFile, MacroDefId,
}; };
use intern::{sym, Interned, Symbol}; use intern::{sym, Symbol};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use span::AstIdMap; use span::AstIdMap;
use stdx::never; use stdx::never;
@ -274,8 +274,8 @@ impl ExprCollector<'_> {
(self.body, self.source_map) (self.body, self.source_map)
} }
fn ctx(&self) -> LowerCtx<'_> { fn ctx(&mut self) -> LowerCtx<'_> {
self.expander.ctx(self.db) self.expander.ctx(self.db, &mut self.body.types, &mut self.source_map.types)
} }
fn collect_expr(&mut self, expr: ast::Expr) -> ExprId { fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
@ -436,7 +436,7 @@ impl ExprCollector<'_> {
} }
ast::Expr::PathExpr(e) => { ast::Expr::PathExpr(e) => {
let (path, hygiene) = self let (path, hygiene) = self
.collect_expr_path(&e) .collect_expr_path(e)
.map(|(path, hygiene)| (Expr::Path(path), hygiene)) .map(|(path, hygiene)| (Expr::Path(path), hygiene))
.unwrap_or((Expr::Missing, HygieneId::ROOT)); .unwrap_or((Expr::Missing, HygieneId::ROOT));
let expr_id = self.alloc_expr(path, syntax_ptr); let expr_id = self.alloc_expr(path, syntax_ptr);
@ -486,8 +486,7 @@ impl ExprCollector<'_> {
self.alloc_expr(Expr::Yeet { expr }, syntax_ptr) self.alloc_expr(Expr::Yeet { expr }, syntax_ptr)
} }
ast::Expr::RecordExpr(e) => { ast::Expr::RecordExpr(e) => {
let path = let path = e.path().and_then(|path| self.parse_path(path)).map(Box::new);
e.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
let record_lit = if let Some(nfl) = e.record_expr_field_list() { let record_lit = if let Some(nfl) = e.record_expr_field_list() {
let fields = nfl let fields = nfl
.fields() .fields()
@ -534,7 +533,7 @@ impl ExprCollector<'_> {
ast::Expr::TryExpr(e) => self.collect_try_operator(syntax_ptr, e), ast::Expr::TryExpr(e) => self.collect_try_operator(syntax_ptr, e),
ast::Expr::CastExpr(e) => { ast::Expr::CastExpr(e) => {
let expr = self.collect_expr_opt(e.expr()); 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) self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
} }
ast::Expr::RefExpr(e) => { ast::Expr::RefExpr(e) => {
@ -573,16 +572,13 @@ impl ExprCollector<'_> {
arg_types.reserve_exact(num_params); arg_types.reserve_exact(num_params);
for param in pl.params() { for param in pl.params() {
let pat = this.collect_pat_top(param.pat()); let pat = this.collect_pat_top(param.pat());
let type_ref = let type_ref = param.ty().map(|it| TypeRef::from_ast(&this.ctx(), it));
param.ty().map(|it| Interned::new(TypeRef::from_ast(&this.ctx(), it)));
args.push(pat); args.push(pat);
arg_types.push(type_ref); arg_types.push(type_ref);
} }
} }
let ret_type = e let ret_type =
.ret_type() e.ret_type().and_then(|r| r.ty()).map(|it| TypeRef::from_ast(&this.ctx(), it));
.and_then(|r| r.ty())
.map(|it| Interned::new(TypeRef::from_ast(&this.ctx(), it)));
let prev_is_lowering_coroutine = mem::take(&mut this.is_lowering_coroutine); let prev_is_lowering_coroutine = mem::take(&mut this.is_lowering_coroutine);
let prev_try_block_label = this.current_try_block_label.take(); 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::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
ast::Expr::AsmExpr(e) => self.lower_inline_asm(e, syntax_ptr), ast::Expr::AsmExpr(e) => self.lower_inline_asm(e, syntax_ptr),
ast::Expr::OffsetOfExpr(e) => { 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(); let fields = e.fields().map(|it| it.as_name()).collect();
self.alloc_expr(Expr::OffsetOf(OffsetOf { container, fields }), syntax_ptr) self.alloc_expr(Expr::OffsetOf(OffsetOf { container, fields }), syntax_ptr)
} }
@ -717,9 +713,13 @@ 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| { e.path().and_then(|path| {
let path = self.expander.parse_path(self.db, path)?; let path = self.parse_path(path)?;
let Path::Normal { type_anchor, mod_path, generic_args } = &path else { let Path::Normal { type_anchor, mod_path, generic_args } = &path else {
panic!("path parsing produced a non-normal path"); panic!("path parsing produced a non-normal path");
}; };
@ -790,16 +790,13 @@ impl ExprCollector<'_> {
} }
ast::Expr::CallExpr(e) => { ast::Expr::CallExpr(e) => {
let path = collect_path(self, e.expr()?)?; let path = collect_path(self, e.expr()?)?;
let path = path let path = path.path().and_then(|path| self.parse_path(path)).map(Box::new);
.path()
.and_then(|path| self.expander.parse_path(self.db, path))
.map(Box::new);
let (ellipsis, args) = collect_tuple(self, e.arg_list()?.args()); let (ellipsis, args) = collect_tuple(self, e.arg_list()?.args());
self.alloc_pat_from_expr(Pat::TupleStruct { path, args, ellipsis }, syntax_ptr) self.alloc_pat_from_expr(Pat::TupleStruct { path, args, ellipsis }, syntax_ptr)
} }
ast::Expr::PathExpr(e) => { ast::Expr::PathExpr(e) => {
let (path, hygiene) = self let (path, hygiene) = self
.collect_expr_path(e) .collect_expr_path(e.clone())
.map(|(path, hygiene)| (Pat::Path(Box::new(path)), hygiene)) .map(|(path, hygiene)| (Pat::Path(Box::new(path)), hygiene))
.unwrap_or((Pat::Missing, HygieneId::ROOT)); .unwrap_or((Pat::Missing, HygieneId::ROOT));
let pat_id = self.alloc_pat_from_expr(path, syntax_ptr); let pat_id = self.alloc_pat_from_expr(path, syntax_ptr);
@ -819,8 +816,7 @@ impl ExprCollector<'_> {
id id
} }
ast::Expr::RecordExpr(e) => { ast::Expr::RecordExpr(e) => {
let path = let path = e.path().and_then(|path| self.parse_path(path)).map(Box::new);
e.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
let record_field_list = e.record_expr_field_list()?; let record_field_list = e.record_expr_field_list()?;
let ellipsis = record_field_list.dotdot_token().is_some(); let ellipsis = record_field_list.dotdot_token().is_some();
// FIXME: Report an error here if `record_field_list.spread().is_some()`. // FIXME: Report an error here if `record_field_list.spread().is_some()`.
@ -1325,8 +1321,7 @@ impl ExprCollector<'_> {
return; return;
} }
let pat = self.collect_pat_top(stmt.pat()); let pat = self.collect_pat_top(stmt.pat());
let type_ref = let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
stmt.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
let initializer = stmt.initializer().map(|e| self.collect_expr(e)); let initializer = stmt.initializer().map(|e| self.collect_expr(e));
let else_branch = stmt let else_branch = stmt
.let_else() .let_else()
@ -1552,8 +1547,7 @@ impl ExprCollector<'_> {
return pat; return pat;
} }
ast::Pat::TupleStructPat(p) => { ast::Pat::TupleStructPat(p) => {
let path = let path = p.path().and_then(|path| self.parse_path(path)).map(Box::new);
p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
let (args, ellipsis) = self.collect_tuple_pat( let (args, ellipsis) = self.collect_tuple_pat(
p.fields(), p.fields(),
comma_follows_token(p.l_paren_token()), comma_follows_token(p.l_paren_token()),
@ -1567,8 +1561,7 @@ impl ExprCollector<'_> {
Pat::Ref { pat, mutability } Pat::Ref { pat, mutability }
} }
ast::Pat::PathPat(p) => { ast::Pat::PathPat(p) => {
let path = let path = p.path().and_then(|path| self.parse_path(path)).map(Box::new);
p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
path.map(Pat::Path).unwrap_or(Pat::Missing) path.map(Pat::Path).unwrap_or(Pat::Missing)
} }
ast::Pat::OrPat(p) => 'b: { ast::Pat::OrPat(p) => 'b: {
@ -1611,8 +1604,7 @@ impl ExprCollector<'_> {
} }
ast::Pat::WildcardPat(_) => Pat::Wild, ast::Pat::WildcardPat(_) => Pat::Wild,
ast::Pat::RecordPat(p) => { ast::Pat::RecordPat(p) => {
let path = let path = p.path().and_then(|path| self.parse_path(path)).map(Box::new);
p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
let record_pat_field_list = let record_pat_field_list =
&p.record_pat_field_list().expect("every struct should have a field list"); &p.record_pat_field_list().expect("every struct should have a field list");
let args = record_pat_field_list let args = record_pat_field_list

View file

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

View file

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

View file

@ -6,7 +6,7 @@ use base_db::CrateId;
use hir_expand::{ use hir_expand::{
name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefKind, name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefKind,
}; };
use intern::{sym, Interned, Symbol}; use intern::{sym, Symbol};
use la_arena::{Idx, RawIdx}; use la_arena::{Idx, RawIdx};
use smallvec::SmallVec; use smallvec::SmallVec;
use syntax::{ast, Parse}; use syntax::{ast, Parse};
@ -25,7 +25,7 @@ use crate::{
DefMap, MacroSubNs, DefMap, MacroSubNs,
}, },
path::ImportAlias, path::ImportAlias,
type_ref::{TraitRef, TypeBound, TypeRef}, type_ref::{TraitRef, TypeBound, TypeRefId, TypesMap},
visibility::RawVisibility, visibility::RawVisibility,
AssocItemId, AstIdWithPath, ConstId, ConstLoc, ExternCrateId, FunctionId, FunctionLoc, AssocItemId, AstIdWithPath, ConstId, ConstLoc, ExternCrateId, FunctionId, FunctionLoc,
HasModule, ImplId, Intern, ItemContainerId, ItemLoc, Lookup, Macro2Id, MacroRulesId, ModuleId, HasModule, ImplId, Intern, ItemContainerId, ItemLoc, Lookup, Macro2Id, MacroRulesId, ModuleId,
@ -35,13 +35,14 @@ use crate::{
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct FunctionData { pub struct FunctionData {
pub name: Name, pub name: Name,
pub params: Box<[Interned<TypeRef>]>, pub params: Box<[TypeRefId]>,
pub ret_type: Interned<TypeRef>, pub ret_type: TypeRefId,
pub attrs: Attrs, pub attrs: Attrs,
pub visibility: RawVisibility, pub visibility: RawVisibility,
pub abi: Option<Symbol>, pub abi: Option<Symbol>,
pub legacy_const_generics_indices: Option<Box<Box<[u32]>>>, pub legacy_const_generics_indices: Option<Box<Box<[u32]>>>,
pub rustc_allow_incoherent_impl: bool, pub rustc_allow_incoherent_impl: bool,
pub types_map: Arc<TypesMap>,
flags: FnFlags, flags: FnFlags,
} }
@ -110,13 +111,14 @@ impl FunctionData {
.filter(|&(idx, _)| { .filter(|&(idx, _)| {
item_tree.attrs(db, krate, attr_owner(idx)).is_cfg_enabled(cfg_options) 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(), .collect(),
ret_type: func.ret_type.clone(), ret_type: func.ret_type,
attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()), attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
visibility, visibility,
abi: func.abi.clone(), abi: func.abi.clone(),
legacy_const_generics_indices, legacy_const_generics_indices,
types_map: func.types_map.clone(),
flags, flags,
rustc_allow_incoherent_impl, 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)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct TypeAliasData { pub struct TypeAliasData {
pub name: Name, pub name: Name,
pub type_ref: Option<Interned<TypeRef>>, pub type_ref: Option<TypeRefId>,
pub visibility: RawVisibility, pub visibility: RawVisibility,
pub is_extern: bool, pub is_extern: bool,
pub rustc_has_incoherent_inherent_impls: bool, pub rustc_has_incoherent_inherent_impls: bool,
pub rustc_allow_incoherent_impl: bool, pub rustc_allow_incoherent_impl: bool,
/// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl). /// 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 { impl TypeAliasData {
@ -216,12 +219,13 @@ impl TypeAliasData {
Arc::new(TypeAliasData { Arc::new(TypeAliasData {
name: typ.name.clone(), name: typ.name.clone(),
type_ref: typ.type_ref.clone(), type_ref: typ.type_ref,
visibility, visibility,
is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)), is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
rustc_has_incoherent_inherent_impls, rustc_has_incoherent_inherent_impls,
rustc_allow_incoherent_impl, rustc_allow_incoherent_impl,
bounds: typ.bounds.clone(), bounds: typ.bounds.clone(),
types_map: typ.types_map.clone(),
}) })
} }
} }
@ -343,13 +347,14 @@ impl TraitAliasData {
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub struct ImplData { pub struct ImplData {
pub target_trait: Option<Interned<TraitRef>>, pub target_trait: Option<TraitRef>,
pub self_ty: Interned<TypeRef>, pub self_ty: TypeRefId,
pub items: Box<[AssocItemId]>, pub items: Box<[AssocItemId]>,
pub is_negative: bool, pub is_negative: bool,
pub is_unsafe: bool, pub is_unsafe: bool,
// box it as the vec is usually empty anyways // box it as the vec is usually empty anyways
pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>, pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
pub types_map: Arc<TypesMap>,
} }
impl ImplData { impl ImplData {
@ -368,7 +373,7 @@ impl ImplData {
let item_tree = tree_id.item_tree(db); let item_tree = tree_id.item_tree(db);
let impl_def = &item_tree[tree_id.value]; let impl_def = &item_tree[tree_id.value];
let target_trait = impl_def.target_trait.clone(); 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_negative = impl_def.is_negative;
let is_unsafe = impl_def.is_unsafe; let is_unsafe = impl_def.is_unsafe;
@ -387,6 +392,7 @@ impl ImplData {
is_negative, is_negative,
is_unsafe, is_unsafe,
macro_calls, macro_calls,
types_map: impl_def.types_map.clone(),
}), }),
DefDiagnostics::new(diagnostics), DefDiagnostics::new(diagnostics),
) )
@ -532,10 +538,11 @@ impl ExternCrateDeclData {
pub struct ConstData { pub struct ConstData {
/// `None` for `const _: () = ();` /// `None` for `const _: () = ();`
pub name: Option<Name>, pub name: Option<Name>,
pub type_ref: Interned<TypeRef>, pub type_ref: TypeRefId,
pub visibility: RawVisibility, pub visibility: RawVisibility,
pub rustc_allow_incoherent_impl: bool, pub rustc_allow_incoherent_impl: bool,
pub has_body: bool, pub has_body: bool,
pub types_map: Arc<TypesMap>,
} }
impl ConstData { impl ConstData {
@ -556,10 +563,11 @@ impl ConstData {
Arc::new(ConstData { Arc::new(ConstData {
name: konst.name.clone(), name: konst.name.clone(),
type_ref: konst.type_ref.clone(), type_ref: konst.type_ref,
visibility, visibility,
rustc_allow_incoherent_impl, rustc_allow_incoherent_impl,
has_body: konst.has_body, has_body: konst.has_body,
types_map: konst.types_map.clone(),
}) })
} }
} }
@ -567,12 +575,13 @@ impl ConstData {
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct StaticData { pub struct StaticData {
pub name: Name, pub name: Name,
pub type_ref: Interned<TypeRef>, pub type_ref: TypeRefId,
pub visibility: RawVisibility, pub visibility: RawVisibility,
pub mutable: bool, pub mutable: bool,
pub is_extern: bool, pub is_extern: bool,
pub has_safe_kw: bool, pub has_safe_kw: bool,
pub has_unsafe_kw: bool, pub has_unsafe_kw: bool,
pub types_map: Arc<TypesMap>,
} }
impl StaticData { impl StaticData {
@ -583,12 +592,13 @@ impl StaticData {
Arc::new(StaticData { Arc::new(StaticData {
name: statik.name.clone(), name: statik.name.clone(),
type_ref: statik.type_ref.clone(), type_ref: statik.type_ref,
visibility: item_tree[statik.visibility].clone(), visibility: item_tree[statik.visibility].clone(),
mutable: statik.mutable, mutable: statik.mutable,
is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)), is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
has_safe_kw: statik.has_safe_kw, has_safe_kw: statik.has_safe_kw,
has_unsafe_kw: statik.has_unsafe_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 either::Either;
use hir_expand::name::Name; use hir_expand::name::Name;
use intern::{sym, Interned}; use intern::sym;
use la_arena::Arena; use la_arena::Arena;
use rustc_abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions}; use rustc_abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions};
use triomphe::Arc; use triomphe::Arc;
@ -21,7 +21,7 @@ use crate::{
lang_item::LangItem, lang_item::LangItem,
nameres::diagnostics::{DefDiagnostic, DefDiagnostics}, nameres::diagnostics::{DefDiagnostic, DefDiagnostics},
tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree}, tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree},
type_ref::TypeRef, type_ref::{TypeRefId, TypesMap},
visibility::RawVisibility, visibility::RawVisibility,
EnumId, EnumVariantId, LocalFieldId, LocalModuleId, Lookup, StructId, UnionId, VariantId, EnumId, EnumVariantId, LocalFieldId, LocalModuleId, Lookup, StructId, UnionId, VariantId,
}; };
@ -73,8 +73,8 @@ pub struct EnumVariantData {
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum VariantData { pub enum VariantData {
Record(Arena<FieldData>), Record { fields: Arena<FieldData>, types_map: Arc<TypesMap> },
Tuple(Arena<FieldData>), Tuple { fields: Arena<FieldData>, types_map: Arc<TypesMap> },
Unit, Unit,
} }
@ -82,7 +82,7 @@ pub enum VariantData {
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct FieldData { pub struct FieldData {
pub name: Name, pub name: Name,
pub type_ref: Interned<TypeRef>, pub type_ref: TypeRefId,
pub visibility: RawVisibility, pub visibility: RawVisibility,
} }
@ -208,7 +208,7 @@ impl StructData {
} }
let strukt = &item_tree[loc.id.value]; let strukt = &item_tree[loc.id.value];
let (data, diagnostics) = lower_fields( let (fields, diagnostics) = lower_fields(
db, db,
krate, krate,
loc.container.local_id, loc.container.local_id,
@ -219,12 +219,13 @@ impl StructData {
&strukt.fields, &strukt.fields,
None, None,
); );
let types_map = strukt.types_map.clone();
( (
Arc::new(StructData { Arc::new(StructData {
name: strukt.name.clone(), name: strukt.name.clone(),
variant_data: Arc::new(match strukt.shape { variant_data: Arc::new(match strukt.shape {
FieldsShape::Record => VariantData::Record(data), FieldsShape::Record => VariantData::Record { fields, types_map },
FieldsShape::Tuple => VariantData::Tuple(data), FieldsShape::Tuple => VariantData::Tuple { fields, types_map },
FieldsShape::Unit => VariantData::Unit, FieldsShape::Unit => VariantData::Unit,
}), }),
repr, repr,
@ -258,7 +259,7 @@ impl StructData {
} }
let union = &item_tree[loc.id.value]; let union = &item_tree[loc.id.value];
let (data, diagnostics) = lower_fields( let (fields, diagnostics) = lower_fields(
db, db,
krate, krate,
loc.container.local_id, loc.container.local_id,
@ -269,10 +270,11 @@ impl StructData {
&union.fields, &union.fields,
None, None,
); );
let types_map = union.types_map.clone();
( (
Arc::new(StructData { Arc::new(StructData {
name: union.name.clone(), name: union.name.clone(),
variant_data: Arc::new(VariantData::Record(data)), variant_data: Arc::new(VariantData::Record { fields, types_map }),
repr, repr,
visibility: item_tree[union.visibility].clone(), visibility: item_tree[union.visibility].clone(),
flags, flags,
@ -360,7 +362,7 @@ impl EnumVariantData {
let item_tree = loc.id.item_tree(db); let item_tree = loc.id.item_tree(db);
let variant = &item_tree[loc.id.value]; let variant = &item_tree[loc.id.value];
let (data, diagnostics) = lower_fields( let (fields, diagnostics) = lower_fields(
db, db,
krate, krate,
container.local_id, container.local_id,
@ -371,13 +373,14 @@ impl EnumVariantData {
&variant.fields, &variant.fields,
Some(item_tree[loc.parent.lookup(db).id.value].visibility), Some(item_tree[loc.parent.lookup(db).id.value].visibility),
); );
let types_map = variant.types_map.clone();
( (
Arc::new(EnumVariantData { Arc::new(EnumVariantData {
name: variant.name.clone(), name: variant.name.clone(),
variant_data: Arc::new(match variant.shape { variant_data: Arc::new(match variant.shape {
FieldsShape::Record => VariantData::Record(data), FieldsShape::Record => VariantData::Record { fields, types_map },
FieldsShape::Tuple => VariantData::Tuple(data), FieldsShape::Tuple => VariantData::Tuple { fields, types_map },
FieldsShape::Unit => VariantData::Unit, FieldsShape::Unit => VariantData::Unit,
}), }),
}), }),
@ -390,11 +393,20 @@ impl VariantData {
pub fn fields(&self) -> &Arena<FieldData> { pub fn fields(&self) -> &Arena<FieldData> {
const EMPTY: &Arena<FieldData> = &Arena::new(); const EMPTY: &Arena<FieldData> = &Arena::new();
match &self { match &self {
VariantData::Record(fields) | VariantData::Tuple(fields) => fields, VariantData::Record { fields, .. } | VariantData::Tuple { fields, .. } => fields,
_ => EMPTY, _ => 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 // FIXME: Linear lookup
pub fn field(&self, name: &Name) -> Option<LocalFieldId> { pub fn field(&self, name: &Name) -> Option<LocalFieldId> {
self.fields().iter().find_map(|(id, data)| if &data.name == name { Some(id) } else { None }) 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 { pub fn kind(&self) -> StructKind {
match self { match self {
VariantData::Record(_) => StructKind::Record, VariantData::Record { .. } => StructKind::Record,
VariantData::Tuple(_) => StructKind::Tuple, VariantData::Tuple { .. } => StructKind::Tuple,
VariantData::Unit => StructKind::Unit, VariantData::Unit => StructKind::Unit,
} }
} }
@ -463,7 +475,7 @@ fn lower_field(
) -> FieldData { ) -> FieldData {
FieldData { FieldData {
name: field.name.clone(), 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(), 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 base_db::{ra_salsa, CrateId, SourceDatabase, Upcast};
use either::Either; use either::Either;
use hir_expand::{db::ExpandDatabase, HirFileId, MacroDefId}; use hir_expand::{db::ExpandDatabase, HirFileId, MacroDefId};
use intern::{sym, Interned}; use intern::sym;
use la_arena::ArenaMap; use la_arena::ArenaMap;
use span::{EditionedFileId, MacroCallId}; use span::{EditionedFileId, MacroCallId};
use syntax::{ast, AstPtr}; use syntax::{ast, AstPtr};
@ -18,9 +18,10 @@ use crate::{
}, },
generics::GenericParams, generics::GenericParams,
import_map::ImportMap, import_map::ImportMap,
item_tree::{AttrOwner, ItemTree}, item_tree::{AttrOwner, ItemTree, ItemTreeSourceMaps},
lang_item::{self, LangItem, LangItemTarget, LangItems}, lang_item::{self, LangItem, LangItemTarget, LangItems},
nameres::{diagnostics::DefDiagnostics, DefMap}, nameres::{diagnostics::DefDiagnostics, DefMap},
type_ref::TypesSourceMap,
visibility::{self, Visibility}, visibility::{self, Visibility},
AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstBlockLoc, ConstId, ConstLoc, DefWithBodyId, AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstBlockLoc, ConstId, ConstLoc, DefWithBodyId,
EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, 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)] #[ra_salsa::invoke(ItemTree::block_item_tree_query)]
fn block_item_tree(&self, block_id: BlockId) -> Arc<ItemTree>; 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)] #[ra_salsa::invoke(DefMap::crate_def_map_query)]
fn crate_def_map(&self, krate: CrateId) -> Arc<DefMap>; 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>; fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>;
#[ra_salsa::invoke(GenericParams::generic_params_query)] #[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 // region:attrs

View file

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

View file

@ -10,7 +10,6 @@ use hir_expand::{
name::{AsName, Name}, name::{AsName, Name},
ExpandResult, ExpandResult,
}; };
use intern::Interned;
use la_arena::{Arena, RawIdx}; use la_arena::{Arena, RawIdx};
use stdx::impl_from; use stdx::impl_from;
use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds}; use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds};
@ -22,7 +21,8 @@ use crate::{
item_tree::{AttrOwner, FileItemTreeId, GenericModItem, GenericsItemTreeNode, ItemTree}, item_tree::{AttrOwner, FileItemTreeId, GenericModItem, GenericsItemTreeNode, ItemTree},
lower::LowerCtx, lower::LowerCtx,
nameres::{DefMap, MacroSubNs}, nameres::{DefMap, MacroSubNs},
type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef}, path::{AssociatedTypeBinding, GenericArg, GenericArgs, Path},
type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef, TypeRefId, TypesMap, TypesSourceMap},
AdtId, ConstParamId, GenericDefId, HasModule, ItemTreeLoc, LifetimeParamId, AdtId, ConstParamId, GenericDefId, HasModule, ItemTreeLoc, LifetimeParamId,
LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
}; };
@ -37,7 +37,7 @@ pub struct TypeParamData {
/// [`None`] only if the type ref is an [`TypeRef::ImplTrait`]. FIXME: Might be better to just /// [`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. /// make it always be a value, giving impl trait a special name.
pub name: Option<Name>, pub name: Option<Name>,
pub default: Option<Interned<TypeRef>>, pub default: Option<TypeRefId>,
pub provenance: TypeParamProvenance, pub provenance: TypeParamProvenance,
} }
@ -51,7 +51,7 @@ pub struct LifetimeParamData {
#[derive(Clone, PartialEq, Eq, Debug, Hash)] #[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct ConstParamData { pub struct ConstParamData {
pub name: Name, pub name: Name,
pub ty: Interned<TypeRef>, pub ty: TypeRefId,
pub default: Option<ConstRef>, pub default: Option<ConstRef>,
} }
@ -161,6 +161,7 @@ pub struct GenericParams {
type_or_consts: Arena<TypeOrConstParamData>, type_or_consts: Arena<TypeOrConstParamData>,
lifetimes: Arena<LifetimeParamData>, lifetimes: Arena<LifetimeParamData>,
where_predicates: Box<[WherePredicate]>, where_predicates: Box<[WherePredicate]>,
pub types_map: TypesMap,
} }
impl ops::Index<LocalTypeOrConstParamId> for GenericParams { impl ops::Index<LocalTypeOrConstParamId> for GenericParams {
@ -183,24 +184,14 @@ impl ops::Index<LocalLifetimeParamId> for GenericParams {
/// associated type bindings like `Iterator<Item = u32>`. /// associated type bindings like `Iterator<Item = u32>`.
#[derive(Clone, PartialEq, Eq, Debug, Hash)] #[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum WherePredicate { pub enum WherePredicate {
TypeBound { TypeBound { target: WherePredicateTypeTarget, bound: TypeBound },
target: WherePredicateTypeTarget, Lifetime { target: LifetimeRef, bound: LifetimeRef },
bound: Interned<TypeBound>, ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound },
},
Lifetime {
target: LifetimeRef,
bound: LifetimeRef,
},
ForLifetime {
lifetimes: Box<[Name]>,
target: WherePredicateTypeTarget,
bound: Interned<TypeBound>,
},
} }
#[derive(Clone, PartialEq, Eq, Debug, Hash)] #[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum WherePredicateTypeTarget { pub enum WherePredicateTypeTarget {
TypeRef(Interned<TypeRef>), TypeRef(TypeRefId),
/// For desugared where predicates that can directly refer to a type param. /// For desugared where predicates that can directly refer to a type param.
TypeOrConstParam(LocalTypeOrConstParamId), TypeOrConstParam(LocalTypeOrConstParamId),
} }
@ -300,7 +291,14 @@ impl GenericParams {
pub(crate) fn generic_params_query( pub(crate) fn generic_params_query(
db: &dyn DefDatabase, db: &dyn DefDatabase,
def: GenericDefId, 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 _p = tracing::info_span!("generic_params_query").entered();
let krate = def.krate(db); let krate = def.krate(db);
@ -309,7 +307,7 @@ impl GenericParams {
// Returns the generic parameters that are enabled under the current `#[cfg]` options // Returns the generic parameters that are enabled under the current `#[cfg]` options
let enabled_params = 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 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_ct = |param| AttrOwner::TypeOrConstParamData(parent, param);
let attr_owner_lt = |param| AttrOwner::LifetimeParamData(parent, param); let attr_owner_lt = |param| AttrOwner::LifetimeParamData(parent, param);
@ -325,7 +323,7 @@ impl GenericParams {
if all_type_or_consts_enabled && all_lifetimes_enabled { if all_type_or_consts_enabled && all_lifetimes_enabled {
params.clone() params.clone()
} else { } else {
Interned::new(GenericParams { Arc::new(GenericParams {
type_or_consts: all_type_or_consts_enabled type_or_consts: all_type_or_consts_enabled
.then(|| params.type_or_consts.clone()) .then(|| params.type_or_consts.clone())
.unwrap_or_else(|| { .unwrap_or_else(|| {
@ -347,6 +345,7 @@ impl GenericParams {
.collect() .collect()
}), }),
where_predicates: params.where_predicates.clone(), where_predicates: params.where_predicates.clone(),
types_map: params.types_map.clone(),
}) })
} }
}; };
@ -357,18 +356,18 @@ impl GenericParams {
Data = impl ItemTreeLoc<Id = Id>, Data = impl ItemTreeLoc<Id = Id>,
>, >,
enabled_params: impl Fn( enabled_params: impl Fn(
&Interned<GenericParams>, &Arc<GenericParams>,
&ItemTree, &ItemTree,
GenericModItem, GenericModItem,
) -> Interned<GenericParams>, ) -> Arc<GenericParams>,
) -> Interned<GenericParams> ) -> (Arc<GenericParams>, Option<Arc<TypesSourceMap>>)
where where
FileItemTreeId<Id>: Into<GenericModItem>, FileItemTreeId<Id>: Into<GenericModItem>,
{ {
let id = id.lookup(db).item_tree_id(); let id = id.lookup(db).item_tree_id();
let tree = id.item_tree(db); let tree = id.item_tree(db);
let item = &tree[id.value]; 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 { match def {
@ -383,28 +382,37 @@ impl GenericParams {
let module = loc.container.module(db); let module = loc.container.module(db);
let func_data = db.function_data(id); let func_data = db.function_data(id);
if func_data.params.is_empty() { if func_data.params.is_empty() {
enabled_params (enabled_params, None)
} else { } else {
let source_maps = loc.id.item_tree_with_source_map(db).1;
let item_source_maps = &source_maps[loc.id.value];
let mut generic_params = GenericParamsCollector { let mut generic_params = GenericParamsCollector {
type_or_consts: enabled_params.type_or_consts.clone(), type_or_consts: enabled_params.type_or_consts.clone(),
lifetimes: enabled_params.lifetimes.clone(), lifetimes: enabled_params.lifetimes.clone(),
where_predicates: enabled_params.where_predicates.clone().into(), 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 // Don't create an `Expander` if not needed since this
// could cause a reparse after the `ItemTree` has been created due to the spanmap. // could cause a reparse after the `ItemTree` has been created due to the spanmap.
let mut expander = None; 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( generic_params.fill_implicit_impl_trait_args(
db, db,
&mut types_map,
&mut types_source_maps,
&mut expander, &mut expander,
&mut || { &mut || {
(module.def_map(db), Expander::new(db, loc.id.file_id(), module)) (module.def_map(db), Expander::new(db, loc.id.file_id(), module))
}, },
param, param,
&item.types_map,
&item_source_maps.item,
); );
} }
Interned::new(generic_params.finish()) let generics = generic_params.finish(types_map, &mut types_source_maps);
(Arc::new(generics), Some(Arc::new(types_source_maps)))
} }
} }
GenericDefId::AdtId(AdtId::StructId(id)) => id_to_generics(db, id, enabled_params), GenericDefId::AdtId(AdtId::StructId(id)) => id_to_generics(db, id, enabled_params),
@ -414,11 +422,15 @@ impl GenericParams {
GenericDefId::TraitAliasId(id) => id_to_generics(db, id, enabled_params), GenericDefId::TraitAliasId(id) => id_to_generics(db, id, enabled_params),
GenericDefId::TypeAliasId(id) => id_to_generics(db, id, enabled_params), GenericDefId::TypeAliasId(id) => id_to_generics(db, id, enabled_params),
GenericDefId::ImplId(id) => id_to_generics(db, id, enabled_params), GenericDefId::ImplId(id) => id_to_generics(db, id, enabled_params),
GenericDefId::ConstId(_) => Interned::new(GenericParams { GenericDefId::ConstId(_) => (
Arc::new(GenericParams {
type_or_consts: Default::default(), type_or_consts: Default::default(),
lifetimes: Default::default(), lifetimes: Default::default(),
where_predicates: Default::default(), where_predicates: Default::default(),
types_map: Default::default(),
}), }),
None,
),
} }
} }
} }
@ -452,7 +464,7 @@ impl GenericParamsCollector {
&mut self, &mut self,
lower_ctx: &LowerCtx<'_>, lower_ctx: &LowerCtx<'_>,
type_bounds: Option<ast::TypeBoundList>, 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()) { 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()); self.add_where_predicate_from_bound(lower_ctx, bound, None, target.clone());
@ -473,16 +485,15 @@ impl GenericParamsCollector {
ast::TypeOrConstParam::Type(type_param) => { ast::TypeOrConstParam::Type(type_param) => {
let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
// FIXME: Use `Path::from_src` // FIXME: Use `Path::from_src`
let default = type_param let default =
.default_type() type_param.default_type().map(|it| TypeRef::from_ast(lower_ctx, it));
.map(|it| Interned::new(TypeRef::from_ast(lower_ctx, it)));
let param = TypeParamData { let param = TypeParamData {
name: Some(name.clone()), name: Some(name.clone()),
default, default,
provenance: TypeParamProvenance::TypeParamList, provenance: TypeParamProvenance::TypeParamList,
}; };
let idx = self.type_or_consts.alloc(param.into()); 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( self.fill_bounds(
lower_ctx, lower_ctx,
type_param.type_bound_list(), type_param.type_bound_list(),
@ -492,12 +503,10 @@ impl GenericParamsCollector {
} }
ast::TypeOrConstParam::Const(const_param) => { ast::TypeOrConstParam::Const(const_param) => {
let name = const_param.name().map_or_else(Name::missing, |it| it.as_name()); let name = const_param.name().map_or_else(Name::missing, |it| it.as_name());
let ty = const_param let ty = TypeRef::from_ast_opt(lower_ctx, const_param.ty());
.ty()
.map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it));
let param = ConstParamData { let param = ConstParamData {
name, name,
ty: Interned::new(ty), ty,
default: ConstRef::from_const_param(lower_ctx, &const_param), default: ConstRef::from_const_param(lower_ctx, &const_param),
}; };
let idx = self.type_or_consts.alloc(param.into()); let idx = self.type_or_consts.alloc(param.into());
@ -557,7 +566,7 @@ impl GenericParamsCollector {
lower_ctx: &LowerCtx<'_>, lower_ctx: &LowerCtx<'_>,
bound: ast::TypeBound, bound: ast::TypeBound,
hrtb_lifetimes: Option<&[Name]>, hrtb_lifetimes: Option<&[Name]>,
target: Either<TypeRef, LifetimeRef>, target: Either<TypeRefId, LifetimeRef>,
) { ) {
let bound = TypeBound::from_ast(lower_ctx, bound); let bound = TypeBound::from_ast(lower_ctx, bound);
self.fill_impl_trait_bounds(lower_ctx.take_impl_traits_bounds()); self.fill_impl_trait_bounds(lower_ctx.take_impl_traits_bounds());
@ -565,12 +574,12 @@ impl GenericParamsCollector {
(Either::Left(type_ref), bound) => match hrtb_lifetimes { (Either::Left(type_ref), bound) => match hrtb_lifetimes {
Some(hrtb_lifetimes) => WherePredicate::ForLifetime { Some(hrtb_lifetimes) => WherePredicate::ForLifetime {
lifetimes: hrtb_lifetimes.to_vec().into_boxed_slice(), lifetimes: hrtb_lifetimes.to_vec().into_boxed_slice(),
target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)), target: WherePredicateTypeTarget::TypeRef(type_ref),
bound: Interned::new(bound), bound,
}, },
None => WherePredicate::TypeBound { None => WherePredicate::TypeBound {
target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)), target: WherePredicateTypeTarget::TypeRef(type_ref),
bound: Interned::new(bound), bound,
}, },
}, },
(Either::Right(lifetime), TypeBound::Lifetime(bound)) => { (Either::Right(lifetime), TypeBound::Lifetime(bound)) => {
@ -581,7 +590,7 @@ impl GenericParamsCollector {
self.where_predicates.push(predicate); 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<Vec<TypeBound>>) {
for bounds in impl_bounds { for bounds in impl_bounds {
let param = TypeParamData { let param = TypeParamData {
name: None, name: None,
@ -601,12 +610,16 @@ impl GenericParamsCollector {
fn fill_implicit_impl_trait_args( fn fill_implicit_impl_trait_args(
&mut self, &mut self,
db: &dyn DefDatabase, 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. // 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: &mut Option<(Arc<DefMap>, Expander)>,
exp_fill: &mut dyn FnMut() -> (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 { if let TypeRef::ImplTrait(bounds) = type_ref {
let param = TypeParamData { let param = TypeParamData {
name: None, name: None,
@ -615,12 +628,20 @@ impl GenericParamsCollector {
}; };
let param_id = self.type_or_consts.alloc(param.into()); let param_id = self.type_or_consts.alloc(param.into());
for bound in bounds { 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 { self.where_predicates.push(WherePredicate::TypeBound {
target: WherePredicateTypeTarget::TypeOrConstParam(param_id), target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
bound: bound.clone(), bound,
}); });
} }
} }
if let TypeRef::Macro(mc) = type_ref { if let TypeRef::Macro(mc) = type_ref {
let macro_call = mc.to_node(db.upcast()); let macro_call = mc.to_node(db.upcast());
let (def_map, expander) = exp.get_or_insert_with(&mut *exp_fill); let (def_map, expander) = exp.get_or_insert_with(&mut *exp_fill);
@ -641,23 +662,210 @@ impl GenericParamsCollector {
if let Ok(ExpandResult { value: Some((mark, expanded)), .. }) = if let Ok(ExpandResult { value: Some((mark, expanded)), .. }) =
expander.enter_expand(db, macro_call, resolver) 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()); 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); exp.get_or_insert_with(&mut *exp_fill).1.exit(mark);
} }
} }
}); });
} }
pub(crate) fn finish(self) -> GenericParams { pub(crate) fn finish(
let Self { mut lifetimes, mut type_or_consts, where_predicates } = self; self,
mut generics_types_map: TypesMap,
generics_types_source_map: &mut TypesSourceMap,
) -> GenericParams {
let Self { mut lifetimes, mut type_or_consts, mut where_predicates } = self;
lifetimes.shrink_to_fit(); lifetimes.shrink_to_fit();
type_or_consts.shrink_to_fit(); type_or_consts.shrink_to_fit();
where_predicates.shrink_to_fit();
generics_types_map.shrink_to_fit();
generics_types_source_map.shrink_to_fit();
GenericParams { GenericParams {
type_or_consts, type_or_consts,
lifetimes, lifetimes,
where_predicates: where_predicates.into_boxed_slice(), 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 { ref params, is_varargs, is_unsafe, ref abi } => {
let params = params
.iter()
.map(|(name, param_type)| {
(
name.clone(),
copy_type_ref(*param_type, from, from_source_map, to, to_source_map),
)
})
.collect();
TypeRef::Fn { params, is_varargs, is_unsafe, abi: abi.clone() }
}
TypeRef::Tuple(types) => TypeRef::Tuple(
types
.iter()
.map(|&t| copy_type_ref(t, from, from_source_map, to, to_source_map))
.collect(),
),
&TypeRef::RawPtr(type_ref, mutbl) => TypeRef::RawPtr(
copy_type_ref(type_ref, from, from_source_map, to, to_source_map),
mutbl,
),
TypeRef::Reference(type_ref, lifetime, mutbl) => TypeRef::Reference(
copy_type_ref(*type_ref, from, from_source_map, to, to_source_map),
lifetime.clone(),
*mutbl,
),
TypeRef::Array(type_ref, len) => TypeRef::Array(
copy_type_ref(*type_ref, from, from_source_map, to, to_source_map),
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(
copy_type_bounds(bounds, from, from_source_map, to, to_source_map).into(),
),
TypeRef::DynTrait(bounds) => TypeRef::DynTrait(
copy_type_bounds(bounds, from, from_source_map, to, to_source_map).into(),
),
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::Normal { type_anchor, mod_path, generic_args } => {
let type_anchor = type_anchor
.map(|type_ref| copy_type_ref(type_ref, from, from_source_map, to, to_source_map));
let mod_path = mod_path.clone();
let generic_args = generic_args.as_ref().map(|generic_args| {
generic_args
.iter()
.map(|generic_args| {
copy_generic_args(generic_args, from, from_source_map, to, to_source_map)
})
.collect()
});
Path::Normal { 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);
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(
bounds: &[TypeBound],
from: &TypesMap,
from_source_map: &TypesSourceMap,
to: &mut TypesMap,
to_source_map: &mut TypesSourceMap,
) -> Box<[TypeBound]> {
bounds
.iter()
.map(|bound| copy_type_bound(bound, from, from_source_map, to, to_source_map))
.collect()
}
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 std::fmt;
use hir_expand::{name::Name, MacroDefId}; use hir_expand::{name::Name, MacroDefId};
use intern::{Interned, Symbol}; use intern::Symbol;
use la_arena::{Idx, RawIdx}; use la_arena::{Idx, RawIdx};
use rustc_apfloat::ieee::{Half as f16, Quad as f128}; use rustc_apfloat::ieee::{Half as f16, Quad as f128};
use syntax::ast; use syntax::ast;
use type_ref::TypeRefId;
use crate::{ use crate::{
builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint}, builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
path::{GenericArgs, Path}, path::{GenericArgs, Path},
type_ref::{Mutability, Rawness, TypeRef}, type_ref::{Mutability, Rawness},
BlockId, ConstBlockId, BlockId, ConstBlockId,
}; };
@ -264,7 +265,7 @@ pub enum Expr {
}, },
Cast { Cast {
expr: ExprId, expr: ExprId,
type_ref: Interned<TypeRef>, type_ref: TypeRefId,
}, },
Ref { Ref {
expr: ExprId, expr: ExprId,
@ -300,8 +301,8 @@ pub enum Expr {
}, },
Closure { Closure {
args: Box<[PatId]>, args: Box<[PatId]>,
arg_types: Box<[Option<Interned<TypeRef>>]>, arg_types: Box<[Option<TypeRefId>]>,
ret_type: Option<Interned<TypeRef>>, ret_type: Option<TypeRefId>,
body: ExprId, body: ExprId,
closure_kind: ClosureKind, closure_kind: ClosureKind,
capture_by: CaptureBy, capture_by: CaptureBy,
@ -318,7 +319,7 @@ pub enum Expr {
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct OffsetOf { pub struct OffsetOf {
pub container: Interned<TypeRef>, pub container: TypeRefId,
pub fields: Box<[Name]>, pub fields: Box<[Name]>,
} }
@ -484,7 +485,7 @@ pub struct RecordLitField {
pub enum Statement { pub enum Statement {
Let { Let {
pat: PatId, pat: PatId,
type_ref: Option<Interned<TypeRef>>, type_ref: Option<TypeRefId>,
initializer: Option<ExprId>, initializer: Option<ExprId>,
else_branch: Option<ExprId>, else_branch: Option<ExprId>,
}, },

View file

@ -2,22 +2,26 @@
//! be directly created from an ast::TypeRef, without further queries. //! be directly created from an ast::TypeRef, without further queries.
use core::fmt; use core::fmt;
use std::fmt::Write; use std::{fmt::Write, ops::Index};
use hir_expand::{ use hir_expand::{
db::ExpandDatabase, db::ExpandDatabase,
name::{AsName, Name}, 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 span::Edition;
use syntax::ast::{self, HasGenericArgs, HasName, IsString}; use syntax::{
ast::{self, HasGenericArgs, HasName, IsString},
AstPtr,
};
use crate::{ use crate::{
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint}, builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
hir::Literal, hir::Literal,
lower::LowerCtx, lower::LowerCtx,
path::Path, path::{GenericArg, Path},
}; };
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
@ -105,34 +109,69 @@ impl TraitRef {
} }
/// Compare ty::Ty /// 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)] #[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum TypeRef { pub enum TypeRef {
Never, Never,
Placeholder, Placeholder,
Tuple(Vec<TypeRef>), Tuple(Vec<TypeRefId>),
Path(Path), Path(Path),
RawPtr(Box<TypeRef>, Mutability), RawPtr(TypeRefId, Mutability),
Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability), Reference(TypeRefId, Option<LifetimeRef>, Mutability),
// FIXME: This should be Array(Box<TypeRef>, Ast<ConstArg>), // FIXME: This should be Array(TypeRefId, Ast<ConstArg>),
Array(Box<TypeRef>, ConstRef), Array(TypeRefId, ConstRef),
Slice(Box<TypeRef>), Slice(TypeRefId),
/// A fn pointer. Last element of the vector is the return type. /// A fn pointer. Last element of the vector is the return type.
Fn( Fn {
Box<[(Option<Name>, TypeRef)]>, params: Box<[(Option<Name>, TypeRefId)]>,
bool, /*varargs*/ is_varargs: bool,
bool, /*is_unsafe*/ is_unsafe: bool,
Option<Symbol>, /* abi */ abi: Option<Symbol>,
), },
ImplTrait(Vec<Interned<TypeBound>>), ImplTrait(Vec<TypeBound>),
DynTrait(Vec<Interned<TypeBound>>), DynTrait(Vec<TypeBound>),
Macro(AstId<ast::MacroCall>), Macro(AstId<ast::MacroCall>),
Error, Error,
} }
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)] #[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct LifetimeRef { pub struct LifetimeRef {
pub name: Name, pub name: Name,
@ -162,7 +201,7 @@ pub enum TypeBound {
} }
#[cfg(target_pointer_width = "64")] #[cfg(target_pointer_width = "64")]
const _: [(); 56] = [(); ::std::mem::size_of::<TypeBound>()]; const _: [(); 48] = [(); ::std::mem::size_of::<TypeBound>()];
#[derive(Clone, PartialEq, Eq, Hash, Debug)] #[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum UseArgRef { pub enum UseArgRef {
@ -172,7 +211,7 @@ pub enum UseArgRef {
/// A modifier on a bound, currently this is only used for `?Sized`, where the /// A modifier on a bound, currently this is only used for `?Sized`, where the
/// modifier is `Maybe`. /// modifier is `Maybe`.
#[derive(Clone, PartialEq, Eq, Hash, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum TraitBoundModifier { pub enum TraitBoundModifier {
None, None,
Maybe, Maybe,
@ -180,9 +219,9 @@ pub enum TraitBoundModifier {
impl TypeRef { impl TypeRef {
/// Converts an `ast::TypeRef` to a `hir::TypeRef`. /// Converts an `ast::TypeRef` to a `hir::TypeRef`.
pub fn from_ast(ctx: &LowerCtx<'_>, node: ast::Type) -> Self { pub fn from_ast(ctx: &LowerCtx<'_>, node: ast::Type) -> TypeRefId {
match node { let ty = match &node {
ast::Type::ParenType(inner) => TypeRef::from_ast_opt(ctx, inner.ty()), ast::Type::ParenType(inner) => return TypeRef::from_ast_opt(ctx, inner.ty()),
ast::Type::TupleType(inner) => { ast::Type::TupleType(inner) => {
TypeRef::Tuple(inner.fields().map(|it| TypeRef::from_ast(ctx, it)).collect()) TypeRef::Tuple(inner.fields().map(|it| TypeRef::from_ast(ctx, it)).collect())
} }
@ -198,20 +237,18 @@ impl TypeRef {
ast::Type::PtrType(inner) => { ast::Type::PtrType(inner) => {
let inner_ty = TypeRef::from_ast_opt(ctx, inner.ty()); let inner_ty = TypeRef::from_ast_opt(ctx, inner.ty());
let mutability = Mutability::from_mutable(inner.mut_token().is_some()); 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) => { ast::Type::ArrayType(inner) => {
let len = ConstRef::from_const_arg(ctx, inner.const_arg()); let len = ConstRef::from_const_arg(ctx, inner.const_arg());
TypeRef::Array(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())), len) TypeRef::Array(TypeRef::from_ast_opt(ctx, inner.ty()), len)
}
ast::Type::SliceType(inner) => {
TypeRef::Slice(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())))
} }
ast::Type::SliceType(inner) => TypeRef::Slice(TypeRef::from_ast_opt(ctx, inner.ty())),
ast::Type::RefType(inner) => { ast::Type::RefType(inner) => {
let inner_ty = TypeRef::from_ast_opt(ctx, inner.ty()); let inner_ty = TypeRef::from_ast_opt(ctx, inner.ty());
let lifetime = inner.lifetime().map(|lt| LifetimeRef::new(&lt)); let lifetime = inner.lifetime().map(|lt| LifetimeRef::new(&lt));
let mutability = Mutability::from_mutable(inner.mut_token().is_some()); let mutability = Mutability::from_mutable(inner.mut_token().is_some());
TypeRef::Reference(Box::new(inner_ty), lifetime, mutability) TypeRef::Reference(inner_ty, lifetime, mutability)
} }
ast::Type::InferType(_inner) => TypeRef::Placeholder, ast::Type::InferType(_inner) => TypeRef::Placeholder,
ast::Type::FnPtrType(inner) => { ast::Type::FnPtrType(inner) => {
@ -219,7 +256,7 @@ impl TypeRef {
.ret_type() .ret_type()
.and_then(|rt| rt.ty()) .and_then(|rt| rt.ty())
.map(|it| TypeRef::from_ast(ctx, it)) .map(|it| TypeRef::from_ast(ctx, it))
.unwrap_or_else(|| TypeRef::Tuple(Vec::new())); .unwrap_or_else(|| ctx.alloc_type_ref_desugared(TypeRef::Tuple(Vec::new())));
let mut is_varargs = false; let mut is_varargs = false;
let mut params = if let Some(pl) = inner.param_list() { let mut params = if let Some(pl) = inner.param_list() {
if let Some(param) = pl.params().last() { if let Some(param) = pl.params().last() {
@ -251,10 +288,15 @@ impl TypeRef {
let abi = inner.abi().map(lower_abi); let abi = inner.abi().map(lower_abi);
params.push((None, ret_ty)); params.push((None, ret_ty));
TypeRef::Fn(params.into(), is_varargs, inner.unsafe_token().is_some(), abi) TypeRef::Fn {
params: params.into(),
is_varargs,
is_unsafe: inner.unsafe_token().is_some(),
abi,
}
} }
// for types are close enough for our purposes to the inner type for now... // 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) => { ast::Type::ImplTraitType(inner) => {
if ctx.outer_impl_trait() { if ctx.outer_impl_trait() {
// Disallow nested impl traits // Disallow nested impl traits
@ -271,13 +313,14 @@ impl TypeRef {
Some(mc) => TypeRef::Macro(ctx.ast_id(&mc)), Some(mc) => TypeRef::Macro(ctx.ast_id(&mc)),
None => TypeRef::Error, 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 { match node {
Some(node) => TypeRef::from_ast(ctx, node), Some(node) => TypeRef::from_ast(ctx, node),
None => TypeRef::Error, None => ctx.alloc_error_type(),
} }
} }
@ -285,58 +328,58 @@ impl TypeRef {
TypeRef::Tuple(Vec::new()) TypeRef::Tuple(Vec::new())
} }
pub fn walk(&self, f: &mut impl FnMut(&TypeRef)) { pub fn walk(this: TypeRefId, map: &TypesMap, f: &mut impl FnMut(&TypeRef)) {
go(self, f); 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); f(type_ref);
match type_ref { match type_ref {
TypeRef::Fn(params, _, _, _) => { TypeRef::Fn { params, is_varargs: _, is_unsafe: _, abi: _ } => {
params.iter().for_each(|(_, param_type)| go(param_type, f)) params.iter().for_each(|&(_, param_type)| go(param_type, f, map))
} }
TypeRef::Tuple(types) => types.iter().for_each(|t| go(t, f)), TypeRef::Tuple(types) => types.iter().for_each(|&t| go(t, f, map)),
TypeRef::RawPtr(type_ref, _) TypeRef::RawPtr(type_ref, _)
| TypeRef::Reference(type_ref, ..) | TypeRef::Reference(type_ref, ..)
| TypeRef::Array(type_ref, _) | TypeRef::Array(type_ref, _)
| TypeRef::Slice(type_ref) => go(type_ref, f), | TypeRef::Slice(type_ref) => go(*type_ref, f, map),
TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => { TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
for bound in bounds { for bound in bounds {
match bound.as_ref() { match bound {
TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => { TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
go_path(path, f) go_path(path, f, map)
} }
TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (), 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 => {} 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() { if let Some(type_ref) = path.type_anchor() {
go(type_ref, f); go(type_ref, f, map);
} }
for segment in path.segments().iter() { for segment in path.segments().iter() {
if let Some(args_and_bindings) = segment.args_and_bindings { if let Some(args_and_bindings) = segment.args_and_bindings {
for arg in args_and_bindings.args.iter() { for arg in args_and_bindings.args.iter() {
match arg { match arg {
crate::path::GenericArg::Type(type_ref) => { GenericArg::Type(type_ref) => {
go(type_ref, f); go(*type_ref, f, map);
} }
crate::path::GenericArg::Const(_) GenericArg::Const(_) | GenericArg::Lifetime(_) => {}
| crate::path::GenericArg::Lifetime(_) => {}
} }
} }
for binding in args_and_bindings.bindings.iter() { for binding in args_and_bindings.bindings.iter() {
if let Some(type_ref) = &binding.type_ref { if let Some(type_ref) = binding.type_ref {
go(type_ref, f); go(type_ref, f, map);
} }
for bound in binding.bounds.iter() { for bound in binding.bounds.iter() {
match bound.as_ref() { match bound {
TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => { TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
go_path(path, f) go_path(path, f, map)
} }
TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (), TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
} }
@ -351,9 +394,9 @@ impl TypeRef {
pub(crate) fn type_bounds_from_ast( pub(crate) fn type_bounds_from_ast(
lower_ctx: &LowerCtx<'_>, lower_ctx: &LowerCtx<'_>,
type_bounds_opt: Option<ast::TypeBoundList>, type_bounds_opt: Option<ast::TypeBoundList>,
) -> Vec<Interned<TypeBound>> { ) -> Vec<TypeBound> {
if let Some(type_bounds) = type_bounds_opt { if let Some(type_bounds) = type_bounds_opt {
type_bounds.bounds().map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it))).collect() type_bounds.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect()
} else { } else {
vec![] vec![]
} }

View file

@ -61,7 +61,7 @@ use crate::{
db::DefDatabase, db::DefDatabase,
generics::GenericParams, generics::GenericParams,
path::{GenericArgs, ImportAlias, ModPath, Path, PathKind}, path::{GenericArgs, ImportAlias, ModPath, Path, PathKind},
type_ref::{Mutability, TraitRef, TypeBound, TypeRef}, type_ref::{Mutability, TraitRef, TypeBound, TypeRefId, TypesMap, TypesSourceMap},
visibility::{RawVisibility, VisibilityExplicitness}, visibility::{RawVisibility, VisibilityExplicitness},
BlockId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, BlockId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup,
}; };
@ -100,13 +100,20 @@ pub struct ItemTree {
impl ItemTree { impl ItemTree {
pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<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(); 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 ctx = lower::Ctx::new(db, file_id);
let syntax = db.parse_or_expand(file_id); let syntax = db.parse_or_expand(file_id);
let mut top_attrs = None; let mut top_attrs = None;
let mut item_tree = match_ast! { let (mut item_tree, mut source_maps) = match_ast! {
match syntax { match syntax {
ast::SourceFile(file) => { ast::SourceFile(file) => {
top_attrs = Some(RawAttrs::new(db.upcast(), &file, ctx.span_map())); top_attrs = Some(RawAttrs::new(db.upcast(), &file, ctx.span_map()));
@ -136,42 +143,57 @@ impl ItemTree {
{ {
EMPTY EMPTY
.get_or_init(|| { .get_or_init(|| {
(
Arc::new(ItemTree { Arc::new(ItemTree {
top_level: SmallVec::new_const(), top_level: SmallVec::new_const(),
attrs: FxHashMap::default(), attrs: FxHashMap::default(),
data: None, data: None,
}) }),
Arc::default(),
)
}) })
.clone() .clone()
} else { } else {
item_tree.shrink_to_fit(); item_tree.shrink_to_fit();
Arc::new(item_tree) source_maps.shrink_to_fit();
(Arc::new(item_tree), Arc::new(source_maps))
} }
} }
pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc<ItemTree> { 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(); 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 loc = block.lookup(db);
let block = loc.ast_id.to_node(db.upcast()); let block = loc.ast_id.to_node(db.upcast());
let ctx = lower::Ctx::new(db, loc.ast_id.file_id); let ctx = lower::Ctx::new(db, loc.ast_id.file_id);
let mut item_tree = ctx.lower_block(&block); let (mut item_tree, mut source_maps) = ctx.lower_block(&block);
if item_tree.data.is_none() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty() if item_tree.data.is_none() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty()
{ {
EMPTY EMPTY
.get_or_init(|| { .get_or_init(|| {
(
Arc::new(ItemTree { Arc::new(ItemTree {
top_level: SmallVec::new_const(), top_level: SmallVec::new_const(),
attrs: FxHashMap::default(), attrs: FxHashMap::default(),
data: None, data: None,
}) }),
Arc::default(),
)
}) })
.clone() .clone()
} else { } else {
item_tree.shrink_to_fit(); item_tree.shrink_to_fit();
Arc::new(item_tree) source_maps.shrink_to_fit();
(Arc::new(item_tree), Arc::new(source_maps))
} }
} }
@ -308,6 +330,82 @@ struct ItemTreeData {
vis: ItemVisibilities, vis: ItemVisibilities,
} }
#[derive(Default, Debug, Eq, PartialEq)]
pub struct GenericItemSourceMap {
pub item: TypesSourceMap,
pub generics: TypesSourceMap,
}
#[derive(Default, Debug, Eq, PartialEq)]
pub struct ItemTreeSourceMaps {
functions: Vec<GenericItemSourceMap>,
structs: Vec<GenericItemSourceMap>,
unions: Vec<GenericItemSourceMap>,
enum_generics: Vec<TypesSourceMap>,
variants: Vec<TypesSourceMap>,
consts: Vec<TypesSourceMap>,
statics: Vec<TypesSourceMap>,
trait_generics: Vec<TypesSourceMap>,
trait_alias_generics: Vec<TypesSourceMap>,
impls: Vec<GenericItemSourceMap>,
type_aliases: Vec<GenericItemSourceMap>,
}
impl ItemTreeSourceMaps {
fn shrink_to_fit(&mut self) {
let ItemTreeSourceMaps {
functions,
structs,
unions,
enum_generics,
variants,
consts,
statics,
trait_generics,
trait_alias_generics,
impls,
type_aliases,
} = self;
functions.shrink_to_fit();
structs.shrink_to_fit();
unions.shrink_to_fit();
enum_generics.shrink_to_fit();
variants.shrink_to_fit();
consts.shrink_to_fit();
statics.shrink_to_fit();
trait_generics.shrink_to_fit();
trait_alias_generics.shrink_to_fit();
impls.shrink_to_fit();
type_aliases.shrink_to_fit();
}
}
macro_rules! index_source_maps {
( $( $field:ident[$tree_id:ident] = $result:ident, )* ) => {
$(
impl Index<FileItemTreeId<$tree_id>> for ItemTreeSourceMaps {
type Output = $result;
fn index(&self, index: FileItemTreeId<$tree_id>) -> &Self::Output {
&self.$field[index.0.into_raw().into_u32() as usize]
}
}
)*
};
}
index_source_maps! {
functions[Function] = GenericItemSourceMap,
structs[Struct] = GenericItemSourceMap,
unions[Union] = GenericItemSourceMap,
enum_generics[Enum] = TypesSourceMap,
variants[Variant] = TypesSourceMap,
consts[Const] = TypesSourceMap,
statics[Static] = TypesSourceMap,
trait_generics[Trait] = TypesSourceMap,
trait_alias_generics[TraitAlias] = TypesSourceMap,
impls[Impl] = GenericItemSourceMap,
type_aliases[TypeAlias] = GenericItemSourceMap,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum AttrOwner { pub enum AttrOwner {
/// Attributes on an item. /// Attributes on an item.
@ -363,7 +461,7 @@ pub trait ItemTreeNode: Clone {
fn attr_owner(id: FileItemTreeId<Self>) -> AttrOwner; fn attr_owner(id: FileItemTreeId<Self>) -> AttrOwner;
} }
pub trait GenericsItemTreeNode: ItemTreeNode { pub trait GenericsItemTreeNode: ItemTreeNode {
fn generic_params(&self) -> &Interned<GenericParams>; fn generic_params(&self) -> &Arc<GenericParams>;
} }
pub struct FileItemTreeId<N>(Idx<N>); pub struct FileItemTreeId<N>(Idx<N>);
@ -428,6 +526,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 { pub fn file_id(self) -> HirFileId {
self.file self.file
} }
@ -460,6 +568,13 @@ impl<N> ItemTreeId<N> {
self.tree.item_tree(db) 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 pub fn resolved<R>(self, db: &dyn DefDatabase, cb: impl FnOnce(&N) -> R) -> R
where where
ItemTree: Index<FileItemTreeId<N>, Output = N>, ItemTree: Index<FileItemTreeId<N>, Output = N>,
@ -592,7 +707,7 @@ macro_rules! mod_items {
$( $(
impl GenericsItemTreeNode for $typ { impl GenericsItemTreeNode for $typ {
fn generic_params(&self) -> &Interned<GenericParams> { fn generic_params(&self) -> &Arc<GenericParams> {
&self.$generic_params &self.$generic_params
} }
} }
@ -730,17 +845,18 @@ pub struct ExternBlock {
pub struct Function { pub struct Function {
pub name: Name, pub name: Name,
pub visibility: RawVisibilityId, pub visibility: RawVisibilityId,
pub explicit_generic_params: Interned<GenericParams>, pub explicit_generic_params: Arc<GenericParams>,
pub abi: Option<Symbol>, pub abi: Option<Symbol>,
pub params: Box<[Param]>, pub params: Box<[Param]>,
pub ret_type: Interned<TypeRef>, pub ret_type: TypeRefId,
pub ast_id: FileAstId<ast::Fn>, pub ast_id: FileAstId<ast::Fn>,
pub types_map: Arc<TypesMap>,
pub(crate) flags: FnFlags, pub(crate) flags: FnFlags,
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct Param { pub struct Param {
pub type_ref: Option<Interned<TypeRef>>, pub type_ref: Option<TypeRefId>,
} }
bitflags::bitflags! { bitflags::bitflags! {
@ -761,26 +877,28 @@ bitflags::bitflags! {
pub struct Struct { pub struct Struct {
pub name: Name, pub name: Name,
pub visibility: RawVisibilityId, pub visibility: RawVisibilityId,
pub generic_params: Interned<GenericParams>, pub generic_params: Arc<GenericParams>,
pub fields: Box<[Field]>, pub fields: Box<[Field]>,
pub shape: FieldsShape, pub shape: FieldsShape,
pub ast_id: FileAstId<ast::Struct>, pub ast_id: FileAstId<ast::Struct>,
pub types_map: Arc<TypesMap>,
} }
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub struct Union { pub struct Union {
pub name: Name, pub name: Name,
pub visibility: RawVisibilityId, pub visibility: RawVisibilityId,
pub generic_params: Interned<GenericParams>, pub generic_params: Arc<GenericParams>,
pub fields: Box<[Field]>, pub fields: Box<[Field]>,
pub ast_id: FileAstId<ast::Union>, pub ast_id: FileAstId<ast::Union>,
pub types_map: Arc<TypesMap>,
} }
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub struct Enum { pub struct Enum {
pub name: Name, pub name: Name,
pub visibility: RawVisibilityId, pub visibility: RawVisibilityId,
pub generic_params: Interned<GenericParams>, pub generic_params: Arc<GenericParams>,
pub variants: Range<FileItemTreeId<Variant>>, pub variants: Range<FileItemTreeId<Variant>>,
pub ast_id: FileAstId<ast::Enum>, pub ast_id: FileAstId<ast::Enum>,
} }
@ -791,6 +909,7 @@ pub struct Variant {
pub fields: Box<[Field]>, pub fields: Box<[Field]>,
pub shape: FieldsShape, pub shape: FieldsShape,
pub ast_id: FileAstId<ast::Variant>, pub ast_id: FileAstId<ast::Variant>,
pub types_map: Arc<TypesMap>,
} }
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
@ -804,7 +923,7 @@ pub enum FieldsShape {
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct Field { pub struct Field {
pub name: Name, pub name: Name,
pub type_ref: Interned<TypeRef>, pub type_ref: TypeRefId,
pub visibility: RawVisibilityId, pub visibility: RawVisibilityId,
} }
@ -813,9 +932,10 @@ pub struct Const {
/// `None` for `const _: () = ();` /// `None` for `const _: () = ();`
pub name: Option<Name>, pub name: Option<Name>,
pub visibility: RawVisibilityId, pub visibility: RawVisibilityId,
pub type_ref: Interned<TypeRef>, pub type_ref: TypeRefId,
pub ast_id: FileAstId<ast::Const>, pub ast_id: FileAstId<ast::Const>,
pub has_body: bool, pub has_body: bool,
pub types_map: Arc<TypesMap>,
} }
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
@ -826,15 +946,16 @@ pub struct Static {
pub mutable: bool, pub mutable: bool,
pub has_safe_kw: bool, pub has_safe_kw: bool,
pub has_unsafe_kw: bool, pub has_unsafe_kw: bool,
pub type_ref: Interned<TypeRef>, pub type_ref: TypeRefId,
pub ast_id: FileAstId<ast::Static>, pub ast_id: FileAstId<ast::Static>,
pub types_map: Arc<TypesMap>,
} }
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub struct Trait { pub struct Trait {
pub name: Name, pub name: Name,
pub visibility: RawVisibilityId, pub visibility: RawVisibilityId,
pub generic_params: Interned<GenericParams>, pub generic_params: Arc<GenericParams>,
pub is_auto: bool, pub is_auto: bool,
pub is_unsafe: bool, pub is_unsafe: bool,
pub items: Box<[AssocItem]>, pub items: Box<[AssocItem]>,
@ -845,19 +966,20 @@ pub struct Trait {
pub struct TraitAlias { pub struct TraitAlias {
pub name: Name, pub name: Name,
pub visibility: RawVisibilityId, pub visibility: RawVisibilityId,
pub generic_params: Interned<GenericParams>, pub generic_params: Arc<GenericParams>,
pub ast_id: FileAstId<ast::TraitAlias>, pub ast_id: FileAstId<ast::TraitAlias>,
} }
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub struct Impl { pub struct Impl {
pub generic_params: Interned<GenericParams>, pub generic_params: Arc<GenericParams>,
pub target_trait: Option<Interned<TraitRef>>, pub target_trait: Option<TraitRef>,
pub self_ty: Interned<TypeRef>, pub self_ty: TypeRefId,
pub is_negative: bool, pub is_negative: bool,
pub is_unsafe: bool, pub is_unsafe: bool,
pub items: Box<[AssocItem]>, pub items: Box<[AssocItem]>,
pub ast_id: FileAstId<ast::Impl>, pub ast_id: FileAstId<ast::Impl>,
pub types_map: Arc<TypesMap>,
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
@ -865,10 +987,11 @@ pub struct TypeAlias {
pub name: Name, pub name: Name,
pub visibility: RawVisibilityId, pub visibility: RawVisibilityId,
/// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`.
pub bounds: Box<[Interned<TypeBound>]>, pub bounds: Box<[TypeBound]>,
pub generic_params: Interned<GenericParams>, pub generic_params: Arc<GenericParams>,
pub type_ref: Option<Interned<TypeRef>>, pub type_ref: Option<TypeRefId>,
pub ast_id: FileAstId<ast::TypeAlias>, pub ast_id: FileAstId<ast::TypeAlias>,
pub types_map: Arc<TypesMap>,
} }
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]

View file

@ -1,8 +1,13 @@
//! AST -> `ItemTree` lowering code. //! 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 intern::{sym, Symbol};
use la_arena::Arena; use la_arena::Arena;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
@ -18,14 +23,18 @@ use crate::{
generics::{GenericParams, GenericParamsCollector, TypeParamData, TypeParamProvenance}, generics::{GenericParams, GenericParamsCollector, TypeParamData, TypeParamProvenance},
item_tree::{ item_tree::{
AssocItem, AttrOwner, Const, Either, Enum, ExternBlock, ExternCrate, Field, FieldParent, AssocItem, AttrOwner, Const, Either, Enum, ExternBlock, ExternCrate, Field, FieldParent,
FieldsShape, FileItemTreeId, FnFlags, Function, GenericArgs, GenericModItem, Idx, Impl, FieldsShape, FileItemTreeId, FnFlags, Function, GenericArgs, GenericItemSourceMap,
ImportAlias, Interned, ItemTree, ItemTreeData, Macro2, MacroCall, MacroRules, Mod, ModItem, GenericModItem, Idx, Impl, ImportAlias, Interned, ItemTree, ItemTreeData,
ModKind, ModPath, Mutability, Name, Param, Path, Range, RawAttrs, RawIdx, RawVisibilityId, ItemTreeSourceMaps, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, ModPath,
Static, Struct, StructKind, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind, Mutability, Name, Param, Path, Range, RawAttrs, RawIdx, RawVisibilityId, Static, Struct,
Variant, StructKind, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind, Variant,
}, },
lower::LowerCtx,
path::AssociatedTypeBinding, path::AssociatedTypeBinding,
type_ref::{LifetimeRef, TraitBoundModifier, TraitRef, TypeBound, TypeRef}, type_ref::{
LifetimeRef, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId, TypesMap,
TypesSourceMap,
},
visibility::RawVisibility, visibility::RawVisibility,
LocalLifetimeParamId, LocalTypeOrConstParamId, LocalLifetimeParamId, LocalTypeOrConstParamId,
}; };
@ -40,7 +49,9 @@ pub(super) struct Ctx<'a> {
source_ast_id_map: Arc<AstIdMap>, source_ast_id_map: Arc<AstIdMap>,
generic_param_attr_buffer: generic_param_attr_buffer:
FxHashMap<Either<LocalTypeOrConstParamId, LocalLifetimeParamId>, RawAttrs>, FxHashMap<Either<LocalTypeOrConstParamId, LocalLifetimeParamId>, RawAttrs>,
body_ctx: crate::lower::LowerCtx<'a>, span_map: OnceCell<SpanMap>,
file: HirFileId,
source_maps: ItemTreeSourceMaps,
} }
impl<'a> Ctx<'a> { impl<'a> Ctx<'a> {
@ -50,22 +61,49 @@ impl<'a> Ctx<'a> {
tree: ItemTree::default(), tree: ItemTree::default(),
generic_param_attr_buffer: FxHashMap::default(), generic_param_attr_buffer: FxHashMap::default(),
source_ast_id_map: db.ast_id_map(file), source_ast_id_map: db.ast_id_map(file),
body_ctx: crate::lower::LowerCtx::new(db, file), file,
span_map: OnceCell::new(),
source_maps: ItemTreeSourceMaps::default(),
} }
} }
pub(super) fn span_map(&self) -> SpanMapRef<'_> { 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 = self.tree.top_level =
item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect(); item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect();
assert!(self.generic_param_attr_buffer.is_empty()); assert!(self.generic_param_attr_buffer.is_empty());
self.tree (self.tree, self.source_maps)
} }
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 self.tree.top_level = stmts
.statements() .statements()
.filter_map(|stmt| { .filter_map(|stmt| {
@ -96,10 +134,10 @@ impl<'a> Ctx<'a> {
} }
assert!(self.generic_param_attr_buffer.is_empty()); assert!(self.generic_param_attr_buffer.is_empty());
self.tree (self.tree, self.source_maps)
} }
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 self.tree
.attrs .attrs
.insert(AttrOwner::TopLevel, RawAttrs::new(self.db.upcast(), block, self.span_map())); .insert(AttrOwner::TopLevel, RawAttrs::new(self.db.upcast(), block, self.span_map()));
@ -125,7 +163,7 @@ impl<'a> Ctx<'a> {
} }
assert!(self.generic_param_attr_buffer.is_empty()); assert!(self.generic_param_attr_buffer.is_empty());
self.tree (self.tree, self.source_maps)
} }
fn data(&mut self) -> &mut ItemTreeData { fn data(&mut self) -> &mut ItemTreeData {
@ -144,7 +182,7 @@ impl<'a> Ctx<'a> {
ast::Item::Module(ast) => self.lower_module(ast)?.into(), ast::Item::Module(ast) => self.lower_module(ast)?.into(),
ast::Item::Trait(ast) => self.lower_trait(ast)?.into(), ast::Item::Trait(ast) => self.lower_trait(ast)?.into(),
ast::Item::TraitAlias(ast) => self.lower_trait_alias(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::Use(ast) => self.lower_use(ast)?.into(),
ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast)?.into(), ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast)?.into(),
ast::Item::MacroCall(ast) => self.lower_macro_call(ast)?.into(), ast::Item::MacroCall(ast) => self.lower_macro_call(ast)?.into(),
@ -190,13 +228,30 @@ impl<'a> Ctx<'a> {
} }
fn lower_struct(&mut self, strukt: &ast::Struct) -> Option<FileItemTreeId<Struct>> { 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 visibility = self.lower_visibility(strukt);
let name = strukt.name()?.as_name(); let name = strukt.name()?.as_name();
let ast_id = self.source_ast_id_map.ast_id(strukt); let ast_id = self.source_ast_id_map.ast_id(strukt);
let (fields, kind, attrs) = self.lower_fields(&strukt.kind()); let (fields, kind, attrs) = self.lower_fields(&strukt.kind(), &body_ctx);
let generic_params = self.lower_generic_params(HasImplicitSelf::No, strukt); let (generic_params, generics_source_map) =
let res = Struct { name, visibility, generic_params, fields, shape: kind, ast_id }; 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)); let id = id(self.data().structs.alloc(res));
self.source_maps
.structs
.push(GenericItemSourceMap { item: types_source_map, generics: generics_source_map });
for (idx, attr) in attrs { for (idx, attr) in attrs {
self.add_attrs( self.add_attrs(
AttrOwner::Field( AttrOwner::Field(
@ -213,6 +268,7 @@ impl<'a> Ctx<'a> {
fn lower_fields( fn lower_fields(
&mut self, &mut self,
strukt_kind: &ast::StructKind, strukt_kind: &ast::StructKind,
body_ctx: &LowerCtx<'_>,
) -> (Box<[Field]>, FieldsShape, Vec<(usize, RawAttrs)>) { ) -> (Box<[Field]>, FieldsShape, Vec<(usize, RawAttrs)>) {
match strukt_kind { match strukt_kind {
ast::StructKind::Record(it) => { ast::StructKind::Record(it) => {
@ -220,7 +276,7 @@ impl<'a> Ctx<'a> {
let mut attrs = vec![]; let mut attrs = vec![];
for (i, field) in it.fields().enumerate() { 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); fields.push(data);
let attr = RawAttrs::new(self.db.upcast(), &field, self.span_map()); let attr = RawAttrs::new(self.db.upcast(), &field, self.span_map());
if !attr.is_empty() { if !attr.is_empty() {
@ -234,7 +290,7 @@ impl<'a> Ctx<'a> {
let mut attrs = vec![]; let mut attrs = vec![];
for (i, field) in it.fields().enumerate() { 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); fields.push(data);
let attr = RawAttrs::new(self.db.upcast(), &field, self.span_map()); let attr = RawAttrs::new(self.db.upcast(), &field, self.span_map());
if !attr.is_empty() { if !attr.is_empty() {
@ -247,35 +303,58 @@ 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() { let name = match field.name() {
Some(name) => name.as_name(), Some(name) => name.as_name(),
None => Name::missing(), None => Name::missing(),
}; };
let visibility = self.lower_visibility(field); 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 } 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 name = Name::new_tuple_field(idx);
let visibility = self.lower_visibility(field); 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 } Field { name, type_ref, visibility }
} }
fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> { 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 visibility = self.lower_visibility(union);
let name = union.name()?.as_name(); let name = union.name()?.as_name();
let ast_id = self.source_ast_id_map.ast_id(union); let ast_id = self.source_ast_id_map.ast_id(union);
let (fields, _, attrs) = match union.record_field_list() { 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()), None => (Box::default(), FieldsShape::Record, Vec::default()),
}; };
let generic_params = self.lower_generic_params(HasImplicitSelf::No, union); let (generic_params, generics_source_map) =
let res = Union { name, visibility, generic_params, fields, ast_id }; 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)); let id = id(self.data().unions.alloc(res));
self.source_maps
.unions
.push(GenericItemSourceMap { item: types_source_map, generics: generics_source_map });
for (idx, attr) in attrs { for (idx, attr) in attrs {
self.add_attrs( self.add_attrs(
AttrOwner::Field( AttrOwner::Field(
@ -299,9 +378,11 @@ impl<'a> Ctx<'a> {
FileItemTreeId(self.next_variant_idx())..FileItemTreeId(self.next_variant_idx()) 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 res = Enum { name, visibility, generic_params, variants, ast_id };
let id = id(self.data().enums.alloc(res)); let id = id(self.data().enums.alloc(res));
self.source_maps.enum_generics.push(generics_source_map);
self.write_generic_params_attributes(id.into()); self.write_generic_params_attributes(id.into());
Some(id) Some(id)
} }
@ -320,14 +401,20 @@ impl<'a> Ctx<'a> {
} }
fn lower_variant(&mut self, variant: &ast::Variant) -> Idx<Variant> { 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() { let name = match variant.name() {
Some(name) => name.as_name(), Some(name) => name.as_name(),
None => Name::missing(), 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 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); let id = self.data().variants.alloc(res);
self.source_maps.variants.push(types_source_map);
for (idx, attr) in attrs { for (idx, attr) in attrs {
self.add_attrs( self.add_attrs(
AttrOwner::Field( AttrOwner::Field(
@ -341,6 +428,10 @@ impl<'a> Ctx<'a> {
} }
fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>> { 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 visibility = self.lower_visibility(func);
let name = func.name()?.as_name(); let name = func.name()?.as_name();
@ -360,27 +451,31 @@ impl<'a> Ctx<'a> {
RawAttrs::new(self.db.upcast(), &self_param, self.span_map()), RawAttrs::new(self.db.upcast(), &self_param, self.span_map()),
); );
let self_type = match self_param.ty() { 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 => { None => {
let self_type = let self_type = body_ctx.alloc_type_ref_desugared(TypeRef::Path(
TypeRef::Path(Name::new_symbol_root(sym::Self_.clone()).into()); Name::new_symbol_root(sym::Self_.clone()).into(),
));
match self_param.kind() { match self_param.kind() {
ast::SelfParamKind::Owned => self_type, ast::SelfParamKind::Owned => self_type,
ast::SelfParamKind::Ref => TypeRef::Reference( ast::SelfParamKind::Ref => {
Box::new(self_type), body_ctx.alloc_type_ref_desugared(TypeRef::Reference(
self_type,
self_param.lifetime().as_ref().map(LifetimeRef::new), self_param.lifetime().as_ref().map(LifetimeRef::new),
Mutability::Shared, Mutability::Shared,
), ))
ast::SelfParamKind::MutRef => TypeRef::Reference( }
Box::new(self_type), ast::SelfParamKind::MutRef => {
body_ctx.alloc_type_ref_desugared(TypeRef::Reference(
self_type,
self_param.lifetime().as_ref().map(LifetimeRef::new), self_param.lifetime().as_ref().map(LifetimeRef::new),
Mutability::Mut, Mutability::Mut,
), ))
}
} }
} }
}; };
let type_ref = Interned::new(self_type); params.push(Param { type_ref: Some(self_type) });
params.push(Param { type_ref: Some(type_ref) });
has_self_param = true; has_self_param = true;
} }
for param in param_list.params() { for param in param_list.params() {
@ -391,9 +486,8 @@ impl<'a> Ctx<'a> {
Param { type_ref: None } Param { type_ref: None }
} }
None => { None => {
let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty()); let type_ref = TypeRef::from_ast_opt(&body_ctx, param.ty());
let ty = Interned::new(type_ref); Param { type_ref: Some(type_ref) }
Param { type_ref: Some(ty) }
} }
}; };
params.push(param); params.push(param);
@ -402,17 +496,17 @@ impl<'a> Ctx<'a> {
let ret_type = match func.ret_type() { let ret_type = match func.ret_type() {
Some(rt) => match rt.ty() { Some(rt) => match rt.ty() {
Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref), Some(type_ref) => TypeRef::from_ast(&body_ctx, type_ref),
None if rt.thin_arrow_token().is_some() => TypeRef::Error, None if rt.thin_arrow_token().is_some() => body_ctx.alloc_error_type(),
None => TypeRef::unit(), 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 ret_type = if func.async_token().is_some() {
let future_impl = desugar_future_path(ret_type); let future_impl = desugar_future_path(ret_type);
let ty_bound = Interned::new(TypeBound::Path(future_impl, TraitBoundModifier::None)); let ty_bound = TypeBound::Path(future_impl, TraitBoundModifier::None);
TypeRef::ImplTrait(vec![ty_bound]) body_ctx.alloc_type_ref_desugared(TypeRef::ImplTrait(vec![ty_bound]))
} else { } else {
ret_type ret_type
}; };
@ -447,18 +541,26 @@ impl<'a> Ctx<'a> {
flags |= FnFlags::IS_VARARGS; 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 { let res = Function {
name, name,
visibility, visibility,
explicit_generic_params: self.lower_generic_params(HasImplicitSelf::No, func), explicit_generic_params: generic_params,
abi, abi,
params: params.into_boxed_slice(), params: params.into_boxed_slice(),
ret_type: Interned::new(ret_type), ret_type,
ast_id, ast_id,
types_map: Arc::new(types_map),
flags, flags,
}; };
let id = id(self.data().functions.alloc(res)); let id = id(self.data().functions.alloc(res));
self.source_maps
.functions
.push(GenericItemSourceMap { item: types_source_map, generics: generics_source_map });
for (idx, attr) in attrs { for (idx, attr) in attrs {
self.add_attrs(AttrOwner::Param(id, Idx::from_raw(RawIdx::from_u32(idx as u32))), attr); self.add_attrs(AttrOwner::Param(id, Idx::from_raw(RawIdx::from_u32(idx as u32))), attr);
} }
@ -470,37 +572,81 @@ impl<'a> Ctx<'a> {
&mut self, &mut self,
type_alias: &ast::TypeAlias, type_alias: &ast::TypeAlias,
) -> Option<FileItemTreeId<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 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 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 ast_id = self.source_ast_id_map.ast_id(type_alias);
let generic_params = self.lower_generic_params(HasImplicitSelf::No, type_alias); let (generic_params, generics_source_map) =
let res = TypeAlias { name, visibility, bounds, generic_params, type_ref, ast_id }; 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)); let id = id(self.data().type_aliases.alloc(res));
self.source_maps
.type_aliases
.push(GenericItemSourceMap { item: types_source_map, generics: generics_source_map });
self.write_generic_params_attributes(id.into()); self.write_generic_params_attributes(id.into());
Some(id) Some(id)
} }
fn lower_static(&mut self, static_: &ast::Static) -> Option<FileItemTreeId<Static>> { 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 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 visibility = self.lower_visibility(static_);
let mutable = static_.mut_token().is_some(); let mutable = static_.mut_token().is_some();
let has_safe_kw = static_.safe_token().is_some(); let has_safe_kw = static_.safe_token().is_some();
let has_unsafe_kw = static_.unsafe_token().is_some(); let has_unsafe_kw = static_.unsafe_token().is_some();
let ast_id = self.source_ast_id_map.ast_id(static_); let ast_id = self.source_ast_id_map.ast_id(static_);
let res = types_map.shrink_to_fit();
Static { name, visibility, mutable, type_ref, ast_id, has_safe_kw, has_unsafe_kw }; 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))) Some(id(self.data().statics.alloc(res)))
} }
fn lower_const(&mut self, konst: &ast::Const) -> FileItemTreeId<Const> { 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 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 visibility = self.lower_visibility(konst);
let ast_id = self.source_ast_id_map.ast_id(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)) id(self.data().consts.alloc(res))
} }
@ -539,10 +685,11 @@ impl<'a> Ctx<'a> {
.filter_map(|item_node| self.lower_assoc_item(&item_node)) .filter_map(|item_node| self.lower_assoc_item(&item_node))
.collect(); .collect();
let generic_params = let (generic_params, generics_source_map) =
self.lower_generic_params(HasImplicitSelf::Yes(trait_def.type_bound_list()), trait_def); self.lower_generic_params(HasImplicitSelf::Yes(trait_def.type_bound_list()), trait_def);
let def = Trait { name, visibility, generic_params, is_auto, is_unsafe, items, ast_id }; let def = Trait { name, visibility, generic_params, is_auto, is_unsafe, items, ast_id };
let id = id(self.data().traits.alloc(def)); let id = id(self.data().traits.alloc(def));
self.source_maps.trait_generics.push(generics_source_map);
self.write_generic_params_attributes(id.into()); self.write_generic_params_attributes(id.into());
Some(id) Some(id)
} }
@ -554,24 +701,29 @@ impl<'a> Ctx<'a> {
let name = trait_alias_def.name()?.as_name(); let name = trait_alias_def.name()?.as_name();
let visibility = self.lower_visibility(trait_alias_def); let visibility = self.lower_visibility(trait_alias_def);
let ast_id = self.source_ast_id_map.ast_id(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()), HasImplicitSelf::Yes(trait_alias_def.type_bound_list()),
trait_alias_def, trait_alias_def,
); );
let alias = TraitAlias { name, visibility, generic_params, ast_id }; let alias = TraitAlias { name, visibility, generic_params, ast_id };
let id = id(self.data().trait_aliases.alloc(alias)); 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()); self.write_generic_params_attributes(id.into());
Some(id) 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); 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 // 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 // as if it was an non-trait impl. Ideally we want to create a unique missing ref that only
// equals itself. // equals itself.
let self_ty = self.lower_type_ref(&impl_def.self_ty()?); let self_ty = TypeRef::from_ast_opt(&body_ctx, impl_def.self_ty());
let target_trait = impl_def.trait_().and_then(|tr| self.lower_trait_ref(&tr)); 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_negative = impl_def.excl_token().is_some();
let is_unsafe = impl_def.unsafe_token().is_some(); let is_unsafe = impl_def.unsafe_token().is_some();
@ -584,12 +736,26 @@ impl<'a> Ctx<'a> {
.collect(); .collect();
// Note that trait impls don't get implicit `Self` unlike traits, because here they are a // 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. // 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 (generic_params, generics_source_map) =
let res = self.lower_generic_params(HasImplicitSelf::No, impl_def);
Impl { generic_params, target_trait, self_ty, is_negative, is_unsafe, items, ast_id }; 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)); let id = id(self.data().impls.alloc(res));
self.source_maps
.impls
.push(GenericItemSourceMap { item: types_source_map, generics: generics_source_map });
self.write_generic_params_attributes(id.into()); self.write_generic_params_attributes(id.into());
Some(id) id
} }
fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Use>> { fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Use>> {
@ -692,14 +858,17 @@ impl<'a> Ctx<'a> {
&mut self, &mut self,
has_implicit_self: HasImplicitSelf, has_implicit_self: HasImplicitSelf,
node: &dyn ast::HasGenericParams, 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(),); debug_assert!(self.generic_param_attr_buffer.is_empty(),);
let add_param_attrs = |item: Either<LocalTypeOrConstParamId, LocalLifetimeParamId>, let add_param_attrs = |item: Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
param| { 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()); 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(); let mut generics = GenericParamsCollector::default();
if let HasImplicitSelf::Yes(bounds) = has_implicit_self { if let HasImplicitSelf::Yes(bounds) = has_implicit_self {
@ -715,23 +884,29 @@ impl<'a> Ctx<'a> {
// add super traits as bounds on Self // add super traits as bounds on Self
// i.e., `trait Foo: Bar` is equivalent to `trait Foo where Self: Bar` // i.e., `trait Foo: Bar` is equivalent to `trait Foo where Self: Bar`
generics.fill_bounds( generics.fill_bounds(
&self.body_ctx, &body_ctx,
bounds, 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);
(Arc::new(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() { match node.type_bound_list() {
Some(bound_list) => bound_list Some(bound_list) => {
.bounds() bound_list.bounds().map(|it| TypeBound::from_ast(body_ctx, it)).collect()
.map(|it| Interned::new(TypeBound::from_ast(&self.body_ctx, it))) }
.collect(),
None => Box::default(), None => Box::default(),
} }
} }
@ -743,23 +918,6 @@ impl<'a> Ctx<'a> {
self.data().vis.alloc(vis) 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> { fn next_variant_idx(&self) -> Idx<Variant> {
Idx::from_raw(RawIdx::from( Idx::from_raw(RawIdx::from(
self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32), self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32),
@ -767,7 +925,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 path = path![core::future::Future];
let mut generic_args: Vec<_> = let mut generic_args: Vec<_> =
std::iter::repeat(None).take(path.segments().len() - 1).collect(); std::iter::repeat(None).take(path.segments().len() - 1).collect();
@ -777,10 +935,7 @@ fn desugar_future_path(orig: TypeRef) -> Path {
type_ref: Some(orig), type_ref: Some(orig),
bounds: Box::default(), bounds: Box::default(),
}; };
generic_args.push(Some(Interned::new(GenericArgs { generic_args.push(Some(GenericArgs { bindings: Box::new([binding]), ..GenericArgs::empty() }));
bindings: Box::new([binding]),
..GenericArgs::empty()
})));
Path::from_known_path(path, generic_args) Path::from_known_path(path, generic_args)
} }

View file

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

View file

@ -1531,11 +1531,3 @@ fn macro_call_as_call_id_with_eager(
pub struct UnresolvedMacro { pub struct UnresolvedMacro {
pub path: hir_expand::mod_path::ModPath, 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,52 @@ use hir_expand::{
span_map::{SpanMap, SpanMapRef}, span_map::{SpanMap, SpanMapRef},
AstId, HirFileId, InFile, AstId, HirFileId, InFile,
}; };
use intern::Interned;
use span::{AstIdMap, AstIdNode}; use span::{AstIdMap, AstIdNode};
use syntax::ast; use syntax::ast;
use triomphe::Arc; 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 struct LowerCtx<'a> {
pub db: &'a dyn DefDatabase, pub db: &'a dyn DefDatabase,
file_id: HirFileId, file_id: HirFileId,
span_map: OnceCell<SpanMap>, span_map: OnceCell<SpanMap>,
ast_id_map: OnceCell<Arc<AstIdMap>>, ast_id_map: OnceCell<Arc<AstIdMap>>,
impl_trait_bounds: RefCell<Vec<Vec<Interned<TypeBound>>>>, impl_trait_bounds: RefCell<Vec<Vec<TypeBound>>>,
// Prevent nested impl traits like `impl Foo<impl Bar>`. // Prevent nested impl traits like `impl Foo<impl Bar>`.
outer_impl_trait: RefCell<bool>, outer_impl_trait: RefCell<bool>,
types_map: RefCell<(&'a mut TypesMap, &'a mut TypesSourceMap)>,
} }
pub(crate) struct OuterImplTraitGuard<'a> { pub(crate) struct OuterImplTraitGuard<'a, 'b> {
ctx: &'a LowerCtx<'a>, ctx: &'a LowerCtx<'b>,
old: bool, old: bool,
} }
impl<'a> OuterImplTraitGuard<'a> { impl<'a, 'b> OuterImplTraitGuard<'a, 'b> {
fn new(ctx: &'a LowerCtx<'a>, impl_trait: bool) -> Self { fn new(ctx: &'a LowerCtx<'b>, impl_trait: bool) -> Self {
let old = ctx.outer_impl_trait.replace(impl_trait); let old = ctx.outer_impl_trait.replace(impl_trait);
Self { ctx, old } Self { ctx, old }
} }
} }
impl Drop for OuterImplTraitGuard<'_> { impl Drop for OuterImplTraitGuard<'_, '_> {
fn drop(&mut self) { fn drop(&mut self) {
self.ctx.outer_impl_trait.replace(self.old); self.ctx.outer_impl_trait.replace(self.old);
} }
} }
impl<'a> LowerCtx<'a> { 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 { LowerCtx {
db, db,
file_id, file_id,
@ -49,6 +58,7 @@ impl<'a> LowerCtx<'a> {
ast_id_map: OnceCell::new(), ast_id_map: OnceCell::new(),
impl_trait_bounds: RefCell::new(Vec::new()), impl_trait_bounds: RefCell::new(Vec::new()),
outer_impl_trait: RefCell::default(), outer_impl_trait: RefCell::default(),
types_map: RefCell::new((types_map, types_source_map)),
} }
} }
@ -56,6 +66,8 @@ impl<'a> LowerCtx<'a> {
db: &'a dyn DefDatabase, db: &'a dyn DefDatabase,
file_id: HirFileId, file_id: HirFileId,
span_map: OnceCell<SpanMap>, span_map: OnceCell<SpanMap>,
types_map: &'a mut TypesMap,
types_source_map: &'a mut TypesSourceMap,
) -> Self { ) -> Self {
LowerCtx { LowerCtx {
db, db,
@ -64,6 +76,7 @@ impl<'a> LowerCtx<'a> {
ast_id_map: OnceCell::new(), ast_id_map: OnceCell::new(),
impl_trait_bounds: RefCell::new(Vec::new()), impl_trait_bounds: RefCell::new(Vec::new()),
outer_impl_trait: RefCell::default(), outer_impl_trait: RefCell::default(),
types_map: RefCell::new((types_map, types_source_map)),
} }
} }
@ -82,11 +95,11 @@ impl<'a> LowerCtx<'a> {
) )
} }
pub fn update_impl_traits_bounds(&self, bounds: Vec<Interned<TypeBound>>) { pub fn update_impl_traits_bounds(&self, bounds: Vec<TypeBound>) {
self.impl_trait_bounds.borrow_mut().push(bounds); 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<Vec<TypeBound>> {
self.impl_trait_bounds.take() self.impl_trait_bounds.take()
} }
@ -94,7 +107,32 @@ impl<'a> LowerCtx<'a> {
*self.outer_impl_trait.borrow() *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) 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(); let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
assert_eq!(module_data.scope.resolutions().count(), 4); 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); assert_eq!(n_recalculated_item_trees, 6);
let n_reparsed_macros = let n_reparsed_macros =
events.iter().filter(|it| it.contains("parse_macro_expansion(")).count(); events.iter().filter(|it| it.contains("parse_macro_expansion(")).count();
@ -308,7 +309,7 @@ pub type Ty = ();
let events = db.log_executed(|| { let events = db.log_executed(|| {
db.file_item_tree(pos.file_id.into()); 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); assert_eq!(n_calculated_item_trees, 1);
let n_parsed_files = events.iter().filter(|it| it.contains("parse(")).count(); let n_parsed_files = events.iter().filter(|it| it.contains("parse(")).count();
assert_eq!(n_parsed_files, 1); assert_eq!(n_parsed_files, 1);

View file

@ -9,7 +9,7 @@ use std::{
use crate::{ use crate::{
lang_item::LangItemTarget, lang_item::LangItemTarget,
lower::LowerCtx, lower::LowerCtx,
type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef}, type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRefId},
}; };
use hir_expand::name::Name; use hir_expand::name::Name;
use intern::Interned; use intern::Interned;
@ -51,10 +51,10 @@ pub enum Path {
Normal { Normal {
/// Type based path like `<T>::foo`. /// Type based path like `<T>::foo`.
/// Note that paths like `<Type as Trait>::foo` are desugared to `Trait::<Self=Type>::foo`. /// Note that paths like `<Type as Trait>::foo` are desugared to `Trait::<Self=Type>::foo`.
type_anchor: Option<Interned<TypeRef>>, type_anchor: Option<TypeRefId>,
mod_path: Interned<ModPath>, mod_path: Interned<ModPath>,
/// Invariant: the same len as `self.mod_path.segments` or `None` if all segments are `None`. /// Invariant: the same len as `self.mod_path.segments` or `None` if all segments are `None`.
generic_args: Option<Box<[Option<Interned<GenericArgs>>]>>, generic_args: Option<Box<[Option<GenericArgs>]>>,
}, },
/// A link to a lang item. It is used in desugaring of things like `it?`. We can show these /// 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. /// links via a normal path since they might be private and not accessible in the usage place.
@ -86,20 +86,20 @@ pub struct AssociatedTypeBinding {
pub name: Name, pub name: Name,
/// The generic arguments to the associated type. e.g. For `Trait<Assoc<'a, T> = &'a T>`, this /// The generic arguments to the associated type. e.g. For `Trait<Assoc<'a, T> = &'a T>`, this
/// would be `['a, T]`. /// 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 /// The type bound to this associated type (in `Item = T`, this would be the
/// `T`). This can be `None` if there are bounds instead. /// `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: /// Bounds for the associated type, like in `Iterator<Item:
/// SomeOtherTrait>`. (This is the unstable `associated_type_bounds` /// SomeOtherTrait>`. (This is the unstable `associated_type_bounds`
/// feature.) /// feature.)
pub bounds: Box<[Interned<TypeBound>]>, pub bounds: Box<[TypeBound]>,
} }
/// A single generic argument. /// A single generic argument.
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum GenericArg { pub enum GenericArg {
Type(TypeRef), Type(TypeRefId),
Lifetime(LifetimeRef), Lifetime(LifetimeRef),
Const(ConstRef), Const(ConstRef),
} }
@ -114,7 +114,7 @@ impl Path {
/// Converts a known mod path to `Path`. /// Converts a known mod path to `Path`.
pub fn from_known_path( pub fn from_known_path(
path: ModPath, path: ModPath,
generic_args: impl Into<Box<[Option<Interned<GenericArgs>>]>>, generic_args: impl Into<Box<[Option<GenericArgs>]>>,
) -> Path { ) -> Path {
let generic_args = generic_args.into(); let generic_args = generic_args.into();
assert_eq!(path.len(), generic_args.len()); assert_eq!(path.len(), generic_args.len());
@ -137,9 +137,9 @@ impl Path {
} }
} }
pub fn type_anchor(&self) -> Option<&TypeRef> { pub fn type_anchor(&self) -> Option<TypeRefId> {
match self { match self {
Path::Normal { type_anchor, .. } => type_anchor.as_deref(), Path::Normal { type_anchor, .. } => *type_anchor,
Path::LangItem(..) => None, Path::LangItem(..) => None,
} }
} }
@ -178,7 +178,7 @@ impl Path {
return None; return None;
} }
let res = Path::Normal { let res = Path::Normal {
type_anchor: type_anchor.clone(), type_anchor: *type_anchor,
mod_path: Interned::new(ModPath::from_segments( mod_path: Interned::new(ModPath::from_segments(
mod_path.kind, mod_path.kind,
mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(), mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(),
@ -204,7 +204,7 @@ pub struct PathSegment<'a> {
pub struct PathSegments<'a> { pub struct PathSegments<'a> {
segments: &'a [Name], segments: &'a [Name],
generic_args: Option<&'a [Option<Interned<GenericArgs>>]>, generic_args: Option<&'a [Option<GenericArgs>]>,
} }
impl<'a> PathSegments<'a> { impl<'a> PathSegments<'a> {
@ -224,7 +224,7 @@ impl<'a> PathSegments<'a> {
pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> { pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> {
let res = PathSegment { let res = PathSegment {
name: self.segments.get(idx)?, 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) Some(res)
} }
@ -244,7 +244,7 @@ impl<'a> PathSegments<'a> {
self.segments self.segments
.iter() .iter()
.zip(self.generic_args.into_iter().flatten().chain(iter::repeat(&None))) .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() })
} }
} }

View file

@ -51,8 +51,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
segment.param_list(), segment.param_list(),
segment.ret_type(), segment.ret_type(),
) )
}) });
.map(Interned::new);
if args.is_some() { if args.is_some() {
generic_args.resize(segments.len(), None); generic_args.resize(segments.len(), None);
generic_args.push(args); generic_args.push(args);
@ -70,7 +69,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
match trait_ref { match trait_ref {
// <T>::foo // <T>::foo
None => { None => {
type_anchor = Some(Interned::new(self_type)); type_anchor = Some(self_type);
kind = PathKind::Plain; kind = PathKind::Plain;
} }
// <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
@ -95,7 +94,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 // 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)?; 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 { Some(it) => GenericArgs {
args: iter::once(self_type) args: iter::once(self_type)
.chain(it.args.iter().cloned()) .chain(it.args.iter().cloned())
@ -110,7 +109,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
has_self_type: true, has_self_type: true,
..GenericArgs::empty() ..GenericArgs::empty()
}, },
})); });
} }
} }
} }
@ -194,11 +193,13 @@ pub(super) fn lower_generic_args(
match generic_arg { match generic_arg {
ast::GenericArg::TypeArg(type_arg) => { ast::GenericArg::TypeArg(type_arg) => {
let type_ref = TypeRef::from_ast_opt(lower_ctx, type_arg.ty()); 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 { if let TypeRef::ImplTrait(bounds) = tr {
lower_ctx.update_impl_traits_bounds(bounds.clone()); lower_ctx.update_impl_traits_bounds(bounds.clone());
} }
}); });
drop(types_map);
args.push(GenericArg::Type(type_ref)); args.push(GenericArg::Type(type_ref));
} }
ast::GenericArg::AssocTypeArg(assoc_type_arg) => { ast::GenericArg::AssocTypeArg(assoc_type_arg) => {
@ -212,20 +213,19 @@ pub(super) fn lower_generic_args(
let name = name_ref.as_name(); let name = name_ref.as_name();
let args = assoc_type_arg let args = assoc_type_arg
.generic_arg_list() .generic_arg_list()
.and_then(|args| lower_generic_args(lower_ctx, args)) .and_then(|args| lower_generic_args(lower_ctx, args));
.map(Interned::new);
let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it)); let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it));
let type_ref = type_ref.inspect(|tr| { let type_ref = type_ref.inspect(|&tr| {
tr.walk(&mut |tr| { let types_map = lower_ctx.types_map();
TypeRef::walk(tr, &types_map, &mut |tr| {
if let TypeRef::ImplTrait(bounds) = tr { if let TypeRef::ImplTrait(bounds) = tr {
lower_ctx.update_impl_traits_bounds(bounds.clone()); lower_ctx.update_impl_traits_bounds(bounds.clone());
} }
}); });
drop(types_map);
}); });
let bounds = if let Some(l) = assoc_type_arg.type_bound_list() { let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
l.bounds() l.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect()
.map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it)))
.collect()
} else { } else {
Box::default() Box::default()
}; };
@ -269,7 +269,8 @@ fn lower_generic_args_from_fn_path(
let type_ref = TypeRef::from_ast_opt(ctx, param.ty()); let type_ref = TypeRef::from_ast_opt(ctx, param.ty());
param_types.push(type_ref); 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(param_types)))]);
let bindings = if let Some(ret_type) = ret_type { let bindings = if let Some(ret_type) = ret_type {
let type_ref = TypeRef::from_ast_opt(ctx, ret_type.ty()); let type_ref = TypeRef::from_ast_opt(ctx, ret_type.ty());
Box::new([AssociatedTypeBinding { Box::new([AssociatedTypeBinding {
@ -280,7 +281,7 @@ fn lower_generic_args_from_fn_path(
}]) }])
} else { } else {
// -> () // -> ()
let type_ref = TypeRef::Tuple(Vec::new()); let type_ref = ctx.alloc_type_ref_desugared(TypeRef::Tuple(Vec::new()));
Box::new([AssociatedTypeBinding { Box::new([AssociatedTypeBinding {
name: Name::new_symbol_root(sym::Output.clone()), name: Name::new_symbol_root(sym::Output.clone()),
args: None, args: None,

View file

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

View file

@ -3,7 +3,7 @@ use std::{fmt, iter, mem};
use base_db::CrateId; use base_db::CrateId;
use hir_expand::{name::Name, MacroDefId}; use hir_expand::{name::Name, MacroDefId};
use intern::{sym, Interned}; use intern::sym;
use itertools::Itertools as _; use itertools::Itertools as _;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
@ -24,7 +24,7 @@ use crate::{
nameres::{DefMap, MacroSubNs}, nameres::{DefMap, MacroSubNs},
path::{ModPath, Path, PathKind}, path::{ModPath, Path, PathKind},
per_ns::PerNs, per_ns::PerNs,
type_ref::LifetimeRef, type_ref::{LifetimeRef, TypesMap},
visibility::{RawVisibility, Visibility}, visibility::{RawVisibility, Visibility},
AdtId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId, AdtId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId,
ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, GenericParamId, HasModule, ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, GenericParamId, HasModule,
@ -76,7 +76,7 @@ enum Scope {
/// All the items and imported names of a module /// All the items and imported names of a module
BlockScope(ModuleItemMap), BlockScope(ModuleItemMap),
/// Brings the generic parameters of an item into scope /// 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 /// Brings `Self` in `impl` block into scope
ImplDefScope(ImplId), ImplDefScope(ImplId),
/// Brings `Self` in enum, struct and union definitions into scope /// Brings `Self` in enum, struct and union definitions into scope
@ -620,13 +620,15 @@ impl Resolver {
pub fn where_predicates_in_scope( pub fn where_predicates_in_scope(
&self, &self,
) -> impl Iterator<Item = (&crate::generics::WherePredicate, &GenericDefId)> { ) -> impl Iterator<Item = (&crate::generics::WherePredicate, (&GenericDefId, &TypesMap))> {
self.scopes() self.scopes()
.filter_map(|scope| match scope { .filter_map(|scope| match scope {
Scope::GenericParams { params, def } => Some((params, def)), Scope::GenericParams { params, def } => Some((params, def)),
_ => None, _ => 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> { pub fn generic_def(&self) -> Option<GenericDefId> {
@ -636,13 +638,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 { self.scopes().find_map(|scope| match scope {
Scope::GenericParams { params, .. } => Some(params), Scope::GenericParams { params, .. } => Some(params),
_ => None, _ => 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> { pub fn body_owner(&self) -> Option<DefWithBodyId> {
self.scopes().find_map(|scope| match scope { self.scopes().find_map(|scope| match scope {
Scope::ExprScope(it) => Some(it.owner), Scope::ExprScope(it) => Some(it.owner),

View file

@ -615,7 +615,8 @@ pub(crate) fn associated_ty_data_query(
let type_alias_data = db.type_alias_data(type_alias); let type_alias_data = db.type_alias_data(type_alias);
let generic_params = generics(db.upcast(), type_alias.into()); let generic_params = generics(db.upcast(), type_alias.into());
let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast()); let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
let ctx = crate::TyLoweringContext::new(db, &resolver, type_alias.into()) let ctx =
crate::TyLoweringContext::new(db, &resolver, &type_alias_data.types_map, type_alias.into())
.with_type_param_mode(crate::lower::ParamLoweringMode::Variable); .with_type_param_mode(crate::lower::ParamLoweringMode::Variable);
let trait_subst = TyBuilder::subst_for_def(db, trait_, None) let trait_subst = TyBuilder::subst_for_def(db, trait_, None)

View file

@ -309,7 +309,7 @@ impl<'a> DeclValidator<'a> {
/// Check incorrect names for struct fields. /// Check incorrect names for struct fields.
fn validate_struct_fields(&mut self, struct_id: StructId) { fn validate_struct_fields(&mut self, struct_id: StructId) {
let data = self.db.struct_data(struct_id); let data = self.db.struct_data(struct_id);
let VariantData::Record(fields) = data.variant_data.as_ref() else { let VariantData::Record { fields, .. } = data.variant_data.as_ref() else {
return; return;
}; };
let edition = self.edition(struct_id); let edition = self.edition(struct_id);
@ -469,7 +469,7 @@ impl<'a> DeclValidator<'a> {
/// Check incorrect names for fields of enum variant. /// Check incorrect names for fields of enum variant.
fn validate_enum_variant_fields(&mut self, variant_id: EnumVariantId) { fn validate_enum_variant_fields(&mut self, variant_id: EnumVariantId) {
let variant_data = self.db.enum_variant_data(variant_id); let variant_data = self.db.enum_variant_data(variant_id);
let VariantData::Record(fields) = variant_data.variant_data.as_ref() else { let VariantData::Record { fields, .. } = variant_data.variant_data.as_ref() else {
return; return;
}; };
let edition = self.edition(variant_id); let edition = self.edition(variant_id);

View file

@ -341,7 +341,7 @@ impl HirDisplay for Pat {
}; };
let variant_data = variant.variant_data(f.db.upcast()); let variant_data = variant.variant_data(f.db.upcast());
if let VariantData::Record(rec_fields) = &*variant_data { if let VariantData::Record { fields: rec_fields, .. } = &*variant_data {
write!(f, " {{ ")?; write!(f, " {{ ")?;
let mut printed = 0; let mut printed = 0;

View file

@ -19,7 +19,9 @@ use hir_def::{
lang_item::{LangItem, LangItemTarget}, lang_item::{LangItem, LangItemTarget},
nameres::DefMap, nameres::DefMap,
path::{Path, PathKind}, path::{Path, PathKind},
type_ref::{TraitBoundModifier, TypeBound, TypeRef, UseArgRef}, type_ref::{
TraitBoundModifier, TypeBound, TypeRef, TypeRefId, TypesMap, TypesSourceMap, UseArgRef,
},
visibility::Visibility, visibility::Visibility,
GenericDefId, HasModule, ImportPathConfig, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, GenericDefId, HasModule, ImportPathConfig, ItemContainerId, LocalFieldId, Lookup, ModuleDefId,
ModuleId, TraitId, ModuleId, TraitId,
@ -806,7 +808,7 @@ fn render_variant_after_name(
memory_map: &MemoryMap, memory_map: &MemoryMap,
) -> Result<(), HirDisplayError> { ) -> Result<(), HirDisplayError> {
match data { match data {
VariantData::Record(fields) | VariantData::Tuple(fields) => { VariantData::Record { fields, .. } | VariantData::Tuple { fields, .. } => {
let render_field = |f: &mut HirFormatter<'_>, id: LocalFieldId| { let render_field = |f: &mut HirFormatter<'_>, id: LocalFieldId| {
let offset = layout.fields.offset(u32::from(id.into_raw()) as usize).bytes_usize(); let offset = layout.fields.offset(u32::from(id.into_raw()) as usize).bytes_usize();
let ty = field_types[id].clone().substitute(Interner, subst); let ty = field_types[id].clone().substitute(Interner, subst);
@ -817,7 +819,7 @@ fn render_variant_after_name(
render_const_scalar(f, &b[offset..offset + size], memory_map, &ty) render_const_scalar(f, &b[offset..offset + size], memory_map, &ty)
}; };
let mut it = fields.iter(); let mut it = fields.iter();
if matches!(data, VariantData::Record(_)) { if matches!(data, VariantData::Record { .. }) {
write!(f, " {{")?; write!(f, " {{")?;
if let Some((id, data)) = it.next() { if let Some((id, data)) = it.next() {
write!(f, " {}: ", data.name.display(f.db.upcast(), f.edition()))?; write!(f, " {}: ", data.name.display(f.db.upcast(), f.edition()))?;
@ -1897,27 +1899,70 @@ pub fn write_visibility(
} }
} }
impl HirDisplay for TypeRef { pub trait HirDisplayWithTypesMap {
fn hir_fmt(
&self,
f: &mut HirFormatter<'_>,
types_map: &TypesMap,
) -> Result<(), HirDisplayError>;
}
impl<T: ?Sized + HirDisplayWithTypesMap> HirDisplayWithTypesMap for &'_ T {
fn hir_fmt(
&self,
f: &mut HirFormatter<'_>,
types_map: &TypesMap,
) -> Result<(), HirDisplayError> {
T::hir_fmt(&**self, f, types_map)
}
}
pub fn hir_display_with_types_map<'a, T: HirDisplayWithTypesMap + 'a>(
value: T,
types_map: &'a TypesMap,
) -> impl HirDisplay + 'a {
TypesMapAdapter(value, types_map)
}
struct TypesMapAdapter<'a, T>(T, &'a TypesMap);
impl<'a, T> TypesMapAdapter<'a, T> {
fn wrap(types_map: &'a TypesMap) -> impl Fn(T) -> TypesMapAdapter<'a, T> {
move |value| TypesMapAdapter(value, types_map)
}
}
impl<T: HirDisplayWithTypesMap> HirDisplay for TypesMapAdapter<'_, T> {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
match self { T::hir_fmt(&self.0, f, self.1)
}
}
impl HirDisplayWithTypesMap for TypeRefId {
fn hir_fmt(
&self,
f: &mut HirFormatter<'_>,
types_map: &TypesMap,
) -> Result<(), HirDisplayError> {
match &types_map[*self] {
TypeRef::Never => write!(f, "!")?, TypeRef::Never => write!(f, "!")?,
TypeRef::Placeholder => write!(f, "_")?, TypeRef::Placeholder => write!(f, "_")?,
TypeRef::Tuple(elems) => { TypeRef::Tuple(elems) => {
write!(f, "(")?; write!(f, "(")?;
f.write_joined(elems, ", ")?; f.write_joined(elems.iter().map(TypesMapAdapter::wrap(types_map)), ", ")?;
if elems.len() == 1 { if elems.len() == 1 {
write!(f, ",")?; write!(f, ",")?;
} }
write!(f, ")")?; write!(f, ")")?;
} }
TypeRef::Path(path) => path.hir_fmt(f)?, TypeRef::Path(path) => path.hir_fmt(f, types_map)?,
TypeRef::RawPtr(inner, mutability) => { TypeRef::RawPtr(inner, mutability) => {
let mutability = match mutability { let mutability = match mutability {
hir_def::type_ref::Mutability::Shared => "*const ", hir_def::type_ref::Mutability::Shared => "*const ",
hir_def::type_ref::Mutability::Mut => "*mut ", hir_def::type_ref::Mutability::Mut => "*mut ",
}; };
write!(f, "{mutability}")?; write!(f, "{mutability}")?;
inner.hir_fmt(f)?; inner.hir_fmt(f, types_map)?;
} }
TypeRef::Reference(inner, lifetime, mutability) => { TypeRef::Reference(inner, lifetime, mutability) => {
let mutability = match mutability { let mutability = match mutability {
@ -1929,19 +1974,19 @@ impl HirDisplay for TypeRef {
write!(f, "{} ", lifetime.name.display(f.db.upcast(), f.edition()))?; write!(f, "{} ", lifetime.name.display(f.db.upcast(), f.edition()))?;
} }
write!(f, "{mutability}")?; write!(f, "{mutability}")?;
inner.hir_fmt(f)?; inner.hir_fmt(f, types_map)?;
} }
TypeRef::Array(inner, len) => { TypeRef::Array(inner, len) => {
write!(f, "[")?; write!(f, "[")?;
inner.hir_fmt(f)?; inner.hir_fmt(f, types_map)?;
write!(f, "; {}]", len.display(f.db.upcast(), f.edition()))?; write!(f, "; {}]", len.display(f.db.upcast(), f.edition()))?;
} }
TypeRef::Slice(inner) => { TypeRef::Slice(inner) => {
write!(f, "[")?; write!(f, "[")?;
inner.hir_fmt(f)?; inner.hir_fmt(f, types_map)?;
write!(f, "]")?; write!(f, "]")?;
} }
&TypeRef::Fn(ref parameters, is_varargs, is_unsafe, ref abi) => { &TypeRef::Fn { params: ref parameters, is_varargs, is_unsafe, ref abi } => {
if is_unsafe { if is_unsafe {
write!(f, "unsafe ")?; write!(f, "unsafe ")?;
} }
@ -1958,7 +2003,7 @@ impl HirDisplay for TypeRef {
write!(f, "{}: ", name.display(f.db.upcast(), f.edition()))?; write!(f, "{}: ", name.display(f.db.upcast(), f.edition()))?;
} }
param_type.hir_fmt(f)?; param_type.hir_fmt(f, types_map)?;
if index != function_parameters.len() - 1 { if index != function_parameters.len() - 1 {
write!(f, ", ")?; write!(f, ", ")?;
@ -1968,29 +2013,36 @@ impl HirDisplay for TypeRef {
write!(f, "{}...", if parameters.len() == 1 { "" } else { ", " })?; write!(f, "{}...", if parameters.len() == 1 { "" } else { ", " })?;
} }
write!(f, ")")?; write!(f, ")")?;
match &return_type { match &types_map[*return_type] {
TypeRef::Tuple(tup) if tup.is_empty() => {} TypeRef::Tuple(tup) if tup.is_empty() => {}
_ => { _ => {
write!(f, " -> ")?; write!(f, " -> ")?;
return_type.hir_fmt(f)?; return_type.hir_fmt(f, types_map)?;
} }
} }
} }
} }
TypeRef::ImplTrait(bounds) => { TypeRef::ImplTrait(bounds) => {
write!(f, "impl ")?; write!(f, "impl ")?;
f.write_joined(bounds, " + ")?; f.write_joined(bounds.iter().map(TypesMapAdapter::wrap(types_map)), " + ")?;
} }
TypeRef::DynTrait(bounds) => { TypeRef::DynTrait(bounds) => {
write!(f, "dyn ")?; write!(f, "dyn ")?;
f.write_joined(bounds, " + ")?; f.write_joined(bounds.iter().map(TypesMapAdapter::wrap(types_map)), " + ")?;
} }
TypeRef::Macro(macro_call) => { TypeRef::Macro(macro_call) => {
let ctx = hir_def::lower::LowerCtx::new(f.db.upcast(), macro_call.file_id); let (mut types_map, mut types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let ctx = hir_def::lower::LowerCtx::new(
f.db.upcast(),
macro_call.file_id,
&mut types_map,
&mut types_source_map,
);
let macro_call = macro_call.to_node(f.db.upcast()); let macro_call = macro_call.to_node(f.db.upcast());
match macro_call.path() { match macro_call.path() {
Some(path) => match Path::from_src(&ctx, path) { Some(path) => match Path::from_src(&ctx, path) {
Some(path) => path.hir_fmt(f)?, Some(path) => path.hir_fmt(f, &types_map)?,
None => write!(f, "{{macro}}")?, None => write!(f, "{{macro}}")?,
}, },
None => write!(f, "{{macro}}")?, None => write!(f, "{{macro}}")?,
@ -2003,15 +2055,19 @@ impl HirDisplay for TypeRef {
} }
} }
impl HirDisplay for TypeBound { impl HirDisplayWithTypesMap for TypeBound {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { fn hir_fmt(
&self,
f: &mut HirFormatter<'_>,
types_map: &TypesMap,
) -> Result<(), HirDisplayError> {
match self { match self {
TypeBound::Path(path, modifier) => { TypeBound::Path(path, modifier) => {
match modifier { match modifier {
TraitBoundModifier::None => (), TraitBoundModifier::None => (),
TraitBoundModifier::Maybe => write!(f, "?")?, TraitBoundModifier::Maybe => write!(f, "?")?,
} }
path.hir_fmt(f) path.hir_fmt(f, types_map)
} }
TypeBound::Lifetime(lifetime) => { TypeBound::Lifetime(lifetime) => {
write!(f, "{}", lifetime.name.display(f.db.upcast(), f.edition())) write!(f, "{}", lifetime.name.display(f.db.upcast(), f.edition()))
@ -2023,7 +2079,7 @@ impl HirDisplay for TypeBound {
"for<{}> ", "for<{}> ",
lifetimes.iter().map(|it| it.display(f.db.upcast(), edition)).format(", ") lifetimes.iter().map(|it| it.display(f.db.upcast(), edition)).format(", ")
)?; )?;
path.hir_fmt(f) path.hir_fmt(f, types_map)
} }
TypeBound::Use(args) => { TypeBound::Use(args) => {
let edition = f.edition(); let edition = f.edition();
@ -2043,12 +2099,16 @@ impl HirDisplay for TypeBound {
} }
} }
impl HirDisplay for Path { impl HirDisplayWithTypesMap for Path {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { fn hir_fmt(
&self,
f: &mut HirFormatter<'_>,
types_map: &TypesMap,
) -> Result<(), HirDisplayError> {
match (self.type_anchor(), self.kind()) { match (self.type_anchor(), self.kind()) {
(Some(anchor), _) => { (Some(anchor), _) => {
write!(f, "<")?; write!(f, "<")?;
anchor.hir_fmt(f)?; anchor.hir_fmt(f, types_map)?;
write!(f, ">")?; write!(f, ">")?;
} }
(_, PathKind::Plain) => {} (_, PathKind::Plain) => {}
@ -2091,7 +2151,7 @@ impl HirDisplay for Path {
}); });
if let Some(ty) = trait_self_ty { if let Some(ty) = trait_self_ty {
write!(f, "<")?; write!(f, "<")?;
ty.hir_fmt(f)?; ty.hir_fmt(f, types_map)?;
write!(f, " as ")?; write!(f, " as ")?;
// Now format the path of the trait... // Now format the path of the trait...
} }
@ -2107,21 +2167,26 @@ impl HirDisplay for Path {
if generic_args.desugared_from_fn { if generic_args.desugared_from_fn {
// First argument will be a tuple, which already includes the parentheses. // First argument will be a tuple, which already includes the parentheses.
// If the tuple only contains 1 item, write it manually to avoid the trailing `,`. // If the tuple only contains 1 item, write it manually to avoid the trailing `,`.
if let hir_def::path::GenericArg::Type(TypeRef::Tuple(v)) = let tuple = match generic_args.args[0] {
&generic_args.args[0] hir_def::path::GenericArg::Type(ty) => match &types_map[ty] {
{ TypeRef::Tuple(it) => Some(it),
_ => None,
},
_ => None,
};
if let Some(v) = tuple {
if v.len() == 1 { if v.len() == 1 {
write!(f, "(")?; write!(f, "(")?;
v[0].hir_fmt(f)?; v[0].hir_fmt(f, types_map)?;
write!(f, ")")?; write!(f, ")")?;
} else { } else {
generic_args.args[0].hir_fmt(f)?; generic_args.args[0].hir_fmt(f, types_map)?;
} }
} }
if let Some(ret) = &generic_args.bindings[0].type_ref { if let Some(ret) = generic_args.bindings[0].type_ref {
if !matches!(ret, TypeRef::Tuple(v) if v.is_empty()) { if !matches!(&types_map[ret], TypeRef::Tuple(v) if v.is_empty()) {
write!(f, " -> ")?; write!(f, " -> ")?;
ret.hir_fmt(f)?; ret.hir_fmt(f, types_map)?;
} }
} }
return Ok(()); return Ok(());
@ -2136,7 +2201,7 @@ impl HirDisplay for Path {
} else { } else {
write!(f, ", ")?; write!(f, ", ")?;
} }
arg.hir_fmt(f)?; arg.hir_fmt(f, types_map)?;
} }
for binding in generic_args.bindings.iter() { for binding in generic_args.bindings.iter() {
if first { if first {
@ -2149,11 +2214,14 @@ impl HirDisplay for Path {
match &binding.type_ref { match &binding.type_ref {
Some(ty) => { Some(ty) => {
write!(f, " = ")?; write!(f, " = ")?;
ty.hir_fmt(f)? ty.hir_fmt(f, types_map)?
} }
None => { None => {
write!(f, ": ")?; write!(f, ": ")?;
f.write_joined(binding.bounds.iter(), " + ")?; f.write_joined(
binding.bounds.iter().map(TypesMapAdapter::wrap(types_map)),
" + ",
)?;
} }
} }
} }
@ -2175,10 +2243,14 @@ impl HirDisplay for Path {
} }
} }
impl HirDisplay for hir_def::path::GenericArg { impl HirDisplayWithTypesMap for hir_def::path::GenericArg {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { fn hir_fmt(
&self,
f: &mut HirFormatter<'_>,
types_map: &TypesMap,
) -> Result<(), HirDisplayError> {
match self { match self {
hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f), hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f, types_map),
hir_def::path::GenericArg::Const(c) => { hir_def::path::GenericArg::Const(c) => {
write!(f, "{}", c.display(f.db.upcast(), f.edition())) write!(f, "{}", c.display(f.db.upcast(), f.edition()))
} }

View file

@ -16,12 +16,13 @@ use hir_def::{
GenericParamDataRef, GenericParams, LifetimeParamData, TypeOrConstParamData, GenericParamDataRef, GenericParams, LifetimeParamData, TypeOrConstParamData,
TypeParamProvenance, TypeParamProvenance,
}, },
type_ref::TypesMap,
ConstParamId, GenericDefId, GenericParamId, ItemContainerId, LifetimeParamId, ConstParamId, GenericDefId, GenericParamId, ItemContainerId, LifetimeParamId,
LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
}; };
use intern::Interned;
use itertools::chain; use itertools::chain;
use stdx::TupleExt; use stdx::TupleExt;
use triomphe::Arc;
use crate::{db::HirDatabase, lt_to_placeholder_idx, to_placeholder_idx, Interner, Substitution}; use crate::{db::HirDatabase, lt_to_placeholder_idx, to_placeholder_idx, Interner, Substitution};
@ -34,7 +35,7 @@ pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) struct Generics { pub(crate) struct Generics {
def: GenericDefId, def: GenericDefId,
params: Interned<GenericParams>, params: Arc<GenericParams>,
parent_generics: Option<Box<Generics>>, parent_generics: Option<Box<Generics>>,
has_trait_self_param: bool, has_trait_self_param: bool,
} }
@ -85,6 +86,18 @@ impl Generics {
self.iter_self().chain(self.iter_parent()) self.iter_self().chain(self.iter_parent())
} }
pub(crate) fn iter_with_types_map(
&self,
) -> impl Iterator<Item = ((GenericParamId, GenericParamDataRef<'_>), &TypesMap)> + '_ {
self.iter_self().zip(std::iter::repeat(&self.params.types_map)).chain(
self.iter_parent().zip(
self.parent_generics()
.into_iter()
.flat_map(|it| std::iter::repeat(&it.params.types_map)),
),
)
}
/// Iterate over the params without parent params. /// Iterate over the params without parent params.
pub(crate) fn iter_self( pub(crate) fn iter_self(
&self, &self,

View file

@ -41,7 +41,7 @@ use hir_def::{
layout::Integer, layout::Integer,
path::{ModPath, Path}, path::{ModPath, Path},
resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs}, resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
type_ref::{LifetimeRef, TypeRef}, type_ref::{LifetimeRef, TypeRefId, TypesMap},
AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, ImplId, ItemContainerId, Lookup, AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, ImplId, ItemContainerId, Lookup,
TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId, TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId,
}; };
@ -858,7 +858,7 @@ impl<'a> InferenceContext<'a> {
} }
fn collect_const(&mut self, data: &ConstData) { fn collect_const(&mut self, data: &ConstData) {
let return_ty = self.make_ty(&data.type_ref); let return_ty = self.make_ty(data.type_ref, &data.types_map);
// Constants might be defining usage sites of TAITs. // Constants might be defining usage sites of TAITs.
self.make_tait_coercion_table(iter::once(&return_ty)); self.make_tait_coercion_table(iter::once(&return_ty));
@ -867,7 +867,7 @@ impl<'a> InferenceContext<'a> {
} }
fn collect_static(&mut self, data: &StaticData) { fn collect_static(&mut self, data: &StaticData) {
let return_ty = self.make_ty(&data.type_ref); let return_ty = self.make_ty(data.type_ref, &data.types_map);
// Statics might be defining usage sites of TAITs. // Statics might be defining usage sites of TAITs.
self.make_tait_coercion_table(iter::once(&return_ty)); self.make_tait_coercion_table(iter::once(&return_ty));
@ -877,11 +877,11 @@ impl<'a> InferenceContext<'a> {
fn collect_fn(&mut self, func: FunctionId) { fn collect_fn(&mut self, func: FunctionId) {
let data = self.db.function_data(func); let data = self.db.function_data(func);
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()) let mut param_tys = self.with_ty_lowering(&data.types_map, |ctx| {
.with_type_param_mode(ParamLoweringMode::Placeholder) ctx.type_param_mode(ParamLoweringMode::Placeholder)
.with_impl_trait_mode(ImplTraitLoweringMode::Param); .impl_trait_mode(ImplTraitLoweringMode::Param);
let mut param_tys = data.params.iter().map(|&type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>()
data.params.iter().map(|type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>(); });
// Check if function contains a va_list, if it does then we append it to the parameter types // Check if function contains a va_list, if it does then we append it to the parameter types
// that are collected from the function data // that are collected from the function data
if data.is_varargs() { if data.is_varargs() {
@ -916,12 +916,13 @@ impl<'a> InferenceContext<'a> {
tait_candidates.insert(ty); tait_candidates.insert(ty);
} }
} }
let return_ty = &*data.ret_type; let return_ty = data.ret_type;
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()) let return_ty = self.with_ty_lowering(&data.types_map, |ctx| {
.with_type_param_mode(ParamLoweringMode::Placeholder) ctx.type_param_mode(ParamLoweringMode::Placeholder)
.with_impl_trait_mode(ImplTraitLoweringMode::Opaque); .impl_trait_mode(ImplTraitLoweringMode::Opaque)
let return_ty = ctx.lower_ty(return_ty); .lower_ty(return_ty)
});
let return_ty = self.insert_type_vars(return_ty); let return_ty = self.insert_type_vars(return_ty);
let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) { let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) {
@ -1225,20 +1226,43 @@ impl<'a> InferenceContext<'a> {
self.result.diagnostics.push(diagnostic); self.result.diagnostics.push(diagnostic);
} }
fn make_ty(&mut self, type_ref: &TypeRef) -> Ty { fn with_ty_lowering<R>(
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()); &self,
let ty = ctx.lower_ty(type_ref); types_map: &TypesMap,
f: impl FnOnce(&mut crate::lower::TyLoweringContext<'_>) -> R,
) -> R {
let mut ctx = crate::lower::TyLoweringContext::new(
self.db,
&self.resolver,
types_map,
self.owner.into(),
);
f(&mut ctx)
}
fn with_body_ty_lowering<R>(
&self,
f: impl FnOnce(&mut crate::lower::TyLoweringContext<'_>) -> R,
) -> R {
self.with_ty_lowering(&self.body.types, f)
}
fn make_ty(&mut self, type_ref: TypeRefId, types_map: &TypesMap) -> Ty {
let ty = self.with_ty_lowering(types_map, |ctx| ctx.lower_ty(type_ref));
let ty = self.insert_type_vars(ty); let ty = self.insert_type_vars(ty);
self.normalize_associated_types_in(ty) self.normalize_associated_types_in(ty)
} }
fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty {
self.make_ty(type_ref, &self.body.types)
}
fn err_ty(&self) -> Ty { fn err_ty(&self) -> Ty {
self.result.standard_types.unknown.clone() self.result.standard_types.unknown.clone()
} }
fn make_lifetime(&mut self, lifetime_ref: &LifetimeRef) -> Lifetime { fn make_lifetime(&mut self, lifetime_ref: &LifetimeRef) -> Lifetime {
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()); let lt = self.with_ty_lowering(TypesMap::EMPTY, |ctx| ctx.lower_lifetime(lifetime_ref));
let lt = ctx.lower_lifetime(lifetime_ref);
self.insert_type_vars(lt) self.insert_type_vars(lt)
} }
@ -1396,7 +1420,12 @@ impl<'a> InferenceContext<'a> {
Some(path) => path, Some(path) => path,
None => return (self.err_ty(), None), None => return (self.err_ty(), None),
}; };
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()); let ctx = crate::lower::TyLoweringContext::new(
self.db,
&self.resolver,
&self.body.types,
self.owner.into(),
);
let (resolution, unresolved) = if value_ns { let (resolution, unresolved) = if value_ns {
match self.resolver.resolve_path_in_value_ns(self.db.upcast(), path, HygieneId::ROOT) { match self.resolver.resolve_path_in_value_ns(self.db.upcast(), path, HygieneId::ROOT) {
Some(ResolveValueResult::ValueNs(value, _)) => match value { Some(ResolveValueResult::ValueNs(value, _)) => match value {

View file

@ -283,11 +283,11 @@ impl CapturedItem {
ProjectionElem::Deref => {} ProjectionElem::Deref => {}
ProjectionElem::Field(Either::Left(f)) => { ProjectionElem::Field(Either::Left(f)) => {
match &*f.parent.variant_data(db.upcast()) { match &*f.parent.variant_data(db.upcast()) {
VariantData::Record(fields) => { VariantData::Record { fields, .. } => {
result.push('_'); result.push('_');
result.push_str(fields[f.local_id].name.as_str()) result.push_str(fields[f.local_id].name.as_str())
} }
VariantData::Tuple(fields) => { VariantData::Tuple { fields, .. } => {
let index = fields.iter().position(|it| it.0 == f.local_id); let index = fields.iter().position(|it| it.0 == f.local_id);
if let Some(index) = index { if let Some(index) = index {
format_to!(result, "_{index}"); format_to!(result, "_{index}");
@ -325,12 +325,12 @@ impl CapturedItem {
ProjectionElem::Field(Either::Left(f)) => { ProjectionElem::Field(Either::Left(f)) => {
let variant_data = f.parent.variant_data(db.upcast()); let variant_data = f.parent.variant_data(db.upcast());
match &*variant_data { match &*variant_data {
VariantData::Record(fields) => format_to!( VariantData::Record { fields, .. } => format_to!(
result, result,
".{}", ".{}",
fields[f.local_id].name.display(db.upcast(), edition) fields[f.local_id].name.display(db.upcast(), edition)
), ),
VariantData::Tuple(fields) => format_to!( VariantData::Tuple { fields, .. } => format_to!(
result, result,
".{}", ".{}",
fields.iter().position(|it| it.0 == f.local_id).unwrap_or_default() fields.iter().position(|it| it.0 == f.local_id).unwrap_or_default()
@ -383,8 +383,10 @@ impl CapturedItem {
} }
let variant_data = f.parent.variant_data(db.upcast()); let variant_data = f.parent.variant_data(db.upcast());
let field = match &*variant_data { let field = match &*variant_data {
VariantData::Record(fields) => fields[f.local_id].name.as_str().to_owned(), VariantData::Record { fields, .. } => {
VariantData::Tuple(fields) => fields fields[f.local_id].name.as_str().to_owned()
}
VariantData::Tuple { fields, .. } => fields
.iter() .iter()
.position(|it| it.0 == f.local_id) .position(|it| it.0 == f.local_id)
.unwrap_or_default() .unwrap_or_default()

View file

@ -382,7 +382,7 @@ impl InferenceContext<'_> {
// collect explicitly written argument types // collect explicitly written argument types
for arg_type in arg_types.iter() { for arg_type in arg_types.iter() {
let arg_ty = match arg_type { let arg_ty = match arg_type {
Some(type_ref) => self.make_ty(type_ref), Some(type_ref) => self.make_body_ty(*type_ref),
None => self.table.new_type_var(), None => self.table.new_type_var(),
}; };
sig_tys.push(arg_ty); sig_tys.push(arg_ty);
@ -390,7 +390,7 @@ impl InferenceContext<'_> {
// add return type // add return type
let ret_ty = match ret_type { let ret_ty = match ret_type {
Some(type_ref) => self.make_ty(type_ref), Some(type_ref) => self.make_body_ty(*type_ref),
None => self.table.new_type_var(), None => self.table.new_type_var(),
}; };
if let ClosureKind::Async = closure_kind { if let ClosureKind::Async = closure_kind {
@ -786,7 +786,7 @@ impl InferenceContext<'_> {
self.resolve_associated_type(inner_ty, self.resolve_future_future_output()) self.resolve_associated_type(inner_ty, self.resolve_future_future_output())
} }
Expr::Cast { expr, type_ref } => { Expr::Cast { expr, type_ref } => {
let cast_ty = self.make_ty(type_ref); let cast_ty = self.make_body_ty(*type_ref);
let expr_ty = self.infer_expr( let expr_ty = self.infer_expr(
*expr, *expr,
&Expectation::Castable(cast_ty.clone()), &Expectation::Castable(cast_ty.clone()),
@ -1598,7 +1598,7 @@ impl InferenceContext<'_> {
Statement::Let { pat, type_ref, initializer, else_branch } => { Statement::Let { pat, type_ref, initializer, else_branch } => {
let decl_ty = type_ref let decl_ty = type_ref
.as_ref() .as_ref()
.map(|tr| this.make_ty(tr)) .map(|&tr| this.make_body_ty(tr))
.unwrap_or_else(|| this.table.new_type_var()); .unwrap_or_else(|| this.table.new_type_var());
let ty = if let Some(expr) = initializer { let ty = if let Some(expr) = initializer {
@ -2141,7 +2141,8 @@ impl InferenceContext<'_> {
kind_id, kind_id,
args.next().unwrap(), // `peek()` is `Some(_)`, so guaranteed no panic args.next().unwrap(), // `peek()` is `Some(_)`, so guaranteed no panic
self, self,
|this, type_ref| this.make_ty(type_ref), &self.body.types,
|this, type_ref| this.make_body_ty(type_ref),
|this, c, ty| { |this, c, ty| {
const_or_path_to_chalk( const_or_path_to_chalk(
this.db, this.db,

View file

@ -94,8 +94,7 @@ impl InferenceContext<'_> {
return Some(ValuePathResolution::NonGeneric(ty)); return Some(ValuePathResolution::NonGeneric(ty));
}; };
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()); let substs = self.with_body_ty_lowering(|ctx| ctx.substs_from_path(path, value_def, true));
let substs = ctx.substs_from_path(path, value_def, true);
let substs = substs.as_slice(Interner); let substs = substs.as_slice(Interner);
if let ValueNs::EnumVariantId(_) = value { if let ValueNs::EnumVariantId(_) = value {
@ -152,8 +151,12 @@ impl InferenceContext<'_> {
let last = path.segments().last()?; let last = path.segments().last()?;
// Don't use `self.make_ty()` here as we need `orig_ns`. // Don't use `self.make_ty()` here as we need `orig_ns`.
let ctx = let ctx = crate::lower::TyLoweringContext::new(
crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()); self.db,
&self.resolver,
&self.body.types,
self.owner.into(),
);
let (ty, orig_ns) = ctx.lower_ty_ext(type_ref); let (ty, orig_ns) = ctx.lower_ty_ext(type_ref);
let ty = self.table.insert_type_vars(ty); let ty = self.table.insert_type_vars(ty);
let ty = self.table.normalize_associated_types_in(ty); let ty = self.table.normalize_associated_types_in(ty);
@ -243,17 +246,10 @@ impl InferenceContext<'_> {
(TypeNs::TraitId(trait_), true) => { (TypeNs::TraitId(trait_), true) => {
let segment = let segment =
remaining_segments.last().expect("there should be at least one segment here"); remaining_segments.last().expect("there should be at least one segment here");
let ctx = crate::lower::TyLoweringContext::new( let self_ty = self.table.new_type_var();
self.db, let trait_ref = self.with_body_ty_lowering(|ctx| {
&self.resolver, ctx.lower_trait_ref_from_resolved_path(trait_, resolved_segment, self_ty)
self.owner.into(), });
);
let trait_ref = ctx.lower_trait_ref_from_resolved_path(
trait_,
resolved_segment,
self.table.new_type_var(),
);
self.resolve_trait_assoc_item(trait_ref, segment, id) self.resolve_trait_assoc_item(trait_ref, segment, id)
} }
(def, _) => { (def, _) => {
@ -263,17 +259,14 @@ impl InferenceContext<'_> {
// as Iterator>::Item::default`) // as Iterator>::Item::default`)
let remaining_segments_for_ty = let remaining_segments_for_ty =
remaining_segments.take(remaining_segments.len() - 1); remaining_segments.take(remaining_segments.len() - 1);
let ctx = crate::lower::TyLoweringContext::new( let (ty, _) = self.with_body_ty_lowering(|ctx| {
self.db, ctx.lower_partly_resolved_path(
&self.resolver,
self.owner.into(),
);
let (ty, _) = ctx.lower_partly_resolved_path(
def, def,
resolved_segment, resolved_segment,
remaining_segments_for_ty, remaining_segments_for_ty,
true, true,
); )
});
if ty.is_unknown() { if ty.is_unknown() {
return None; return None;
} }

View file

@ -34,6 +34,7 @@ use hir_def::{
resolver::{HasResolver, LifetimeNs, Resolver, TypeNs}, resolver::{HasResolver, LifetimeNs, Resolver, TypeNs},
type_ref::{ type_ref::{
ConstRef, LifetimeRef, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef, ConstRef, LifetimeRef, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef,
TypeRefId, TypesMap, TypesSourceMap,
}, },
AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId,
FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstLoc, ItemContainerId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstLoc, ItemContainerId,
@ -41,7 +42,6 @@ use hir_def::{
TypeOwnerId, UnionId, VariantId, TypeOwnerId, UnionId, VariantId,
}; };
use hir_expand::{name::Name, ExpandResult}; use hir_expand::{name::Name, ExpandResult};
use intern::Interned;
use la_arena::{Arena, ArenaMap}; use la_arena::{Arena, ArenaMap};
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use rustc_pattern_analysis::Captures; use rustc_pattern_analysis::Captures;
@ -122,6 +122,11 @@ pub struct TyLoweringContext<'a> {
pub db: &'a dyn HirDatabase, pub db: &'a dyn HirDatabase,
resolver: &'a Resolver, resolver: &'a Resolver,
generics: OnceCell<Option<Generics>>, generics: OnceCell<Option<Generics>>,
types_map: &'a TypesMap,
/// If this is set, that means we're in a context of a freshly expanded macro, and that means
/// we should not use `TypeRefId` in diagnostics because the caller won't have the `TypesMap`,
/// instead we need to put `TypeSource` from the source map.
types_source_map: Option<&'a TypesSourceMap>,
in_binders: DebruijnIndex, in_binders: DebruijnIndex,
// FIXME: Should not be an `Option` but `Resolver` currently does not return owners in all cases // FIXME: Should not be an `Option` but `Resolver` currently does not return owners in all cases
// where expected // where expected
@ -138,13 +143,20 @@ pub struct TyLoweringContext<'a> {
} }
impl<'a> TyLoweringContext<'a> { impl<'a> TyLoweringContext<'a> {
pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver, owner: TypeOwnerId) -> Self { pub fn new(
Self::new_maybe_unowned(db, resolver, Some(owner)) db: &'a dyn HirDatabase,
resolver: &'a Resolver,
types_map: &'a TypesMap,
owner: TypeOwnerId,
) -> Self {
Self::new_maybe_unowned(db, resolver, types_map, None, Some(owner))
} }
pub fn new_maybe_unowned( pub fn new_maybe_unowned(
db: &'a dyn HirDatabase, db: &'a dyn HirDatabase,
resolver: &'a Resolver, resolver: &'a Resolver,
types_map: &'a TypesMap,
types_source_map: Option<&'a TypesSourceMap>,
owner: Option<TypeOwnerId>, owner: Option<TypeOwnerId>,
) -> Self { ) -> Self {
let impl_trait_mode = ImplTraitLoweringState::Disallowed; let impl_trait_mode = ImplTraitLoweringState::Disallowed;
@ -154,6 +166,8 @@ impl<'a> TyLoweringContext<'a> {
db, db,
resolver, resolver,
generics: OnceCell::new(), generics: OnceCell::new(),
types_map,
types_source_map,
owner, owner,
in_binders, in_binders,
impl_trait_mode, impl_trait_mode,
@ -201,6 +215,16 @@ impl<'a> TyLoweringContext<'a> {
pub fn with_type_param_mode(self, type_param_mode: ParamLoweringMode) -> Self { pub fn with_type_param_mode(self, type_param_mode: ParamLoweringMode) -> Self {
Self { type_param_mode, ..self } Self { type_param_mode, ..self }
} }
pub fn impl_trait_mode(&mut self, impl_trait_mode: ImplTraitLoweringMode) -> &mut Self {
self.impl_trait_mode = ImplTraitLoweringState::new(impl_trait_mode);
self
}
pub fn type_param_mode(&mut self, type_param_mode: ParamLoweringMode) -> &mut Self {
self.type_param_mode = type_param_mode;
self
}
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@ -230,7 +254,7 @@ pub enum ParamLoweringMode {
} }
impl<'a> TyLoweringContext<'a> { impl<'a> TyLoweringContext<'a> {
pub fn lower_ty(&self, type_ref: &TypeRef) -> Ty { pub fn lower_ty(&self, type_ref: TypeRefId) -> Ty {
self.lower_ty_ext(type_ref).0 self.lower_ty_ext(type_ref).0
} }
@ -254,12 +278,13 @@ impl<'a> TyLoweringContext<'a> {
.as_ref() .as_ref()
} }
pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) { pub fn lower_ty_ext(&self, type_ref_id: TypeRefId) -> (Ty, Option<TypeNs>) {
let mut res = None; let mut res = None;
let type_ref = &self.types_map[type_ref_id];
let ty = match type_ref { let ty = match type_ref {
TypeRef::Never => TyKind::Never.intern(Interner), TypeRef::Never => TyKind::Never.intern(Interner),
TypeRef::Tuple(inner) => { TypeRef::Tuple(inner) => {
let inner_tys = inner.iter().map(|tr| self.lower_ty(tr)); let inner_tys = inner.iter().map(|&tr| self.lower_ty(tr));
TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys)) TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys))
.intern(Interner) .intern(Interner)
} }
@ -268,21 +293,21 @@ impl<'a> TyLoweringContext<'a> {
res = res_; res = res_;
ty ty
} }
TypeRef::RawPtr(inner, mutability) => { &TypeRef::RawPtr(inner, mutability) => {
let inner_ty = self.lower_ty(inner); let inner_ty = self.lower_ty(inner);
TyKind::Raw(lower_to_chalk_mutability(*mutability), inner_ty).intern(Interner) TyKind::Raw(lower_to_chalk_mutability(mutability), inner_ty).intern(Interner)
} }
TypeRef::Array(inner, len) => { TypeRef::Array(inner, len) => {
let inner_ty = self.lower_ty(inner); let inner_ty = self.lower_ty(*inner);
let const_len = self.lower_const(len, TyBuilder::usize()); let const_len = self.lower_const(len, TyBuilder::usize());
TyKind::Array(inner_ty, const_len).intern(Interner) TyKind::Array(inner_ty, const_len).intern(Interner)
} }
TypeRef::Slice(inner) => { &TypeRef::Slice(inner) => {
let inner_ty = self.lower_ty(inner); let inner_ty = self.lower_ty(inner);
TyKind::Slice(inner_ty).intern(Interner) TyKind::Slice(inner_ty).intern(Interner)
} }
TypeRef::Reference(inner, lifetime, mutability) => { TypeRef::Reference(inner, lifetime, mutability) => {
let inner_ty = self.lower_ty(inner); let inner_ty = self.lower_ty(*inner);
// FIXME: It should infer the eldided lifetimes instead of stubbing with static // FIXME: It should infer the eldided lifetimes instead of stubbing with static
let lifetime = let lifetime =
lifetime.as_ref().map_or_else(error_lifetime, |lr| self.lower_lifetime(lr)); lifetime.as_ref().map_or_else(error_lifetime, |lr| self.lower_lifetime(lr));
@ -290,9 +315,12 @@ impl<'a> TyLoweringContext<'a> {
.intern(Interner) .intern(Interner)
} }
TypeRef::Placeholder => TyKind::Error.intern(Interner), TypeRef::Placeholder => TyKind::Error.intern(Interner),
&TypeRef::Fn(ref params, variadic, is_unsafe, ref abi) => { &TypeRef::Fn { ref params, is_varargs: variadic, is_unsafe, ref abi } => {
let substs = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { let substs = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
Substitution::from_iter(Interner, params.iter().map(|(_, tr)| ctx.lower_ty(tr))) Substitution::from_iter(
Interner,
params.iter().map(|&(_, tr)| ctx.lower_ty(tr)),
)
}); });
TyKind::Function(FnPointer { TyKind::Function(FnPointer {
num_binders: 0, // FIXME lower `for<'a> fn()` correctly num_binders: 0, // FIXME lower `for<'a> fn()` correctly
@ -352,7 +380,7 @@ impl<'a> TyLoweringContext<'a> {
let idx = counter.get(); let idx = counter.get();
// Count the number of `impl Trait` things that appear within our bounds. // Count the number of `impl Trait` things that appear within our bounds.
// Since those have been emitted as implicit type args already. // Since those have been emitted as implicit type args already.
counter.set(idx + count_impl_traits(type_ref) as u16); counter.set(idx + self.count_impl_traits(type_ref_id) as u16);
let kind = self let kind = self
.generics() .generics()
.expect("param impl trait lowering must be in a generic def") .expect("param impl trait lowering must be in a generic def")
@ -376,7 +404,7 @@ impl<'a> TyLoweringContext<'a> {
let idx = counter.get(); let idx = counter.get();
// Count the number of `impl Trait` things that appear within our bounds. // Count the number of `impl Trait` things that appear within our bounds.
// Since t hose have been emitted as implicit type args already. // Since t hose have been emitted as implicit type args already.
counter.set(idx + count_impl_traits(type_ref) as u16); counter.set(idx + self.count_impl_traits(type_ref_id) as u16);
let kind = self let kind = self
.generics() .generics()
.expect("variable impl trait lowering must be in a generic def") .expect("variable impl trait lowering must be in a generic def")
@ -432,12 +460,40 @@ impl<'a> TyLoweringContext<'a> {
match expander.enter_expand::<ast::Type>(self.db.upcast(), macro_call, resolver) match expander.enter_expand::<ast::Type>(self.db.upcast(), macro_call, resolver)
{ {
Ok(ExpandResult { value: Some((mark, expanded)), .. }) => { Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
let ctx = expander.ctx(self.db.upcast()); let (mut types_map, mut types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let ctx = expander.ctx(
self.db.upcast(),
&mut types_map,
&mut types_source_map,
);
// FIXME: Report syntax errors in expansion here // FIXME: Report syntax errors in expansion here
let type_ref = TypeRef::from_ast(&ctx, expanded.tree()); let type_ref = TypeRef::from_ast(&ctx, expanded.tree());
drop(expander); drop(expander);
let ty = self.lower_ty(&type_ref);
// FIXME: That may be better served by mutating `self` then restoring, but this requires
// making it `&mut self`.
let inner_ctx = TyLoweringContext {
db: self.db,
resolver: self.resolver,
generics: self.generics.clone(),
types_map: &types_map,
types_source_map: Some(&types_source_map),
in_binders: self.in_binders,
owner: self.owner,
type_param_mode: self.type_param_mode,
impl_trait_mode: self.impl_trait_mode.take(),
expander: RefCell::new(self.expander.take()),
unsized_types: RefCell::new(self.unsized_types.take()),
};
let ty = inner_ctx.lower_ty(type_ref);
self.impl_trait_mode.swap(&inner_ctx.impl_trait_mode);
*self.expander.borrow_mut() = inner_ctx.expander.into_inner();
*self.unsized_types.borrow_mut() = inner_ctx.unsized_types.into_inner();
self.expander.borrow_mut().as_mut().unwrap().exit(mark); self.expander.borrow_mut().as_mut().unwrap().exit(mark);
Some(ty) Some(ty)
@ -463,7 +519,8 @@ impl<'a> TyLoweringContext<'a> {
/// This is only for `generic_predicates_for_param`, where we can't just /// This is only for `generic_predicates_for_param`, where we can't just
/// lower the self types of the predicates since that could lead to cycles. /// lower the self types of the predicates since that could lead to cycles.
/// So we just check here if the `type_ref` resolves to a generic param, and which. /// So we just check here if the `type_ref` resolves to a generic param, and which.
fn lower_ty_only_param(&self, type_ref: &TypeRef) -> Option<TypeOrConstParamId> { fn lower_ty_only_param(&self, type_ref: TypeRefId) -> Option<TypeOrConstParamId> {
let type_ref = &self.types_map[type_ref];
let path = match type_ref { let path = match type_ref {
TypeRef::Path(path) => path, TypeRef::Path(path) => path,
_ => return None, _ => return None,
@ -663,7 +720,7 @@ impl<'a> TyLoweringContext<'a> {
if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() { if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() {
// trait object type without dyn // trait object type without dyn
let bound = TypeBound::Path(path.clone(), TraitBoundModifier::None); let bound = TypeBound::Path(path.clone(), TraitBoundModifier::None);
let ty = self.lower_dyn_trait(&[Interned::new(bound)]); let ty = self.lower_dyn_trait(&[bound]);
return (ty, None); return (ty, None);
} }
@ -864,7 +921,7 @@ impl<'a> TyLoweringContext<'a> {
assert!(matches!(id, GenericParamId::TypeParamId(_))); assert!(matches!(id, GenericParamId::TypeParamId(_)));
had_explicit_args = true; had_explicit_args = true;
if let GenericArg::Type(ty) = &args[0] { if let GenericArg::Type(ty) = &args[0] {
substs.push(self.lower_ty(ty).cast(Interner)); substs.push(self.lower_ty(*ty).cast(Interner));
} }
} }
} else { } else {
@ -901,6 +958,7 @@ impl<'a> TyLoweringContext<'a> {
id, id,
arg, arg,
&mut (), &mut (),
self.types_map,
|_, type_ref| self.lower_ty(type_ref), |_, type_ref| self.lower_ty(type_ref),
|_, const_ref, ty| self.lower_const(const_ref, ty), |_, const_ref, ty| self.lower_const(const_ref, ty),
|_, lifetime_ref| self.lower_lifetime(lifetime_ref), |_, lifetime_ref| self.lower_lifetime(lifetime_ref),
@ -998,7 +1056,7 @@ impl<'a> TyLoweringContext<'a> {
WherePredicate::ForLifetime { target, bound, .. } WherePredicate::ForLifetime { target, bound, .. }
| WherePredicate::TypeBound { target, bound } => { | WherePredicate::TypeBound { target, bound } => {
let self_ty = match target { let self_ty = match target {
WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(type_ref), WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(*type_ref),
&WherePredicateTypeTarget::TypeOrConstParam(local_id) => { &WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
let param_id = hir_def::TypeOrConstParamId { parent: def, local_id }; let param_id = hir_def::TypeOrConstParamId { parent: def, local_id };
match self.type_param_mode { match self.type_param_mode {
@ -1029,12 +1087,12 @@ impl<'a> TyLoweringContext<'a> {
pub(crate) fn lower_type_bound( pub(crate) fn lower_type_bound(
&'a self, &'a self,
bound: &'a Interned<TypeBound>, bound: &'a TypeBound,
self_ty: Ty, self_ty: Ty,
ignore_bindings: bool, ignore_bindings: bool,
) -> impl Iterator<Item = QuantifiedWhereClause> + 'a { ) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
let mut trait_ref = None; let mut trait_ref = None;
let clause = match bound.as_ref() { let clause = match bound {
TypeBound::Path(path, TraitBoundModifier::None) => { TypeBound::Path(path, TraitBoundModifier::None) => {
trait_ref = self.lower_trait_ref_from_path(path, self_ty); trait_ref = self.lower_trait_ref_from_path(path, self_ty);
trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders) trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
@ -1079,10 +1137,10 @@ impl<'a> TyLoweringContext<'a> {
fn assoc_type_bindings_from_type_bound( fn assoc_type_bindings_from_type_bound(
&'a self, &'a self,
bound: &'a Interned<TypeBound>, bound: &'a TypeBound,
trait_ref: TraitRef, trait_ref: TraitRef,
) -> impl Iterator<Item = QuantifiedWhereClause> + 'a { ) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
let last_segment = match bound.as_ref() { let last_segment = match bound {
TypeBound::Path(path, TraitBoundModifier::None) | TypeBound::ForLifetime(_, path) => { TypeBound::Path(path, TraitBoundModifier::None) | TypeBound::ForLifetime(_, path) => {
path.segments().last() path.segments().last()
} }
@ -1111,7 +1169,7 @@ impl<'a> TyLoweringContext<'a> {
// this point (`super_trait_ref.substitution`). // this point (`super_trait_ref.substitution`).
let substitution = self.substs_from_path_segment( let substitution = self.substs_from_path_segment(
// FIXME: This is hack. We shouldn't really build `PathSegment` directly. // FIXME: This is hack. We shouldn't really build `PathSegment` directly.
PathSegment { name: &binding.name, args_and_bindings: binding.args.as_deref() }, PathSegment { name: &binding.name, args_and_bindings: binding.args.as_ref() },
Some(associated_ty.into()), Some(associated_ty.into()),
false, // this is not relevant false, // this is not relevant
Some(super_trait_ref.self_type_parameter(Interner)), Some(super_trait_ref.self_type_parameter(Interner)),
@ -1131,8 +1189,8 @@ impl<'a> TyLoweringContext<'a> {
let mut predicates: SmallVec<[_; 1]> = SmallVec::with_capacity( let mut predicates: SmallVec<[_; 1]> = SmallVec::with_capacity(
binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
); );
if let Some(type_ref) = &binding.type_ref { if let Some(type_ref) = binding.type_ref {
match (type_ref, &self.impl_trait_mode) { match (&self.types_map[type_ref], &self.impl_trait_mode) {
(TypeRef::ImplTrait(_), ImplTraitLoweringState::Disallowed) => (), (TypeRef::ImplTrait(_), ImplTraitLoweringState::Disallowed) => (),
( (
_, _,
@ -1179,6 +1237,8 @@ impl<'a> TyLoweringContext<'a> {
let mut ext = TyLoweringContext::new_maybe_unowned( let mut ext = TyLoweringContext::new_maybe_unowned(
self.db, self.db,
self.resolver, self.resolver,
self.types_map,
self.types_source_map,
self.owner, self.owner,
) )
.with_type_param_mode(self.type_param_mode); .with_type_param_mode(self.type_param_mode);
@ -1216,7 +1276,7 @@ impl<'a> TyLoweringContext<'a> {
}) })
} }
fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty { fn lower_dyn_trait(&self, bounds: &[TypeBound]) -> Ty {
let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner); let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
// INVARIANT: The principal trait bound, if present, must come first. Others may be in any // INVARIANT: The principal trait bound, if present, must come first. Others may be in any
// order but should be in the same order for the same set but possibly different order of // order but should be in the same order for the same set but possibly different order of
@ -1314,7 +1374,7 @@ impl<'a> TyLoweringContext<'a> {
} }
} }
fn lower_impl_trait(&self, bounds: &[Interned<TypeBound>], krate: CrateId) -> ImplTrait { fn lower_impl_trait(&self, bounds: &[TypeBound], krate: CrateId) -> ImplTrait {
cov_mark::hit!(lower_rpit); cov_mark::hit!(lower_rpit);
let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner); let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
@ -1366,6 +1426,17 @@ impl<'a> TyLoweringContext<'a> {
None => error_lifetime(), None => error_lifetime(),
} }
} }
// FIXME: This does not handle macros!
fn count_impl_traits(&self, type_ref: TypeRefId) -> usize {
let mut count = 0;
TypeRef::walk(type_ref, self.types_map, &mut |type_ref| {
if matches!(type_ref, TypeRef::ImplTrait(_)) {
count += 1;
}
});
count
}
} }
/// Build the signature of a callable item (function, struct or enum variant). /// Build the signature of a callable item (function, struct or enum variant).
@ -1386,17 +1457,6 @@ pub fn associated_type_shorthand_candidates<R>(
named_associated_type_shorthand_candidates(db, def, res, None, |name, _, id| cb(name, id)) named_associated_type_shorthand_candidates(db, def, res, None, |name, _, id| cb(name, id))
} }
// FIXME: This does not handle macros!
fn count_impl_traits(type_ref: &TypeRef) -> usize {
let mut count = 0;
type_ref.walk(&mut |type_ref| {
if matches!(type_ref, TypeRef::ImplTrait(_)) {
count += 1;
}
});
count
}
fn named_associated_type_shorthand_candidates<R>( fn named_associated_type_shorthand_candidates<R>(
db: &dyn HirDatabase, db: &dyn HirDatabase,
// If the type parameter is defined in an impl and we're in a method, there // If the type parameter is defined in an impl and we're in a method, there
@ -1500,10 +1560,10 @@ pub(crate) fn field_types_query(
}; };
let generics = generics(db.upcast(), def); let generics = generics(db.upcast(), def);
let mut res = ArenaMap::default(); let mut res = ArenaMap::default();
let ctx = TyLoweringContext::new(db, &resolver, def.into()) let ctx = TyLoweringContext::new(db, &resolver, var_data.types_map(), def.into())
.with_type_param_mode(ParamLoweringMode::Variable); .with_type_param_mode(ParamLoweringMode::Variable);
for (field_id, field_data) in var_data.fields().iter() { for (field_id, field_data) in var_data.fields().iter() {
res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref))); res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(field_data.type_ref)));
} }
Arc::new(res) Arc::new(res)
} }
@ -1523,38 +1583,38 @@ pub(crate) fn generic_predicates_for_param_query(
assoc_name: Option<Name>, assoc_name: Option<Name>,
) -> GenericPredicates { ) -> GenericPredicates {
let resolver = def.resolver(db.upcast()); let resolver = def.resolver(db.upcast());
let ctx = if let GenericDefId::FunctionId(_) = def { let mut ctx = if let GenericDefId::FunctionId(_) = def {
TyLoweringContext::new(db, &resolver, def.into()) TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
.with_impl_trait_mode(ImplTraitLoweringMode::Variable) .with_impl_trait_mode(ImplTraitLoweringMode::Variable)
.with_type_param_mode(ParamLoweringMode::Variable) .with_type_param_mode(ParamLoweringMode::Variable)
} else { } else {
TyLoweringContext::new(db, &resolver, def.into()) TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
.with_type_param_mode(ParamLoweringMode::Variable) .with_type_param_mode(ParamLoweringMode::Variable)
}; };
let generics = generics(db.upcast(), def); let generics = generics(db.upcast(), def);
// we have to filter out all other predicates *first*, before attempting to lower them // we have to filter out all other predicates *first*, before attempting to lower them
let predicate = |(pred, &def): &(&_, _)| match pred { let predicate = |pred: &_, def: &_, ctx: &TyLoweringContext<'_>| match pred {
WherePredicate::ForLifetime { target, bound, .. } WherePredicate::ForLifetime { target, bound, .. }
| WherePredicate::TypeBound { target, bound, .. } => { | WherePredicate::TypeBound { target, bound, .. } => {
let invalid_target = match target { let invalid_target = match target {
WherePredicateTypeTarget::TypeRef(type_ref) => { WherePredicateTypeTarget::TypeRef(type_ref) => {
ctx.lower_ty_only_param(type_ref) != Some(param_id) ctx.lower_ty_only_param(*type_ref) != Some(param_id)
} }
&WherePredicateTypeTarget::TypeOrConstParam(local_id) => { &WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
let target_id = TypeOrConstParamId { parent: def, local_id }; let target_id = TypeOrConstParamId { parent: *def, local_id };
target_id != param_id target_id != param_id
} }
}; };
if invalid_target { if invalid_target {
// If this is filtered out without lowering, `?Sized` is not gathered into `ctx.unsized_types` // If this is filtered out without lowering, `?Sized` is not gathered into `ctx.unsized_types`
if let TypeBound::Path(_, TraitBoundModifier::Maybe) = &**bound { if let TypeBound::Path(_, TraitBoundModifier::Maybe) = bound {
ctx.lower_where_predicate(pred, &def, true).for_each(drop); ctx.lower_where_predicate(pred, def, true).for_each(drop);
} }
return false; return false;
} }
match &**bound { match bound {
TypeBound::ForLifetime(_, path) | TypeBound::Path(path, _) => { TypeBound::ForLifetime(_, path) | TypeBound::Path(path, _) => {
// Only lower the bound if the trait could possibly define the associated // Only lower the bound if the trait could possibly define the associated
// type we're looking for. // type we're looking for.
@ -1577,13 +1637,15 @@ pub(crate) fn generic_predicates_for_param_query(
} }
WherePredicate::Lifetime { .. } => false, WherePredicate::Lifetime { .. } => false,
}; };
let mut predicates: Vec<_> = resolver let mut predicates = Vec::new();
.where_predicates_in_scope() for (params, def) in resolver.all_generic_params() {
.filter(predicate) ctx.types_map = &params.types_map;
.flat_map(|(pred, def)| { predicates.extend(
params.where_predicates().filter(|pred| predicate(pred, def, &ctx)).flat_map(|pred| {
ctx.lower_where_predicate(pred, def, true).map(|p| make_binders(db, &generics, p)) ctx.lower_where_predicate(pred, def, true).map(|p| make_binders(db, &generics, p))
}) }),
.collect(); );
}
let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
if !subst.is_empty(Interner) { if !subst.is_empty(Interner) {
@ -1630,25 +1692,29 @@ pub(crate) fn trait_environment_query(
def: GenericDefId, def: GenericDefId,
) -> Arc<TraitEnvironment> { ) -> Arc<TraitEnvironment> {
let resolver = def.resolver(db.upcast()); let resolver = def.resolver(db.upcast());
let ctx = if let GenericDefId::FunctionId(_) = def { let mut ctx = if let GenericDefId::FunctionId(_) = def {
TyLoweringContext::new(db, &resolver, def.into()) TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
.with_impl_trait_mode(ImplTraitLoweringMode::Param) .with_impl_trait_mode(ImplTraitLoweringMode::Param)
.with_type_param_mode(ParamLoweringMode::Placeholder) .with_type_param_mode(ParamLoweringMode::Placeholder)
} else { } else {
TyLoweringContext::new(db, &resolver, def.into()) TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
.with_type_param_mode(ParamLoweringMode::Placeholder) .with_type_param_mode(ParamLoweringMode::Placeholder)
}; };
let mut traits_in_scope = Vec::new(); let mut traits_in_scope = Vec::new();
let mut clauses = Vec::new(); let mut clauses = Vec::new();
for (pred, def) in resolver.where_predicates_in_scope() { for (params, def) in resolver.all_generic_params() {
ctx.types_map = &params.types_map;
for pred in params.where_predicates() {
for pred in ctx.lower_where_predicate(pred, def, false) { for pred in ctx.lower_where_predicate(pred, def, false) {
if let WhereClause::Implemented(tr) = &pred.skip_binders() { if let WhereClause::Implemented(tr) = pred.skip_binders() {
traits_in_scope.push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id())); traits_in_scope
.push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id()));
} }
let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(Interner); let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(Interner);
clauses.push(program_clause.into_from_env_clause(Interner)); clauses.push(program_clause.into_from_env_clause(Interner));
} }
} }
}
if let Some(trait_id) = def.assoc_trait_container(db.upcast()) { if let Some(trait_id) = def.assoc_trait_container(db.upcast()) {
// add `Self: Trait<T1, T2, ...>` to the environment in trait // add `Self: Trait<T1, T2, ...>` to the environment in trait
@ -1725,18 +1791,20 @@ where
} }
_ => (ImplTraitLoweringMode::Disallowed, ParamLoweringMode::Variable), _ => (ImplTraitLoweringMode::Disallowed, ParamLoweringMode::Variable),
}; };
let ctx = TyLoweringContext::new(db, &resolver, def.into()) let mut ctx = TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
.with_impl_trait_mode(impl_trait_lowering) .with_impl_trait_mode(impl_trait_lowering)
.with_type_param_mode(param_lowering); .with_type_param_mode(param_lowering);
let generics = generics(db.upcast(), def); let generics = generics(db.upcast(), def);
let mut predicates = resolver let mut predicates = Vec::new();
.where_predicates_in_scope() for (params, def) in resolver.all_generic_params() {
.filter(|(pred, def)| filter(pred, def)) ctx.types_map = &params.types_map;
.flat_map(|(pred, def)| { predicates.extend(params.where_predicates().filter(|pred| filter(pred, def)).flat_map(
|pred| {
ctx.lower_where_predicate(pred, def, false).map(|p| make_binders(db, &generics, p)) ctx.lower_where_predicate(pred, def, false).map(|p| make_binders(db, &generics, p))
}) },
.collect::<Vec<_>>(); ));
}
if generics.len() > 0 { if generics.len() > 0 {
let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
@ -1812,18 +1880,19 @@ pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) ->
let resolver = def.resolver(db.upcast()); let resolver = def.resolver(db.upcast());
let parent_start_idx = generic_params.len_self(); let parent_start_idx = generic_params.len_self();
let ctx = TyLoweringContext::new(db, &resolver, def.into()) let mut ctx = TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
.with_impl_trait_mode(ImplTraitLoweringMode::Disallowed) .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed)
.with_type_param_mode(ParamLoweringMode::Variable); .with_type_param_mode(ParamLoweringMode::Variable);
GenericDefaults(Some(Arc::from_iter(generic_params.iter().enumerate().map( GenericDefaults(Some(Arc::from_iter(generic_params.iter_with_types_map().enumerate().map(
|(idx, (id, p))| { |(idx, ((id, p), types_map))| {
ctx.types_map = types_map;
match p { match p {
GenericParamDataRef::TypeParamData(p) => { GenericParamDataRef::TypeParamData(p) => {
let ty = p.default.as_ref().map_or(TyKind::Error.intern(Interner), |ty| { let ty = p.default.as_ref().map_or(TyKind::Error.intern(Interner), |ty| {
// Each default can only refer to previous parameters. // Each default can only refer to previous parameters.
// Type variable default referring to parameter coming // Type variable default referring to parameter coming
// after it is forbidden (FIXME: report diagnostic) // after it is forbidden (FIXME: report diagnostic)
fallback_bound_vars(ctx.lower_ty(ty), idx, parent_start_idx) fallback_bound_vars(ctx.lower_ty(*ty), idx, parent_start_idx)
}); });
crate::make_binders(db, &generic_params, ty.cast(Interner)) crate::make_binders(db, &generic_params, ty.cast(Interner))
} }
@ -1835,7 +1904,7 @@ pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) ->
let mut val = p.default.as_ref().map_or_else( let mut val = p.default.as_ref().map_or_else(
|| unknown_const_as_generic(db.const_param_ty(id)), || unknown_const_as_generic(db.const_param_ty(id)),
|c| { |c| {
let c = ctx.lower_const(c, ctx.lower_ty(&p.ty)); let c = ctx.lower_const(c, ctx.lower_ty(p.ty));
c.cast(Interner) c.cast(Interner)
}, },
); );
@ -1875,14 +1944,14 @@ pub(crate) fn generic_defaults_recover(
fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
let data = db.function_data(def); let data = db.function_data(def);
let resolver = def.resolver(db.upcast()); let resolver = def.resolver(db.upcast());
let ctx_params = TyLoweringContext::new(db, &resolver, def.into()) let ctx_params = TyLoweringContext::new(db, &resolver, &data.types_map, def.into())
.with_impl_trait_mode(ImplTraitLoweringMode::Variable) .with_impl_trait_mode(ImplTraitLoweringMode::Variable)
.with_type_param_mode(ParamLoweringMode::Variable); .with_type_param_mode(ParamLoweringMode::Variable);
let params = data.params.iter().map(|tr| ctx_params.lower_ty(tr)); let params = data.params.iter().map(|&tr| ctx_params.lower_ty(tr));
let ctx_ret = TyLoweringContext::new(db, &resolver, def.into()) let ctx_ret = TyLoweringContext::new(db, &resolver, &data.types_map, def.into())
.with_impl_trait_mode(ImplTraitLoweringMode::Opaque) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
.with_type_param_mode(ParamLoweringMode::Variable); .with_type_param_mode(ParamLoweringMode::Variable);
let ret = ctx_ret.lower_ty(&data.ret_type); let ret = ctx_ret.lower_ty(data.ret_type);
let generics = generics(db.upcast(), def.into()); let generics = generics(db.upcast(), def.into());
let sig = CallableSig::from_params_and_return( let sig = CallableSig::from_params_and_return(
params, params,
@ -1911,28 +1980,33 @@ fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> Binders<Ty> {
let data = db.const_data(def); let data = db.const_data(def);
let generics = generics(db.upcast(), def.into()); let generics = generics(db.upcast(), def.into());
let resolver = def.resolver(db.upcast()); let resolver = def.resolver(db.upcast());
let ctx = TyLoweringContext::new(db, &resolver, def.into()) let ctx = TyLoweringContext::new(db, &resolver, &data.types_map, def.into())
.with_type_param_mode(ParamLoweringMode::Variable); .with_type_param_mode(ParamLoweringMode::Variable);
make_binders(db, &generics, ctx.lower_ty(&data.type_ref)) make_binders(db, &generics, ctx.lower_ty(data.type_ref))
} }
/// Build the declared type of a static. /// Build the declared type of a static.
fn type_for_static(db: &dyn HirDatabase, def: StaticId) -> Binders<Ty> { fn type_for_static(db: &dyn HirDatabase, def: StaticId) -> Binders<Ty> {
let data = db.static_data(def); let data = db.static_data(def);
let resolver = def.resolver(db.upcast()); let resolver = def.resolver(db.upcast());
let ctx = TyLoweringContext::new(db, &resolver, def.into()); let ctx = TyLoweringContext::new(db, &resolver, &data.types_map, def.into());
Binders::empty(Interner, ctx.lower_ty(&data.type_ref)) Binders::empty(Interner, ctx.lower_ty(data.type_ref))
} }
fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnSig { fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnSig {
let struct_data = db.struct_data(def); let struct_data = db.struct_data(def);
let fields = struct_data.variant_data.fields(); let fields = struct_data.variant_data.fields();
let resolver = def.resolver(db.upcast()); let resolver = def.resolver(db.upcast());
let ctx = TyLoweringContext::new(db, &resolver, AdtId::from(def).into()) let ctx = TyLoweringContext::new(
db,
&resolver,
struct_data.variant_data.types_map(),
AdtId::from(def).into(),
)
.with_type_param_mode(ParamLoweringMode::Variable); .with_type_param_mode(ParamLoweringMode::Variable);
let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)); let params = fields.iter().map(|(_, field)| ctx.lower_ty(field.type_ref));
let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders(); let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders();
Binders::new( Binders::new(
binders, binders,
@ -1962,9 +2036,14 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId)
let var_data = db.enum_variant_data(def); let var_data = db.enum_variant_data(def);
let fields = var_data.variant_data.fields(); let fields = var_data.variant_data.fields();
let resolver = def.resolver(db.upcast()); let resolver = def.resolver(db.upcast());
let ctx = TyLoweringContext::new(db, &resolver, DefWithBodyId::VariantId(def).into()) let ctx = TyLoweringContext::new(
db,
&resolver,
var_data.variant_data.types_map(),
DefWithBodyId::VariantId(def).into(),
)
.with_type_param_mode(ParamLoweringMode::Variable); .with_type_param_mode(ParamLoweringMode::Variable);
let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)); let params = fields.iter().map(|(_, field)| ctx.lower_ty(field.type_ref));
let (ret, binders) = let (ret, binders) =
type_for_adt(db, def.lookup(db.upcast()).parent.into()).into_value_and_skipped_binders(); type_for_adt(db, def.lookup(db.upcast()).parent.into()).into_value_and_skipped_binders();
Binders::new( Binders::new(
@ -2005,15 +2084,17 @@ fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> { fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
let generics = generics(db.upcast(), t.into()); let generics = generics(db.upcast(), t.into());
let resolver = t.resolver(db.upcast()); let resolver = t.resolver(db.upcast());
let ctx = TyLoweringContext::new(db, &resolver, t.into()) let type_alias_data = db.type_alias_data(t);
let ctx = TyLoweringContext::new(db, &resolver, &type_alias_data.types_map, t.into())
.with_impl_trait_mode(ImplTraitLoweringMode::Opaque) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
.with_type_param_mode(ParamLoweringMode::Variable); .with_type_param_mode(ParamLoweringMode::Variable);
let type_alias_data = db.type_alias_data(t);
let inner = if type_alias_data.is_extern { let inner = if type_alias_data.is_extern {
TyKind::Foreign(crate::to_foreign_def_id(t)).intern(Interner) TyKind::Foreign(crate::to_foreign_def_id(t)).intern(Interner)
} else { } else {
let type_ref = &type_alias_data.type_ref; type_alias_data
ctx.lower_ty(type_ref.as_deref().unwrap_or(&TypeRef::Error)) .type_ref
.map(|type_ref| ctx.lower_ty(type_ref))
.unwrap_or_else(|| TyKind::Error.intern(Interner))
}; };
make_binders(db, &generics, inner) make_binders(db, &generics, inner)
} }
@ -2086,9 +2167,9 @@ pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binde
let impl_data = db.impl_data(impl_id); let impl_data = db.impl_data(impl_id);
let resolver = impl_id.resolver(db.upcast()); let resolver = impl_id.resolver(db.upcast());
let generics = generics(db.upcast(), impl_id.into()); let generics = generics(db.upcast(), impl_id.into());
let ctx = TyLoweringContext::new(db, &resolver, impl_id.into()) let ctx = TyLoweringContext::new(db, &resolver, &impl_data.types_map, impl_id.into())
.with_type_param_mode(ParamLoweringMode::Variable); .with_type_param_mode(ParamLoweringMode::Variable);
make_binders(db, &generics, ctx.lower_ty(&impl_data.self_ty)) make_binders(db, &generics, ctx.lower_ty(impl_data.self_ty))
} }
// returns None if def is a type arg // returns None if def is a type arg
@ -2096,13 +2177,13 @@ pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> T
let parent_data = db.generic_params(def.parent()); let parent_data = db.generic_params(def.parent());
let data = &parent_data[def.local_id()]; let data = &parent_data[def.local_id()];
let resolver = def.parent().resolver(db.upcast()); let resolver = def.parent().resolver(db.upcast());
let ctx = TyLoweringContext::new(db, &resolver, def.parent().into()); let ctx = TyLoweringContext::new(db, &resolver, &parent_data.types_map, def.parent().into());
match data { match data {
TypeOrConstParamData::TypeParamData(_) => { TypeOrConstParamData::TypeParamData(_) => {
never!(); never!();
Ty::new(Interner, TyKind::Error) Ty::new(Interner, TyKind::Error)
} }
TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(&d.ty), TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(d.ty),
} }
} }
@ -2118,7 +2199,7 @@ pub(crate) fn impl_self_ty_recover(
pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> { pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> {
let impl_data = db.impl_data(impl_id); let impl_data = db.impl_data(impl_id);
let resolver = impl_id.resolver(db.upcast()); let resolver = impl_id.resolver(db.upcast());
let ctx = TyLoweringContext::new(db, &resolver, impl_id.into()) let ctx = TyLoweringContext::new(db, &resolver, &impl_data.types_map, impl_id.into())
.with_type_param_mode(ParamLoweringMode::Variable); .with_type_param_mode(ParamLoweringMode::Variable);
let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders(); let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders();
let target_trait = impl_data.target_trait.as_ref()?; let target_trait = impl_data.target_trait.as_ref()?;
@ -2132,10 +2213,10 @@ pub(crate) fn return_type_impl_traits(
// FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe
let data = db.function_data(def); let data = db.function_data(def);
let resolver = def.resolver(db.upcast()); let resolver = def.resolver(db.upcast());
let ctx_ret = TyLoweringContext::new(db, &resolver, def.into()) let ctx_ret = TyLoweringContext::new(db, &resolver, &data.types_map, def.into())
.with_impl_trait_mode(ImplTraitLoweringMode::Opaque) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
.with_type_param_mode(ParamLoweringMode::Variable); .with_type_param_mode(ParamLoweringMode::Variable);
let _ret = ctx_ret.lower_ty(&data.ret_type); let _ret = ctx_ret.lower_ty(data.ret_type);
let generics = generics(db.upcast(), def.into()); let generics = generics(db.upcast(), def.into());
let return_type_impl_traits = ImplTraits { let return_type_impl_traits = ImplTraits {
impl_traits: match ctx_ret.impl_trait_mode { impl_traits: match ctx_ret.impl_trait_mode {
@ -2156,10 +2237,10 @@ pub(crate) fn type_alias_impl_traits(
) -> Option<Arc<Binders<ImplTraits>>> { ) -> Option<Arc<Binders<ImplTraits>>> {
let data = db.type_alias_data(def); let data = db.type_alias_data(def);
let resolver = def.resolver(db.upcast()); let resolver = def.resolver(db.upcast());
let ctx = TyLoweringContext::new(db, &resolver, def.into()) let ctx = TyLoweringContext::new(db, &resolver, &data.types_map, def.into())
.with_impl_trait_mode(ImplTraitLoweringMode::Opaque) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
.with_type_param_mode(ParamLoweringMode::Variable); .with_type_param_mode(ParamLoweringMode::Variable);
if let Some(type_ref) = &data.type_ref { if let Some(type_ref) = data.type_ref {
let _ty = ctx.lower_ty(type_ref); let _ty = ctx.lower_ty(type_ref);
} }
let type_alias_impl_traits = ImplTraits { let type_alias_impl_traits = ImplTraits {
@ -2191,7 +2272,8 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
kind_id: GenericParamId, kind_id: GenericParamId,
arg: &'a GenericArg, arg: &'a GenericArg,
this: &mut T, this: &mut T,
for_type: impl FnOnce(&mut T, &TypeRef) -> Ty + 'a, types_map: &TypesMap,
for_type: impl FnOnce(&mut T, TypeRefId) -> Ty + 'a,
for_const: impl FnOnce(&mut T, &ConstRef, Ty) -> Const + 'a, for_const: impl FnOnce(&mut T, &ConstRef, Ty) -> Const + 'a,
for_lifetime: impl FnOnce(&mut T, &LifetimeRef) -> Lifetime + 'a, for_lifetime: impl FnOnce(&mut T, &LifetimeRef) -> Lifetime + 'a,
) -> crate::GenericArg { ) -> crate::GenericArg {
@ -2204,7 +2286,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime, GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime,
}; };
match (arg, kind) { match (arg, kind) {
(GenericArg::Type(type_ref), ParamKind::Type) => for_type(this, type_ref).cast(Interner), (GenericArg::Type(type_ref), ParamKind::Type) => for_type(this, *type_ref).cast(Interner),
(GenericArg::Const(c), ParamKind::Const(c_ty)) => for_const(this, c, c_ty).cast(Interner), (GenericArg::Const(c), ParamKind::Const(c_ty)) => for_const(this, c, c_ty).cast(Interner),
(GenericArg::Lifetime(lifetime_ref), ParamKind::Lifetime) => { (GenericArg::Lifetime(lifetime_ref), ParamKind::Lifetime) => {
for_lifetime(this, lifetime_ref).cast(Interner) for_lifetime(this, lifetime_ref).cast(Interner)
@ -2215,7 +2297,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
// We want to recover simple idents, which parser detects them // We want to recover simple idents, which parser detects them
// as types. Maybe here is not the best place to do it, but // as types. Maybe here is not the best place to do it, but
// it works. // it works.
if let TypeRef::Path(p) = t { if let TypeRef::Path(p) = &types_map[*t] {
if let Some(p) = p.mod_path() { if let Some(p) = p.mod_path() {
if p.kind == PathKind::Plain { if p.kind == PathKind::Plain {
if let [n] = p.segments() { if let [n] = p.segments() {

View file

@ -2849,7 +2849,8 @@ impl Evaluator<'_> {
} }
let layout = self.layout_adt(id.0, subst.clone())?; let layout = self.layout_adt(id.0, subst.clone())?;
match data.variant_data.as_ref() { match data.variant_data.as_ref() {
VariantData::Record(fields) | VariantData::Tuple(fields) => { VariantData::Record { fields, .. }
| VariantData::Tuple { fields, .. } => {
let field_types = self.db.field_types(s.into()); let field_types = self.db.field_types(s.into());
for (field, _) in fields.iter() { for (field, _) in fields.iter() {
let offset = layout let offset = layout

View file

@ -14,6 +14,7 @@ use hir_def::{
lang_item::{LangItem, LangItemTarget}, lang_item::{LangItem, LangItemTarget},
path::Path, path::Path,
resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs}, resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs},
type_ref::TypesMap,
AdtId, DefWithBodyId, EnumVariantId, GeneralConstId, HasModule, ItemContainerId, LocalFieldId, AdtId, DefWithBodyId, EnumVariantId, GeneralConstId, HasModule, ItemContainerId, LocalFieldId,
Lookup, TraitId, TupleId, TypeOrConstParamId, Lookup, TraitId, TupleId, TypeOrConstParamId,
}; };
@ -28,7 +29,7 @@ use triomphe::Arc;
use crate::{ use crate::{
consteval::ConstEvalError, consteval::ConstEvalError,
db::{HirDatabase, InternedClosure}, db::{HirDatabase, InternedClosure},
display::HirDisplay, display::{hir_display_with_types_map, HirDisplay},
error_lifetime, error_lifetime,
generics::generics, generics::generics,
infer::{cast::CastTy, unify::InferenceTable, CaptureKind, CapturedItem, TypeMismatch}, infer::{cast::CastTy, unify::InferenceTable, CaptureKind, CapturedItem, TypeMismatch},
@ -247,8 +248,15 @@ impl From<LayoutError> for MirLowerError {
} }
impl MirLowerError { impl MirLowerError {
fn unresolved_path(db: &dyn HirDatabase, p: &Path, edition: Edition) -> Self { fn unresolved_path(
Self::UnresolvedName(p.display(db, edition).to_string()) db: &dyn HirDatabase,
p: &Path,
edition: Edition,
types_map: &TypesMap,
) -> Self {
Self::UnresolvedName(
hir_display_with_types_map(p, types_map).display(db, edition).to_string(),
)
} }
} }
@ -451,7 +459,12 @@ impl<'ctx> MirLowerCtx<'ctx> {
.resolver .resolver
.resolve_path_in_value_ns_fully(self.db.upcast(), p, hygiene) .resolve_path_in_value_ns_fully(self.db.upcast(), p, hygiene)
.ok_or_else(|| { .ok_or_else(|| {
MirLowerError::unresolved_path(self.db, p, self.edition()) MirLowerError::unresolved_path(
self.db,
p,
self.edition(),
&self.body.types,
)
})?; })?;
self.resolver.reset_to_guard(resolver_guard); self.resolver.reset_to_guard(resolver_guard);
result result
@ -824,7 +837,9 @@ impl<'ctx> MirLowerCtx<'ctx> {
let variant_id = let variant_id =
self.infer.variant_resolution_for_expr(expr_id).ok_or_else(|| match path { self.infer.variant_resolution_for_expr(expr_id).ok_or_else(|| match path {
Some(p) => MirLowerError::UnresolvedName( Some(p) => MirLowerError::UnresolvedName(
p.display(self.db, self.edition()).to_string(), hir_display_with_types_map(&**p, &self.body.types)
.display(self.db, self.edition())
.to_string(),
), ),
None => MirLowerError::RecordLiteralWithoutPath, None => MirLowerError::RecordLiteralWithoutPath,
})?; })?;
@ -1358,8 +1373,9 @@ impl<'ctx> MirLowerCtx<'ctx> {
), ),
}; };
let edition = self.edition(); let edition = self.edition();
let unresolved_name = let unresolved_name = || {
|| MirLowerError::unresolved_path(self.db, c.as_ref(), edition); MirLowerError::unresolved_path(self.db, c.as_ref(), edition, &self.body.types)
};
let pr = self let pr = self
.resolver .resolver
.resolve_path_in_value_ns(self.db.upcast(), c.as_ref(), HygieneId::ROOT) .resolve_path_in_value_ns(self.db.upcast(), c.as_ref(), HygieneId::ROOT)

View file

@ -349,8 +349,9 @@ impl MirLowerCtx<'_> {
mode, mode,
)?, )?,
None => { None => {
let unresolved_name = let unresolved_name = || {
|| MirLowerError::unresolved_path(self.db, p, self.edition()); MirLowerError::unresolved_path(self.db, p, self.edition(), &self.body.types)
};
let hygiene = self.body.pat_path_hygiene(pattern); let hygiene = self.body.pat_path_hygiene(pattern);
let pr = self let pr = self
.resolver .resolver

View file

@ -163,10 +163,12 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(Tra
WherePredicate::ForLifetime { target, bound, .. } WherePredicate::ForLifetime { target, bound, .. }
| WherePredicate::TypeBound { target, bound } => { | WherePredicate::TypeBound { target, bound } => {
let is_trait = match target { let is_trait = match target {
WherePredicateTypeTarget::TypeRef(type_ref) => match &**type_ref { WherePredicateTypeTarget::TypeRef(type_ref) => {
match &generic_params.types_map[*type_ref] {
TypeRef::Path(p) => p.is_self_type(), TypeRef::Path(p) => p.is_self_type(),
_ => false, _ => false,
}, }
}
WherePredicateTypeTarget::TypeOrConstParam(local_id) => { WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
Some(*local_id) == trait_self Some(*local_id) == trait_self
} }

View file

@ -12,12 +12,11 @@ use hir_def::{
}; };
use hir_ty::{ use hir_ty::{
display::{ display::{
write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError, hir_display_with_types_map, write_bounds_like_dyn_trait_with_prefix, write_visibility,
HirFormatter, SizedByDefault, HirDisplay, HirDisplayError, HirDisplayWithTypesMap, HirFormatter, SizedByDefault,
}, },
AliasEq, AliasTy, Interner, ProjectionTyExt, TraitRefExt, TyKind, WhereClause, AliasEq, AliasTy, Interner, ProjectionTyExt, TraitRefExt, TyKind, WhereClause,
}; };
use intern::Interned;
use itertools::Itertools; use itertools::Itertools;
use crate::{ use crate::{
@ -113,7 +112,7 @@ impl HirDisplay for Function {
f.write_str(&pat_str)?; f.write_str(&pat_str)?;
f.write_str(": ")?; f.write_str(": ")?;
type_ref.hir_fmt(f)?; type_ref.hir_fmt(f, &data.types_map)?;
} }
if data.is_varargs() { if data.is_varargs() {
@ -129,28 +128,30 @@ impl HirDisplay for Function {
// Use ugly pattern match to strip the Future trait. // Use ugly pattern match to strip the Future trait.
// Better way? // Better way?
let ret_type = if !data.is_async() { let ret_type = if !data.is_async() {
&data.ret_type Some(data.ret_type)
} else { } else {
match &*data.ret_type { match &data.types_map[data.ret_type] {
TypeRef::ImplTrait(bounds) => match bounds[0].as_ref() { TypeRef::ImplTrait(bounds) => match &bounds[0] {
TypeBound::Path(path, _) => { TypeBound::Path(path, _) => Some(
path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings *path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings
[0] [0]
.type_ref .type_ref
.as_ref() .as_ref()
.unwrap() .unwrap(),
} ),
_ => &TypeRef::Error, _ => None,
}, },
_ => &TypeRef::Error, _ => None,
} }
}; };
match ret_type { if let Some(ret_type) = ret_type {
match &data.types_map[ret_type] {
TypeRef::Tuple(tup) if tup.is_empty() => {} TypeRef::Tuple(tup) if tup.is_empty() => {}
ty => { _ => {
f.write_str(" -> ")?; f.write_str(" -> ")?;
ty.hir_fmt(f)?; ret_type.hir_fmt(f, &data.types_map)?;
}
} }
} }
@ -192,10 +193,10 @@ fn write_impl_header(impl_: &Impl, f: &mut HirFormatter<'_>) -> Result<(), HirDi
impl HirDisplay for SelfParam { impl HirDisplay for SelfParam {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
let data = f.db.function_data(self.func); let data = f.db.function_data(self.func);
let param = data.params.first().unwrap(); let param = *data.params.first().unwrap();
match &**param { match &data.types_map[param] {
TypeRef::Path(p) if p.is_self_type() => f.write_str("self"), TypeRef::Path(p) if p.is_self_type() => f.write_str("self"),
TypeRef::Reference(inner, lifetime, mut_) if matches!(&**inner, TypeRef::Path(p) if p.is_self_type()) => TypeRef::Reference(inner, lifetime, mut_) if matches!(&data.types_map[*inner], TypeRef::Path(p) if p.is_self_type()) =>
{ {
f.write_char('&')?; f.write_char('&')?;
if let Some(lifetime) = lifetime { if let Some(lifetime) = lifetime {
@ -206,9 +207,9 @@ impl HirDisplay for SelfParam {
} }
f.write_str("self") f.write_str("self")
} }
ty => { _ => {
f.write_str("self: ")?; f.write_str("self: ")?;
ty.hir_fmt(f) param.hir_fmt(f, &data.types_map)
} }
} }
} }
@ -393,7 +394,7 @@ impl HirDisplay for Variant {
let data = self.variant_data(f.db); let data = self.variant_data(f.db);
match &*data { match &*data {
VariantData::Unit => {} VariantData::Unit => {}
VariantData::Tuple(fields) => { VariantData::Tuple { fields, types_map } => {
f.write_char('(')?; f.write_char('(')?;
let mut first = true; let mut first = true;
for (_, field) in fields.iter() { for (_, field) in fields.iter() {
@ -403,11 +404,11 @@ impl HirDisplay for Variant {
f.write_str(", ")?; f.write_str(", ")?;
} }
// Enum variant fields must be pub. // Enum variant fields must be pub.
field.type_ref.hir_fmt(f)?; field.type_ref.hir_fmt(f, types_map)?;
} }
f.write_char(')')?; f.write_char(')')?;
} }
VariantData::Record(_) => { VariantData::Record { .. } => {
if let Some(limit) = f.entity_limit { if let Some(limit) = f.entity_limit {
write_fields(&self.fields(f.db), false, limit, true, f)?; write_fields(&self.fields(f.db), false, limit, true, f)?;
} }
@ -579,13 +580,13 @@ fn write_generic_params(
write!(f, "{}", name.display(f.db.upcast(), f.edition()))?; write!(f, "{}", name.display(f.db.upcast(), f.edition()))?;
if let Some(default) = &ty.default { if let Some(default) = &ty.default {
f.write_str(" = ")?; f.write_str(" = ")?;
default.hir_fmt(f)?; default.hir_fmt(f, &params.types_map)?;
} }
} }
TypeOrConstParamData::ConstParamData(c) => { TypeOrConstParamData::ConstParamData(c) => {
delim(f)?; delim(f)?;
write!(f, "const {}: ", name.display(f.db.upcast(), f.edition()))?; write!(f, "const {}: ", name.display(f.db.upcast(), f.edition()))?;
c.ty.hir_fmt(f)?; c.ty.hir_fmt(f, &params.types_map)?;
if let Some(default) = &c.default { if let Some(default) = &c.default {
f.write_str(" = ")?; f.write_str(" = ")?;
@ -615,7 +616,7 @@ fn write_where_clause(
Ok(true) Ok(true)
} }
fn has_disaplayable_predicates(params: &Interned<GenericParams>) -> bool { fn has_disaplayable_predicates(params: &GenericParams) -> bool {
params.where_predicates().any(|pred| { params.where_predicates().any(|pred| {
!matches!( !matches!(
pred, pred,
@ -626,21 +627,20 @@ fn has_disaplayable_predicates(params: &Interned<GenericParams>) -> bool {
} }
fn write_where_predicates( fn write_where_predicates(
params: &Interned<GenericParams>, params: &GenericParams,
f: &mut HirFormatter<'_>, f: &mut HirFormatter<'_>,
) -> Result<(), HirDisplayError> { ) -> Result<(), HirDisplayError> {
use WherePredicate::*; use WherePredicate::*;
// unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`. // unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`.
let is_unnamed_type_target = let is_unnamed_type_target = |params: &GenericParams, target: &WherePredicateTypeTarget| {
|params: &Interned<GenericParams>, target: &WherePredicateTypeTarget| {
matches!(target, matches!(target,
WherePredicateTypeTarget::TypeOrConstParam(id) if params[*id].name().is_none() WherePredicateTypeTarget::TypeOrConstParam(id) if params[*id].name().is_none()
) )
}; };
let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter<'_>| match target { let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter<'_>| match target {
WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f), WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f, &params.types_map),
WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() { WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() {
Some(name) => write!(f, "{}", name.display(f.db.upcast(), f.edition())), Some(name) => write!(f, "{}", name.display(f.db.upcast(), f.edition())),
None => f.write_str("{unnamed}"), None => f.write_str("{unnamed}"),
@ -668,7 +668,7 @@ fn write_where_predicates(
TypeBound { target, bound } => { TypeBound { target, bound } => {
write_target(target, f)?; write_target(target, f)?;
f.write_str(": ")?; f.write_str(": ")?;
bound.hir_fmt(f)?; bound.hir_fmt(f, &params.types_map)?;
} }
Lifetime { target, bound } => { Lifetime { target, bound } => {
let target = target.name.display(f.db.upcast(), f.edition()); let target = target.name.display(f.db.upcast(), f.edition());
@ -681,14 +681,16 @@ fn write_where_predicates(
write!(f, "for<{lifetimes}> ")?; write!(f, "for<{lifetimes}> ")?;
write_target(target, f)?; write_target(target, f)?;
f.write_str(": ")?; f.write_str(": ")?;
bound.hir_fmt(f)?; bound.hir_fmt(f, &params.types_map)?;
} }
} }
while let Some(nxt) = iter.next_if(|nxt| check_same_target(pred, nxt)) { while let Some(nxt) = iter.next_if(|nxt| check_same_target(pred, nxt)) {
f.write_str(" + ")?; f.write_str(" + ")?;
match nxt { match nxt {
TypeBound { bound, .. } | ForLifetime { bound, .. } => bound.hir_fmt(f)?, TypeBound { bound, .. } | ForLifetime { bound, .. } => {
bound.hir_fmt(f, &params.types_map)?
}
Lifetime { bound, .. } => { Lifetime { bound, .. } => {
write!(f, "{}", bound.name.display(f.db.upcast(), f.edition()))? write!(f, "{}", bound.name.display(f.db.upcast(), f.edition()))?
} }
@ -716,7 +718,7 @@ impl HirDisplay for Const {
Some(name) => write!(f, "{}: ", name.display(f.db.upcast(), f.edition()))?, Some(name) => write!(f, "{}: ", name.display(f.db.upcast(), f.edition()))?,
None => f.write_str("_: ")?, None => f.write_str("_: ")?,
} }
data.type_ref.hir_fmt(f)?; data.type_ref.hir_fmt(f, &data.types_map)?;
Ok(()) Ok(())
} }
} }
@ -730,7 +732,7 @@ impl HirDisplay for Static {
f.write_str("mut ")?; f.write_str("mut ")?;
} }
write!(f, "{}: ", data.name.display(f.db.upcast(), f.edition()))?; write!(f, "{}: ", data.name.display(f.db.upcast(), f.edition()))?;
data.type_ref.hir_fmt(f)?; data.type_ref.hir_fmt(f, &data.types_map)?;
Ok(()) Ok(())
} }
} }
@ -813,11 +815,14 @@ impl HirDisplay for TypeAlias {
write_generic_params(def_id, f)?; write_generic_params(def_id, f)?;
if !data.bounds.is_empty() { if !data.bounds.is_empty() {
f.write_str(": ")?; f.write_str(": ")?;
f.write_joined(data.bounds.iter(), " + ")?; f.write_joined(
data.bounds.iter().map(|bound| hir_display_with_types_map(bound, &data.types_map)),
" + ",
)?;
} }
if let Some(ty) = &data.type_ref { if let Some(ty) = data.type_ref {
f.write_str(" = ")?; f.write_str(" = ")?;
ty.hir_fmt(f)?; ty.hir_fmt(f, &data.types_map)?;
} }
write_where_clause(def_id, f)?; write_where_clause(def_id, f)?;
Ok(()) Ok(())

View file

@ -2420,7 +2420,7 @@ impl SelfParam {
func_data func_data
.params .params
.first() .first()
.map(|param| match &**param { .map(|&param| match func_data.types_map[param] {
TypeRef::Reference(.., mutability) => match mutability { TypeRef::Reference(.., mutability) => match mutability {
hir_def::type_ref::Mutability::Shared => Access::Shared, hir_def::type_ref::Mutability::Shared => Access::Shared,
hir_def::type_ref::Mutability::Mut => Access::Exclusive, hir_def::type_ref::Mutability::Mut => Access::Exclusive,
@ -2747,10 +2747,6 @@ impl TypeAlias {
Module { id: self.id.module(db.upcast()) } Module { id: self.id.module(db.upcast()) }
} }
pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> {
db.type_alias_data(self.id).type_ref.as_deref().cloned()
}
pub fn ty(self, db: &dyn HirDatabase) -> Type { pub fn ty(self, db: &dyn HirDatabase) -> Type {
Type::from_def(db, self.id) Type::from_def(db, self.id)
} }

View file

@ -16,7 +16,7 @@ use hir_def::{
nameres::{MacroSubNs, ModuleOrigin}, nameres::{MacroSubNs, ModuleOrigin},
path::ModPath, path::ModPath,
resolver::{self, HasResolver, Resolver, TypeNs}, resolver::{self, HasResolver, Resolver, TypeNs},
type_ref::Mutability, type_ref::{Mutability, TypesMap, TypesSourceMap},
AsMacroCall, DefWithBodyId, FunctionId, MacroId, StructId, TraitId, VariantId, AsMacroCall, DefWithBodyId, FunctionId, MacroId, StructId, TraitId, VariantId,
}; };
use hir_expand::{ use hir_expand::{
@ -1259,19 +1259,28 @@ impl<'db> SemanticsImpl<'db> {
pub fn resolve_type(&self, ty: &ast::Type) -> Option<Type> { pub fn resolve_type(&self, ty: &ast::Type) -> Option<Type> {
let analyze = self.analyze(ty.syntax())?; let analyze = self.analyze(ty.syntax())?;
let ctx = LowerCtx::new(self.db.upcast(), analyze.file_id); let (mut types_map, mut types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let ctx =
LowerCtx::new(self.db.upcast(), analyze.file_id, &mut types_map, &mut types_source_map);
let type_ref = crate::TypeRef::from_ast(&ctx, ty.clone());
let ty = hir_ty::TyLoweringContext::new_maybe_unowned( let ty = hir_ty::TyLoweringContext::new_maybe_unowned(
self.db, self.db,
&analyze.resolver, &analyze.resolver,
&types_map,
None,
analyze.resolver.type_owner(), analyze.resolver.type_owner(),
) )
.lower_ty(&crate::TypeRef::from_ast(&ctx, ty.clone())); .lower_ty(type_ref);
Some(Type::new_with_resolver(self.db, &analyze.resolver, ty)) Some(Type::new_with_resolver(self.db, &analyze.resolver, ty))
} }
pub fn resolve_trait(&self, path: &ast::Path) -> Option<Trait> { pub fn resolve_trait(&self, path: &ast::Path) -> Option<Trait> {
let analyze = self.analyze(path.syntax())?; let analyze = self.analyze(path.syntax())?;
let ctx = LowerCtx::new(self.db.upcast(), analyze.file_id); let (mut types_map, mut types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let ctx =
LowerCtx::new(self.db.upcast(), analyze.file_id, &mut types_map, &mut types_source_map);
let hir_path = Path::from_src(&ctx, path.clone())?; let hir_path = Path::from_src(&ctx, path.clone())?;
match analyze.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), &hir_path)? { match analyze.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), &hir_path)? {
TypeNs::TraitId(id) => Some(Trait { id }), TypeNs::TraitId(id) => Some(Trait { id }),
@ -1953,13 +1962,17 @@ impl SemanticsScope<'_> {
/// Resolve a path as-if it was written at the given scope. This is /// Resolve a path as-if it was written at the given scope. This is
/// necessary a heuristic, as it doesn't take hygiene into account. /// necessary a heuristic, as it doesn't take hygiene into account.
pub fn speculative_resolve(&self, ast_path: &ast::Path) -> Option<PathResolution> { pub fn speculative_resolve(&self, ast_path: &ast::Path) -> Option<PathResolution> {
let ctx = LowerCtx::new(self.db.upcast(), self.file_id); let (mut types_map, mut types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let ctx =
LowerCtx::new(self.db.upcast(), self.file_id, &mut types_map, &mut types_source_map);
let path = Path::from_src(&ctx, ast_path.clone())?; let path = Path::from_src(&ctx, ast_path.clone())?;
resolve_hir_path( resolve_hir_path(
self.db, self.db,
&self.resolver, &self.resolver,
&path, &path,
name_hygiene(self.db, InFile::new(self.file_id, ast_path.syntax())), name_hygiene(self.db, InFile::new(self.file_id, ast_path.syntax())),
&types_map,
) )
} }

View file

@ -24,7 +24,7 @@ use hir_def::{
nameres::MacroSubNs, nameres::MacroSubNs,
path::{ModPath, Path, PathKind}, path::{ModPath, Path, PathKind},
resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs}, resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
type_ref::Mutability, type_ref::{Mutability, TypesMap, TypesSourceMap},
AsMacroCall, AssocItemId, ConstId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, AsMacroCall, AssocItemId, ConstId, DefWithBodyId, FieldId, FunctionId, ItemContainerId,
LocalFieldId, Lookup, ModuleDefId, StructId, TraitId, VariantId, LocalFieldId, Lookup, ModuleDefId, StructId, TraitId, VariantId,
}; };
@ -614,7 +614,10 @@ impl SourceAnalyzer {
db: &dyn HirDatabase, db: &dyn HirDatabase,
macro_call: InFile<&ast::MacroCall>, macro_call: InFile<&ast::MacroCall>,
) -> Option<Macro> { ) -> Option<Macro> {
let ctx = LowerCtx::new(db.upcast(), macro_call.file_id); let (mut types_map, mut types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let ctx =
LowerCtx::new(db.upcast(), macro_call.file_id, &mut types_map, &mut types_source_map);
let path = macro_call.value.path().and_then(|ast| Path::from_src(&ctx, ast))?; let path = macro_call.value.path().and_then(|ast| Path::from_src(&ctx, ast))?;
self.resolver self.resolver
.resolve_path_as_macro(db.upcast(), path.mod_path()?, Some(MacroSubNs::Bang)) .resolve_path_as_macro(db.upcast(), path.mod_path()?, Some(MacroSubNs::Bang))
@ -632,7 +635,7 @@ impl SourceAnalyzer {
Pat::Path(path) => path, Pat::Path(path) => path,
_ => return None, _ => return None,
}; };
let res = resolve_hir_path(db, &self.resolver, path, HygieneId::ROOT)?; let res = resolve_hir_path(db, &self.resolver, path, HygieneId::ROOT, TypesMap::EMPTY)?;
match res { match res {
PathResolution::Def(def) => Some(def), PathResolution::Def(def) => Some(def),
_ => None, _ => None,
@ -726,14 +729,16 @@ impl SourceAnalyzer {
return resolved; return resolved;
} }
let ctx = LowerCtx::new(db.upcast(), self.file_id); let (mut types_map, mut types_source_map) =
(TypesMap::default(), TypesSourceMap::default());
let ctx = LowerCtx::new(db.upcast(), self.file_id, &mut types_map, &mut types_source_map);
let hir_path = Path::from_src(&ctx, path.clone())?; let hir_path = Path::from_src(&ctx, path.clone())?;
// Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are // Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are
// trying to resolve foo::bar. // trying to resolve foo::bar.
if let Some(use_tree) = parent().and_then(ast::UseTree::cast) { if let Some(use_tree) = parent().and_then(ast::UseTree::cast) {
if use_tree.coloncolon_token().is_some() { if use_tree.coloncolon_token().is_some() {
return resolve_hir_path_qualifier(db, &self.resolver, &hir_path); return resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &types_map);
} }
} }
@ -750,7 +755,7 @@ impl SourceAnalyzer {
// Case where path is a qualifier of another path, e.g. foo::bar::Baz where we are // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we are
// trying to resolve foo::bar. // trying to resolve foo::bar.
if path.parent_path().is_some() { if path.parent_path().is_some() {
return match resolve_hir_path_qualifier(db, &self.resolver, &hir_path) { return match resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &types_map) {
None if meta_path.is_some() => { None if meta_path.is_some() => {
path.first_segment().and_then(|it| it.name_ref()).and_then(|name_ref| { path.first_segment().and_then(|it| it.name_ref()).and_then(|name_ref| {
ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text()) ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text())
@ -821,7 +826,7 @@ impl SourceAnalyzer {
}; };
} }
if parent().map_or(false, |it| ast::Visibility::can_cast(it.kind())) { if parent().map_or(false, |it| ast::Visibility::can_cast(it.kind())) {
resolve_hir_path_qualifier(db, &self.resolver, &hir_path) resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &types_map)
} else { } else {
resolve_hir_path_( resolve_hir_path_(
db, db,
@ -829,6 +834,7 @@ impl SourceAnalyzer {
&hir_path, &hir_path,
prefer_value_ns, prefer_value_ns,
name_hygiene(db, InFile::new(self.file_id, path.syntax())), name_hygiene(db, InFile::new(self.file_id, path.syntax())),
&types_map,
) )
} }
} }
@ -1156,8 +1162,9 @@ pub(crate) fn resolve_hir_path(
resolver: &Resolver, resolver: &Resolver,
path: &Path, path: &Path,
hygiene: HygieneId, hygiene: HygieneId,
types_map: &TypesMap,
) -> Option<PathResolution> { ) -> Option<PathResolution> {
resolve_hir_path_(db, resolver, path, false, hygiene) resolve_hir_path_(db, resolver, path, false, hygiene, types_map)
} }
#[inline] #[inline]
@ -1178,12 +1185,18 @@ fn resolve_hir_path_(
path: &Path, path: &Path,
prefer_value_ns: bool, prefer_value_ns: bool,
hygiene: HygieneId, hygiene: HygieneId,
types_map: &TypesMap,
) -> Option<PathResolution> { ) -> Option<PathResolution> {
let types = || { let types = || {
let (ty, unresolved) = match path.type_anchor() { let (ty, unresolved) = match path.type_anchor() {
Some(type_ref) => { Some(type_ref) => {
let (_, res) = let (_, res) = TyLoweringContext::new_maybe_unowned(
TyLoweringContext::new_maybe_unowned(db, resolver, resolver.type_owner()) db,
resolver,
types_map,
None,
resolver.type_owner(),
)
.lower_ty_ext(type_ref); .lower_ty_ext(type_ref);
res.map(|ty_ns| (ty_ns, path.segments().first())) res.map(|ty_ns| (ty_ns, path.segments().first()))
} }
@ -1305,12 +1318,18 @@ fn resolve_hir_path_qualifier(
db: &dyn HirDatabase, db: &dyn HirDatabase,
resolver: &Resolver, resolver: &Resolver,
path: &Path, path: &Path,
types_map: &TypesMap,
) -> Option<PathResolution> { ) -> Option<PathResolution> {
(|| { (|| {
let (ty, unresolved) = match path.type_anchor() { let (ty, unresolved) = match path.type_anchor() {
Some(type_ref) => { Some(type_ref) => {
let (_, res) = let (_, res) = TyLoweringContext::new_maybe_unowned(
TyLoweringContext::new_maybe_unowned(db, resolver, resolver.type_owner()) db,
resolver,
types_map,
None,
resolver.type_owner(),
)
.lower_ty_ext(type_ref); .lower_ty_ext(type_ref);
res.map(|ty_ns| (ty_ns, path.segments().first())) res.map(|ty_ns| (ty_ns, path.segments().first()))
} }

View file

@ -8,7 +8,10 @@ use hir_def::{
TraitId, TraitId,
}; };
use hir_expand::HirFileId; use hir_expand::HirFileId;
use hir_ty::{db::HirDatabase, display::HirDisplay}; use hir_ty::{
db::HirDatabase,
display::{hir_display_with_types_map, HirDisplay},
};
use span::Edition; use span::Edition;
use syntax::{ast::HasName, AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, ToSmolStr}; use syntax::{ast::HasName, AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, ToSmolStr};
@ -214,7 +217,11 @@ impl<'a> SymbolCollector<'a> {
fn collect_from_impl(&mut self, impl_id: ImplId) { fn collect_from_impl(&mut self, impl_id: ImplId) {
let impl_data = self.db.impl_data(impl_id); let impl_data = self.db.impl_data(impl_id);
let impl_name = Some(impl_data.self_ty.display(self.db, self.edition).to_smolstr()); let impl_name = Some(
hir_display_with_types_map(impl_data.self_ty, &impl_data.types_map)
.display(self.db, self.edition)
.to_smolstr(),
);
self.with_container_name(impl_name, |s| { self.with_container_name(impl_name, |s| {
for &assoc_item_id in impl_data.items.iter() { for &assoc_item_id in impl_data.items.iter() {
s.push_assoc_item(assoc_item_id) s.push_assoc_item(assoc_item_id)