Auto merge of #17584 - Veykril:landing-page, r=Veykril

Implement symbol interning infra

Will fix https://github.com/rust-lang/rust-analyzer/issues/15590

My unsafe-fu is not the best but it does satisfy miri.

There is still some follow up work to do, notably a lot of places using strings instead of symbols/names, most notably the token tree.
This commit is contained in:
bors 2024-07-15 09:39:22 +00:00
commit 5784915618
86 changed files with 1415 additions and 789 deletions

View file

@ -14,6 +14,8 @@ extend-ignore-re = [
"\\w*\\.{3,4}\\w*", "\\w*\\.{3,4}\\w*",
'"flate2"', '"flate2"',
"raison d'être", "raison d'être",
"inout",
"optin"
] ]
[default.extend-words] [default.extend-words]

7
Cargo.lock generated
View file

@ -835,6 +835,7 @@ dependencies = [
"dashmap", "dashmap",
"hashbrown", "hashbrown",
"rustc-hash", "rustc-hash",
"sptr",
"triomphe", "triomphe",
] ]
@ -1885,6 +1886,12 @@ dependencies = [
"vfs", "vfs",
] ]
[[package]]
name = "sptr"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a"
[[package]] [[package]]
name = "stable_deref_trait" name = "stable_deref_trait"
version = "1.2.0" version = "1.2.0"

View file

@ -9,6 +9,7 @@ use hir_expand::{
attrs::{collect_attrs, Attr, AttrId, RawAttrs}, attrs::{collect_attrs, Attr, AttrId, RawAttrs},
HirFileId, InFile, HirFileId, InFile,
}; };
use intern::{sym, Symbol};
use la_arena::{ArenaMap, Idx, RawIdx}; use la_arena::{ArenaMap, Idx, RawIdx};
use mbe::DelimiterKind; use mbe::DelimiterKind;
use syntax::{ use syntax::{
@ -152,7 +153,7 @@ impl Attrs {
} }
pub fn lang_item(&self) -> Option<LangItem> { pub fn lang_item(&self) -> Option<LangItem> {
self.by_key("lang").string_value().and_then(LangItem::from_str) self.by_key("lang").string_value().and_then(|it| LangItem::from_symbol(&Symbol::intern(it)))
} }
pub fn has_doc_hidden(&self) -> bool { pub fn has_doc_hidden(&self) -> bool {
@ -199,8 +200,12 @@ impl Attrs {
.segments() .segments()
.iter() .iter()
.rev() .rev()
.zip(["core", "prelude", "v1", "test"].iter().rev()) .zip(
.all(|it| it.0.as_str() == Some(it.1)) [sym::core.clone(), sym::prelude.clone(), sym::v1.clone(), sym::test.clone()]
.iter()
.rev(),
)
.all(|it| it.0 == it.1)
}) })
} }
@ -568,6 +573,10 @@ impl<'attr> AttrQuery<'attr> {
self.attrs().find_map(|attr| attr.string_value()) self.attrs().find_map(|attr| attr.string_value())
} }
pub fn string_value_with_span(self) -> Option<(&'attr str, span::Span)> {
self.attrs().find_map(|attr| attr.string_value_with_span())
}
pub fn string_value_unescape(self) -> Option<Cow<'attr, str>> { pub fn string_value_unescape(self) -> Option<Cow<'attr, str>> {
self.attrs().find_map(|attr| attr.string_value_unescape()) self.attrs().find_map(|attr| attr.string_value_unescape())
} }

View file

@ -5,10 +5,10 @@ use std::mem;
use base_db::CrateId; use base_db::CrateId;
use hir_expand::{ use hir_expand::{
name::{name, AsName, Name}, name::{AsName, Name},
ExpandError, InFile, ExpandError, InFile,
}; };
use intern::Interned; use intern::{sym, Interned};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use smallvec::SmallVec; use smallvec::SmallVec;
use span::AstIdMap; use span::AstIdMap;
@ -187,8 +187,10 @@ impl ExprCollector<'_> {
{ {
let is_mutable = let is_mutable =
self_param.mut_token().is_some() && self_param.amp_token().is_none(); self_param.mut_token().is_some() && self_param.amp_token().is_none();
let binding_id: la_arena::Idx<Binding> = let binding_id: la_arena::Idx<Binding> = self.alloc_binding(
self.alloc_binding(name![self], BindingAnnotation::new(is_mutable, false)); Name::new_symbol_root(sym::self_.clone()),
BindingAnnotation::new(is_mutable, false),
);
self.body.self_param = Some(binding_id); self.body.self_param = Some(binding_id);
self.source_map.self_param = Some(self.expander.in_file(AstPtr::new(&self_param))); self.source_map.self_param = Some(self.expander.in_file(AstPtr::new(&self_param)));
} }
@ -1588,18 +1590,22 @@ impl ExprCollector<'_> {
}); });
let mut mappings = vec![]; let mut mappings = vec![];
let fmt = match template.and_then(|it| self.expand_macros_to_string(it)) { let fmt = match template.and_then(|it| self.expand_macros_to_string(it)) {
Some((s, is_direct_literal)) => format_args::parse( Some((s, is_direct_literal)) => {
&s, let call_ctx = self.expander.syntax_context();
fmt_snippet, format_args::parse(
args, &s,
is_direct_literal, fmt_snippet,
|name| self.alloc_expr_desugared(Expr::Path(Path::from(name))), args,
|name, span| { is_direct_literal,
if let Some(span) = span { |name| self.alloc_expr_desugared(Expr::Path(Path::from(name))),
mappings.push((span, name)) |name, span| {
} if let Some(span) = span {
}, mappings.push((span, name))
), }
},
call_ctx,
)
}
None => FormatArgs { None => FormatArgs {
template: Default::default(), template: Default::default(),
arguments: args.finish(), arguments: args.finish(),
@ -1723,14 +1729,18 @@ impl ExprCollector<'_> {
// unsafe { ::core::fmt::UnsafeArg::new() } // unsafe { ::core::fmt::UnsafeArg::new() }
// ) // )
let Some(new_v1_formatted) = let Some(new_v1_formatted) = LangItem::FormatArguments.ty_rel_path(
LangItem::FormatArguments.ty_rel_path(self.db, self.krate, name![new_v1_formatted]) self.db,
else { self.krate,
Name::new_symbol_root(sym::new_v1_formatted.clone()),
) else {
return self.missing_expr(); return self.missing_expr();
}; };
let Some(unsafe_arg_new) = let Some(unsafe_arg_new) = LangItem::FormatUnsafeArg.ty_rel_path(
LangItem::FormatUnsafeArg.ty_rel_path(self.db, self.krate, name![new]) self.db,
else { self.krate,
Name::new_symbol_root(sym::new.clone()),
) else {
return self.missing_expr(); return self.missing_expr();
}; };
let new_v1_formatted = self.alloc_expr_desugared(Expr::Path(new_v1_formatted)); let new_v1_formatted = self.alloc_expr_desugared(Expr::Path(new_v1_formatted));
@ -1812,10 +1822,10 @@ impl ExprCollector<'_> {
self.db, self.db,
self.krate, self.krate,
match alignment { match alignment {
Some(FormatAlignment::Left) => name![Left], Some(FormatAlignment::Left) => Name::new_symbol_root(sym::Left.clone()),
Some(FormatAlignment::Right) => name![Right], Some(FormatAlignment::Right) => Name::new_symbol_root(sym::Right.clone()),
Some(FormatAlignment::Center) => name![Center], Some(FormatAlignment::Center) => Name::new_symbol_root(sym::Center.clone()),
None => name![Unknown], None => Name::new_symbol_root(sym::Unknown.clone()),
}, },
); );
match align { match align {
@ -1838,8 +1848,11 @@ impl ExprCollector<'_> {
let width = self.make_count(width, argmap); let width = self.make_count(width, argmap);
let format_placeholder_new = { let format_placeholder_new = {
let format_placeholder_new = let format_placeholder_new = LangItem::FormatPlaceholder.ty_rel_path(
LangItem::FormatPlaceholder.ty_rel_path(self.db, self.krate, name![new]); self.db,
self.krate,
Name::new_symbol_root(sym::new.clone()),
);
match format_placeholder_new { match format_placeholder_new {
Some(path) => self.alloc_expr_desugared(Expr::Path(path)), Some(path) => self.alloc_expr_desugared(Expr::Path(path)),
None => self.missing_expr(), None => self.missing_expr(),
@ -1883,11 +1896,14 @@ impl ExprCollector<'_> {
*n as u128, *n as u128,
Some(BuiltinUint::Usize), Some(BuiltinUint::Usize),
))); )));
let count_is = let count_is = match LangItem::FormatCount.ty_rel_path(
match LangItem::FormatCount.ty_rel_path(self.db, self.krate, name![Is]) { self.db,
Some(count_is) => self.alloc_expr_desugared(Expr::Path(count_is)), self.krate,
None => self.missing_expr(), Name::new_symbol_root(sym::Is.clone()),
}; ) {
Some(count_is) => self.alloc_expr_desugared(Expr::Path(count_is)),
None => self.missing_expr(),
};
self.alloc_expr_desugared(Expr::Call { self.alloc_expr_desugared(Expr::Call {
callee: count_is, callee: count_is,
args: Box::new([args]), args: Box::new([args]),
@ -1905,7 +1921,7 @@ impl ExprCollector<'_> {
let count_param = match LangItem::FormatCount.ty_rel_path( let count_param = match LangItem::FormatCount.ty_rel_path(
self.db, self.db,
self.krate, self.krate,
name![Param], Name::new_symbol_root(sym::Param.clone()),
) { ) {
Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)), Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)),
None => self.missing_expr(), None => self.missing_expr(),
@ -1921,7 +1937,11 @@ impl ExprCollector<'_> {
self.missing_expr() self.missing_expr()
} }
} }
None => match LangItem::FormatCount.ty_rel_path(self.db, self.krate, name![Implied]) { None => match LangItem::FormatCount.ty_rel_path(
self.db,
self.krate,
Name::new_symbol_root(sym::Implied.clone()),
) {
Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)), Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)),
None => self.missing_expr(), None => self.missing_expr(),
}, },
@ -1942,18 +1962,18 @@ impl ExprCollector<'_> {
let new_fn = match LangItem::FormatArgument.ty_rel_path( let new_fn = match LangItem::FormatArgument.ty_rel_path(
self.db, self.db,
self.krate, self.krate,
match ty { Name::new_symbol_root(match ty {
Format(Display) => name![new_display], Format(Display) => sym::new_display.clone(),
Format(Debug) => name![new_debug], Format(Debug) => sym::new_debug.clone(),
Format(LowerExp) => name![new_lower_exp], Format(LowerExp) => sym::new_lower_exp.clone(),
Format(UpperExp) => name![new_upper_exp], Format(UpperExp) => sym::new_upper_exp.clone(),
Format(Octal) => name![new_octal], Format(Octal) => sym::new_octal.clone(),
Format(Pointer) => name![new_pointer], Format(Pointer) => sym::new_pointer.clone(),
Format(Binary) => name![new_binary], Format(Binary) => sym::new_binary.clone(),
Format(LowerHex) => name![new_lower_hex], Format(LowerHex) => sym::new_lower_hex.clone(),
Format(UpperHex) => name![new_upper_hex], Format(UpperHex) => sym::new_upper_hex.clone(),
Usize => name![from_usize], Usize => sym::from_usize.clone(),
}, }),
) { ) {
Some(new_fn) => self.alloc_expr_desugared(Expr::Path(new_fn)), Some(new_fn) => self.alloc_expr_desugared(Expr::Path(new_fn)),
None => self.missing_expr(), None => self.missing_expr(),

View file

@ -5,7 +5,8 @@
use std::fmt; use std::fmt;
use hir_expand::name::{name, AsName, Name}; use hir_expand::name::{AsName, Name};
use intern::sym;
/// Different signed int types. /// Different signed int types.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum BuiltinInt { pub enum BuiltinInt {
@ -48,63 +49,67 @@ pub enum BuiltinType {
impl BuiltinType { impl BuiltinType {
#[rustfmt::skip] #[rustfmt::skip]
pub const ALL: &'static [(Name, BuiltinType)] = &[ pub fn all_builtin_types() -> [(Name, BuiltinType); 19] {
(name![char], BuiltinType::Char), [
(name![bool], BuiltinType::Bool), (Name::new_symbol_root(sym::char.clone()), BuiltinType::Char),
(name![str], BuiltinType::Str), (Name::new_symbol_root(sym::bool.clone()), BuiltinType::Bool),
(Name::new_symbol_root(sym::str.clone()), BuiltinType::Str),
(name![isize], BuiltinType::Int(BuiltinInt::Isize)), (Name::new_symbol_root(sym::isize.clone()), BuiltinType::Int(BuiltinInt::Isize)),
(name![i8], BuiltinType::Int(BuiltinInt::I8)), (Name::new_symbol_root(sym::i8.clone()), BuiltinType::Int(BuiltinInt::I8)),
(name![i16], BuiltinType::Int(BuiltinInt::I16)), (Name::new_symbol_root(sym::i16.clone()), BuiltinType::Int(BuiltinInt::I16)),
(name![i32], BuiltinType::Int(BuiltinInt::I32)), (Name::new_symbol_root(sym::i32.clone()), BuiltinType::Int(BuiltinInt::I32)),
(name![i64], BuiltinType::Int(BuiltinInt::I64)), (Name::new_symbol_root(sym::i64.clone()), BuiltinType::Int(BuiltinInt::I64)),
(name![i128], BuiltinType::Int(BuiltinInt::I128)), (Name::new_symbol_root(sym::i128.clone()), BuiltinType::Int(BuiltinInt::I128)),
(name![usize], BuiltinType::Uint(BuiltinUint::Usize)), (Name::new_symbol_root(sym::usize.clone()), BuiltinType::Uint(BuiltinUint::Usize)),
(name![u8], BuiltinType::Uint(BuiltinUint::U8)), (Name::new_symbol_root(sym::u8.clone()), BuiltinType::Uint(BuiltinUint::U8)),
(name![u16], BuiltinType::Uint(BuiltinUint::U16)), (Name::new_symbol_root(sym::u16.clone()), BuiltinType::Uint(BuiltinUint::U16)),
(name![u32], BuiltinType::Uint(BuiltinUint::U32)), (Name::new_symbol_root(sym::u32.clone()), BuiltinType::Uint(BuiltinUint::U32)),
(name![u64], BuiltinType::Uint(BuiltinUint::U64)), (Name::new_symbol_root(sym::u64.clone()), BuiltinType::Uint(BuiltinUint::U64)),
(name![u128], BuiltinType::Uint(BuiltinUint::U128)), (Name::new_symbol_root(sym::u128.clone()), BuiltinType::Uint(BuiltinUint::U128)),
(name![f16], BuiltinType::Float(BuiltinFloat::F16)), (Name::new_symbol_root(sym::f16.clone()), BuiltinType::Float(BuiltinFloat::F16)),
(name![f32], BuiltinType::Float(BuiltinFloat::F32)), (Name::new_symbol_root(sym::f32.clone()), BuiltinType::Float(BuiltinFloat::F32)),
(name![f64], BuiltinType::Float(BuiltinFloat::F64)), (Name::new_symbol_root(sym::f64.clone()), BuiltinType::Float(BuiltinFloat::F64)),
(name![f128], BuiltinType::Float(BuiltinFloat::F128)), (Name::new_symbol_root(sym::f128.clone()), BuiltinType::Float(BuiltinFloat::F128)),
]; ]
}
pub fn by_name(name: &Name) -> Option<Self> { pub fn by_name(name: &Name) -> Option<Self> {
Self::ALL.iter().find_map(|(n, ty)| if n == name { Some(*ty) } else { None }) Self::all_builtin_types()
.iter()
.find_map(|(n, ty)| if n == name { Some(*ty) } else { None })
} }
} }
impl AsName for BuiltinType { impl AsName for BuiltinType {
fn as_name(&self) -> Name { fn as_name(&self) -> Name {
match self { match self {
BuiltinType::Char => name![char], BuiltinType::Char => Name::new_symbol_root(sym::char.clone()),
BuiltinType::Bool => name![bool], BuiltinType::Bool => Name::new_symbol_root(sym::bool.clone()),
BuiltinType::Str => name![str], BuiltinType::Str => Name::new_symbol_root(sym::str.clone()),
BuiltinType::Int(it) => match it { BuiltinType::Int(it) => match it {
BuiltinInt::Isize => name![isize], BuiltinInt::Isize => Name::new_symbol_root(sym::isize.clone()),
BuiltinInt::I8 => name![i8], BuiltinInt::I8 => Name::new_symbol_root(sym::i8.clone()),
BuiltinInt::I16 => name![i16], BuiltinInt::I16 => Name::new_symbol_root(sym::i16.clone()),
BuiltinInt::I32 => name![i32], BuiltinInt::I32 => Name::new_symbol_root(sym::i32.clone()),
BuiltinInt::I64 => name![i64], BuiltinInt::I64 => Name::new_symbol_root(sym::i64.clone()),
BuiltinInt::I128 => name![i128], BuiltinInt::I128 => Name::new_symbol_root(sym::i128.clone()),
}, },
BuiltinType::Uint(it) => match it { BuiltinType::Uint(it) => match it {
BuiltinUint::Usize => name![usize], BuiltinUint::Usize => Name::new_symbol_root(sym::usize.clone()),
BuiltinUint::U8 => name![u8], BuiltinUint::U8 => Name::new_symbol_root(sym::u8.clone()),
BuiltinUint::U16 => name![u16], BuiltinUint::U16 => Name::new_symbol_root(sym::u16.clone()),
BuiltinUint::U32 => name![u32], BuiltinUint::U32 => Name::new_symbol_root(sym::u32.clone()),
BuiltinUint::U64 => name![u64], BuiltinUint::U64 => Name::new_symbol_root(sym::u64.clone()),
BuiltinUint::U128 => name![u128], BuiltinUint::U128 => Name::new_symbol_root(sym::u128.clone()),
}, },
BuiltinType::Float(it) => match it { BuiltinType::Float(it) => match it {
BuiltinFloat::F16 => name![f16], BuiltinFloat::F16 => Name::new_symbol_root(sym::f16.clone()),
BuiltinFloat::F32 => name![f32], BuiltinFloat::F32 => Name::new_symbol_root(sym::f32.clone()),
BuiltinFloat::F64 => name![f64], BuiltinFloat::F64 => Name::new_symbol_root(sym::f64.clone()),
BuiltinFloat::F128 => name![f128], BuiltinFloat::F128 => Name::new_symbol_root(sym::f128.clone()),
}, },
} }
} }

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::Interned; use intern::{sym, Interned};
use smallvec::SmallVec; use smallvec::SmallVec;
use syntax::{ast, Parse}; use syntax::{ast, Parse};
use triomphe::Arc; use triomphe::Arc;
@ -485,7 +485,7 @@ impl ExternCrateDeclData {
let name = extern_crate.name.clone(); let name = extern_crate.name.clone();
let krate = loc.container.krate(); let krate = loc.container.krate();
let crate_id = if name == hir_expand::name![self] { let crate_id = if name == sym::self_.clone() {
Some(krate) Some(krate)
} else { } else {
db.crate_def_map(krate) db.crate_def_map(krate)

View file

@ -2,7 +2,7 @@
use base_db::{salsa, CrateId, FileId, SourceDatabase, Upcast}; use base_db::{salsa, CrateId, FileId, SourceDatabase, Upcast};
use either::Either; use either::Either;
use hir_expand::{db::ExpandDatabase, HirFileId, MacroDefId}; use hir_expand::{db::ExpandDatabase, HirFileId, MacroDefId};
use intern::Interned; use intern::{sym, Interned};
use la_arena::ArenaMap; use la_arena::ArenaMap;
use span::MacroCallId; use span::MacroCallId;
use syntax::{ast, AstPtr}; use syntax::{ast, AstPtr};
@ -261,9 +261,9 @@ fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: CrateId) -> bool {
let item_tree = db.file_item_tree(file.into()); let item_tree = db.file_item_tree(file.into());
let attrs = item_tree.raw_attrs(AttrOwner::TopLevel); let attrs = item_tree.raw_attrs(AttrOwner::TopLevel);
for attr in &**attrs { for attr in &**attrs {
match attr.path().as_ident().and_then(|id| id.as_text()) { match attr.path().as_ident() {
Some(ident) if ident == "no_std" => return true, Some(ident) if *ident == sym::no_std.clone() => return true,
Some(ident) if ident == "cfg_attr" => {} Some(ident) if *ident == sym::cfg_attr.clone() => {}
_ => continue, _ => continue,
} }

View file

@ -10,6 +10,7 @@ use hir_expand::{
InFile, MacroCallId, InFile, MacroCallId,
}; };
use limit::Limit; use limit::Limit;
use span::SyntaxContextId;
use syntax::{ast, Parse}; use syntax::{ast, Parse};
use triomphe::Arc; use triomphe::Arc;
@ -52,6 +53,11 @@ impl Expander {
self.module.krate self.module.krate
} }
pub fn syntax_context(&self) -> SyntaxContextId {
// FIXME:
SyntaxContextId::ROOT
}
pub fn enter_expand<T: ast::AstNode>( pub fn enter_expand<T: ast::AstNode>(
&mut self, &mut self,
db: &dyn DefDatabase, db: &dyn DefDatabase,

View file

@ -3,9 +3,10 @@
use std::{cell::Cell, cmp::Ordering, iter}; use std::{cell::Cell, cmp::Ordering, iter};
use hir_expand::{ use hir_expand::{
name::{known, AsName, Name}, name::{AsName, Name},
Lookup, Lookup,
}; };
use intern::{sym, Symbol};
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use crate::{ use crate::{
@ -414,13 +415,13 @@ fn select_best_path(
(Unstable, Stable) => return new_path, (Unstable, Stable) => return new_path,
_ => {} _ => {}
} }
const STD_CRATES: [Name; 3] = [known::std, known::core, known::alloc]; let std_crates: [Symbol; 3] = [sym::std.clone(), sym::core.clone(), sym::alloc.clone()];
let choose = |new: (ModPath, _), old: (ModPath, _)| { let choose = |new: (ModPath, _), old: (ModPath, _)| {
let (new_path, _) = &new; let (new_path, _) = &new;
let (old_path, _) = &old; let (old_path, _) = &old;
let new_has_prelude = new_path.segments().iter().any(|seg| seg == &known::prelude); let new_has_prelude = new_path.segments().iter().any(|seg| *seg == sym::prelude.clone());
let old_has_prelude = old_path.segments().iter().any(|seg| seg == &known::prelude); let old_has_prelude = old_path.segments().iter().any(|seg| *seg == sym::prelude.clone());
match (new_has_prelude, old_has_prelude, cfg.prefer_prelude) { match (new_has_prelude, old_has_prelude, cfg.prefer_prelude) {
(true, false, true) | (false, true, false) => new, (true, false, true) | (false, true, false) => new,
(true, false, false) | (false, true, true) => old, (true, false, false) | (false, true, true) => old,
@ -441,18 +442,20 @@ fn select_best_path(
}; };
match (old_path.0.segments().first(), new_path.0.segments().first()) { match (old_path.0.segments().first(), new_path.0.segments().first()) {
(Some(old), Some(new)) if STD_CRATES.contains(old) && STD_CRATES.contains(new) => { (Some(old), Some(new))
if std_crates.contains(old.symbol()) && std_crates.contains(new.symbol()) =>
{
let rank = match cfg.prefer_no_std { let rank = match cfg.prefer_no_std {
false => |name: &Name| match name { false => |name: &Name| match name {
name if name == &known::core => 0, name if *name == sym::core.clone() => 0,
name if name == &known::alloc => 1, name if *name == sym::alloc.clone() => 1,
name if name == &known::std => 2, name if *name == sym::std.clone() => 2,
_ => unreachable!(), _ => unreachable!(),
}, },
true => |name: &Name| match name { true => |name: &Name| match name {
name if name == &known::core => 2, name if *name == sym::core.clone() => 2,
name if name == &known::alloc => 1, name if *name == sym::alloc.clone() => 1,
name if name == &known::std => 0, name if *name == sym::std.clone() => 0,
_ => unreachable!(), _ => unreachable!(),
}, },
}; };

View file

@ -3,10 +3,11 @@ use std::mem;
use hir_expand::name::Name; use hir_expand::name::Name;
use rustc_parse_format as parse; use rustc_parse_format as parse;
use span::SyntaxContextId;
use stdx::TupleExt; use stdx::TupleExt;
use syntax::{ use syntax::{
ast::{self, IsString}, ast::{self, IsString},
SmolStr, TextRange, TextSize, TextRange, TextSize,
}; };
use crate::hir::ExprId; use crate::hir::ExprId;
@ -174,6 +175,7 @@ pub(crate) fn parse(
is_direct_literal: bool, is_direct_literal: bool,
mut synth: impl FnMut(Name) -> ExprId, mut synth: impl FnMut(Name) -> ExprId,
mut record_usage: impl FnMut(Name, Option<TextRange>), mut record_usage: impl FnMut(Name, Option<TextRange>),
call_ctx: SyntaxContextId,
) -> FormatArgs { ) -> FormatArgs {
let Ok(text) = s.value() else { let Ok(text) = s.value() else {
return FormatArgs { return FormatArgs {
@ -248,7 +250,7 @@ pub(crate) fn parse(
} }
} }
ArgRef::Name(name, span) => { ArgRef::Name(name, span) => {
let name = Name::new_text_dont_use(SmolStr::new(name)); let name = Name::new(name, call_ctx);
if let Some((index, _)) = args.by_name(&name) { if let Some((index, _)) = args.by_name(&name) {
record_usage(name, span); record_usage(name, span);
// Name found in `args`, so we resolve it to its index. // Name found in `args`, so we resolve it to its index.

View file

@ -1,10 +1,9 @@
//! Describes items defined or visible (ie, imported) in a certain scope. //! Describes items defined or visible (ie, imported) in a certain scope.
//! This is shared between modules and blocks. //! This is shared between modules and blocks.
use std::collections::hash_map::Entry;
use base_db::CrateId; use base_db::CrateId;
use hir_expand::{attrs::AttrId, db::ExpandDatabase, name::Name, AstId, MacroCallId}; use hir_expand::{attrs::AttrId, db::ExpandDatabase, name::Name, AstId, MacroCallId};
use indexmap::map::Entry;
use itertools::Itertools; use itertools::Itertools;
use la_arena::Idx; use la_arena::Idx;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
@ -17,8 +16,8 @@ use crate::{
db::DefDatabase, db::DefDatabase,
per_ns::PerNs, per_ns::PerNs,
visibility::{Visibility, VisibilityExplicitness}, visibility::{Visibility, VisibilityExplicitness},
AdtId, BuiltinType, ConstId, ExternCrateId, HasModule, ImplId, LocalModuleId, Lookup, MacroId, AdtId, BuiltinType, ConstId, ExternCrateId, FxIndexMap, HasModule, ImplId, LocalModuleId,
ModuleDefId, ModuleId, TraitId, UseId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, UseId,
}; };
#[derive(Debug, Default)] #[derive(Debug, Default)]
@ -67,9 +66,9 @@ pub struct ItemScope {
/// Defs visible in this scope. This includes `declarations`, but also /// Defs visible in this scope. This includes `declarations`, but also
/// imports. The imports belong to this module and can be resolved by using them on /// imports. The imports belong to this module and can be resolved by using them on
/// the `use_imports_*` fields. /// the `use_imports_*` fields.
types: FxHashMap<Name, (ModuleDefId, Visibility, Option<ImportOrExternCrate>)>, types: FxIndexMap<Name, (ModuleDefId, Visibility, Option<ImportOrExternCrate>)>,
values: FxHashMap<Name, (ModuleDefId, Visibility, Option<ImportId>)>, values: FxIndexMap<Name, (ModuleDefId, Visibility, Option<ImportId>)>,
macros: FxHashMap<Name, (MacroId, Visibility, Option<ImportId>)>, macros: FxIndexMap<Name, (MacroId, Visibility, Option<ImportId>)>,
unresolved: FxHashSet<Name>, unresolved: FxHashSet<Name>,
/// The defs declared in this scope. Each def has a single scope where it is /// The defs declared in this scope. Each def has a single scope where it is
@ -118,8 +117,8 @@ struct DeriveMacroInvocation {
derive_call_ids: SmallVec<[Option<MacroCallId>; 1]>, derive_call_ids: SmallVec<[Option<MacroCallId>; 1]>,
} }
pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| { pub(crate) static BUILTIN_SCOPE: Lazy<FxIndexMap<Name, PerNs>> = Lazy::new(|| {
BuiltinType::ALL BuiltinType::all_builtin_types()
.iter() .iter()
.map(|(name, ty)| (name.clone(), PerNs::types((*ty).into(), Visibility::Public, None))) .map(|(name, ty)| (name.clone(), PerNs::types((*ty).into(), Visibility::Public, None)))
.collect() .collect()

View file

@ -2,7 +2,8 @@
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
use hir_expand::{mod_path::path, name, name::AsName, span_map::SpanMapRef, HirFileId}; use hir_expand::{mod_path::path, name::AsName, span_map::SpanMapRef, HirFileId};
use intern::sym;
use la_arena::Arena; use la_arena::Arena;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use span::{AstIdMap, SyntaxContextId}; use span::{AstIdMap, SyntaxContextId};
@ -323,7 +324,8 @@ impl<'a> Ctx<'a> {
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(&self.body_ctx, type_ref),
None => { None => {
let self_type = TypeRef::Path(name![Self].into()); let self_type =
TypeRef::Path(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 => TypeRef::Reference(
@ -669,7 +671,7 @@ impl<'a> Ctx<'a> {
// Traits and trait aliases get the Self type as an implicit first type parameter. // Traits and trait aliases get the Self type as an implicit first type parameter.
generics.type_or_consts.alloc( generics.type_or_consts.alloc(
TypeParamData { TypeParamData {
name: Some(name![Self]), name: Some(Name::new_symbol_root(sym::Self_.clone())),
default: None, default: None,
provenance: TypeParamProvenance::TraitSelf, provenance: TypeParamProvenance::TraitSelf,
} }
@ -680,7 +682,7 @@ impl<'a> Ctx<'a> {
generics.fill_bounds( generics.fill_bounds(
&self.body_ctx, &self.body_ctx,
bounds, bounds,
Either::Left(TypeRef::Path(name![Self].into())), Either::Left(TypeRef::Path(Name::new_symbol_root(sym::Self_.clone()).into())),
); );
} }
@ -745,7 +747,7 @@ fn desugar_future_path(orig: TypeRef) -> Path {
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();
let binding = AssociatedTypeBinding { let binding = AssociatedTypeBinding {
name: name![Output], name: Name::new_symbol_root(sym::Output.clone()),
args: None, args: None,
type_ref: Some(orig), type_ref: Some(orig),
bounds: Box::default(), bounds: Box::default(),

View file

@ -3,6 +3,7 @@
//! This attribute to tell the compiler about semi built-in std library //! This attribute to tell the compiler about semi built-in std library
//! features, such as Fn family of traits. //! features, such as Fn family of traits.
use hir_expand::name::Name; use hir_expand::name::Name;
use intern::{sym, Symbol};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use syntax::SmolStr; use syntax::SmolStr;
use triomphe::Arc; use triomphe::Arc;
@ -191,8 +192,7 @@ impl LangItems {
} }
pub(crate) fn lang_attr(db: &dyn DefDatabase, item: AttrDefId) -> Option<LangItem> { pub(crate) fn lang_attr(db: &dyn DefDatabase, item: AttrDefId) -> Option<LangItem> {
let attrs = db.attrs(item); db.attrs(item).lang_item()
attrs.by_key("lang").string_value().and_then(LangItem::from_str)
} }
pub(crate) fn notable_traits_in_deps( pub(crate) fn notable_traits_in_deps(
@ -260,10 +260,9 @@ macro_rules! language_item_table {
} }
/// Opposite of [`LangItem::name`] /// Opposite of [`LangItem::name`]
#[allow(clippy::should_implement_trait)] pub fn from_symbol(sym: &Symbol) -> Option<Self> {
pub fn from_str(name: &str) -> Option<Self> { match sym {
match name { $(sym if *sym == $module::$name => Some(LangItem::$variant), )*
$( stringify!($name) => Some(LangItem::$variant), )*
_ => None, _ => None,
} }
} }
@ -274,7 +273,7 @@ macro_rules! language_item_table {
impl LangItem { impl LangItem {
/// Opposite of [`LangItem::name`] /// Opposite of [`LangItem::name`]
pub fn from_name(name: &hir_expand::name::Name) -> Option<Self> { pub fn from_name(name: &hir_expand::name::Name) -> Option<Self> {
Self::from_str(name.as_str()?) Self::from_symbol(name.symbol())
} }
pub fn path(&self, db: &dyn DefDatabase, start_crate: CrateId) -> Option<Path> { pub fn path(&self, db: &dyn DefDatabase, start_crate: CrateId) -> Option<Path> {
@ -360,7 +359,7 @@ language_item_table! {
DerefTarget, sym::deref_target, deref_target, Target::AssocTy, GenericRequirement::None; DerefTarget, sym::deref_target, deref_target, Target::AssocTy, GenericRequirement::None;
Receiver, sym::receiver, receiver_trait, Target::Trait, GenericRequirement::None; Receiver, sym::receiver, receiver_trait, Target::Trait, GenericRequirement::None;
Fn, kw::fn, fn_trait, Target::Trait, GenericRequirement::Exact(1); Fn, sym::fn_, fn_trait, Target::Trait, GenericRequirement::Exact(1);
FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1);
FnOnce, sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1); FnOnce, sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1);

View file

@ -862,7 +862,7 @@ impl GeneralConstId {
.const_data(const_id) .const_data(const_id)
.name .name
.as_ref() .as_ref()
.and_then(|it| it.as_str()) .map(|it| it.as_str())
.unwrap_or("_") .unwrap_or("_")
.to_owned(), .to_owned(),
GeneralConstId::ConstBlockId(id) => format!("{{anonymous const {id:?}}}"), GeneralConstId::ConstBlockId(id) => format!("{{anonymous const {id:?}}}"),

View file

@ -323,7 +323,7 @@ pub struct ModuleData {
/// ///
/// [`None`] for block modules because they are always its `DefMap`'s root. /// [`None`] for block modules because they are always its `DefMap`'s root.
pub parent: Option<LocalModuleId>, pub parent: Option<LocalModuleId>,
pub children: FxHashMap<Name, LocalModuleId>, pub children: FxIndexMap<Name, LocalModuleId>,
pub scope: ItemScope, pub scope: ItemScope,
} }
@ -593,10 +593,8 @@ impl DefMap {
self.data.extern_prelude.iter().map(|(name, &def)| (name, def)) self.data.extern_prelude.iter().map(|(name, &def)| (name, def))
} }
pub(crate) fn macro_use_prelude( pub(crate) fn macro_use_prelude(&self) -> &FxHashMap<Name, (MacroId, Option<ExternCrateId>)> {
&self, &self.macro_use_prelude
) -> impl Iterator<Item = (&Name, (MacroId, Option<ExternCrateId>))> + '_ {
self.macro_use_prelude.iter().map(|(name, &def)| (name, def))
} }
pub(crate) fn resolve_path( pub(crate) fn resolve_path(
@ -668,7 +666,7 @@ impl ModuleData {
origin, origin,
visibility, visibility,
parent: None, parent: None,
children: FxHashMap::default(), children: Default::default(),
scope: ItemScope::default(), scope: ItemScope::default(),
} }
} }

View file

@ -13,11 +13,11 @@ use hir_expand::{
builtin_attr_macro::find_builtin_attr, builtin_attr_macro::find_builtin_attr,
builtin_derive_macro::find_builtin_derive, builtin_derive_macro::find_builtin_derive,
builtin_fn_macro::find_builtin_macro, builtin_fn_macro::find_builtin_macro,
name::{name, AsName, Name}, name::{AsName, Name},
proc_macro::CustomProcMacroExpander, proc_macro::CustomProcMacroExpander,
ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
}; };
use intern::Interned; use intern::{sym, Interned};
use itertools::{izip, Itertools}; use itertools::{izip, Itertools};
use la_arena::Idx; use la_arena::Idx;
use limit::Limit; use limit::Limit;
@ -76,25 +76,28 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI
let proc_macros = if krate.is_proc_macro { let proc_macros = if krate.is_proc_macro {
match db.proc_macros().get(&def_map.krate) { match db.proc_macros().get(&def_map.krate) {
Some(Ok(proc_macros)) => Ok(proc_macros Some(Ok(proc_macros)) => Ok({
.iter() let ctx = db.syntax_context(tree_id.file_id());
.enumerate() proc_macros
.map(|(idx, it)| { .iter()
let name = Name::new_text_dont_use(it.name.clone()); .enumerate()
( .map(|(idx, it)| {
name, let name = Name::new(&it.name, ctx);
if !db.expand_proc_attr_macros() { (
CustomProcMacroExpander::dummy() name,
} else if it.disabled { if !db.expand_proc_attr_macros() {
CustomProcMacroExpander::disabled() CustomProcMacroExpander::dummy()
} else { } else if it.disabled {
CustomProcMacroExpander::new(hir_expand::proc_macro::ProcMacroId::new( CustomProcMacroExpander::disabled()
idx as u32, } else {
)) CustomProcMacroExpander::new(
}, hir_expand::proc_macro::ProcMacroId::new(idx as u32),
) )
}) },
.collect()), )
})
.collect()
}),
Some(Err(e)) => Err(e.clone().into_boxed_str()), Some(Err(e)) => Err(e.clone().into_boxed_str()),
None => Err("No proc-macros present for crate".to_owned().into_boxed_str()), None => Err("No proc-macros present for crate".to_owned().into_boxed_str()),
} }
@ -291,24 +294,24 @@ impl DefCollector<'_> {
let Some(attr_name) = attr.path.as_ident() else { continue }; let Some(attr_name) = attr.path.as_ident() else { continue };
match () { match () {
() if *attr_name == hir_expand::name![recursion_limit] => { () if *attr_name == sym::recursion_limit.clone() => {
if let Some(limit) = attr.string_value() { if let Some(limit) = attr.string_value() {
if let Ok(limit) = limit.parse() { if let Ok(limit) = limit.parse() {
crate_data.recursion_limit = Some(limit); crate_data.recursion_limit = Some(limit);
} }
} }
} }
() if *attr_name == hir_expand::name![crate_type] => { () if *attr_name == sym::crate_type.clone() => {
if let Some("proc-macro") = attr.string_value() { if let Some("proc-macro") = attr.string_value() {
self.is_proc_macro = true; self.is_proc_macro = true;
} }
} }
() if *attr_name == hir_expand::name![no_core] => crate_data.no_core = true, () if *attr_name == sym::no_core.clone() => crate_data.no_core = true,
() if *attr_name == hir_expand::name![no_std] => crate_data.no_std = true, () if *attr_name == sym::no_std.clone() => crate_data.no_std = true,
() if attr_name.as_text().as_deref() == Some("rustc_coherence_is_core") => { () if *attr_name == sym::rustc_coherence_is_core.clone() => {
crate_data.rustc_coherence_is_core = true; crate_data.rustc_coherence_is_core = true;
} }
() if *attr_name == hir_expand::name![feature] => { () if *attr_name == sym::feature.clone() => {
let features = attr let features = attr
.parse_path_comma_token_tree(self.db.upcast()) .parse_path_comma_token_tree(self.db.upcast())
.into_iter() .into_iter()
@ -319,13 +322,13 @@ impl DefCollector<'_> {
}); });
crate_data.unstable_features.extend(features); crate_data.unstable_features.extend(features);
} }
() if *attr_name == hir_expand::name![register_attr] => { () if *attr_name == sym::register_attr.clone() => {
if let Some(ident) = attr.single_ident_value() { if let Some(ident) = attr.single_ident_value() {
crate_data.registered_attrs.push(ident.text.clone()); crate_data.registered_attrs.push(ident.text.clone());
cov_mark::hit!(register_attr); cov_mark::hit!(register_attr);
} }
} }
() if *attr_name == hir_expand::name![register_tool] => { () if *attr_name == sym::register_tool.clone() => {
if let Some(ident) = attr.single_ident_value() { if let Some(ident) = attr.single_ident_value() {
crate_data.registered_tools.push(ident.text.clone()); crate_data.registered_tools.push(ident.text.clone());
cov_mark::hit!(register_tool); cov_mark::hit!(register_tool);
@ -535,27 +538,30 @@ impl DefCollector<'_> {
} }
let krate = if self.def_map.data.no_std { let krate = if self.def_map.data.no_std {
name![core] Name::new_symbol_root(sym::core.clone())
} else if self.def_map.extern_prelude().any(|(name, _)| *name == name![std]) { } else if self.def_map.extern_prelude().any(|(name, _)| *name == sym::std.clone()) {
name![std] Name::new_symbol_root(sym::std.clone())
} else { } else {
// If `std` does not exist for some reason, fall back to core. This mostly helps // If `std` does not exist for some reason, fall back to core. This mostly helps
// keep r-a's own tests minimal. // keep r-a's own tests minimal.
name![core] Name::new_symbol_root(sym::core.clone())
}; };
let edition = match self.def_map.data.edition { let edition = match self.def_map.data.edition {
Edition::Edition2015 => name![rust_2015], Edition::Edition2015 => Name::new_symbol_root(sym::rust_2015.clone()),
Edition::Edition2018 => name![rust_2018], Edition::Edition2018 => Name::new_symbol_root(sym::rust_2018.clone()),
Edition::Edition2021 => name![rust_2021], Edition::Edition2021 => Name::new_symbol_root(sym::rust_2021.clone()),
Edition::Edition2024 => name![rust_2024], Edition::Edition2024 => Name::new_symbol_root(sym::rust_2024.clone()),
}; };
let path_kind = match self.def_map.data.edition { let path_kind = match self.def_map.data.edition {
Edition::Edition2015 => PathKind::Plain, Edition::Edition2015 => PathKind::Plain,
_ => PathKind::Abs, _ => PathKind::Abs,
}; };
let path = ModPath::from_segments(path_kind, [krate, name![prelude], edition]); let path = ModPath::from_segments(
path_kind,
[krate, Name::new_symbol_root(sym::prelude.clone()), edition],
);
let (per_ns, _) = let (per_ns, _) =
self.def_map.resolve_path(self.db, DefMap::ROOT, &path, BuiltinShadowMode::Other, None); self.def_map.resolve_path(self.db, DefMap::ROOT, &path, BuiltinShadowMode::Other, None);
@ -838,7 +844,7 @@ impl DefCollector<'_> {
} }
fn resolve_extern_crate(&self, name: &Name) -> Option<CrateRootModuleId> { fn resolve_extern_crate(&self, name: &Name) -> Option<CrateRootModuleId> {
if *name == name![self] { if *name == sym::self_.clone() {
cov_mark::hit!(extern_crate_self_as); cov_mark::hit!(extern_crate_self_as);
Some(self.def_map.crate_root()) Some(self.def_map.crate_root())
} else { } else {
@ -2136,9 +2142,9 @@ impl ModCollector<'_, '_> {
let expander = if attrs.by_key("rustc_builtin_macro").exists() { let expander = if attrs.by_key("rustc_builtin_macro").exists() {
// `#[rustc_builtin_macro = "builtin_name"]` overrides the `macro_rules!` name. // `#[rustc_builtin_macro = "builtin_name"]` overrides the `macro_rules!` name.
let name; let name;
let name = match attrs.by_key("rustc_builtin_macro").string_value() { let name = match attrs.by_key("rustc_builtin_macro").string_value_with_span() {
Some(it) => { Some((it, span)) => {
name = Name::new_text_dont_use(it.into()); name = Name::new(it, span.ctx);
&name &name
} }
None => { None => {

View file

@ -1348,6 +1348,7 @@ fn proc_attr(a: TokenStream, b: TokenStream) -> TokenStream { a }
.keys() .keys()
.map(|name| name.display(&db).to_string()) .map(|name| name.display(&db).to_string())
.sorted() .sorted()
.sorted()
.join("\n"); .join("\n");
expect![[r#" expect![[r#"

View file

@ -6,9 +6,9 @@ use crate::{lower::LowerCtx, type_ref::ConstRef};
use hir_expand::{ use hir_expand::{
mod_path::resolve_crate_root, mod_path::resolve_crate_root,
name::{name, AsName}, name::{AsName, Name},
}; };
use intern::Interned; use intern::{sym, Interned};
use syntax::ast::{self, AstNode, HasGenericArgs, HasTypeBounds}; use syntax::ast::{self, AstNode, HasGenericArgs, HasTypeBounds};
use crate::{ use crate::{
@ -60,7 +60,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
segments.push(name); segments.push(name);
} }
ast::PathSegmentKind::SelfTypeKw => { ast::PathSegmentKind::SelfTypeKw => {
segments.push(name![Self]); segments.push(Name::new_symbol_root(sym::Self_.clone()));
} }
ast::PathSegmentKind::Type { type_ref, trait_ref } => { ast::PathSegmentKind::Type { type_ref, trait_ref } => {
assert!(path.qualifier().is_none()); // this can only occur at the first segment assert!(path.qualifier().is_none()); // this can only occur at the first segment
@ -268,7 +268,7 @@ fn lower_generic_args_from_fn_path(
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 {
name: name![Output], name: Name::new_symbol_root(sym::Output.clone()),
args: None, args: None,
type_ref: Some(type_ref), type_ref: Some(type_ref),
bounds: Box::default(), bounds: Box::default(),
@ -277,7 +277,7 @@ fn lower_generic_args_from_fn_path(
// -> () // -> ()
let type_ref = TypeRef::Tuple(Vec::new()); let type_ref = TypeRef::Tuple(Vec::new());
Box::new([AssociatedTypeBinding { Box::new([AssociatedTypeBinding {
name: name![Output], name: Name::new_symbol_root(sym::Output.clone()),
args: None, args: None,
type_ref: Some(type_ref), type_ref: Some(type_ref),
bounds: Box::default(), bounds: Box::default(),

View file

@ -2,11 +2,9 @@
use std::{fmt, iter, mem}; use std::{fmt, iter, mem};
use base_db::CrateId; use base_db::CrateId;
use hir_expand::{ use hir_expand::{name::Name, MacroDefId};
name::{name, Name}, use intern::{sym, Interned};
MacroDefId, use itertools::Itertools as _;
};
use intern::Interned;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
use triomphe::Arc; use triomphe::Arc;
@ -197,12 +195,12 @@ impl Resolver {
} }
} }
&Scope::ImplDefScope(impl_) => { &Scope::ImplDefScope(impl_) => {
if first_name == &name![Self] { if *first_name == sym::Self_.clone() {
return Some((TypeNs::SelfType(impl_), remaining_idx(), None)); return Some((TypeNs::SelfType(impl_), remaining_idx(), None));
} }
} }
&Scope::AdtScope(adt) => { &Scope::AdtScope(adt) => {
if first_name == &name![Self] { if *first_name == sym::Self_.clone() {
return Some((TypeNs::AdtSelfType(adt), remaining_idx(), None)); return Some((TypeNs::AdtSelfType(adt), remaining_idx(), None));
} }
} }
@ -294,7 +292,7 @@ impl Resolver {
} }
}; };
let n_segments = path.segments().len(); let n_segments = path.segments().len();
let tmp = name![self]; let tmp = Name::new_symbol_root(sym::self_.clone());
let first_name = if path.is_self() { &tmp } else { path.segments().first()? }; let first_name = if path.is_self() { &tmp } else { path.segments().first()? };
let skip_to_mod = path.kind != PathKind::Plain && !path.is_self(); let skip_to_mod = path.kind != PathKind::Plain && !path.is_self();
if skip_to_mod { if skip_to_mod {
@ -325,7 +323,7 @@ impl Resolver {
} }
} }
&Scope::ImplDefScope(impl_) => { &Scope::ImplDefScope(impl_) => {
if first_name == &name![Self] { if *first_name == sym::Self_.clone() {
return Some(ResolveValueResult::ValueNs( return Some(ResolveValueResult::ValueNs(
ValueNs::ImplSelf(impl_), ValueNs::ImplSelf(impl_),
None, None,
@ -352,7 +350,7 @@ impl Resolver {
} }
} }
&Scope::ImplDefScope(impl_) => { &Scope::ImplDefScope(impl_) => {
if first_name == &name![Self] { if *first_name == sym::Self_.clone() {
return Some(ResolveValueResult::Partial( return Some(ResolveValueResult::Partial(
TypeNs::SelfType(impl_), TypeNs::SelfType(impl_),
1, 1,
@ -361,7 +359,7 @@ impl Resolver {
} }
} }
Scope::AdtScope(adt) => { Scope::AdtScope(adt) => {
if first_name == &name![Self] { if *first_name == sym::Self_.clone() {
let ty = TypeNs::AdtSelfType(*adt); let ty = TypeNs::AdtSelfType(*adt);
return Some(ResolveValueResult::Partial(ty, 1, None)); return Some(ResolveValueResult::Partial(ty, 1, None));
} }
@ -425,7 +423,7 @@ impl Resolver {
} }
pub fn resolve_lifetime(&self, lifetime: &LifetimeRef) -> Option<LifetimeNs> { pub fn resolve_lifetime(&self, lifetime: &LifetimeRef) -> Option<LifetimeNs> {
if lifetime.name == name::known::STATIC_LIFETIME { if lifetime.name == sym::tick_static.clone() {
return Some(LifetimeNs::Static); return Some(LifetimeNs::Static);
} }
@ -500,9 +498,11 @@ impl Resolver {
res.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(mac))); res.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(mac)));
}) })
}); });
def_map.macro_use_prelude().for_each(|(name, (def, _extern_crate))| { def_map.macro_use_prelude().iter().sorted_by_key(|&(k, _)| k.clone()).for_each(
res.add(name, ScopeDef::ModuleDef(def.into())); |(name, &(def, _extern_crate))| {
}); res.add(name, ScopeDef::ModuleDef(def.into()));
},
);
def_map.extern_prelude().for_each(|(name, (def, _extern_crate))| { def_map.extern_prelude().for_each(|(name, (def, _extern_crate))| {
res.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def.into()))); res.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def.into())));
}); });
@ -781,10 +781,10 @@ impl Scope {
} }
} }
Scope::ImplDefScope(i) => { Scope::ImplDefScope(i) => {
acc.add(&name![Self], ScopeDef::ImplSelfType(*i)); acc.add(&Name::new_symbol_root(sym::Self_.clone()), ScopeDef::ImplSelfType(*i));
} }
Scope::AdtScope(i) => { Scope::AdtScope(i) => {
acc.add(&name![Self], ScopeDef::AdtSelfType(*i)); acc.add(&Name::new_symbol_root(sym::Self_.clone()), ScopeDef::AdtSelfType(*i));
} }
Scope::ExprScope(scope) => { Scope::ExprScope(scope) => {
if let Some((label, name)) = scope.expr_scopes.label(scope.scope_id) { if let Some((label, name)) = scope.expr_scopes.label(scope.scope_id) {

View file

@ -4,7 +4,7 @@ use std::{borrow::Cow, fmt, ops};
use base_db::CrateId; use base_db::CrateId;
use cfg::CfgExpr; use cfg::CfgExpr;
use either::Either; use either::Either;
use intern::Interned; use intern::{sym, Interned};
use mbe::{syntax_node_to_token_tree, DelimiterKind, DocCommentDesugarMode, Punct}; use mbe::{syntax_node_to_token_tree, DelimiterKind, DocCommentDesugarMode, Punct};
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
use span::{Span, SyntaxContextId}; use span::{Span, SyntaxContextId};
@ -12,6 +12,7 @@ use syntax::unescape;
use syntax::{ast, format_smolstr, match_ast, AstNode, AstToken, SmolStr, SyntaxNode}; use syntax::{ast, format_smolstr, match_ast, AstNode, AstToken, SmolStr, SyntaxNode};
use triomphe::ThinArc; use triomphe::ThinArc;
use crate::name::Name;
use crate::{ use crate::{
db::ExpandDatabase, db::ExpandDatabase,
mod_path::ModPath, mod_path::ModPath,
@ -58,7 +59,10 @@ impl RawAttrs {
text: SmolStr::new(format_smolstr!("\"{}\"", Self::escape_chars(doc))), text: SmolStr::new(format_smolstr!("\"{}\"", Self::escape_chars(doc))),
span, span,
}))), }))),
path: Interned::new(ModPath::from(crate::name!(doc))), path: Interned::new(ModPath::from(Name::new_symbol(
sym::doc.clone(),
span.ctx,
))),
ctxt: span.ctx, ctxt: span.ctx,
} }
}), }),
@ -115,7 +119,7 @@ impl RawAttrs {
pub fn filter(self, db: &dyn ExpandDatabase, krate: CrateId) -> RawAttrs { pub fn filter(self, db: &dyn ExpandDatabase, krate: CrateId) -> RawAttrs {
let has_cfg_attrs = self let has_cfg_attrs = self
.iter() .iter()
.any(|attr| attr.path.as_ident().map_or(false, |name| *name == crate::name![cfg_attr])); .any(|attr| attr.path.as_ident().map_or(false, |name| *name == sym::cfg_attr.clone()));
if !has_cfg_attrs { if !has_cfg_attrs {
return self; return self;
} }
@ -125,7 +129,7 @@ impl RawAttrs {
self.iter() self.iter()
.flat_map(|attr| -> SmallVec<[_; 1]> { .flat_map(|attr| -> SmallVec<[_; 1]> {
let is_cfg_attr = let is_cfg_attr =
attr.path.as_ident().map_or(false, |name| *name == crate::name![cfg_attr]); attr.path.as_ident().map_or(false, |name| *name == sym::cfg_attr.clone());
if !is_cfg_attr { if !is_cfg_attr {
return smallvec![attr.clone()]; return smallvec![attr.clone()];
} }
@ -316,6 +320,20 @@ impl Attr {
} }
} }
/// #[path = "string"]
pub fn string_value_with_span(&self) -> Option<(&str, span::Span)> {
match self.input.as_deref()? {
AttrInput::Literal(it) => match it.text.strip_prefix('r') {
Some(it) => it.trim_matches('#'),
None => it.text.as_str(),
}
.strip_prefix('"')?
.strip_suffix('"')
.zip(Some(it.span)),
_ => None,
}
}
pub fn string_value_unescape(&self) -> Option<Cow<'_, str>> { pub fn string_value_unescape(&self) -> Option<Cow<'_, str>> {
match self.input.as_deref()? { match self.input.as_deref()? {
AttrInput::Literal(it) => match it.text.strip_prefix('r') { AttrInput::Literal(it) => match it.text.strip_prefix('r') {
@ -369,7 +387,7 @@ impl Attr {
} }
pub fn cfg(&self) -> Option<CfgExpr> { pub fn cfg(&self) -> Option<CfgExpr> {
if *self.path.as_ident()? == crate::name![cfg] { if *self.path.as_ident()? == sym::cfg.clone() {
self.token_tree_value().map(CfgExpr::parse) self.token_tree_value().map(CfgExpr::parse)
} else { } else {
None None

View file

@ -1,4 +1,5 @@
//! Builtin attributes. //! Builtin attributes.
use intern::sym;
use span::{MacroCallId, Span}; use span::{MacroCallId, Span};
use crate::{db::ExpandDatabase, name, tt, ExpandResult, MacroCallKind}; use crate::{db::ExpandDatabase, name, tt, ExpandResult, MacroCallKind};
@ -19,7 +20,7 @@ macro_rules! register_builtin {
fn find_by_name(name: &name::Name) -> Option<Self> { fn find_by_name(name: &name::Name) -> Option<Self> {
match name { match name {
$( id if id == &name::name![$name] => Some(BuiltinAttrExpander::$variant), )* $( id if id == &sym::$name => Some(BuiltinAttrExpander::$variant), )*
_ => None, _ => None,
} }
} }

View file

@ -1,5 +1,6 @@
//! Builtin derives. //! Builtin derives.
use intern::sym;
use itertools::izip; use itertools::izip;
use mbe::DocCommentDesugarMode; use mbe::DocCommentDesugarMode;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
@ -36,7 +37,7 @@ macro_rules! register_builtin {
fn find_by_name(name: &name::Name) -> Option<Self> { fn find_by_name(name: &name::Name) -> Option<Self> {
match name { match name {
$( id if id == &name::name![$trait] => Some(BuiltinDeriveExpander::$trait), )* $( id if id == &sym::$trait => Some(BuiltinDeriveExpander::$trait), )*
_ => None, _ => None,
} }
} }

View file

@ -3,6 +3,7 @@
use base_db::{AnchoredPath, FileId}; use base_db::{AnchoredPath, FileId};
use cfg::CfgExpr; use cfg::CfgExpr;
use either::Either; use either::Either;
use intern::sym;
use itertools::Itertools; use itertools::Itertools;
use mbe::{parse_exprs_with_sep, parse_to_token_tree}; use mbe::{parse_exprs_with_sep, parse_to_token_tree};
use span::{Edition, Span, SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID}; use span::{Edition, Span, SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID};
@ -11,8 +12,7 @@ use syntax::ast::{self, AstToken};
use crate::{ use crate::{
db::ExpandDatabase, db::ExpandDatabase,
hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt}, hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt},
name::{self, known}, name, quote,
quote,
quote::dollar_crate, quote::dollar_crate,
tt::{self, DelimSpan}, tt::{self, DelimSpan},
ExpandError, ExpandResult, HirFileIdExt, MacroCallId, MacroFileIdExt, ExpandError, ExpandResult, HirFileIdExt, MacroCallId, MacroFileIdExt,
@ -48,8 +48,8 @@ macro_rules! register_builtin {
fn find_by_name(ident: &name::Name) -> Option<Either<BuiltinFnLikeExpander, EagerExpander>> { fn find_by_name(ident: &name::Name) -> Option<Either<BuiltinFnLikeExpander, EagerExpander>> {
match ident { match ident {
$( id if id == &name::name![$name] => Some(Either::Left(BuiltinFnLikeExpander::$kind)), )* $( id if id == &sym::$name => Some(Either::Left(BuiltinFnLikeExpander::$kind)), )*
$( id if id == &name::name![$e_name] => Some(Either::Right(EagerExpander::$e_kind)), )* $( id if id == &sym::$e_name => Some(Either::Right(EagerExpander::$e_kind)), )*
_ => return None, _ => return None,
} }
} }
@ -367,8 +367,11 @@ fn panic_expand(
let dollar_crate = dollar_crate(span); let dollar_crate = dollar_crate(span);
let call_site_span = span_with_call_site_ctxt(db, span, id); let call_site_span = span_with_call_site_ctxt(db, span, id);
let mac = let mac = if use_panic_2021(db, call_site_span) {
if use_panic_2021(db, call_site_span) { known::panic_2021 } else { known::panic_2015 }; sym::panic_2021.clone()
} else {
sym::panic_2015.clone()
};
// Expand to a macro call `$crate::panic::panic_{edition}` // Expand to a macro call `$crate::panic::panic_{edition}`
let mut call = quote!(call_site_span =>#dollar_crate::panic::#mac!); let mut call = quote!(call_site_span =>#dollar_crate::panic::#mac!);
@ -397,9 +400,9 @@ fn unreachable_expand(
let call_site_span = span_with_call_site_ctxt(db, span, id); let call_site_span = span_with_call_site_ctxt(db, span, id);
let mac = if use_panic_2021(db, call_site_span) { let mac = if use_panic_2021(db, call_site_span) {
known::unreachable_2021 sym::unreachable_2021.clone()
} else { } else {
known::unreachable_2015 sym::unreachable_2015.clone()
}; };
// Expand to a macro call `$crate::panic::panic_{edition}` // Expand to a macro call `$crate::panic::panic_{edition}`
@ -432,7 +435,7 @@ fn use_panic_2021(db: &dyn ExpandDatabase, span: Span) -> bool {
// FIXME: Record allow_internal_unstable in the macro def (not been done yet because it // FIXME: Record allow_internal_unstable in the macro def (not been done yet because it
// would consume quite a bit extra memory for all call locs...) // would consume quite a bit extra memory for all call locs...)
// if let Some(features) = expn.def.allow_internal_unstable { // if let Some(features) = expn.def.allow_internal_unstable {
// if features.iter().any(|&f| f == sym::edition_panic) { // if features.iter().any(|&f| f == sym::edition_panic.clone()) {
// span = expn.call_site; // span = expn.call_site;
// continue; // continue;
// } // }

View file

@ -133,6 +133,15 @@ pub trait ExpandDatabase: SourceDatabase {
&self, &self,
macro_call: MacroCallId, macro_call: MacroCallId,
) -> Option<Arc<ExpandResult<Arc<[SyntaxError]>>>>; ) -> Option<Arc<ExpandResult<Arc<[SyntaxError]>>>>;
#[salsa::transparent]
fn syntax_context(&self, file: HirFileId) -> SyntaxContextId;
}
fn syntax_context(db: &dyn ExpandDatabase, file: HirFileId) -> SyntaxContextId {
match file.repr() {
HirFileIdRepr::FileId(_) => SyntaxContextId::ROOT,
HirFileIdRepr::MacroFile(m) => db.macro_arg(m.macro_call_id).2.ctx,
}
} }
/// This expands the given macro call, but with different arguments. This is /// This expands the given macro call, but with different arguments. This is

View file

@ -2,6 +2,7 @@
use std::sync::OnceLock; use std::sync::OnceLock;
use base_db::{CrateId, VersionReq}; use base_db::{CrateId, VersionReq};
use intern::sym;
use mbe::DocCommentDesugarMode; use mbe::DocCommentDesugarMode;
use span::{Edition, MacroCallId, Span, SyntaxContextId}; use span::{Edition, MacroCallId, Span, SyntaxContextId};
use stdx::TupleExt; use stdx::TupleExt;
@ -111,8 +112,10 @@ impl DeclarativeMacroExpander {
match &*attrs match &*attrs
.iter() .iter()
.find(|it| { .find(|it| {
it.path.as_ident().and_then(|it| it.as_str()) it.path
== Some("rustc_macro_transparency") .as_ident()
.map(|it| *it == sym::rustc_macro_transparency.clone())
.unwrap_or(false)
})? })?
.token_tree_value()? .token_tree_value()?
.token_trees .token_trees

View file

@ -553,7 +553,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
), ),
BuiltinAttribute { BuiltinAttribute {
// name: sym::rustc_diagnostic_item, // name: sym::rustc_diagnostic_item.clone(),
name: "rustc_diagnostic_item", name: "rustc_diagnostic_item",
// FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`. // FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`.
// only_local: false, // only_local: false,
@ -562,7 +562,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
// duplicates: ErrorFollowing, // duplicates: ErrorFollowing,
// gate: Gated( // gate: Gated(
// Stability::Unstable, // Stability::Unstable,
// sym::rustc_attrs, // sym::rustc_attrs.clone(),
// "diagnostic items compiler internal support for linting", // "diagnostic items compiler internal support for linting",
// cfg_fn!(rustc_attrs), // cfg_fn!(rustc_attrs),
// ), // ),

View file

@ -8,10 +8,11 @@ use std::{
use crate::{ use crate::{
db::ExpandDatabase, db::ExpandDatabase,
hygiene::{marks_rev, SyntaxContextExt, Transparency}, hygiene::{marks_rev, SyntaxContextExt, Transparency},
name::{known, AsName, Name}, name::{AsName, Name},
tt, tt,
}; };
use base_db::CrateId; use base_db::CrateId;
use intern::sym;
use smallvec::SmallVec; use smallvec::SmallVec;
use span::SyntaxContextId; use span::SyntaxContextId;
use syntax::{ast, AstNode}; use syntax::{ast, AstNode};
@ -106,10 +107,7 @@ impl ModPath {
PathKind::Abs => 0, PathKind::Abs => 0,
PathKind::DollarCrate(_) => "$crate".len(), PathKind::DollarCrate(_) => "$crate".len(),
}; };
self.segments() self.segments().iter().map(|segment| segment.as_str().len()).fold(base, core::ops::Add::add)
.iter()
.map(|segment| segment.as_str().map_or(0, str::len))
.fold(base, core::ops::Add::add)
} }
pub fn is_ident(&self) -> bool { pub fn is_ident(&self) -> bool {
@ -123,7 +121,7 @@ impl ModPath {
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn is_Self(&self) -> bool { pub fn is_Self(&self) -> bool {
self.kind == PathKind::Plain self.kind == PathKind::Plain
&& matches!(&*self.segments, [name] if *name == known::SELF_TYPE) && matches!(&*self.segments, [name] if *name == sym::Self_.clone())
} }
/// If this path is a single identifier, like `foo`, return its name. /// If this path is a single identifier, like `foo`, return its name.
@ -265,9 +263,10 @@ fn convert_path(
res res
} }
} }
ast::PathSegmentKind::SelfTypeKw => { ast::PathSegmentKind::SelfTypeKw => ModPath::from_segments(
ModPath::from_segments(PathKind::Plain, Some(known::SELF_TYPE)) PathKind::Plain,
} Some(Name::new_symbol(sym::Self_.clone(), SyntaxContextId::ROOT)),
),
ast::PathSegmentKind::CrateKw => ModPath::from_segments(PathKind::Crate, iter::empty()), ast::PathSegmentKind::CrateKw => ModPath::from_segments(PathKind::Crate, iter::empty()),
ast::PathSegmentKind::SelfKw => handle_super_kw(0)?, ast::PathSegmentKind::SelfKw => handle_super_kw(0)?,
ast::PathSegmentKind::SuperKw => handle_super_kw(1)?, ast::PathSegmentKind::SuperKw => handle_super_kw(1)?,
@ -323,9 +322,9 @@ fn convert_path_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree]) -> Option<ModP
tt::Leaf::Ident(tt::Ident { text, .. }) if text == "self" => PathKind::SELF, tt::Leaf::Ident(tt::Ident { text, .. }) if text == "self" => PathKind::SELF,
tt::Leaf::Ident(tt::Ident { text, .. }) if text == "super" => { tt::Leaf::Ident(tt::Ident { text, .. }) if text == "super" => {
let mut deg = 1; let mut deg = 1;
while let Some(tt::Leaf::Ident(tt::Ident { text, .. })) = leaves.next() { while let Some(tt::Leaf::Ident(tt::Ident { text, span, .. })) = leaves.next() {
if text != "super" { if text != "super" {
segments.push(Name::new_text_dont_use(text.clone())); segments.push(Name::new(text, span.ctx));
break; break;
} }
deg += 1; deg += 1;
@ -334,13 +333,13 @@ fn convert_path_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree]) -> Option<ModP
} }
tt::Leaf::Ident(tt::Ident { text, .. }) if text == "crate" => PathKind::Crate, tt::Leaf::Ident(tt::Ident { text, .. }) if text == "crate" => PathKind::Crate,
tt::Leaf::Ident(ident) => { tt::Leaf::Ident(ident) => {
segments.push(Name::new_text_dont_use(ident.text.clone())); segments.push(Name::new(&ident.text, ident.span.ctx));
PathKind::Plain PathKind::Plain
} }
_ => return None, _ => return None,
}; };
segments.extend(leaves.filter_map(|leaf| match leaf { segments.extend(leaves.filter_map(|leaf| match leaf {
::tt::Leaf::Ident(ident) => Some(Name::new_text_dont_use(ident.text.clone())), ::tt::Leaf::Ident(ident) => Some(Name::new(&ident.text, ident.span.ctx)),
_ => None, _ => None,
})); }));
Some(ModPath { kind, segments }) Some(ModPath { kind, segments })
@ -385,6 +384,8 @@ macro_rules! __known_path {
(core::ops::RangeInclusive) => {}; (core::ops::RangeInclusive) => {};
(core::future::Future) => {}; (core::future::Future) => {};
(core::future::IntoFuture) => {}; (core::future::IntoFuture) => {};
(core::fmt::Debug) => {};
(std::fmt::format) => {};
(core::ops::Try) => {}; (core::ops::Try) => {};
($path:path) => { ($path:path) => {
compile_error!("Please register your known path in the path module") compile_error!("Please register your known path in the path module")
@ -396,7 +397,7 @@ macro_rules! __path {
($start:ident $(:: $seg:ident)*) => ({ ($start:ident $(:: $seg:ident)*) => ({
$crate::__known_path!($start $(:: $seg)*); $crate::__known_path!($start $(:: $seg)*);
$crate::mod_path::ModPath::from_segments($crate::mod_path::PathKind::Abs, vec![ $crate::mod_path::ModPath::from_segments($crate::mod_path::PathKind::Abs, vec![
$crate::mod_path::__name![$start], $($crate::mod_path::__name![$seg],)* $crate::name::Name::new_symbol_root(intern::sym::$start.clone()), $($crate::name::Name::new_symbol_root(intern::sym::$seg.clone()),)*
]) ])
}); });
} }

View file

@ -2,6 +2,8 @@
use std::fmt; use std::fmt;
use intern::{sym, Symbol};
use span::SyntaxContextId;
use syntax::{ast, format_smolstr, utils::is_raw_identifier, SmolStr}; use syntax::{ast, format_smolstr, utils::is_raw_identifier, SmolStr};
/// `Name` is a wrapper around string, which is used in hir for both references /// `Name` is a wrapper around string, which is used in hir for both references
@ -11,32 +13,58 @@ use syntax::{ast, format_smolstr, utils::is_raw_identifier, SmolStr};
/// Note that `Name` holds and prints escaped name i.e. prefixed with "r#" when it /// Note that `Name` holds and prints escaped name i.e. prefixed with "r#" when it
/// is a raw identifier. Use [`unescaped()`][Name::unescaped] when you need the /// is a raw identifier. Use [`unescaped()`][Name::unescaped] when you need the
/// name without "r#". /// name without "r#".
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] #[derive(Clone, PartialEq, Eq, Hash)]
pub struct Name(Repr); pub struct Name {
symbol: Symbol,
ctx: (),
}
impl fmt::Debug for Name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Name")
.field("symbol", &self.symbol.as_str())
.field("ctx", &self.ctx)
.finish()
}
}
impl Ord for Name {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.symbol.as_str().cmp(other.symbol.as_str())
}
}
impl PartialOrd for Name {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq<Symbol> for Name {
fn eq(&self, sym: &Symbol) -> bool {
self.symbol == *sym
}
}
impl PartialEq<Name> for Symbol {
fn eq(&self, name: &Name) -> bool {
*self == name.symbol
}
}
/// Wrapper of `Name` to print the name without "r#" even when it is a raw identifier. /// Wrapper of `Name` to print the name without "r#" even when it is a raw identifier.
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct UnescapedName<'a>(&'a Name); pub struct UnescapedName<'a>(&'a Name);
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
enum Repr {
Text(SmolStr),
TupleField(usize),
}
impl UnescapedName<'_> { impl UnescapedName<'_> {
/// Returns the textual representation of this name as a [`SmolStr`]. Prefer using this over /// Returns the textual representation of this name as a [`SmolStr`]. Prefer using this over
/// [`ToString::to_string`] if possible as this conversion is cheaper in the general case. /// [`ToString::to_string`] if possible as this conversion is cheaper in the general case.
pub fn to_smol_str(&self) -> SmolStr { pub fn to_smol_str(&self) -> SmolStr {
match &self.0 .0 { let it = self.0.symbol.as_str();
Repr::Text(it) => { if let Some(stripped) = it.strip_prefix("r#") {
if let Some(stripped) = it.strip_prefix("r#") { SmolStr::new(stripped)
SmolStr::new(stripped) } else {
} else { it.into()
it.clone()
}
}
Repr::TupleField(it) => SmolStr::new(it.to_string()),
} }
} }
@ -50,27 +78,26 @@ impl Name {
/// Note: this is private to make creating name from random string hard. /// Note: this is private to make creating name from random string hard.
/// Hopefully, this should allow us to integrate hygiene cleaner in the /// Hopefully, this should allow us to integrate hygiene cleaner in the
/// future, and to switch to interned representation of names. /// future, and to switch to interned representation of names.
const fn new_text(text: SmolStr) -> Name { fn new_text(text: &str) -> Name {
Name(Repr::Text(text)) Name { symbol: Symbol::intern(text), ctx: () }
} }
// FIXME: See above, unfortunately some places really need this right now pub fn new(text: &str, ctx: SyntaxContextId) -> Name {
#[doc(hidden)] _ = ctx;
pub const fn new_text_dont_use(text: SmolStr) -> Name { Name { symbol: Symbol::intern(text), ctx: () }
Name(Repr::Text(text))
} }
pub fn new_tuple_field(idx: usize) -> Name { pub fn new_tuple_field(idx: usize) -> Name {
Name(Repr::TupleField(idx)) Name { symbol: Symbol::intern(&idx.to_string()), ctx: () }
} }
pub fn new_lifetime(lt: &ast::Lifetime) -> Name { pub fn new_lifetime(lt: &ast::Lifetime) -> Name {
Self::new_text(lt.text().into()) Name { symbol: Symbol::intern(lt.text().as_str()), ctx: () }
} }
/// Shortcut to create a name from a string literal. /// Shortcut to create a name from a string literal.
const fn new_static(text: &'static str) -> Name { fn new_ref(text: &str) -> Name {
Name::new_text(SmolStr::new_static(text)) Name { symbol: Symbol::intern(text), ctx: () }
} }
/// Resolve a name from the text of token. /// Resolve a name from the text of token.
@ -78,14 +105,14 @@ impl Name {
match raw_text.strip_prefix("r#") { match raw_text.strip_prefix("r#") {
// When `raw_text` starts with "r#" but the name does not coincide with any // When `raw_text` starts with "r#" but the name does not coincide with any
// keyword, we never need the prefix so we strip it. // keyword, we never need the prefix so we strip it.
Some(text) if !is_raw_identifier(text) => Name::new_text(SmolStr::new(text)), Some(text) if !is_raw_identifier(text) => Name::new_ref(text),
// Keywords (in the current edition) *can* be used as a name in earlier editions of // Keywords (in the current edition) *can* be used as a name in earlier editions of
// Rust, e.g. "try" in Rust 2015. Even in such cases, we keep track of them in their // Rust, e.g. "try" in Rust 2015. Even in such cases, we keep track of them in their
// escaped form. // escaped form.
None if is_raw_identifier(raw_text) => { None if is_raw_identifier(raw_text) => {
Name::new_text(format_smolstr!("r#{}", raw_text)) Name::new_text(&format_smolstr!("r#{}", raw_text))
} }
_ => Name::new_text(raw_text.into()), _ => Name::new_text(raw_text),
} }
} }
@ -98,8 +125,8 @@ impl Name {
/// Ideally, we want a `gensym` semantics for missing names -- each missing /// Ideally, we want a `gensym` semantics for missing names -- each missing
/// name is equal only to itself. It's not clear how to implement this in /// name is equal only to itself. It's not clear how to implement this in
/// salsa though, so we punt on that bit for a moment. /// salsa though, so we punt on that bit for a moment.
pub const fn missing() -> Name { pub fn missing() -> Name {
Name::new_static("[missing name]") Name { symbol: sym::MISSING_NAME.clone(), ctx: () }
} }
/// Returns true if this is a fake name for things missing in the source code. See /// Returns true if this is a fake name for things missing in the source code. See
@ -115,41 +142,25 @@ impl Name {
/// creating desugared locals and labels. The caller is responsible for picking an index /// creating desugared locals and labels. The caller is responsible for picking an index
/// that is stable across re-executions /// that is stable across re-executions
pub fn generate_new_name(idx: usize) -> Name { pub fn generate_new_name(idx: usize) -> Name {
Name::new_text(format_smolstr!("<ra@gennew>{idx}")) Name::new_text(&format_smolstr!("<ra@gennew>{idx}"))
} }
/// Returns the tuple index this name represents if it is a tuple field. /// Returns the tuple index this name represents if it is a tuple field.
pub fn as_tuple_index(&self) -> Option<usize> { pub fn as_tuple_index(&self) -> Option<usize> {
match self.0 { self.symbol.as_str().parse().ok()
Repr::TupleField(idx) => Some(idx),
_ => None,
}
} }
/// Returns the text this name represents if it isn't a tuple field. /// Returns the text this name represents if it isn't a tuple field.
pub fn as_text(&self) -> Option<SmolStr> { pub fn as_str(&self) -> &str {
match &self.0 { self.symbol.as_str()
Repr::Text(it) => Some(it.clone()),
_ => None,
}
}
/// Returns the text this name represents if it isn't a tuple field.
pub fn as_str(&self) -> Option<&str> {
match &self.0 {
Repr::Text(it) => Some(it),
_ => None,
}
} }
// FIXME: Remove this
/// Returns the textual representation of this name as a [`SmolStr`]. /// Returns the textual representation of this name as a [`SmolStr`].
/// Prefer using this over [`ToString::to_string`] if possible as this conversion is cheaper in /// Prefer using this over [`ToString::to_string`] if possible as this conversion is cheaper in
/// the general case. /// the general case.
pub fn to_smol_str(&self) -> SmolStr { pub fn to_smol_str(&self) -> SmolStr {
match &self.0 { self.symbol.as_str().into()
Repr::Text(it) => it.clone(),
Repr::TupleField(it) => SmolStr::new(it.to_string()),
}
} }
pub fn unescaped(&self) -> UnescapedName<'_> { pub fn unescaped(&self) -> UnescapedName<'_> {
@ -157,16 +168,27 @@ impl Name {
} }
pub fn is_escaped(&self) -> bool { pub fn is_escaped(&self) -> bool {
match &self.0 { self.symbol.as_str().starts_with("r#")
Repr::Text(it) => it.starts_with("r#"),
Repr::TupleField(_) => false,
}
} }
pub fn display<'a>(&'a self, db: &dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a { pub fn display<'a>(&'a self, db: &dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a {
_ = db; _ = db;
Display { name: self } Display { name: self }
} }
pub fn symbol(&self) -> &Symbol {
&self.symbol
}
pub const fn new_symbol(doc: Symbol, ctx: SyntaxContextId) -> Self {
_ = ctx;
Self { symbol: doc, ctx: () }
}
// FIXME: This needs to go once we have hygiene
pub const fn new_symbol_root(doc: Symbol) -> Self {
Self { symbol: doc, ctx: () }
}
} }
struct Display<'a> { struct Display<'a> {
@ -175,10 +197,7 @@ struct Display<'a> {
impl fmt::Display for Display<'_> { impl fmt::Display for Display<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.name.0 { fmt::Display::fmt(self.name.symbol.as_str(), f)
Repr::Text(text) => fmt::Display::fmt(&text, f),
Repr::TupleField(idx) => fmt::Display::fmt(&idx, f),
}
} }
} }
@ -188,13 +207,9 @@ struct UnescapedDisplay<'a> {
impl fmt::Display for UnescapedDisplay<'_> { impl fmt::Display for UnescapedDisplay<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.name.0 .0 { let symbol = &self.name.0.symbol.as_str();
Repr::Text(text) => { let text = symbol.strip_prefix("r#").unwrap_or(symbol);
let text = text.strip_prefix("r#").unwrap_or(text); fmt::Display::fmt(&text, f)
fmt::Display::fmt(&text, f)
}
Repr::TupleField(idx) => fmt::Display::fmt(&idx, f),
}
} }
} }
@ -246,251 +261,6 @@ impl AsName for ast::FieldKind {
impl AsName for base_db::Dependency { impl AsName for base_db::Dependency {
fn as_name(&self) -> Name { fn as_name(&self) -> Name {
Name::new_text(SmolStr::new(&*self.name)) Name::new_text(&self.name)
} }
} }
pub mod known {
macro_rules! known_names {
($($ident:ident),* $(,)?) => {
$(
#[allow(bad_style)]
pub const $ident: super::Name =
super::Name::new_static(stringify!($ident));
)*
};
}
known_names!(
// Primitives
isize,
i8,
i16,
i32,
i64,
i128,
usize,
u8,
u16,
u32,
u64,
u128,
f16,
f32,
f64,
f128,
bool,
char,
str,
// Special names
macro_rules,
doc,
cfg,
cfg_attr,
register_attr,
register_tool,
// Components of known path (value or mod name)
std,
core,
alloc,
iter,
ops,
fmt,
future,
result,
string,
boxed,
option,
prelude,
rust_2015,
rust_2018,
rust_2021,
rust_2024,
v1,
new_display,
new_debug,
new_lower_exp,
new_upper_exp,
new_octal,
new_pointer,
new_binary,
new_lower_hex,
new_upper_hex,
from_usize,
panic_2015,
panic_2021,
unreachable_2015,
unreachable_2021,
// Components of known path (type name)
Iterator,
IntoIterator,
Item,
IntoIter,
Try,
Ok,
Future,
IntoFuture,
Result,
Option,
Output,
Target,
Box,
RangeFrom,
RangeFull,
RangeInclusive,
RangeToInclusive,
RangeTo,
Range,
String,
Neg,
Not,
None,
Index,
Left,
Right,
Center,
Unknown,
Is,
Param,
Implied,
// Components of known path (function name)
filter_map,
next,
iter_mut,
len,
is_empty,
as_str,
new,
new_v1_formatted,
none,
// Builtin macros
asm,
assert,
column,
compile_error,
concat_idents,
concat_bytes,
concat,
const_format_args,
core_panic,
env,
file,
format,
format_args_nl,
format_args,
global_asm,
include_bytes,
include_str,
include,
line,
llvm_asm,
log_syntax,
module_path,
option_env,
quote,
std_panic,
stringify,
trace_macros,
unreachable,
// Builtin derives
Copy,
Clone,
Default,
Debug,
Hash,
Ord,
PartialOrd,
Eq,
PartialEq,
// Builtin attributes
bench,
cfg_accessible,
cfg_eval,
crate_type,
derive,
derive_const,
global_allocator,
no_core,
no_std,
test,
test_case,
recursion_limit,
feature,
// known methods of lang items
call_once,
call_mut,
call,
eq,
ne,
ge,
gt,
le,
lt,
// known fields of lang items
pieces,
// lang items
add_assign,
add,
bitand_assign,
bitand,
bitor_assign,
bitor,
bitxor_assign,
bitxor,
branch,
deref_mut,
deref,
div_assign,
div,
drop,
fn_mut,
fn_once,
future_trait,
index,
index_mut,
into_future,
mul_assign,
mul,
neg,
not,
owned_box,
partial_ord,
poll,
r#fn,
rem_assign,
rem,
shl_assign,
shl,
shr_assign,
shr,
sub_assign,
sub,
unsafe_cell,
va_list
);
// self/Self cannot be used as an identifier
pub const SELF_PARAM: super::Name = super::Name::new_static("self");
pub const SELF_TYPE: super::Name = super::Name::new_static("Self");
pub const STATIC_LIFETIME: super::Name = super::Name::new_static("'static");
pub const DOLLAR_CRATE: super::Name = super::Name::new_static("$crate");
#[macro_export]
macro_rules! name {
(self) => {
$crate::name::known::SELF_PARAM
};
(Self) => {
$crate::name::known::SELF_TYPE
};
('static) => {
$crate::name::known::STATIC_LIFETIME
};
($ident:ident) => {
$crate::name::known::$ident
};
}
}
pub use crate::name;

View file

@ -1,6 +1,7 @@
//! A simplified version of quote-crate like quasi quote macro //! A simplified version of quote-crate like quasi quote macro
#![allow(clippy::crate_in_macro_def)] #![allow(clippy::crate_in_macro_def)]
use intern::Symbol;
use span::Span; use span::Span;
use syntax::format_smolstr; use syntax::format_smolstr;
@ -219,6 +220,7 @@ impl_to_to_tokentrees! {
span: &str => self { crate::tt::Literal{text: format_smolstr!("\"{}\"", self.escape_default()), span}}; span: &str => self { crate::tt::Literal{text: format_smolstr!("\"{}\"", self.escape_default()), span}};
span: String => self { crate::tt::Literal{text: format_smolstr!("\"{}\"", self.escape_default()), span}}; span: String => self { crate::tt::Literal{text: format_smolstr!("\"{}\"", self.escape_default()), span}};
span: Name => self { crate::tt::Ident{text: self.to_smol_str(), span}}; span: Name => self { crate::tt::Ident{text: self.to_smol_str(), span}};
span: Symbol => self { crate::tt::Ident{text: self.as_str().into(), span}};
} }
#[cfg(test)] #[cfg(test)]

View file

@ -5,7 +5,8 @@
use chalk_ir::cast::Cast; use chalk_ir::cast::Cast;
use hir_def::lang_item::LangItem; use hir_def::lang_item::LangItem;
use hir_expand::name::name; use hir_expand::name::Name;
use intern::sym;
use limit::Limit; use limit::Limit;
use triomphe::Arc; use triomphe::Arc;
@ -151,7 +152,9 @@ pub(crate) fn deref_by_trait(
let deref_trait = let deref_trait =
db.lang_item(table.trait_env.krate, LangItem::Deref).and_then(|l| l.as_trait())?; db.lang_item(table.trait_env.krate, LangItem::Deref).and_then(|l| l.as_trait())?;
let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?; let target = db
.trait_data(deref_trait)
.associated_type_by_name(&Name::new_symbol_root(sym::Target.clone()))?;
let projection = { let projection = {
let b = TyBuilder::subst_for_def(db, deref_trait, None); let b = TyBuilder::subst_for_def(db, deref_trait, None);

View file

@ -3,6 +3,8 @@
use core::ops; use core::ops;
use std::{iter, ops::ControlFlow, sync::Arc}; use std::{iter, ops::ControlFlow, sync::Arc};
use hir_expand::name::Name;
use intern::sym;
use tracing::debug; use tracing::debug;
use chalk_ir::{cast::Caster, fold::shift::Shift, CanonicalVarKinds}; use chalk_ir::{cast::Caster, fold::shift::Shift, CanonicalVarKinds};
@ -16,7 +18,6 @@ use hir_def::{
AssocItemId, BlockId, CallableDefId, GenericDefId, HasModule, ItemContainerId, Lookup, AssocItemId, BlockId, CallableDefId, GenericDefId, HasModule, ItemContainerId, Lookup,
TypeAliasId, VariantId, TypeAliasId, VariantId,
}; };
use hir_expand::name::name;
use crate::{ use crate::{
db::{HirDatabase, InternedCoroutine}, db::{HirDatabase, InternedCoroutine},
@ -288,15 +289,16 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
chalk_ir::Binders::new(binders, bound) chalk_ir::Binders::new(binders, bound)
} }
crate::ImplTraitId::AsyncBlockTypeImplTrait(..) => { crate::ImplTraitId::AsyncBlockTypeImplTrait(..) => {
if let Some((future_trait, future_output)) = self if let Some((future_trait, future_output)) =
.db self.db
.lang_item(self.krate, LangItem::Future) .lang_item(self.krate, LangItem::Future)
.and_then(|item| item.as_trait()) .and_then(|item| item.as_trait())
.and_then(|trait_| { .and_then(|trait_| {
let alias = let alias = self.db.trait_data(trait_).associated_type_by_name(
self.db.trait_data(trait_).associated_type_by_name(&name![Output])?; &Name::new_symbol_root(sym::Output.clone()),
Some((trait_, alias)) )?;
}) Some((trait_, alias))
})
{ {
// Making up Symbols value as variable is void: AsyncBlock<T>: // Making up Symbols value as variable is void: AsyncBlock<T>:
// //

View file

@ -247,7 +247,7 @@ impl<'a> DeclValidator<'a> {
// Check the module name. // Check the module name.
let Some(module_name) = module_id.name(self.db.upcast()) else { return }; let Some(module_name) = module_id.name(self.db.upcast()) else { return };
let Some(module_name_replacement) = let Some(module_name_replacement) =
module_name.as_str().and_then(to_lower_snake_case).map(|new_name| Replacement { to_lower_snake_case(module_name.as_str()).map(|new_name| Replacement {
current_name: module_name, current_name: module_name,
suggested_text: new_name, suggested_text: new_name,
expected_case: CaseType::LowerSnakeCase, expected_case: CaseType::LowerSnakeCase,

View file

@ -8,7 +8,7 @@ use either::Either;
use hir_def::lang_item::LangItem; use hir_def::lang_item::LangItem;
use hir_def::{resolver::HasResolver, AdtId, AssocItemId, DefWithBodyId, HasModule}; use hir_def::{resolver::HasResolver, AdtId, AssocItemId, DefWithBodyId, HasModule};
use hir_def::{ItemContainerId, Lookup}; use hir_def::{ItemContainerId, Lookup};
use hir_expand::name; use intern::sym;
use itertools::Itertools; use itertools::Itertools;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use rustc_pattern_analysis::constructor::Constructor; use rustc_pattern_analysis::constructor::Constructor;
@ -423,7 +423,9 @@ impl FilterMapNextChecker {
ItemContainerId::TraitId(iterator_trait_id) => { ItemContainerId::TraitId(iterator_trait_id) => {
let iterator_trait_items = &db.trait_data(iterator_trait_id).items; let iterator_trait_items = &db.trait_data(iterator_trait_id).items;
iterator_trait_items.iter().find_map(|(name, it)| match it { iterator_trait_items.iter().find_map(|(name, it)| match it {
&AssocItemId::FunctionId(id) if *name == name![filter_map] => Some(id), &AssocItemId::FunctionId(id) if *name == sym::filter_map.clone() => {
Some(id)
}
_ => None, _ => None,
}) })
} }

View file

@ -25,7 +25,7 @@ use hir_def::{
ModuleId, TraitId, ModuleId, TraitId,
}; };
use hir_expand::name::Name; use hir_expand::name::Name;
use intern::{Internable, Interned}; use intern::{sym, Internable, Interned};
use itertools::Itertools; use itertools::Itertools;
use la_arena::ArenaMap; use la_arena::ArenaMap;
use rustc_apfloat::{ use rustc_apfloat::{
@ -1171,7 +1171,9 @@ impl HirDisplay for Ty {
.lang_item(body.module(db.upcast()).krate(), LangItem::Future) .lang_item(body.module(db.upcast()).krate(), LangItem::Future)
.and_then(LangItemTarget::as_trait); .and_then(LangItemTarget::as_trait);
let output = future_trait.and_then(|t| { let output = future_trait.and_then(|t| {
db.trait_data(t).associated_type_by_name(&hir_expand::name!(Output)) db.trait_data(t).associated_type_by_name(&Name::new_symbol_root(
sym::Output.clone(),
))
}); });
write!(f, "impl ")?; write!(f, "impl ")?;
if let Some(t) = future_trait { if let Some(t) = future_trait {

View file

@ -46,8 +46,9 @@ use hir_def::{
AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, Lookup, TraitId, AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, Lookup, TraitId,
TupleFieldId, TupleId, TypeAliasId, VariantId, TupleFieldId, TupleId, TypeAliasId, VariantId,
}; };
use hir_expand::name::{name, Name}; use hir_expand::name::Name;
use indexmap::IndexSet; use indexmap::IndexSet;
use intern::sym;
use la_arena::{ArenaMap, Entry}; use la_arena::{ArenaMap, Entry};
use once_cell::unsync::OnceCell; use once_cell::unsync::OnceCell;
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
@ -1424,7 +1425,9 @@ impl<'a> InferenceContext<'a> {
} }
fn resolve_output_on(&self, trait_: TraitId) -> Option<TypeAliasId> { fn resolve_output_on(&self, trait_: TraitId) -> Option<TypeAliasId> {
self.db.trait_data(trait_).associated_type_by_name(&name![Output]) self.db
.trait_data(trait_)
.associated_type_by_name(&Name::new_symbol_root(sym::Output.clone()))
} }
fn resolve_lang_trait(&self, lang: LangItem) -> Option<TraitId> { fn resolve_lang_trait(&self, lang: LangItem) -> Option<TraitId> {

View file

@ -15,7 +15,8 @@ use hir_def::{
resolver::{resolver_for_expr, ResolveValueResult, ValueNs}, resolver::{resolver_for_expr, ResolveValueResult, ValueNs},
DefWithBodyId, FieldId, HasModule, TupleFieldId, TupleId, VariantId, DefWithBodyId, FieldId, HasModule, TupleFieldId, TupleId, VariantId,
}; };
use hir_expand::name; use hir_expand::name::Name;
use intern::sym;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use smallvec::SmallVec; use smallvec::SmallVec;
use stdx::never; use stdx::never;
@ -268,9 +269,7 @@ 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) => { VariantData::Record(fields) => fields[f.local_id].name.as_str().to_owned(),
fields[f.local_id].name.as_str().unwrap_or("[missing field]").to_owned()
}
VariantData::Tuple(fields) => fields VariantData::Tuple(fields) => fields
.iter() .iter()
.position(|it| it.0 == f.local_id) .position(|it| it.0 == f.local_id)
@ -621,8 +620,10 @@ impl InferenceContext<'_> {
if let Some(deref_trait) = if let Some(deref_trait) =
self.resolve_lang_item(LangItem::DerefMut).and_then(|it| it.as_trait()) self.resolve_lang_item(LangItem::DerefMut).and_then(|it| it.as_trait())
{ {
if let Some(deref_fn) = if let Some(deref_fn) = self
self.db.trait_data(deref_trait).method_by_name(&name![deref_mut]) .db
.trait_data(deref_trait)
.method_by_name(&Name::new_symbol_root(sym::deref_mut.clone()))
{ {
break 'b deref_fn == f; break 'b deref_fn == f;
} }

View file

@ -15,7 +15,8 @@ use hir_def::{
path::{GenericArgs, Path}, path::{GenericArgs, Path},
BlockId, FieldId, GenericDefId, GenericParamId, ItemContainerId, Lookup, TupleFieldId, TupleId, BlockId, FieldId, GenericDefId, GenericParamId, ItemContainerId, Lookup, TupleFieldId, TupleId,
}; };
use hir_expand::name::{name, Name}; use hir_expand::name::Name;
use intern::sym;
use stdx::always; use stdx::always;
use syntax::ast::RangeOp; use syntax::ast::RangeOp;
@ -646,8 +647,10 @@ impl InferenceContext<'_> {
match op { match op {
UnaryOp::Deref => { UnaryOp::Deref => {
if let Some(deref_trait) = self.resolve_lang_trait(LangItem::Deref) { if let Some(deref_trait) = self.resolve_lang_trait(LangItem::Deref) {
if let Some(deref_fn) = if let Some(deref_fn) = self
self.db.trait_data(deref_trait).method_by_name(&name![deref]) .db
.trait_data(deref_trait)
.method_by_name(&Name::new_symbol_root(sym::deref.clone()))
{ {
// FIXME: this is wrong in multiple ways, subst is empty, and we emit it even for builtin deref (note that // FIXME: this is wrong in multiple ways, subst is empty, and we emit it even for builtin deref (note that
// the mutability is not wrong, and will be fixed in `self.infer_mut`). // the mutability is not wrong, and will be fixed in `self.infer_mut`).
@ -785,8 +788,10 @@ impl InferenceContext<'_> {
// mutability will be fixed up in `InferenceContext::infer_mut`; // mutability will be fixed up in `InferenceContext::infer_mut`;
adj.push(Adjustment::borrow(Mutability::Not, self_ty.clone())); adj.push(Adjustment::borrow(Mutability::Not, self_ty.clone()));
self.write_expr_adj(*base, adj); self.write_expr_adj(*base, adj);
if let Some(func) = if let Some(func) = self
self.db.trait_data(index_trait).method_by_name(&name!(index)) .db
.trait_data(index_trait)
.method_by_name(&Name::new_symbol_root(sym::index.clone()))
{ {
let substs = TyBuilder::subst_for_def(self.db, index_trait, None) let substs = TyBuilder::subst_for_def(self.db, index_trait, None)
.push(self_ty.clone()) .push(self_ty.clone())

View file

@ -6,7 +6,8 @@ use hir_def::{
hir::{Array, BinaryOp, BindingAnnotation, Expr, ExprId, PatId, Statement, UnaryOp}, hir::{Array, BinaryOp, BindingAnnotation, Expr, ExprId, PatId, Statement, UnaryOp},
lang_item::LangItem, lang_item::LangItem,
}; };
use hir_expand::name; use hir_expand::name::Name;
use intern::sym;
use crate::{lower::lower_to_chalk_mutability, Adjust, Adjustment, AutoBorrow, OverloadedDeref}; use crate::{lower::lower_to_chalk_mutability, Adjust, Adjustment, AutoBorrow, OverloadedDeref};
@ -108,8 +109,10 @@ impl InferenceContext<'_> {
.lang_item(self.table.trait_env.krate, LangItem::IndexMut) .lang_item(self.table.trait_env.krate, LangItem::IndexMut)
.and_then(|l| l.as_trait()) .and_then(|l| l.as_trait())
{ {
if let Some(index_fn) = if let Some(index_fn) = self
self.db.trait_data(index_trait).method_by_name(&name![index_mut]) .db
.trait_data(index_trait)
.method_by_name(&Name::new_symbol_root(sym::index_mut.clone()))
{ {
*f = index_fn; *f = index_fn;
let base_adjustments = self let base_adjustments = self
@ -139,8 +142,10 @@ impl InferenceContext<'_> {
.lang_item(self.table.trait_env.krate, LangItem::DerefMut) .lang_item(self.table.trait_env.krate, LangItem::DerefMut)
.and_then(|l| l.as_trait()) .and_then(|l| l.as_trait())
{ {
if let Some(deref_fn) = if let Some(deref_fn) = self
self.db.trait_data(deref_trait).method_by_name(&name![deref_mut]) .db
.trait_data(deref_trait)
.method_by_name(&Name::new_symbol_root(sym::deref_mut.clone()))
{ {
*f = deref_fn; *f = deref_fn;
} }

View file

@ -7,6 +7,7 @@ use hir_def::{
AdtId, AssocItemId, GenericDefId, ItemContainerId, Lookup, AdtId, AssocItemId, GenericDefId, ItemContainerId, Lookup,
}; };
use hir_expand::name::Name; use hir_expand::name::Name;
use intern::sym;
use stdx::never; use stdx::never;
use crate::{ use crate::{
@ -227,7 +228,7 @@ impl InferenceContext<'_> {
Path::LangItem(..) => ( Path::LangItem(..) => (
PathSegment { PathSegment {
name: { name: {
_d = hir_expand::name::known::Unknown; _d = Name::new_symbol_root(sym::Unknown.clone());
&_d &_d
}, },
args_and_bindings: None, args_and_bindings: None,

View file

@ -9,7 +9,8 @@ use chalk_ir::{
use chalk_solve::infer::ParameterEnaVariableExt; use chalk_solve::infer::ParameterEnaVariableExt;
use either::Either; use either::Either;
use ena::unify::UnifyKey; use ena::unify::UnifyKey;
use hir_expand::name; use hir_expand::name::Name;
use intern::sym;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use smallvec::SmallVec; use smallvec::SmallVec;
use triomphe::Arc; use triomphe::Arc;
@ -781,7 +782,8 @@ impl<'a> InferenceTable<'a> {
let krate = self.trait_env.krate; let krate = self.trait_env.krate;
let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?; let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?;
let trait_data = self.db.trait_data(fn_once_trait); let trait_data = self.db.trait_data(fn_once_trait);
let output_assoc_type = trait_data.associated_type_by_name(&name![Output])?; let output_assoc_type =
trait_data.associated_type_by_name(&Name::new_symbol_root(sym::Output.clone()))?;
let mut arg_tys = Vec::with_capacity(num_args); let mut arg_tys = Vec::with_capacity(num_args);
let arg_ty = TyBuilder::tuple(num_args) let arg_ty = TyBuilder::tuple(num_args)

View file

@ -2,6 +2,7 @@
use hir_def::{data::adt::StructFlags, lang_item::LangItem, AdtId}; use hir_def::{data::adt::StructFlags, lang_item::LangItem, AdtId};
use hir_expand::name::Name; use hir_expand::name::Name;
use intern::sym;
use crate::db::HirDatabase; use crate::db::HirDatabase;
@ -16,48 +17,57 @@ pub fn is_unsafe_cell(db: &dyn HirDatabase, adt: AdtId) -> bool {
} }
pub fn lang_items_for_bin_op(op: syntax::ast::BinaryOp) -> Option<(Name, LangItem)> { pub fn lang_items_for_bin_op(op: syntax::ast::BinaryOp) -> Option<(Name, LangItem)> {
use hir_expand::name;
use syntax::ast::{ArithOp, BinaryOp, CmpOp, Ordering}; use syntax::ast::{ArithOp, BinaryOp, CmpOp, Ordering};
Some(match op { Some(match op {
BinaryOp::LogicOp(_) => return None, BinaryOp::LogicOp(_) => return None,
BinaryOp::ArithOp(aop) => match aop { BinaryOp::ArithOp(aop) => match aop {
ArithOp::Add => (name![add], LangItem::Add), ArithOp::Add => (Name::new_symbol_root(sym::add.clone()), LangItem::Add),
ArithOp::Mul => (name![mul], LangItem::Mul), ArithOp::Mul => (Name::new_symbol_root(sym::mul.clone()), LangItem::Mul),
ArithOp::Sub => (name![sub], LangItem::Sub), ArithOp::Sub => (Name::new_symbol_root(sym::sub.clone()), LangItem::Sub),
ArithOp::Div => (name![div], LangItem::Div), ArithOp::Div => (Name::new_symbol_root(sym::div.clone()), LangItem::Div),
ArithOp::Rem => (name![rem], LangItem::Rem), ArithOp::Rem => (Name::new_symbol_root(sym::rem.clone()), LangItem::Rem),
ArithOp::Shl => (name![shl], LangItem::Shl), ArithOp::Shl => (Name::new_symbol_root(sym::shl.clone()), LangItem::Shl),
ArithOp::Shr => (name![shr], LangItem::Shr), ArithOp::Shr => (Name::new_symbol_root(sym::shr.clone()), LangItem::Shr),
ArithOp::BitXor => (name![bitxor], LangItem::BitXor), ArithOp::BitXor => (Name::new_symbol_root(sym::bitxor.clone()), LangItem::BitXor),
ArithOp::BitOr => (name![bitor], LangItem::BitOr), ArithOp::BitOr => (Name::new_symbol_root(sym::bitor.clone()), LangItem::BitOr),
ArithOp::BitAnd => (name![bitand], LangItem::BitAnd), ArithOp::BitAnd => (Name::new_symbol_root(sym::bitand.clone()), LangItem::BitAnd),
}, },
BinaryOp::Assignment { op: Some(aop) } => match aop { BinaryOp::Assignment { op: Some(aop) } => match aop {
ArithOp::Add => (name![add_assign], LangItem::AddAssign), ArithOp::Add => (Name::new_symbol_root(sym::add_assign.clone()), LangItem::AddAssign),
ArithOp::Mul => (name![mul_assign], LangItem::MulAssign), ArithOp::Mul => (Name::new_symbol_root(sym::mul_assign.clone()), LangItem::MulAssign),
ArithOp::Sub => (name![sub_assign], LangItem::SubAssign), ArithOp::Sub => (Name::new_symbol_root(sym::sub_assign.clone()), LangItem::SubAssign),
ArithOp::Div => (name![div_assign], LangItem::DivAssign), ArithOp::Div => (Name::new_symbol_root(sym::div_assign.clone()), LangItem::DivAssign),
ArithOp::Rem => (name![rem_assign], LangItem::RemAssign), ArithOp::Rem => (Name::new_symbol_root(sym::rem_assign.clone()), LangItem::RemAssign),
ArithOp::Shl => (name![shl_assign], LangItem::ShlAssign), ArithOp::Shl => (Name::new_symbol_root(sym::shl_assign.clone()), LangItem::ShlAssign),
ArithOp::Shr => (name![shr_assign], LangItem::ShrAssign), ArithOp::Shr => (Name::new_symbol_root(sym::shr_assign.clone()), LangItem::ShrAssign),
ArithOp::BitXor => (name![bitxor_assign], LangItem::BitXorAssign), ArithOp::BitXor => {
ArithOp::BitOr => (name![bitor_assign], LangItem::BitOrAssign), (Name::new_symbol_root(sym::bitxor_assign.clone()), LangItem::BitXorAssign)
ArithOp::BitAnd => (name![bitand_assign], LangItem::BitAndAssign), }
ArithOp::BitOr => {
(Name::new_symbol_root(sym::bitor_assign.clone()), LangItem::BitOrAssign)
}
ArithOp::BitAnd => {
(Name::new_symbol_root(sym::bitand_assign.clone()), LangItem::BitAndAssign)
}
}, },
BinaryOp::CmpOp(cop) => match cop { BinaryOp::CmpOp(cop) => match cop {
CmpOp::Eq { negated: false } => (name![eq], LangItem::PartialEq), CmpOp::Eq { negated: false } => {
CmpOp::Eq { negated: true } => (name![ne], LangItem::PartialEq), (Name::new_symbol_root(sym::eq.clone()), LangItem::PartialEq)
}
CmpOp::Eq { negated: true } => {
(Name::new_symbol_root(sym::ne.clone()), LangItem::PartialEq)
}
CmpOp::Ord { ordering: Ordering::Less, strict: false } => { CmpOp::Ord { ordering: Ordering::Less, strict: false } => {
(name![le], LangItem::PartialOrd) (Name::new_symbol_root(sym::le.clone()), LangItem::PartialOrd)
} }
CmpOp::Ord { ordering: Ordering::Less, strict: true } => { CmpOp::Ord { ordering: Ordering::Less, strict: true } => {
(name![lt], LangItem::PartialOrd) (Name::new_symbol_root(sym::lt.clone()), LangItem::PartialOrd)
} }
CmpOp::Ord { ordering: Ordering::Greater, strict: false } => { CmpOp::Ord { ordering: Ordering::Greater, strict: false } => {
(name![ge], LangItem::PartialOrd) (Name::new_symbol_root(sym::ge.clone()), LangItem::PartialOrd)
} }
CmpOp::Ord { ordering: Ordering::Greater, strict: true } => { CmpOp::Ord { ordering: Ordering::Greater, strict: true } => {
(name![gt], LangItem::PartialOrd) (Name::new_symbol_root(sym::gt.clone()), LangItem::PartialOrd)
} }
}, },
BinaryOp::Assignment { op: None } => return None, BinaryOp::Assignment { op: None } => return None,

View file

@ -61,7 +61,8 @@ use chalk_ir::{
}; };
use either::Either; use either::Either;
use hir_def::{hir::ExprId, type_ref::Rawness, CallableDefId, GeneralConstId, TypeOrConstParamId}; use hir_def::{hir::ExprId, type_ref::Rawness, CallableDefId, GeneralConstId, TypeOrConstParamId};
use hir_expand::name; use hir_expand::name::Name;
use intern::sym;
use la_arena::{Arena, Idx}; use la_arena::{Arena, Idx};
use mir::{MirEvalError, VTableMap}; use mir::{MirEvalError, VTableMap};
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
@ -894,7 +895,9 @@ pub fn callable_sig_from_fn_trait(
) -> Option<(FnTrait, CallableSig)> { ) -> Option<(FnTrait, CallableSig)> {
let krate = trait_env.krate; let krate = trait_env.krate;
let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?; let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?;
let output_assoc_type = db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?; let output_assoc_type = db
.trait_data(fn_once_trait)
.associated_type_by_name(&Name::new_symbol_root(sym::Output.clone()))?;
let mut table = InferenceTable::new(db, trait_env.clone()); let mut table = InferenceTable::new(db, trait_env.clone());
let b = TyBuilder::trait_ref(db, fn_once_trait); let b = TyBuilder::trait_ref(db, fn_once_trait);

View file

@ -14,8 +14,8 @@ use hir_def::{
AdtId, ConstId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, AdtId, ConstId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup,
StaticId, VariantId, StaticId, VariantId,
}; };
use hir_expand::{mod_path::ModPath, HirFileIdExt, InFile}; use hir_expand::{mod_path::path, name::Name, HirFileIdExt, InFile};
use intern::Interned; use intern::{sym, Interned};
use la_arena::ArenaMap; use la_arena::ArenaMap;
use rustc_abi::TargetDataLayout; use rustc_abi::TargetDataLayout;
use rustc_apfloat::{ use rustc_apfloat::{
@ -35,7 +35,7 @@ use crate::{
layout::{Layout, LayoutError, RustcEnumVariantIdx}, layout::{Layout, LayoutError, RustcEnumVariantIdx},
mapping::from_chalk, mapping::from_chalk,
method_resolution::{is_dyn_method, lookup_impl_const}, method_resolution::{is_dyn_method, lookup_impl_const},
name, static_lifetime, static_lifetime,
traits::FnTrait, traits::FnTrait,
utils::{detect_variant_from_bytes, ClosureSubst}, utils::{detect_variant_from_bytes, ClosureSubst},
CallableDefId, ClosureId, ComplexMemoryMap, Const, ConstScalar, FnDefId, Interner, MemoryMap, CallableDefId, ClosureId, ComplexMemoryMap, Const, ConstScalar, FnDefId, Interner, MemoryMap,
@ -631,15 +631,21 @@ impl Evaluator<'_> {
cached_fn_trait_func: db cached_fn_trait_func: db
.lang_item(crate_id, LangItem::Fn) .lang_item(crate_id, LangItem::Fn)
.and_then(|x| x.as_trait()) .and_then(|x| x.as_trait())
.and_then(|x| db.trait_data(x).method_by_name(&name![call])), .and_then(|x| {
db.trait_data(x).method_by_name(&Name::new_symbol_root(sym::call.clone()))
}),
cached_fn_mut_trait_func: db cached_fn_mut_trait_func: db
.lang_item(crate_id, LangItem::FnMut) .lang_item(crate_id, LangItem::FnMut)
.and_then(|x| x.as_trait()) .and_then(|x| x.as_trait())
.and_then(|x| db.trait_data(x).method_by_name(&name![call_mut])), .and_then(|x| {
db.trait_data(x).method_by_name(&Name::new_symbol_root(sym::call_mut.clone()))
}),
cached_fn_once_trait_func: db cached_fn_once_trait_func: db
.lang_item(crate_id, LangItem::FnOnce) .lang_item(crate_id, LangItem::FnOnce)
.and_then(|x| x.as_trait()) .and_then(|x| x.as_trait())
.and_then(|x| db.trait_data(x).method_by_name(&name![call_once])), .and_then(|x| {
db.trait_data(x).method_by_name(&Name::new_symbol_root(sym::call_once.clone()))
}),
}) })
} }
@ -2633,10 +2639,7 @@ impl Evaluator<'_> {
let static_data = self.db.static_data(st); let static_data = self.db.static_data(st);
let result = if !static_data.is_extern { let result = if !static_data.is_extern {
let konst = self.db.const_eval_static(st).map_err(|e| { let konst = self.db.const_eval_static(st).map_err(|e| {
MirEvalError::ConstEvalError( MirEvalError::ConstEvalError(static_data.name.as_str().to_owned(), Box::new(e))
static_data.name.as_str().unwrap_or("_").to_owned(),
Box::new(e),
)
})?; })?;
self.allocate_const_in_heap(locals, &konst)? self.allocate_const_in_heap(locals, &konst)?
} else { } else {
@ -2693,7 +2696,7 @@ impl Evaluator<'_> {
) -> Result<()> { ) -> Result<()> {
let Some(drop_fn) = (|| { let Some(drop_fn) = (|| {
let drop_trait = self.db.lang_item(self.crate_id, LangItem::Drop)?.as_trait()?; let drop_trait = self.db.lang_item(self.crate_id, LangItem::Drop)?.as_trait()?;
self.db.trait_data(drop_trait).method_by_name(&name![drop]) self.db.trait_data(drop_trait).method_by_name(&Name::new_symbol_root(sym::drop.clone()))
})() else { })() else {
// in some tests we don't have drop trait in minicore, and // in some tests we don't have drop trait in minicore, and
// we can ignore drop in them. // we can ignore drop in them.
@ -2797,14 +2800,13 @@ pub fn render_const_using_debug_impl(
let resolver = owner.resolver(db.upcast()); let resolver = owner.resolver(db.upcast());
let Some(TypeNs::TraitId(debug_trait)) = resolver.resolve_path_in_type_ns_fully( let Some(TypeNs::TraitId(debug_trait)) = resolver.resolve_path_in_type_ns_fully(
db.upcast(), db.upcast(),
&hir_def::path::Path::from_known_path_with_no_generic(ModPath::from_segments( &hir_def::path::Path::from_known_path_with_no_generic(path![core::fmt::Debug]),
hir_expand::mod_path::PathKind::Abs,
[name![core], name![fmt], name![Debug]],
)),
) else { ) else {
not_supported!("core::fmt::Debug not found"); not_supported!("core::fmt::Debug not found");
}; };
let Some(debug_fmt_fn) = db.trait_data(debug_trait).method_by_name(&name![fmt]) else { let Some(debug_fmt_fn) =
db.trait_data(debug_trait).method_by_name(&Name::new_symbol_root(sym::fmt.clone()))
else {
not_supported!("core::fmt::Debug::fmt not found"); not_supported!("core::fmt::Debug::fmt not found");
}; };
// a1 = &[""] // a1 = &[""]
@ -2829,10 +2831,7 @@ pub fn render_const_using_debug_impl(
evaluator.write_memory(a3.offset(5 * evaluator.ptr_size()), &[1])?; evaluator.write_memory(a3.offset(5 * evaluator.ptr_size()), &[1])?;
let Some(ValueNs::FunctionId(format_fn)) = resolver.resolve_path_in_value_ns_fully( let Some(ValueNs::FunctionId(format_fn)) = resolver.resolve_path_in_value_ns_fully(
db.upcast(), db.upcast(),
&hir_def::path::Path::from_known_path_with_no_generic(ModPath::from_segments( &hir_def::path::Path::from_known_path_with_no_generic(path![std::fmt::format]),
hir_expand::mod_path::PathKind::Abs,
[name![std], name![fmt], name![format]],
)),
) else { ) else {
not_supported!("std::fmt::format not found"); not_supported!("std::fmt::format not found");
}; };

View file

@ -8,12 +8,14 @@ use hir_def::{
builtin_type::{BuiltinInt, BuiltinUint}, builtin_type::{BuiltinInt, BuiltinUint},
resolver::HasResolver, resolver::HasResolver,
}; };
use hir_expand::name::Name;
use intern::sym;
use crate::{ use crate::{
error_lifetime, error_lifetime,
mir::eval::{ mir::eval::{
name, pad16, Address, AdtId, Arc, BuiltinType, Evaluator, FunctionId, HasModule, pad16, Address, AdtId, Arc, BuiltinType, Evaluator, FunctionId, HasModule, HirDisplay,
HirDisplay, Interned, InternedClosure, Interner, Interval, IntervalAndTy, IntervalOrOwned, Interned, InternedClosure, Interner, Interval, IntervalAndTy, IntervalOrOwned,
ItemContainerId, LangItem, Layout, Locals, Lookup, MirEvalError, MirSpan, Mutability, ItemContainerId, LangItem, Layout, Locals, Lookup, MirEvalError, MirSpan, Mutability,
Result, Substitution, Ty, TyBuilder, TyExt, Result, Substitution, Ty, TyBuilder, TyExt,
}, },
@ -64,7 +66,7 @@ impl Evaluator<'_> {
}; };
if is_intrinsic { if is_intrinsic {
self.exec_intrinsic( self.exec_intrinsic(
function_data.name.as_text().unwrap_or_default().as_str(), function_data.name.as_str(),
args, args,
generic_args, generic_args,
destination, destination,
@ -86,7 +88,7 @@ impl Evaluator<'_> {
}; };
if is_platform_intrinsic { if is_platform_intrinsic {
self.exec_platform_intrinsic( self.exec_platform_intrinsic(
function_data.name.as_text().unwrap_or_default().as_str(), function_data.name.as_str(),
args, args,
generic_args, generic_args,
destination, destination,
@ -104,7 +106,7 @@ impl Evaluator<'_> {
}; };
if is_extern_c { if is_extern_c {
self.exec_extern_c( self.exec_extern_c(
function_data.name.as_text().unwrap_or_default().as_str(), function_data.name.as_str(),
args, args,
generic_args, generic_args,
destination, destination,
@ -117,7 +119,7 @@ impl Evaluator<'_> {
.attrs .attrs
.iter() .iter()
.filter_map(|it| it.path().as_ident()) .filter_map(|it| it.path().as_ident())
.filter_map(|it| it.as_str()) .map(|it| it.as_str())
.find(|it| { .find(|it| {
[ [
"rustc_allocator", "rustc_allocator",
@ -317,7 +319,7 @@ impl Evaluator<'_> {
return Some(LangItem::BeginPanic); return Some(LangItem::BeginPanic);
} }
let candidate = attrs.by_key("lang").string_value().and_then(LangItem::from_str)?; let candidate = attrs.lang_item()?;
// We want to execute these functions with special logic // We want to execute these functions with special logic
// `PanicFmt` is not detected here as it's redirected later. // `PanicFmt` is not detected here as it's redirected later.
if [BeginPanic, SliceLen, DropInPlace].contains(&candidate) { if [BeginPanic, SliceLen, DropInPlace].contains(&candidate) {
@ -1274,10 +1276,11 @@ impl Evaluator<'_> {
args.push(IntervalAndTy::new(addr, field, self, locals)?); args.push(IntervalAndTy::new(addr, field, self, locals)?);
} }
if let Some(target) = self.db.lang_item(self.crate_id, LangItem::FnOnce) { if let Some(target) = self.db.lang_item(self.crate_id, LangItem::FnOnce) {
if let Some(def) = target if let Some(def) = target.as_trait().and_then(|it| {
.as_trait() self.db
.and_then(|it| self.db.trait_data(it).method_by_name(&name![call_once])) .trait_data(it)
{ .method_by_name(&Name::new_symbol_root(sym::call_once.clone()))
}) {
self.exec_fn_trait( self.exec_fn_trait(
def, def,
&args, &args,

View file

@ -1113,9 +1113,9 @@ impl<'ctx> MirLowerCtx<'ctx> {
.iter() .iter()
.map(|it| { .map(|it| {
let o = match it.1.name.as_str() { let o = match it.1.name.as_str() {
Some("start") => lp.take(), "start" => lp.take(),
Some("end") => rp.take(), "end" => rp.take(),
Some("exhausted") => { "exhausted" => {
Some(Operand::from_bytes(Box::new([0]), TyBuilder::bool())) Some(Operand::from_bytes(Box::new([0]), TyBuilder::bool()))
} }
_ => None, _ => None,

View file

@ -4,7 +4,7 @@ use crate::mir::MutBorrowKind;
use super::*; use super::*;
use hir_def::FunctionId; use hir_def::FunctionId;
use hir_expand::name; use intern::sym;
macro_rules! not_supported { macro_rules! not_supported {
($it: expr) => { ($it: expr) => {
@ -189,10 +189,10 @@ impl MirLowerCtx<'_> {
if let Some(deref_trait) = if let Some(deref_trait) =
self.resolve_lang_item(LangItem::DerefMut)?.as_trait() self.resolve_lang_item(LangItem::DerefMut)?.as_trait()
{ {
if let Some(deref_fn) = self if let Some(deref_fn) =
.db self.db.trait_data(deref_trait).method_by_name(
.trait_data(deref_trait) &Name::new_symbol_root(sym::deref_mut.clone()),
.method_by_name(&name![deref_mut]) )
{ {
break 'b deref_fn == f; break 'b deref_fn == f;
} }
@ -324,12 +324,17 @@ impl MirLowerCtx<'_> {
mutability: bool, mutability: bool,
) -> Result<Option<(Place, BasicBlockId)>> { ) -> Result<Option<(Place, BasicBlockId)>> {
let (chalk_mut, trait_lang_item, trait_method_name, borrow_kind) = if !mutability { let (chalk_mut, trait_lang_item, trait_method_name, borrow_kind) = if !mutability {
(Mutability::Not, LangItem::Deref, name![deref], BorrowKind::Shared) (
Mutability::Not,
LangItem::Deref,
Name::new_symbol_root(sym::deref.clone()),
BorrowKind::Shared,
)
} else { } else {
( (
Mutability::Mut, Mutability::Mut,
LangItem::DerefMut, LangItem::DerefMut,
name![deref_mut], Name::new_symbol_root(sym::deref_mut.clone()),
BorrowKind::Mut { kind: MutBorrowKind::Default }, BorrowKind::Mut { kind: MutBorrowKind::Default },
) )
}; };

View file

@ -12,7 +12,8 @@ use hir_def::{
lang_item::{LangItem, LangItemTarget}, lang_item::{LangItem, LangItemTarget},
BlockId, TraitId, BlockId, TraitId,
}; };
use hir_expand::name::{name, Name}; use hir_expand::name::Name;
use intern::sym;
use stdx::panic_context; use stdx::panic_context;
use triomphe::Arc; use triomphe::Arc;
@ -256,9 +257,9 @@ impl FnTrait {
pub fn method_name(self) -> Name { pub fn method_name(self) -> Name {
match self { match self {
FnTrait::FnOnce => name!(call_once), FnTrait::FnOnce => Name::new_symbol_root(sym::call_once.clone()),
FnTrait::FnMut => name!(call_mut), FnTrait::FnMut => Name::new_symbol_root(sym::call_mut.clone()),
FnTrait::Fn => name!(call), FnTrait::Fn => Name::new_symbol_root(sym::call.clone()),
} }
} }

View file

@ -12,6 +12,7 @@ use hir_def::{
}; };
use hir_expand::{mod_path::PathKind, name::Name}; use hir_expand::{mod_path::PathKind, name::Name};
use hir_ty::{db::HirDatabase, method_resolution}; use hir_ty::{db::HirDatabase, method_resolution};
use span::SyntaxContextId;
use crate::{ use crate::{
Adt, AsAssocItem, AssocItem, BuiltinType, Const, ConstParam, DocLinkDef, Enum, ExternCrateDecl, Adt, AsAssocItem, AssocItem, BuiltinType, Const, ConstParam, DocLinkDef, Enum, ExternCrateDecl,
@ -328,7 +329,7 @@ fn doc_modpath_from_str(link: &str) -> Option<ModPath> {
let parts = first_segment.into_iter().chain(parts).map(|segment| match segment.parse() { let parts = first_segment.into_iter().chain(parts).map(|segment| match segment.parse() {
Ok(idx) => Name::new_tuple_field(idx), Ok(idx) => Name::new_tuple_field(idx),
Err(_) => { Err(_) => {
Name::new_text_dont_use(segment.split_once('<').map_or(segment, |it| it.0).into()) Name::new(segment.split_once('<').map_or(segment, |it| it.0), SyntaxContextId::ROOT)
} }
}); });
Some(ModPath::from_segments(kind, parts)) Some(ModPath::from_segments(kind, parts))

View file

@ -58,7 +58,7 @@ use hir_def::{
TypeOrConstParamId, TypeParamId, UnionId, TypeOrConstParamId, TypeParamId, UnionId,
}; };
use hir_expand::{ use hir_expand::{
attrs::collect_attrs, name::name, proc_macro::ProcMacroKind, AstId, MacroCallKind, ValueResult, attrs::collect_attrs, proc_macro::ProcMacroKind, AstId, MacroCallKind, ValueResult,
}; };
use hir_ty::{ use hir_ty::{
all_super_traits, autoderef, check_orphan_rules, all_super_traits, autoderef, check_orphan_rules,
@ -131,7 +131,7 @@ pub use {
change::ChangeWithProcMacros, change::ChangeWithProcMacros,
hygiene::{marks_rev, SyntaxContextExt}, hygiene::{marks_rev, SyntaxContextExt},
inert_attr_macro::AttributeTemplate, inert_attr_macro::AttributeTemplate,
name::{known, Name}, name::Name,
proc_macro::ProcMacros, proc_macro::ProcMacros,
tt, ExpandResult, HirFileId, HirFileIdExt, InFile, InMacroFile, InRealFile, MacroFileId, tt, ExpandResult, HirFileId, HirFileIdExt, InFile, InMacroFile, InRealFile, MacroFileId,
MacroFileIdExt, MacroFileIdExt,
@ -145,6 +145,7 @@ pub use {
}, },
// FIXME: Properly encapsulate mir // FIXME: Properly encapsulate mir
hir_ty::{mir, Interner as ChalkTyInterner}, hir_ty::{mir, Interner as ChalkTyInterner},
intern::{sym, Symbol},
}; };
// These are negative re-exports: pub using these names is forbidden, they // These are negative re-exports: pub using these names is forbidden, they
@ -1826,7 +1827,7 @@ impl DefWithBody {
continue; continue;
} }
let mut need_mut = &mol[local]; let mut need_mut = &mol[local];
if body[binding_id].name.as_str() == Some("self") if body[binding_id].name == sym::self_.clone()
&& need_mut == &mir::MutabilityReason::Unused && need_mut == &mir::MutabilityReason::Unused
{ {
need_mut = &mir::MutabilityReason::Not; need_mut = &mir::MutabilityReason::Not;
@ -1836,7 +1837,7 @@ impl DefWithBody {
match (need_mut, is_mut) { match (need_mut, is_mut) {
(mir::MutabilityReason::Unused, _) => { (mir::MutabilityReason::Unused, _) => {
let should_ignore = matches!(body[binding_id].name.as_str(), Some(it) if it.starts_with('_')); let should_ignore = body[binding_id].name.as_str().starts_with('_');
if !should_ignore { if !should_ignore {
acc.push(UnusedVariable { local }.into()) acc.push(UnusedVariable { local }.into())
} }
@ -1866,7 +1867,7 @@ impl DefWithBody {
} }
(mir::MutabilityReason::Not, true) => { (mir::MutabilityReason::Not, true) => {
if !infer.mutated_bindings_in_closure.contains(&binding_id) { if !infer.mutated_bindings_in_closure.contains(&binding_id) {
let should_ignore = matches!(body[binding_id].name.as_str(), Some(it) if it.starts_with('_')); let should_ignore = body[binding_id].name.as_str().starts_with('_');
if !should_ignore { if !should_ignore {
acc.push(UnusedMut { local }.into()) acc.push(UnusedMut { local }.into())
} }
@ -2588,7 +2589,7 @@ pub struct StaticLifetime;
impl StaticLifetime { impl StaticLifetime {
pub fn name(self) -> Name { pub fn name(self) -> Name {
known::STATIC_LIFETIME Name::new_symbol_root(sym::tick_static.clone())
} }
} }
@ -3248,7 +3249,7 @@ impl Local {
} }
pub fn is_self(self, db: &dyn HirDatabase) -> bool { pub fn is_self(self, db: &dyn HirDatabase) -> bool {
self.name(db) == name![self] self.name(db) == sym::self_.clone()
} }
pub fn is_mut(self, db: &dyn HirDatabase) -> bool { pub fn is_mut(self, db: &dyn HirDatabase) -> bool {

View file

@ -25,11 +25,8 @@ use hir_def::{
}; };
use hir_expand::{ use hir_expand::{
mod_path::path, mod_path::path,
name::{AsName, Name},
HirFileId, InFile, InMacroFile, MacroFileId, MacroFileIdExt, HirFileId, InFile, InMacroFile, MacroFileId, MacroFileIdExt,
{
name,
name::{AsName, Name},
},
}; };
use hir_ty::{ use hir_ty::{
diagnostics::{ diagnostics::{
@ -40,6 +37,7 @@ use hir_ty::{
method_resolution, Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, method_resolution, Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind,
TyLoweringContext, TyLoweringContext,
}; };
use intern::sym;
use itertools::Itertools; use itertools::Itertools;
use smallvec::SmallVec; use smallvec::SmallVec;
use syntax::{ use syntax::{
@ -368,7 +366,7 @@ impl SourceAnalyzer {
let items = into_future_trait.items(db); let items = into_future_trait.items(db);
let into_future_type = items.into_iter().find_map(|item| match item { let into_future_type = items.into_iter().find_map(|item| match item {
AssocItem::TypeAlias(alias) AssocItem::TypeAlias(alias)
if alias.name(db) == hir_expand::name![IntoFuture] => if alias.name(db) == Name::new_symbol_root(sym::IntoFuture.clone()) =>
{ {
Some(alias) Some(alias)
} }
@ -397,15 +395,21 @@ impl SourceAnalyzer {
// This can be either `Deref::deref` or `DerefMut::deref_mut`. // This can be either `Deref::deref` or `DerefMut::deref_mut`.
// Since deref kind is inferenced and stored in `InferenceResult.method_resolution`, // Since deref kind is inferenced and stored in `InferenceResult.method_resolution`,
// use that result to find out which one it is. // use that result to find out which one it is.
let (deref_trait, deref) = let (deref_trait, deref) = self.lang_trait_fn(
self.lang_trait_fn(db, LangItem::Deref, &name![deref])?; db,
LangItem::Deref,
&Name::new_symbol_root(sym::deref.clone()),
)?;
self.infer self.infer
.as_ref() .as_ref()
.and_then(|infer| { .and_then(|infer| {
let expr = self.expr_id(db, &prefix_expr.clone().into())?; let expr = self.expr_id(db, &prefix_expr.clone().into())?;
let (func, _) = infer.method_resolution(expr)?; let (func, _) = infer.method_resolution(expr)?;
let (deref_mut_trait, deref_mut) = let (deref_mut_trait, deref_mut) = self.lang_trait_fn(
self.lang_trait_fn(db, LangItem::DerefMut, &name![deref_mut])?; db,
LangItem::DerefMut,
&Name::new_symbol_root(sym::deref_mut.clone()),
)?;
if func == deref_mut { if func == deref_mut {
Some((deref_mut_trait, deref_mut)) Some((deref_mut_trait, deref_mut))
} else { } else {
@ -414,8 +418,12 @@ impl SourceAnalyzer {
}) })
.unwrap_or((deref_trait, deref)) .unwrap_or((deref_trait, deref))
} }
ast::UnaryOp::Not => self.lang_trait_fn(db, LangItem::Not, &name![not])?, ast::UnaryOp::Not => {
ast::UnaryOp::Neg => self.lang_trait_fn(db, LangItem::Neg, &name![neg])?, self.lang_trait_fn(db, LangItem::Not, &Name::new_symbol_root(sym::not.clone()))?
}
ast::UnaryOp::Neg => {
self.lang_trait_fn(db, LangItem::Neg, &Name::new_symbol_root(sym::neg.clone()))?
}
}; };
let ty = self.ty_of_expr(db, &prefix_expr.expr()?)?; let ty = self.ty_of_expr(db, &prefix_expr.expr()?)?;
@ -435,15 +443,19 @@ impl SourceAnalyzer {
let base_ty = self.ty_of_expr(db, &index_expr.base()?)?; let base_ty = self.ty_of_expr(db, &index_expr.base()?)?;
let index_ty = self.ty_of_expr(db, &index_expr.index()?)?; let index_ty = self.ty_of_expr(db, &index_expr.index()?)?;
let (index_trait, index_fn) = self.lang_trait_fn(db, LangItem::Index, &name![index])?; let (index_trait, index_fn) =
self.lang_trait_fn(db, LangItem::Index, &Name::new_symbol_root(sym::index.clone()))?;
let (op_trait, op_fn) = self let (op_trait, op_fn) = self
.infer .infer
.as_ref() .as_ref()
.and_then(|infer| { .and_then(|infer| {
let expr = self.expr_id(db, &index_expr.clone().into())?; let expr = self.expr_id(db, &index_expr.clone().into())?;
let (func, _) = infer.method_resolution(expr)?; let (func, _) = infer.method_resolution(expr)?;
let (index_mut_trait, index_mut_fn) = let (index_mut_trait, index_mut_fn) = self.lang_trait_fn(
self.lang_trait_fn(db, LangItem::IndexMut, &name![index_mut])?; db,
LangItem::IndexMut,
&Name::new_symbol_root(sym::index_mut.clone()),
)?;
if func == index_mut_fn { if func == index_mut_fn {
Some((index_mut_trait, index_mut_fn)) Some((index_mut_trait, index_mut_fn))
} else { } else {

View file

@ -239,7 +239,7 @@ impl<'a> SymbolCollector<'a> {
fn collect_from_trait(&mut self, trait_id: TraitId) { fn collect_from_trait(&mut self, trait_id: TraitId) {
let trait_data = self.db.trait_data(trait_id); let trait_data = self.db.trait_data(trait_id);
self.with_container_name(trait_data.name.as_text(), |s| { self.with_container_name(Some(trait_data.name.as_str().into()), |s| {
for &(_, assoc_item_id) in &trait_data.items { for &(_, assoc_item_id) in &trait_data.items {
s.push_assoc_item(assoc_item_id); s.push_assoc_item(assoc_item_id);
} }

View file

@ -1637,8 +1637,8 @@ mod bar {
#[test] #[test]
fn local_inline_import_has_alias() { fn local_inline_import_has_alias() {
// FIXME // FIXME wrong import
check_assist_not_applicable( check_assist(
auto_import, auto_import,
r#" r#"
struct S<T>(T); struct S<T>(T);
@ -1647,14 +1647,24 @@ use S as IoResult;
mod foo { mod foo {
pub fn bar() -> S$0<()> {} pub fn bar() -> S$0<()> {}
} }
"#,
r#"
struct S<T>(T);
use S as IoResult;
mod foo {
use crate::S;
pub fn bar() -> S<()> {}
}
"#, "#,
); );
} }
#[test] #[test]
fn alias_local() { fn alias_local() {
// FIXME // FIXME wrong import
check_assist_not_applicable( check_assist(
auto_import, auto_import,
r#" r#"
struct S<T>(T); struct S<T>(T);
@ -1663,6 +1673,16 @@ use S as IoResult;
mod foo { mod foo {
pub fn bar() -> IoResult$0<()> {} pub fn bar() -> IoResult$0<()> {}
} }
"#,
r#"
struct S<T>(T);
use S as IoResult;
mod foo {
use crate::S;
pub fn bar() -> IoResult<()> {}
}
"#, "#,
); );
} }

View file

@ -470,7 +470,7 @@ fn add_enum_def(
.module() .module()
.scope(ctx.db(), Some(*target_module)) .scope(ctx.db(), Some(*target_module))
.iter() .iter()
.any(|(name, _)| name.as_str() == Some("Bool")) .any(|(name, _)| name.as_str() == "Bool")
{ {
return None; return None;
} }

View file

@ -1,4 +1,4 @@
use hir::{known, AsAssocItem, Semantics}; use hir::{sym, AsAssocItem, Semantics};
use ide_db::{ use ide_db::{
famous_defs::FamousDefs, famous_defs::FamousDefs,
syntax_helpers::node_ext::{ syntax_helpers::node_ext::{
@ -223,7 +223,7 @@ fn option_variants(
let fam = FamousDefs(sema, sema.scope(expr)?.krate()); let fam = FamousDefs(sema, sema.scope(expr)?.krate());
let option_variants = fam.core_option_Option()?.variants(sema.db); let option_variants = fam.core_option_Option()?.variants(sema.db);
match &*option_variants { match &*option_variants {
&[variant0, variant1] => Some(if variant0.name(sema.db) == known::None { &[variant0, variant1] => Some(if variant0.name(sema.db) == sym::None.clone() {
(variant0, variant1) (variant0, variant1)
} else { } else {
(variant1, variant0) (variant1, variant0)

View file

@ -1,4 +1,4 @@
use hir::known; use hir::{sym, Name};
use ide_db::famous_defs::FamousDefs; use ide_db::famous_defs::FamousDefs;
use stdx::format_to; use stdx::format_to;
use syntax::{ use syntax::{
@ -149,7 +149,11 @@ fn is_ref_and_impls_iter_method(
ast::Expr::RefExpr(r) => r, ast::Expr::RefExpr(r) => r,
_ => return None, _ => return None,
}; };
let wanted_method = if ref_expr.mut_token().is_some() { known::iter_mut } else { known::iter }; let wanted_method = Name::new_symbol_root(if ref_expr.mut_token().is_some() {
sym::iter_mut.clone()
} else {
sym::iter.clone()
});
let expr_behind_ref = ref_expr.expr()?; let expr_behind_ref = ref_expr.expr()?;
let ty = sema.type_of_expr(&expr_behind_ref)?.adjusted(); let ty = sema.type_of_expr(&expr_behind_ref)?.adjusted();
let scope = sema.scope(iterable.syntax())?; let scope = sema.scope(iterable.syntax())?;

View file

@ -169,8 +169,8 @@ fn get_names_in_scope(
let mut names = FxHashSet::default(); let mut names = FxHashSet::default();
scope.process_all_names(&mut |name, scope| { scope.process_all_names(&mut |name, scope| {
if let (Some(name), hir::ScopeDef::Local(_)) = (name.as_text(), scope) { if let hir::ScopeDef::Local(_) = scope {
names.insert(name); names.insert(name.as_str().into());
} }
}); });
Some(names) Some(names)

View file

@ -1,4 +1,4 @@
use hir::{known, HasSource, Name}; use hir::{sym, HasSource, Name};
use syntax::{ use syntax::{
ast::{self, HasName}, ast::{self, HasName},
AstNode, AstNode,
@ -54,13 +54,13 @@ pub(crate) fn generate_is_empty_from_len(acc: &mut Assists, ctx: &AssistContext<
} }
let impl_ = fn_node.syntax().ancestors().find_map(ast::Impl::cast)?; let impl_ = fn_node.syntax().ancestors().find_map(ast::Impl::cast)?;
let len_fn = get_impl_method(ctx, &impl_, &known::len)?; let len_fn = get_impl_method(ctx, &impl_, &Name::new_symbol_root(sym::len.clone()))?;
if !len_fn.ret_type(ctx.sema.db).is_usize() { if !len_fn.ret_type(ctx.sema.db).is_usize() {
cov_mark::hit!(len_fn_different_return_type); cov_mark::hit!(len_fn_different_return_type);
return None; return None;
} }
if get_impl_method(ctx, &impl_, &known::is_empty).is_some() { if get_impl_method(ctx, &impl_, &Name::new_symbol_root(sym::is_empty.clone())).is_some() {
cov_mark::hit!(is_empty_already_implemented); cov_mark::hit!(is_empty_already_implemented);
return None; return None;
} }

View file

@ -2,7 +2,7 @@ use std::collections::BTreeSet;
use ast::make; use ast::make;
use either::Either; use either::Either;
use hir::{db::HirDatabase, PathResolution, Semantics, TypeInfo}; use hir::{db::HirDatabase, sym, PathResolution, Semantics, TypeInfo};
use ide_db::{ use ide_db::{
base_db::{FileId, FileRange}, base_db::{FileId, FileRange},
defs::Definition, defs::Definition,
@ -430,10 +430,7 @@ fn inline(
let ty = sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty); let ty = sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty);
let is_self = param let is_self = param.name(sema.db).is_some_and(|name| name == sym::self_.clone());
.name(sema.db)
.and_then(|name| name.as_text())
.is_some_and(|name| name == "self");
if is_self { if is_self {
let mut this_pat = make::ident_pat(false, false, make::name("this")); let mut this_pat = make::ident_pat(false, false, make::name("this"));

View file

@ -47,7 +47,7 @@ pub(crate) fn replace_with_lazy_method(acc: &mut Assists, ctx: &AssistContext<'_
None, None,
None, None,
|func| { |func| {
let valid = func.name(ctx.sema.db).as_str() == Some(&*method_name_lazy) let valid = func.name(ctx.sema.db).as_str() == &*method_name_lazy
&& func.num_params(ctx.sema.db) == n_params && func.num_params(ctx.sema.db) == n_params
&& { && {
let params = func.params_without_self(ctx.sema.db); let params = func.params_without_self(ctx.sema.db);
@ -133,7 +133,7 @@ pub(crate) fn replace_with_eager_method(acc: &mut Assists, ctx: &AssistContext<'
None, None,
None, None,
|func| { |func| {
let valid = func.name(ctx.sema.db).as_str() == Some(method_name_eager) let valid = func.name(ctx.sema.db).as_str() == method_name_eager
&& func.num_params(ctx.sema.db) == n_params; && func.num_params(ctx.sema.db) == n_params;
valid.then_some(func) valid.then_some(func)
}, },

View file

@ -88,8 +88,8 @@ pub fn has_test_related_attribute(attrs: &hir::AttrsWithOwner) -> bool {
let path = attr.path(); let path = attr.path();
(|| { (|| {
Some( Some(
path.segments().first()?.as_text()?.starts_with("test") path.segments().first()?.as_str().starts_with("test")
|| path.segments().last()?.as_text()?.ends_with("test"), || path.segments().last()?.as_str().ends_with("test"),
) )
})() })()
.unwrap_or_default() .unwrap_or_default()

View file

@ -24,7 +24,7 @@ pub(crate) mod vis;
use std::iter; use std::iter;
use hir::{known, HasAttrs, ImportPathConfig, ScopeDef, Variant}; use hir::{sym, HasAttrs, ImportPathConfig, Name, ScopeDef, Variant};
use ide_db::{imports::import_assets::LocatedImport, RootDatabase, SymbolKind}; use ide_db::{imports::import_assets::LocatedImport, RootDatabase, SymbolKind};
use syntax::{ast, SmolStr}; use syntax::{ast, SmolStr};
@ -618,7 +618,8 @@ fn enum_variants_with_paths(
let mut process_variant = |variant: Variant| { let mut process_variant = |variant: Variant| {
let self_path = hir::ModPath::from_segments( let self_path = hir::ModPath::from_segments(
hir::PathKind::Plain, hir::PathKind::Plain,
iter::once(known::SELF_TYPE).chain(iter::once(variant.name(ctx.db))), iter::once(Name::new_symbol_root(sym::Self_.clone()))
.chain(iter::once(variant.name(ctx.db))),
); );
cb(acc, ctx, variant, self_path); cb(acc, ctx, variant, self_path);

View file

@ -18,7 +18,7 @@ pub(super) fn complete_macro_use(
for mod_def in krate.root_module().declarations(ctx.db) { for mod_def in krate.root_module().declarations(ctx.db) {
if let ModuleDef::Macro(mac) = mod_def { if let ModuleDef::Macro(mac) = mod_def {
let mac_name = mac.name(ctx.db); let mac_name = mac.name(ctx.db);
let Some(mac_name) = mac_name.as_str() else { continue }; let mac_name = mac_name.as_str();
let existing_import = existing_imports let existing_import = existing_imports
.iter() .iter()

View file

@ -1,5 +1,6 @@
//! Completes references after dot (fields and method calls). //! Completes references after dot (fields and method calls).
use hir::{sym, Name};
use ide_db::FxHashSet; use ide_db::FxHashSet;
use syntax::SmolStr; use syntax::SmolStr;
@ -90,12 +91,14 @@ pub(crate) fn complete_undotted_self(
in_breakable: expr_ctx.in_breakable, in_breakable: expr_ctx.in_breakable,
}, },
}, },
Some(hir::known::SELF_PARAM), Some(Name::new_symbol_root(sym::self_.clone())),
field, field,
&ty, &ty,
) )
}, },
|acc, field, ty| acc.add_tuple_field(ctx, Some(hir::known::SELF_PARAM), field, &ty), |acc, field, ty| {
acc.add_tuple_field(ctx, Some(Name::new_symbol_root(sym::self_.clone())), field, &ty)
},
true, true,
false, false,
); );
@ -112,7 +115,7 @@ pub(crate) fn complete_undotted_self(
}, },
}, },
func, func,
Some(hir::known::SELF_PARAM), Some(Name::new_symbol_root(sym::self_.clone())),
None, None,
) )
}); });

View file

@ -1,6 +1,6 @@
//! Completion of names from the current scope in expression position. //! Completion of names from the current scope in expression position.
use hir::{ImportPathConfig, ScopeDef}; use hir::{sym, ImportPathConfig, Name, ScopeDef};
use syntax::ast; use syntax::ast;
use crate::{ use crate::{
@ -190,7 +190,7 @@ pub(crate) fn complete_expr_path(
path_ctx, path_ctx,
strukt, strukt,
None, None,
Some(hir::known::SELF_TYPE), Some(Name::new_symbol_root(sym::Self_.clone())),
); );
} }
} }
@ -210,7 +210,12 @@ pub(crate) fn complete_expr_path(
acc.add_union_literal(ctx, un, path, None); acc.add_union_literal(ctx, un, path, None);
if complete_self { if complete_self {
acc.add_union_literal(ctx, un, None, Some(hir::known::SELF_TYPE)); acc.add_union_literal(
ctx,
un,
None,
Some(Name::new_symbol_root(sym::Self_.clone())),
);
} }
} }
hir::Adt::Enum(e) => { hir::Adt::Enum(e) => {

View file

@ -31,7 +31,7 @@ pub(crate) fn format_string(
}; };
let source_range = TextRange::new(brace_offset, cursor); let source_range = TextRange::new(brace_offset, cursor);
ctx.locals.iter().for_each(|(name, _)| { ctx.locals.iter().sorted_by_key(|&(k, _)| k.clone()).for_each(|(name, _)| {
CompletionItem::new(CompletionItemKind::Binding, source_range, name.to_smol_str()) CompletionItem::new(CompletionItemKind::Binding, source_range, name.to_smol_str())
.add_to(acc, ctx.db); .add_to(acc, ctx.db);
}); });

View file

@ -7,7 +7,7 @@
//! there is no value in lifting these out into the outline module test since they will either not //! there is no value in lifting these out into the outline module test since they will either not
//! show up for normal completions, or they won't show completions other than lifetimes depending //! show up for normal completions, or they won't show completions other than lifetimes depending
//! on the fixture input. //! on the fixture input.
use hir::{known, ScopeDef}; use hir::{sym, Name, ScopeDef};
use syntax::{ast, TokenText}; use syntax::{ast, TokenText};
use crate::{ use crate::{
@ -47,7 +47,7 @@ pub(crate) fn complete_lifetime(
} }
}); });
if param_lifetime.is_none() { if param_lifetime.is_none() {
acc.add_lifetime(ctx, known::STATIC_LIFETIME); acc.add_lifetime(ctx, Name::new_symbol_root(sym::tick_static.clone()));
} }
} }

View file

@ -55,9 +55,8 @@ pub(crate) fn complete_use_path(
if !ctx.check_stability(def.attrs(ctx.db).as_deref()) { if !ctx.check_stability(def.attrs(ctx.db).as_deref()) {
continue; continue;
} }
let is_name_already_imported = name let is_name_already_imported =
.as_text() already_imported_names.contains(name.as_str());
.map_or(false, |text| already_imported_names.contains(text.as_str()));
let add_resolution = match def { let add_resolution = match def {
ScopeDef::Unknown if unknown_is_current(&name) => { ScopeDef::Unknown if unknown_is_current(&name) => {

View file

@ -823,13 +823,13 @@ fn classify_name_ref(
for item in trait_.items_with_supertraits(sema.db) { for item in trait_.items_with_supertraits(sema.db) {
match item { match item {
hir::AssocItem::TypeAlias(assoc_ty) => { hir::AssocItem::TypeAlias(assoc_ty) => {
if assoc_ty.name(sema.db).as_str()? == arg_name { if assoc_ty.name(sema.db).as_str() == arg_name {
override_location = Some(TypeLocation::AssocTypeEq); override_location = Some(TypeLocation::AssocTypeEq);
return None; return None;
} }
}, },
hir::AssocItem::Const(const_) => { hir::AssocItem::Const(const_) => {
if const_.name(sema.db)?.as_str()? == arg_name { if const_.name(sema.db)?.as_str() == arg_name {
override_location = Some(TypeLocation::AssocConstEq); override_location = Some(TypeLocation::AssocConstEq);
return None; return None;
} }
@ -867,7 +867,7 @@ fn classify_name_ref(
let trait_items = trait_.items_with_supertraits(sema.db); let trait_items = trait_.items_with_supertraits(sema.db);
let assoc_ty = trait_items.iter().find_map(|item| match item { let assoc_ty = trait_items.iter().find_map(|item| match item {
hir::AssocItem::TypeAlias(assoc_ty) => { hir::AssocItem::TypeAlias(assoc_ty) => {
(assoc_ty.name(sema.db).as_str()? == arg_name) (assoc_ty.name(sema.db).as_str() == arg_name)
.then_some(assoc_ty) .then_some(assoc_ty)
}, },
_ => None, _ => None,

View file

@ -280,8 +280,7 @@ pub(crate) fn render_expr(
let mut snippet_formatter = |ty: &hir::Type| { let mut snippet_formatter = |ty: &hir::Type| {
let arg_name = ty let arg_name = ty
.as_adt() .as_adt()
.and_then(|adt| adt.name(ctx.db).as_text()) .map(|adt| stdx::to_lower_snake_case(adt.name(ctx.db).as_str()))
.map(|s| stdx::to_lower_snake_case(s.as_str()))
.unwrap_or_else(|| String::from("_")); .unwrap_or_else(|| String::from("_"));
let res = format!("${{{i}:{arg_name}}}"); let res = format!("${{{i}:{arg_name}}}");
i += 1; i += 1;
@ -290,8 +289,7 @@ pub(crate) fn render_expr(
let mut label_formatter = |ty: &hir::Type| { let mut label_formatter = |ty: &hir::Type| {
ty.as_adt() ty.as_adt()
.and_then(|adt| adt.name(ctx.db).as_text()) .map(|adt| stdx::to_lower_snake_case(adt.name(ctx.db).as_str()))
.map(|s| stdx::to_lower_snake_case(s.as_str()))
.unwrap_or_else(|| String::from("...")) .unwrap_or_else(|| String::from("..."))
}; };

View file

@ -188,7 +188,7 @@ fn compute_return_type_match(
CompletionRelevanceReturnType::Constructor CompletionRelevanceReturnType::Constructor
} else if ret_type } else if ret_type
.as_adt() .as_adt()
.and_then(|adt| adt.name(db).as_str().map(|name| name.ends_with("Builder"))) .map(|adt| adt.name(db).as_str().ends_with("Builder"))
.unwrap_or(false) .unwrap_or(false)
{ {
// fn([..]) -> [..]Builder // fn([..]) -> [..]Builder
@ -227,11 +227,7 @@ pub(super) fn add_call_parens<'b>(
None => { None => {
let name = match param.ty().as_adt() { let name = match param.ty().as_adt() {
None => "_".to_owned(), None => "_".to_owned(),
Some(adt) => adt Some(adt) => to_lower_snake_case(adt.name(ctx.db).as_str()),
.name(ctx.db)
.as_text()
.map(|s| to_lower_snake_case(s.as_str()))
.unwrap_or_else(|| "_".to_owned()),
}; };
f(&format_args!("${{{}:{name}}}", index + offset)) f(&format_args!("${{{}:{name}}}", index + offset))
} }
@ -263,8 +259,8 @@ pub(super) fn add_call_parens<'b>(
fn ref_of_param(ctx: &CompletionContext<'_>, arg: &str, ty: &hir::Type) -> &'static str { fn ref_of_param(ctx: &CompletionContext<'_>, arg: &str, ty: &hir::Type) -> &'static str {
if let Some(derefed_ty) = ty.remove_ref() { if let Some(derefed_ty) = ty.remove_ref() {
for (name, local) in ctx.locals.iter() { for (name, local) in ctx.locals.iter().sorted_by_key(|&(k, _)| k.clone()) {
if name.as_text().as_deref() == Some(arg) { if name.as_str() == arg {
return if local.ty(ctx.db) == derefed_ty { return if local.ty(ctx.db) == derefed_ty {
if ty.is_mutable_reference() { if ty.is_mutable_reference() {
"&mut " "&mut "

View file

@ -767,8 +767,8 @@ fn main() {
} }
"#, "#,
expect![[r#" expect![[r#"
fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED
ct SPECIAL_CONST (use dep::test_mod::TestTrait) u8 DEPRECATED ct SPECIAL_CONST (use dep::test_mod::TestTrait) u8 DEPRECATED
fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED
me random_method() (use dep::test_mod::TestTrait) fn(&self) DEPRECATED me random_method() (use dep::test_mod::TestTrait) fn(&self) DEPRECATED
"#]], "#]],
); );

View file

@ -144,7 +144,7 @@ impl Definition {
Definition::Local(it) => it.name(db), Definition::Local(it) => it.name(db),
Definition::GenericParam(it) => it.name(db), Definition::GenericParam(it) => it.name(db),
Definition::Label(it) => it.name(db), Definition::Label(it) => it.name(db),
Definition::BuiltinLifetime(StaticLifetime) => hir::known::STATIC_LIFETIME, Definition::BuiltinLifetime(it) => it.name(),
Definition::BuiltinAttr(_) => return None, // FIXME Definition::BuiltinAttr(_) => return None, // FIXME
Definition::ToolModule(_) => return None, // FIXME Definition::ToolModule(_) => return None, // FIXME
Definition::DeriveHelper(it) => it.name(db), Definition::DeriveHelper(it) => it.name(db),

View file

@ -15,7 +15,7 @@ use syntax::{
use crate::{ use crate::{
helpers::item_name, helpers::item_name,
items_locator::{self, AssocSearchMode, DEFAULT_QUERY_SEARCH_LIMIT}, items_locator::{self, AssocSearchMode, DEFAULT_QUERY_SEARCH_LIMIT},
RootDatabase, FxIndexSet, RootDatabase,
}; };
/// A candidate for import, derived during various IDE activities: /// A candidate for import, derived during various IDE activities:
@ -262,7 +262,7 @@ impl ImportAssets {
let scope = match sema.scope(&self.candidate_node) { let scope = match sema.scope(&self.candidate_node) {
Some(it) => it, Some(it) => it,
None => return <FxHashSet<_>>::default().into_iter(), None => return <FxIndexSet<_>>::default().into_iter(),
}; };
let krate = self.module_with_candidate.krate(); let krate = self.module_with_candidate.krate();
@ -319,7 +319,7 @@ fn path_applicable_imports(
path_candidate: &PathImportCandidate, path_candidate: &PathImportCandidate,
mod_path: impl Fn(ItemInNs) -> Option<ModPath> + Copy, mod_path: impl Fn(ItemInNs) -> Option<ModPath> + Copy,
scope_filter: impl Fn(ItemInNs) -> bool + Copy, scope_filter: impl Fn(ItemInNs) -> bool + Copy,
) -> FxHashSet<LocatedImport> { ) -> FxIndexSet<LocatedImport> {
let _p = tracing::info_span!("ImportAssets::path_applicable_imports").entered(); let _p = tracing::info_span!("ImportAssets::path_applicable_imports").entered();
match &path_candidate.qualifier { match &path_candidate.qualifier {
@ -389,16 +389,16 @@ fn import_for_item(
let mut import_path_candidate_segments = import_path_candidate.segments().iter().rev(); let mut import_path_candidate_segments = import_path_candidate.segments().iter().rev();
let predicate = |it: EitherOrBoth<&SmolStr, &Name>| match it { let predicate = |it: EitherOrBoth<&SmolStr, &Name>| match it {
// segments match, check next one // segments match, check next one
EitherOrBoth::Both(a, b) if b.as_str() == Some(&**a) => None, EitherOrBoth::Both(a, b) if b.as_str() == &**a => None,
// segments mismatch / qualifier is longer than the path, bail out // segments mismatch / qualifier is longer than the path, bail out
EitherOrBoth::Both(..) | EitherOrBoth::Left(_) => Some(false), EitherOrBoth::Both(..) | EitherOrBoth::Left(_) => Some(false),
// all segments match and we have exhausted the qualifier, proceed // all segments match and we have exhausted the qualifier, proceed
EitherOrBoth::Right(_) => Some(true), EitherOrBoth::Right(_) => Some(true),
}; };
if item_as_assoc.is_none() { if item_as_assoc.is_none() {
let item_name = item_name(db, original_item)?.as_text()?; let item_name = item_name(db, original_item)?;
let last_segment = import_path_candidate_segments.next()?; let last_segment = import_path_candidate_segments.next()?;
if last_segment.as_str() != Some(&*item_name) { if *last_segment != item_name {
return None; return None;
} }
} }
@ -500,7 +500,7 @@ fn trait_applicable_items(
trait_assoc_item: bool, trait_assoc_item: bool,
mod_path: impl Fn(ItemInNs) -> Option<ModPath>, mod_path: impl Fn(ItemInNs) -> Option<ModPath>,
scope_filter: impl Fn(hir::Trait) -> bool, scope_filter: impl Fn(hir::Trait) -> bool,
) -> FxHashSet<LocatedImport> { ) -> FxIndexSet<LocatedImport> {
let _p = tracing::info_span!("ImportAssets::trait_applicable_items").entered(); let _p = tracing::info_span!("ImportAssets::trait_applicable_items").entered();
let db = sema.db; let db = sema.db;
@ -566,7 +566,7 @@ fn trait_applicable_items(
definitions_exist_in_trait_crate || definitions_exist_in_receiver_crate() definitions_exist_in_trait_crate || definitions_exist_in_receiver_crate()
}); });
let mut located_imports = FxHashSet::default(); let mut located_imports = FxIndexSet::default();
let mut trait_import_paths = FxHashMap::default(); let mut trait_import_paths = FxHashMap::default();
if trait_assoc_item { if trait_assoc_item {

View file

@ -472,7 +472,7 @@ fn find_trait_for_assoc_item(
}); });
for name in names { for name in names {
if assoc_item_name.as_str() == name.as_text()?.as_str() { if assoc_item_name.as_str() == name.as_str() {
// It is fine to return the first match because in case of // It is fine to return the first match because in case of
// multiple possibilities, the exact trait must be disambiguated // multiple possibilities, the exact trait must be disambiguated
// in the definition of trait being implemented, so this search // in the definition of trait being implemented, so this search

View file

@ -1,7 +1,7 @@
use either::Either; use either::Either;
use hir::{ use hir::{
db::{ExpandDatabase, HirDatabase}, db::{ExpandDatabase, HirDatabase},
known, AssocItem, HirDisplay, HirFileIdExt, ImportPathConfig, InFile, Type, sym, AssocItem, HirDisplay, HirFileIdExt, ImportPathConfig, InFile, Type,
}; };
use ide_db::{ use ide_db::{
assists::Assist, famous_defs::FamousDefs, imports::import_assets::item_for_path_search, assists::Assist, famous_defs::FamousDefs, imports::import_assets::item_for_path_search,
@ -210,7 +210,7 @@ fn get_default_constructor(
let has_new_func = ty let has_new_func = ty
.iterate_assoc_items(ctx.sema.db, krate, |assoc_item| { .iterate_assoc_items(ctx.sema.db, krate, |assoc_item| {
if let AssocItem::Function(func) = assoc_item { if let AssocItem::Function(func) = assoc_item {
if func.name(ctx.sema.db) == known::new if func.name(ctx.sema.db) == sym::new.clone()
&& func.assoc_fn_params(ctx.sema.db).is_empty() && func.assoc_fn_params(ctx.sema.db).is_empty()
{ {
return Some(()); return Some(());

View file

@ -76,7 +76,7 @@ fn field_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Option<A
let expr = d.expr.value.to_node(&root); let expr = d.expr.value.to_node(&root);
let error_range = ctx.sema.original_range_opt(expr.syntax())?; let error_range = ctx.sema.original_range_opt(expr.syntax())?;
let field_name = d.name.as_str()?; let field_name = d.name.as_str();
// Convert the receiver to an ADT // Convert the receiver to an ADT
let adt = d.receiver.strip_references().as_adt()?; let adt = d.receiver.strip_references().as_adt()?;
let target_module = adt.module(ctx.sema.db); let target_module = adt.module(ctx.sema.db);

View file

@ -150,7 +150,7 @@ fn try_lookup_macro_def_in_macro_use(
for mod_def in krate.root_module().declarations(sema.db) { for mod_def in krate.root_module().declarations(sema.db) {
if let ModuleDef::Macro(mac) = mod_def { if let ModuleDef::Macro(mac) = mod_def {
if mac.name(sema.db).as_str() == Some(token.text()) { if mac.name(sema.db).as_str() == token.text() {
if let Some(nav) = mac.try_to_nav(sema.db) { if let Some(nav) = mac.try_to_nav(sema.db) {
return Some(nav.call_site); return Some(nav.call_site);
} }

View file

@ -5,7 +5,7 @@ use std::{
use either::Either; use either::Either;
use hir::{ use hir::{
known, ClosureStyle, HasVisibility, HirDisplay, HirDisplayError, HirWrite, ModuleDef, sym, ClosureStyle, HasVisibility, HirDisplay, HirDisplayError, HirWrite, ModuleDef,
ModuleDefId, Semantics, ModuleDefId, Semantics,
}; };
use ide_db::{base_db::FileRange, famous_defs::FamousDefs, RootDatabase}; use ide_db::{base_db::FileRange, famous_defs::FamousDefs, RootDatabase};
@ -633,7 +633,7 @@ fn hint_iterator(
if ty.impls_trait(db, iter_trait, &[]) { if ty.impls_trait(db, iter_trait, &[]) {
let assoc_type_item = iter_trait.items(db).into_iter().find_map(|item| match item { let assoc_type_item = iter_trait.items(db).into_iter().find_map(|item| match item {
hir::AssocItem::TypeAlias(alias) if alias.name(db) == known::Item => Some(alias), hir::AssocItem::TypeAlias(alias) if alias.name(db) == sym::Item.clone() => Some(alias),
_ => None, _ => None,
})?; })?;
if let Some(ty) = ty.normalize_trait_assoc_type(db, &[], assoc_type_item) { if let Some(ty) = ty.normalize_trait_assoc_type(db, &[], assoc_type_item) {

View file

@ -46,7 +46,7 @@ pub(crate) fn hints(
} }
let name = param.name(sema.db); let name = param.name(sema.db);
let param_name = name.as_str()?; let param_name = name.as_str();
let should_hide = { let should_hide = {
let argument = get_string_representation(&arg)?; let argument = get_string_representation(&arg)?;

View file

@ -6,6 +6,7 @@ use ide_db::{
defs::{Definition, IdentClass, NameClass, NameRefClass}, defs::{Definition, IdentClass, NameClass, NameRefClass},
FxHashMap, RootDatabase, SymbolKind, FxHashMap, RootDatabase, SymbolKind,
}; };
use stdx::hash_once;
use syntax::{ use syntax::{
ast, match_ast, AstNode, AstToken, NodeOrToken, ast, match_ast, AstNode, AstToken, NodeOrToken,
SyntaxKind::{self, *}, SyntaxKind::{self, *},
@ -358,17 +359,7 @@ fn highlight_name(
} }
fn calc_binding_hash(name: &hir::Name, shadow_count: u32) -> u64 { fn calc_binding_hash(name: &hir::Name, shadow_count: u32) -> u64 {
fn hash<T: std::hash::Hash + std::fmt::Debug>(x: T) -> u64 { hash_once::<ide_db::FxHasher>((name.as_str(), shadow_count))
use ide_db::FxHasher;
use std::hash::Hasher;
let mut hasher = FxHasher::default();
x.hash(&mut hasher);
hasher.finish()
}
hash((name, shadow_count))
} }
pub(super) fn highlight_def( pub(super) fn highlight_def(

View file

@ -66,8 +66,11 @@ fn discover_tests_in_module(
let mut r = vec![]; let mut r = vec![];
for c in module.children(db) { for c in module.children(db) {
let module_name = let module_name = c
c.name(db).as_ref().and_then(|n| n.as_str()).unwrap_or("[mod without name]").to_owned(); .name(db)
.as_ref()
.map(|n| n.as_str().to_owned())
.unwrap_or_else(|| "[mod without name]".to_owned());
let module_id = format!("{prefix_id}::{module_name}"); let module_id = format!("{prefix_id}::{module_name}");
let module_children = discover_tests_in_module(db, c, module_id.clone(), only_in_this_file); let module_children = discover_tests_in_module(db, c, module_id.clone(), only_in_this_file);
if !module_children.is_empty() { if !module_children.is_empty() {
@ -94,7 +97,7 @@ fn discover_tests_in_module(
continue; continue;
} }
let nav = f.try_to_nav(db).map(|r| r.call_site); let nav = f.try_to_nav(db).map(|r| r.call_site);
let fn_name = f.name(db).as_str().unwrap_or("[function without name]").to_owned(); let fn_name = f.name(db).as_str().to_owned();
r.push(TestItem { r.push(TestItem {
id: format!("{prefix_id}::{fn_name}"), id: format!("{prefix_id}::{fn_name}"),
kind: TestItemKind::Function, kind: TestItemKind::Function,
@ -153,7 +156,7 @@ fn find_module_id_and_test_parents(
let parent = Some(id.clone()); let parent = Some(id.clone());
id += "::"; id += "::";
let module_name = &module.name(sema.db); let module_name = &module.name(sema.db);
let module_name = module_name.as_ref().and_then(|n| n.as_str()).unwrap_or("[mod without name]"); let module_name = module_name.as_ref().map(|n| n.as_str()).unwrap_or("[mod without name]");
id += module_name; id += module_name;
let nav = NavigationTarget::from_module_to_decl(sema.db, module).call_site; let nav = NavigationTarget::from_module_to_decl(sema.db, module).call_site;
r.push(TestItem { r.push(TestItem {

View file

@ -64,11 +64,7 @@ enum FieldOrTupleIdx {
impl FieldOrTupleIdx { impl FieldOrTupleIdx {
fn name(&self, db: &RootDatabase) -> String { fn name(&self, db: &RootDatabase) -> String {
match *self { match *self {
FieldOrTupleIdx::Field(f) => f FieldOrTupleIdx::Field(f) => f.name(db).as_str().to_owned(),
.name(db)
.as_str()
.map(|s| s.to_owned())
.unwrap_or_else(|| format!(".{}", f.name(db).as_tuple_index().unwrap())),
FieldOrTupleIdx::TupleIdx(i) => format!(".{i}"), FieldOrTupleIdx::TupleIdx(i) => format!(".{i}"),
} }
} }
@ -189,14 +185,7 @@ pub(crate) fn view_memory_layout(
| Definition::SelfType(_) => "[ROOT]".to_owned(), | Definition::SelfType(_) => "[ROOT]".to_owned(),
// def is an item // def is an item
def => def def => def.name(db).map(|n| n.as_str().to_owned()).unwrap_or("[ROOT]".to_owned()),
.name(db)
.map(|n| {
n.as_str()
.map(|s| s.to_owned())
.unwrap_or_else(|| format!(".{}", n.as_tuple_index().unwrap()))
})
.unwrap_or("[ROOT]".to_owned()),
}; };
let typename = ty.display(db).to_string(); let typename = ty.display(db).to_string();

View file

@ -18,6 +18,7 @@ dashmap.workspace = true
hashbrown.workspace = true hashbrown.workspace = true
rustc-hash.workspace = true rustc-hash.workspace = true
triomphe.workspace = true triomphe.workspace = true
sptr = "0.3.2"
[lints] [lints]
workspace = true workspace = true

View file

@ -20,6 +20,9 @@ type Guard<T> = dashmap::RwLockWriteGuard<
HashMap<Arc<T>, SharedValue<()>, BuildHasherDefault<FxHasher>>, HashMap<Arc<T>, SharedValue<()>, BuildHasherDefault<FxHasher>>,
>; >;
mod symbol;
pub use self::symbol::{symbols as sym, Symbol};
pub struct Interned<T: Internable + ?Sized> { pub struct Interned<T: Internable + ?Sized> {
arc: Arc<T>, arc: Arc<T>,
} }

328
crates/intern/src/symbol.rs Normal file
View file

@ -0,0 +1,328 @@
//! Attempt at flexible symbol interning, allowing to intern and free strings at runtime while also
//! supporting compile time declaration of symbols that will never be freed.
use std::{
borrow::Borrow,
fmt,
hash::{BuildHasherDefault, Hash, Hasher},
mem::{self, ManuallyDrop},
ptr::NonNull,
sync::OnceLock,
};
use dashmap::{DashMap, SharedValue};
use hashbrown::{hash_map::RawEntryMut, HashMap};
use rustc_hash::FxHasher;
use sptr::Strict;
use triomphe::Arc;
pub mod symbols;
// some asserts for layout compatibility
const _: () = assert!(std::mem::size_of::<Box<str>>() == std::mem::size_of::<&str>());
const _: () = assert!(std::mem::align_of::<Box<str>>() == std::mem::align_of::<&str>());
const _: () = assert!(std::mem::size_of::<Arc<Box<str>>>() == std::mem::size_of::<&&str>());
const _: () = assert!(std::mem::align_of::<Arc<Box<str>>>() == std::mem::align_of::<&&str>());
const _: () =
assert!(std::mem::size_of::<*const *const str>() == std::mem::size_of::<TaggedArcPtr>());
const _: () =
assert!(std::mem::align_of::<*const *const str>() == std::mem::align_of::<TaggedArcPtr>());
const _: () = assert!(std::mem::size_of::<Arc<Box<str>>>() == std::mem::size_of::<TaggedArcPtr>());
const _: () =
assert!(std::mem::align_of::<Arc<Box<str>>>() == std::mem::align_of::<TaggedArcPtr>());
/// A pointer that points to a pointer to a `str`, it may be backed as a `&'static &'static str` or
/// `Arc<Box<str>>` but its size is that of a thin pointer. The active variant is encoded as a tag
/// in the LSB of the alignment niche.
// Note, Ideally this would encode a `ThinArc<str>` and `ThinRef<str>`/`ThinConstPtr<str>` instead of the double indirection.
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
struct TaggedArcPtr {
packed: NonNull<*const str>,
}
unsafe impl Send for TaggedArcPtr {}
unsafe impl Sync for TaggedArcPtr {}
impl TaggedArcPtr {
const BOOL_BITS: usize = true as usize;
const fn non_arc(r: &'static &'static str) -> Self {
assert!(
mem::align_of::<&'static &'static str>().trailing_zeros() as usize > Self::BOOL_BITS
);
// SAFETY: The pointer is non-null as it is derived from a reference
// Ideally we would call out to `pack_arc` but for a `false` tag, unfortunately the
// packing stuff requires reading out the pointer to an integer which is not supported
// in const contexts, so here we make use of the fact that for the non-arc version the
// tag is false (0) and thus does not need touching the actual pointer value.ext)
let packed =
unsafe { NonNull::new_unchecked((r as *const &str).cast::<*const str>().cast_mut()) };
Self { packed }
}
fn arc(arc: Arc<Box<str>>) -> Self {
assert!(
mem::align_of::<&'static &'static str>().trailing_zeros() as usize > Self::BOOL_BITS
);
Self {
packed: Self::pack_arc(
// Safety: `Arc::into_raw` always returns a non null pointer
unsafe { NonNull::new_unchecked(Arc::into_raw(arc).cast_mut().cast()) },
),
}
}
/// Retrieves the tag.
#[inline]
pub(crate) fn try_as_arc_owned(self) -> Option<ManuallyDrop<Arc<Box<str>>>> {
// Unpack the tag from the alignment niche
let tag = Strict::addr(self.packed.as_ptr()) & Self::BOOL_BITS;
if tag != 0 {
// Safety: We checked that the tag is non-zero -> true, so we are pointing to the data offset of an `Arc`
Some(ManuallyDrop::new(unsafe {
Arc::from_raw(self.pointer().as_ptr().cast::<Box<str>>())
}))
} else {
None
}
}
#[inline]
fn pack_arc(ptr: NonNull<*const str>) -> NonNull<*const str> {
let packed_tag = true as usize;
// can't use this strict provenance stuff here due to trait methods not being const
// unsafe {
// // Safety: The pointer is derived from a non-null
// NonNull::new_unchecked(Strict::map_addr(ptr.as_ptr(), |addr| {
// // Safety:
// // - The pointer is `NonNull` => it's address is `NonZero<usize>`
// // - `P::BITS` least significant bits are always zero (`Pointer` contract)
// // - `T::BITS <= P::BITS` (from `Self::ASSERTION`)
// //
// // Thus `addr >> T::BITS` is guaranteed to be non-zero.
// //
// // `{non_zero} | packed_tag` can't make the value zero.
// (addr >> Self::BOOL_BITS) | packed_tag
// }))
// }
// so what follows is roughly what the above looks like but inlined
let self_addr = ptr.as_ptr() as *const *const str as usize;
let addr = self_addr | packed_tag;
let dest_addr = addr as isize;
let offset = dest_addr.wrapping_sub(self_addr as isize);
// SAFETY: The resulting pointer is guaranteed to be NonNull as we only modify the niche bytes
unsafe { NonNull::new_unchecked(ptr.as_ptr().cast::<u8>().wrapping_offset(offset).cast()) }
}
#[inline]
pub(crate) fn pointer(self) -> NonNull<*const str> {
// SAFETY: The resulting pointer is guaranteed to be NonNull as we only modify the niche bytes
unsafe {
NonNull::new_unchecked(Strict::map_addr(self.packed.as_ptr(), |addr| {
addr & !Self::BOOL_BITS
}))
}
}
#[inline]
pub(crate) fn as_str(&self) -> &str {
// SAFETY: We always point to a pointer to a str no matter what variant is active
unsafe { *self.pointer().as_ptr().cast::<&str>() }
}
}
#[derive(PartialEq, Eq, Hash, Debug)]
pub struct Symbol {
repr: TaggedArcPtr,
}
const _: () = assert!(std::mem::size_of::<Symbol>() == std::mem::size_of::<NonNull<()>>());
const _: () = assert!(std::mem::align_of::<Symbol>() == std::mem::align_of::<NonNull<()>>());
static MAP: OnceLock<DashMap<SymbolProxy, (), BuildHasherDefault<FxHasher>>> = OnceLock::new();
impl Symbol {
pub fn intern(s: &str) -> Self {
let (mut shard, hash) = Self::select_shard(s);
// Atomically,
// - check if `obj` is already in the map
// - if so, copy out its entry, conditionally bumping the backing Arc and return it
// - if not, put it into a box and then into an Arc, insert it, bump the ref-count and return the copy
// This needs to be atomic (locking the shard) to avoid races with other thread, which could
// insert the same object between us looking it up and inserting it.
match shard.raw_entry_mut().from_key_hashed_nocheck(hash, s) {
RawEntryMut::Occupied(occ) => Self { repr: increase_arc_refcount(occ.key().0) },
RawEntryMut::Vacant(vac) => Self {
repr: increase_arc_refcount(
vac.insert_hashed_nocheck(
hash,
SymbolProxy(TaggedArcPtr::arc(Arc::new(Box::<str>::from(s)))),
SharedValue::new(()),
)
.0
.0,
),
},
}
}
pub fn as_str(&self) -> &str {
self.repr.as_str()
}
#[inline]
fn select_shard(
s: &str,
) -> (
dashmap::RwLockWriteGuard<
'static,
HashMap<SymbolProxy, SharedValue<()>, BuildHasherDefault<FxHasher>>,
>,
u64,
) {
let storage = MAP.get_or_init(symbols::prefill);
let hash = {
let mut hasher = std::hash::BuildHasher::build_hasher(storage.hasher());
s.hash(&mut hasher);
hasher.finish()
};
let shard_idx = storage.determine_shard(hash as usize);
let shard = &storage.shards()[shard_idx];
(shard.write(), hash)
}
#[cold]
fn drop_slow(arc: &Arc<Box<str>>) {
let (mut shard, hash) = Self::select_shard(arc);
match Arc::count(arc) {
0 => unreachable!(),
1 => unreachable!(),
2 => (),
_ => {
// Another thread has interned another copy
return;
}
}
ManuallyDrop::into_inner(
match shard.raw_entry_mut().from_key_hashed_nocheck::<str>(hash, arc.as_ref()) {
RawEntryMut::Occupied(occ) => occ.remove_entry(),
RawEntryMut::Vacant(_) => unreachable!(),
}
.0
.0
.try_as_arc_owned()
.unwrap(),
);
debug_assert_eq!(Arc::count(arc), 1);
// Shrink the backing storage if the shard is less than 50% occupied.
if shard.len() * 2 < shard.capacity() {
shard.shrink_to_fit();
}
}
}
impl Drop for Symbol {
#[inline]
fn drop(&mut self) {
let Some(arc) = self.repr.try_as_arc_owned() else {
return;
};
// When the last `Ref` is dropped, remove the object from the global map.
if Arc::count(&arc) == 2 {
// Only `self` and the global map point to the object.
Self::drop_slow(&arc);
}
// decrement the ref count
ManuallyDrop::into_inner(arc);
}
}
impl Clone for Symbol {
fn clone(&self) -> Self {
Self { repr: increase_arc_refcount(self.repr) }
}
}
fn increase_arc_refcount(repr: TaggedArcPtr) -> TaggedArcPtr {
let Some(arc) = repr.try_as_arc_owned() else {
return repr;
};
// increase the ref count
mem::forget(Arc::clone(&arc));
repr
}
impl fmt::Display for Symbol {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_str().fmt(f)
}
}
// only exists so we can use `from_key_hashed_nocheck` with a &str
#[derive(Debug, PartialEq, Eq)]
struct SymbolProxy(TaggedArcPtr);
impl Hash for SymbolProxy {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.as_str().hash(state);
}
}
impl Borrow<str> for SymbolProxy {
fn borrow(&self) -> &str {
self.0.as_str()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn smoke_test() {
Symbol::intern("isize");
let base_len = MAP.get().unwrap().len();
let hello = Symbol::intern("hello");
let world = Symbol::intern("world");
let more_worlds = world.clone();
let bang = Symbol::intern("!");
let q = Symbol::intern("?");
assert_eq!(MAP.get().unwrap().len(), base_len + 4);
let bang2 = Symbol::intern("!");
assert_eq!(MAP.get().unwrap().len(), base_len + 4);
drop(bang2);
assert_eq!(MAP.get().unwrap().len(), base_len + 4);
drop(q);
assert_eq!(MAP.get().unwrap().len(), base_len + 3);
let default = Symbol::intern("default");
let many_worlds = world.clone();
assert_eq!(MAP.get().unwrap().len(), base_len + 3);
assert_eq!(
"hello default world!",
format!("{} {} {}{}", hello.as_str(), default.as_str(), world.as_str(), bang.as_str())
);
drop(default);
assert_eq!(
"hello world!",
format!("{} {}{}", hello.as_str(), world.as_str(), bang.as_str())
);
drop(many_worlds);
drop(more_worlds);
drop(hello);
drop(world);
drop(bang);
assert_eq!(MAP.get().unwrap().len(), base_len);
}
}

View file

@ -0,0 +1,360 @@
//! Module defining all known symbols required by the rest of rust-analyzer.
#![allow(non_upper_case_globals)]
use std::hash::{BuildHasherDefault, Hash as _, Hasher as _};
use dashmap::{DashMap, SharedValue};
use rustc_hash::FxHasher;
use crate::{
symbol::{SymbolProxy, TaggedArcPtr},
Symbol,
};
macro_rules! define_symbols {
(@WITH_NAME: $($alias:ident = $value:literal),* $(,)? @PLAIN: $($name:ident),* $(,)?) => {
// Ideally we would be emitting `const` here, but then we no longer have stable addresses
// which is what we are relying on for equality! In the future if consts can refer to
// statics we should swap these for `const`s and have the the string literal being pointed
// to be statics to refer to such that their address is stable.
$(
pub static $name: Symbol = Symbol { repr: TaggedArcPtr::non_arc(&stringify!($name)) };
)*
$(
pub static $alias: Symbol = Symbol { repr: TaggedArcPtr::non_arc(&$value) };
)*
pub(super) fn prefill() -> DashMap<SymbolProxy, (), BuildHasherDefault<FxHasher>> {
let mut dashmap_ = <DashMap<SymbolProxy, (), BuildHasherDefault<FxHasher>>>::with_hasher(BuildHasherDefault::default());
let hash_thing_ = |hasher_: &BuildHasherDefault<FxHasher>, it_: &SymbolProxy| {
let mut hasher_ = std::hash::BuildHasher::build_hasher(hasher_);
it_.hash(&mut hasher_);
hasher_.finish()
};
{
$(
let proxy_ = SymbolProxy($name.repr);
let hash_ = hash_thing_(dashmap_.hasher(), &proxy_);
let shard_idx_ = dashmap_.determine_shard(hash_ as usize);
dashmap_.shards_mut()[shard_idx_].get_mut().raw_entry_mut().from_hash(hash_, |k| k == &proxy_).insert(proxy_, SharedValue::new(()));
)*
$(
let proxy_ = SymbolProxy($alias.repr);
let hash_ = hash_thing_(dashmap_.hasher(), &proxy_);
let shard_idx_ = dashmap_.determine_shard(hash_ as usize);
dashmap_.shards_mut()[shard_idx_].get_mut().raw_entry_mut().from_hash(hash_, |k| k == &proxy_).insert(proxy_, SharedValue::new(()));
)*
}
dashmap_
}
};
}
define_symbols! {
@WITH_NAME:
self_ = "self",
Self_ = "Self",
tick_static = "'static",
dollar_crate = "$crate",
MISSING_NAME = "[missing name]",
INTEGER_0 = "0",
INTEGER_1 = "1",
INTEGER_2 = "2",
INTEGER_3 = "3",
INTEGER_4 = "4",
INTEGER_5 = "5",
INTEGER_6 = "6",
INTEGER_7 = "7",
INTEGER_8 = "8",
INTEGER_9 = "9",
INTEGER_10 = "10",
INTEGER_11 = "11",
INTEGER_12 = "12",
INTEGER_13 = "13",
INTEGER_14 = "14",
INTEGER_15 = "15",
fn_ = "fn",
@PLAIN:
add_assign,
add,
align_offset,
alloc_layout,
alloc,
as_str,
asm,
assert,
begin_panic,
bench,
bitand_assign,
bitand,
bitor_assign,
bitor,
bitxor_assign,
bitxor,
bool,
box_free,
Box,
boxed,
branch,
Break,
c_void,
call_mut,
call_once,
call,
Center,
cfg_accessible,
cfg_attr,
cfg_eval,
cfg,
char,
clone,
Clone,
coerce_unsized,
column,
compile_error,
concat_bytes,
concat_idents,
concat,
const_format_args,
const_panic_fmt,
const_param_ty,
Context,
Continue,
copy,
Copy,
core_panic,
core,
coroutine_state,
coroutine,
crate_type,
CStr,
Debug,
default,
Default,
deref_mut,
deref_target,
deref,
derive_const,
derive,
discriminant_kind,
discriminant_type,
dispatch_from_dyn,destruct,
div_assign,
div,
doc,
drop_in_place,
drop,
dyn_metadata,
eh_catch_typeinfo,
eh_personality,
env,
eq,
Eq,
Err,
exchange_malloc,
f128,
f16,
f32,
f64,
feature,
file,
filter_map,
fmt,
fn_mut,
fn_once_output,
fn_once,
fn_ptr_addr,
fn_ptr_trait,
format_alignment,
format_args_nl,
format_args,
format_argument,
format_arguments,
format_count,
format_placeholder,
format_unsafe_arg,
format,
freeze,
from_output,
from_residual,
from_usize,
from_yeet,
future_trait,
future,
Future,
ge,
get_context,
global_allocator,
global_asm,
gt,
Hash,
i128,
i16,
i32,
i64,
i8,
Implied,
include_bytes,
include_str,
include,
index_mut,
index,
Index,
into_future,
into_iter,
IntoFuture,
IntoIter,
IntoIterator,
is_empty,
Is,
isize,
Item,
iter_mut,
iter,
Iterator,
le,
Left,
len,
line,
llvm_asm,
log_syntax,
lt,
macro_rules,
manually_drop,
maybe_uninit,
metadata_type,
module_path,
mul_assign,
mul,
ne,
neg,
Neg,
new_binary,
new_debug,
new_display,
new_lower_exp,
new_lower_hex,
new_octal,
new_pointer,
new_unchecked,
new_upper_exp,
new_upper_hex,
new_v1_formatted,
new,
next,
no_core,
no_std,
none,
None,
not,
Not,
Ok,
opaque,
ops,
option_env,
option,
Option,
Ord,
Output,
owned_box,
panic_2015,
panic_2021,
panic_bounds_check,
panic_cannot_unwind,
panic_display,
panic_fmt,
panic_impl,
panic_info,
panic_location,
panic_misaligned_pointer_dereference,
panic_nounwind,
panic,
Param,
partial_ord,
PartialEq,
PartialOrd,
Pending,
phantom_data,
pieces,
pin,
pointee_trait,
pointer_like,
poll,
Poll,
prelude,
quote,
range_inclusive_new,
Range,
RangeFrom,
RangeFull,
RangeInclusive,
RangeTo,
RangeToInclusive,
Ready,
receiver,
recursion_limit,
register_attr,
register_tool,
rem_assign,
rem,
result,
Result,
ResumeTy,
Right,
rust_2015,
rust_2018,
rust_2021,
rust_2024,
rustc_coherence_is_core,
rustc_macro_transparency,
semitransparent,
shl_assign,
shl,
shr_assign,
shr,
sized,
slice_len_fn,
Some,
start,
std_panic,
std,
str,
string,
String,
stringify,
structural_peq,
structural_teq,
sub_assign,
sub,
sync,
Target,
termination,
test_case,
test,
trace_macros,
transmute_opts,
transmute_trait,
transparent,
Try,
tuple_trait,
u128,
u16,
u32,
u64,
u8,
Unknown,
unpin,
unreachable_2015,
unreachable_2021,
unreachable,
unsafe_cell,
unsize,
usize,
v1,
va_list
}