Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/base-db/src/editioned_file_id.rs3
-rw-r--r--crates/hir-def/src/expr_store.rs8
-rw-r--r--crates/hir-def/src/expr_store/expander.rs7
-rw-r--r--crates/hir-def/src/expr_store/lower.rs20
-rw-r--r--crates/hir-def/src/expr_store/lower/format_args.rs3
-rw-r--r--crates/hir-def/src/hir/generics.rs3
-rw-r--r--crates/hir-def/src/hir/type_ref.rs58
-rw-r--r--crates/hir-def/src/item_scope.rs16
-rw-r--r--crates/hir-def/src/item_tree.rs4
-rw-r--r--crates/hir-def/src/item_tree/lower.rs2
-rw-r--r--crates/hir-def/src/item_tree/pretty.rs2
-rw-r--r--crates/hir-def/src/lang_item.rs6
-rw-r--r--crates/hir-def/src/macro_expansion_tests/mod.rs4
-rw-r--r--crates/hir-def/src/nameres/collector.rs4
-rw-r--r--crates/hir-def/src/nameres/path_resolution.rs2
-rw-r--r--crates/hir-def/src/resolver.rs2
-rw-r--r--crates/hir-expand/src/db.rs14
-rw-r--r--crates/hir-expand/src/lib.rs24
-rw-r--r--crates/hir-expand/src/proc_macro.rs4
-rw-r--r--crates/hir-ty/src/consteval.rs127
-rw-r--r--crates/hir-ty/src/consteval/tests.rs3
-rw-r--r--crates/hir-ty/src/display.rs18
-rw-r--r--crates/hir-ty/src/lower.rs26
-rw-r--r--crates/hir-ty/src/method_resolution.rs17
-rw-r--r--crates/hir-ty/src/next_solver/infer/mod.rs8
-rw-r--r--crates/hir-ty/src/next_solver/infer/opaque_types/table.rs2
-rw-r--r--crates/hir-ty/src/next_solver/ty.rs18
-rw-r--r--crates/hir-ty/src/tests/incremental.rs58
-rw-r--r--crates/hir-ty/src/tests/patterns.rs19
-rw-r--r--crates/hir-ty/src/tests/regression.rs1
-rw-r--r--crates/hir-ty/src/tests/regression/new_solver.rs1
-rw-r--r--crates/hir-ty/src/tests/simple.rs36
-rw-r--r--crates/hir-ty/src/variance.rs13
-rw-r--r--crates/hir/src/has_source.rs2
-rw-r--r--crates/hir/src/lib.rs61
-rw-r--r--crates/ide-assists/src/handlers/move_guard.rs74
-rw-r--r--crates/ide-completion/src/tests/flyimport.rs2
-rw-r--r--crates/ide-db/src/syntax_helpers/suggest_name.rs2
-rw-r--r--crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs1
-rw-r--r--crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs18
-rw-r--r--crates/ide/src/hover/tests.rs1
-rw-r--r--crates/ide/src/inlay_hints.rs19
-rw-r--r--crates/ide/src/inlay_hints/bind_pat.rs129
-rw-r--r--crates/ide/src/inlay_hints/bounds.rs2
-rw-r--r--crates/ide/src/references.rs27
-rw-r--r--crates/intern/src/intern.rs2
-rw-r--r--crates/intern/src/intern_slice.rs7
-rw-r--r--crates/intern/src/symbol/symbols.rs1
-rw-r--r--crates/load-cargo/src/lib.rs61
-rw-r--r--crates/proc-macro-api/src/bidirectional_protocol/msg.rs6
-rw-r--r--crates/proc-macro-srv-cli/Cargo.toml1
-rw-r--r--crates/proc-macro-srv-cli/README.md65
-rw-r--r--crates/proc-macro-srv-cli/src/main_loop.rs62
-rw-r--r--crates/proc-macro-srv/src/lib.rs5
-rw-r--r--crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs16
-rw-r--r--crates/rust-analyzer/src/lib.rs3
-rw-r--r--crates/span/src/hygiene.rs3
-rw-r--r--crates/test-fixture/src/lib.rs20
-rw-r--r--crates/test-utils/src/minicore.rs1
-rw-r--r--editors/code/package-lock.json6
60 files changed, 764 insertions, 366 deletions
diff --git a/crates/base-db/src/editioned_file_id.rs b/crates/base-db/src/editioned_file_id.rs
index e2791ffe6f..13fb05d565 100644
--- a/crates/base-db/src/editioned_file_id.rs
+++ b/crates/base-db/src/editioned_file_id.rs
@@ -26,6 +26,9 @@ const _: () = {
krate: Crate,
}
+ // FIXME: This poses an invalidation problem, if one constructs an `EditionedFileId` with a
+ // different crate then whatever the input of a memo used, it will invalidate the memo causing
+ // it to recompute even if the crate is not really used.
/// We like to include the origin crate in an `EditionedFileId` (for use in the item tree),
/// but this poses us a problem.
///
diff --git a/crates/hir-def/src/expr_store.rs b/crates/hir-def/src/expr_store.rs
index 66f7e25ffa..10cd460d1d 100644
--- a/crates/hir-def/src/expr_store.rs
+++ b/crates/hir-def/src/expr_store.rs
@@ -57,8 +57,7 @@ impl HygieneId {
Self(ctx)
}
- // FIXME: Inline this
- pub(crate) fn lookup(self) -> SyntaxContext {
+ pub(crate) fn syntax_context(self) -> SyntaxContext {
self.0
}
@@ -73,7 +72,8 @@ pub type ExprSource = InFile<ExprPtr>;
pub type PatPtr = AstPtr<ast::Pat>;
pub type PatSource = InFile<PatPtr>;
-pub type LabelPtr = AstPtr<ast::Label>;
+/// BlockExpr -> Desugared label from try block
+pub type LabelPtr = AstPtr<Either<ast::Label, ast::BlockExpr>>;
pub type LabelSource = InFile<LabelPtr>;
pub type FieldPtr = AstPtr<ast::RecordExprField>;
@@ -942,7 +942,7 @@ impl ExpressionStoreSourceMap {
}
pub fn node_label(&self, node: InFile<&ast::Label>) -> Option<LabelId> {
- let src = node.map(AstPtr::new);
+ let src = node.map(AstPtr::new).map(AstPtr::wrap_left);
self.expr_only()?.label_map.get(&src).cloned()
}
diff --git a/crates/hir-def/src/expr_store/expander.rs b/crates/hir-def/src/expr_store/expander.rs
index 6a2f06b0a6..de5974fff1 100644
--- a/crates/hir-def/src/expr_store/expander.rs
+++ b/crates/hir-def/src/expr_store/expander.rs
@@ -11,7 +11,7 @@ use hir_expand::{
ExpandError, ExpandErrorKind, ExpandResult, HirFileId, InFile, Lookup, MacroCallId,
eager::EagerCallBackFn, mod_path::ModPath, span_map::SpanMap,
};
-use span::{AstIdMap, Edition, SyntaxContext};
+use span::{AstIdMap, SyntaxContext};
use syntax::ast::HasAttrs;
use syntax::{AstNode, Parse, ast};
use triomphe::Arc;
@@ -75,11 +75,6 @@ impl Expander {
AttrFlags::is_cfg_enabled_for(owner, cfg_options)
}
- pub(super) fn call_syntax_ctx(&self) -> SyntaxContext {
- // FIXME:
- SyntaxContext::root(Edition::CURRENT_FIXME)
- }
-
pub(super) fn enter_expand<T: ast::AstNode>(
&mut self,
db: &dyn DefDatabase,
diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs
index 42b076abb2..d3774ded39 100644
--- a/crates/hir-def/src/expr_store/lower.rs
+++ b/crates/hir-def/src/expr_store/lower.rs
@@ -1096,7 +1096,7 @@ impl<'db> ExprCollector<'db> {
ast::Expr::WhileExpr(e) => self.collect_while_loop(syntax_ptr, e),
ast::Expr::ForExpr(e) => self.collect_for_loop(syntax_ptr, e),
ast::Expr::CallExpr(e) => {
- // FIXME: Remove this once we drop support for <1.86, https://github.com/rust-lang/rust/commit/ac9cb908ac4301dfc25e7a2edee574320022ae2c
+ // FIXME(MINIMUM_SUPPORTED_TOOLCHAIN_VERSION): Remove this once we drop support for <1.86, https://github.com/rust-lang/rust/commit/ac9cb908ac4301dfc25e7a2edee574320022ae2c
let is_rustc_box = {
let attrs = e.attrs();
attrs.filter_map(|it| it.as_simple_atom()).any(|it| it == "rustc_box")
@@ -1649,7 +1649,7 @@ impl<'db> ExprCollector<'db> {
fn desugar_try_block(&mut self, e: BlockExpr) -> ExprId {
let try_from_output = self.lang_path(self.lang_items().TryTraitFromOutput);
let label = self.generate_new_name();
- let label = self.alloc_label_desugared(Label { name: label });
+ let label = self.alloc_label_desugared(Label { name: label }, AstPtr::new(&e).wrap_right());
let old_label = self.current_try_block_label.replace(label);
let ptr = AstPtr::new(&e).upcast();
@@ -2319,7 +2319,6 @@ impl<'db> ExprCollector<'db> {
ast::Pat::SlicePat(p) => {
let SlicePatComponents { prefix, slice, suffix } = p.components();
- // FIXME properly handle `RestPat`
Pat::Slice {
prefix: prefix.into_iter().map(|p| self.collect_pat(p, binding_list)).collect(),
slice: slice.map(|p| self.collect_pat(p, binding_list)),
@@ -2399,7 +2398,6 @@ impl<'db> ExprCollector<'db> {
};
let start = range_part_lower(p.start());
let end = range_part_lower(p.end());
- // FIXME: Exclusive ended pattern range is stabilised
match p.op_kind() {
Some(range_type) => Pat::Range { start, end, range_type },
None => Pat::Missing,
@@ -2519,9 +2517,9 @@ impl<'db> ExprCollector<'db> {
let mut hygiene_info = if hygiene_id.is_root() {
None
} else {
- hygiene_id.lookup().outer_expn(self.db).map(|expansion| {
+ hygiene_id.syntax_context().outer_expn(self.db).map(|expansion| {
let expansion = self.db.lookup_intern_macro_call(expansion.into());
- (hygiene_id.lookup().parent(self.db), expansion.def)
+ (hygiene_id.syntax_context().parent(self.db), expansion.def)
})
};
let name = Name::new_lifetime(&lifetime.text());
@@ -2727,17 +2725,17 @@ impl ExprCollector<'_> {
self.store.pats.alloc(Pat::Missing)
}
- fn alloc_label(&mut self, label: Label, ptr: LabelPtr) -> LabelId {
+ fn alloc_label(&mut self, label: Label, ptr: AstPtr<ast::Label>) -> LabelId {
+ self.alloc_label_desugared(label, ptr.wrap_left())
+ }
+
+ fn alloc_label_desugared(&mut self, label: Label, ptr: LabelPtr) -> LabelId {
let src = self.expander.in_file(ptr);
let id = self.store.labels.alloc(label);
self.store.label_map_back.insert(id, src);
self.store.label_map.insert(src, id);
id
}
- // FIXME: desugared labels don't have ptr, that's wrong and should be fixed somehow.
- fn alloc_label_desugared(&mut self, label: Label) -> LabelId {
- self.store.labels.alloc(label)
- }
fn is_lowering_awaitable_block(&self) -> &Awaitable {
self.awaitable_context.as_ref().unwrap_or(&Awaitable::No("unknown"))
diff --git a/crates/hir-def/src/expr_store/lower/format_args.rs b/crates/hir-def/src/expr_store/lower/format_args.rs
index 32c9df3dfe..7ef84f27f6 100644
--- a/crates/hir-def/src/expr_store/lower/format_args.rs
+++ b/crates/hir-def/src/expr_store/lower/format_args.rs
@@ -3,6 +3,7 @@
use base_db::FxIndexSet;
use hir_expand::name::Name;
use intern::{Symbol, sym};
+use span::SyntaxContext;
use syntax::{AstPtr, AstToken as _, ast};
use crate::{
@@ -49,7 +50,7 @@ impl<'db> ExprCollector<'db> {
self.expand_macros_to_string(template.clone()).map(|it| (it, template))
}) {
Some(((s, is_direct_literal), template)) => {
- let call_ctx = self.expander.call_syntax_ctx();
+ let call_ctx = SyntaxContext::root(self.def_map.edition());
let hygiene = self.hygiene_id_for(s.syntax().text_range());
let fmt = format_args::parse(
&s,
diff --git a/crates/hir-def/src/hir/generics.rs b/crates/hir-def/src/hir/generics.rs
index 1a2d5ebba4..482cf36f95 100644
--- a/crates/hir-def/src/hir/generics.rs
+++ b/crates/hir-def/src/hir/generics.rs
@@ -20,8 +20,7 @@ pub type LocalLifetimeParamId = Idx<LifetimeParamData>;
/// Data about a generic type parameter (to a function, struct, impl, ...).
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct TypeParamData {
- /// [`None`] only if the type ref is an [`crate::type_ref::TypeRef::ImplTrait`]. FIXME: Might be better to just
- /// make it always be a value, giving impl trait a special name.
+ /// [`None`] only if the type ref is an [`crate::type_ref::TypeRef::ImplTrait`].
pub name: Option<Name>,
pub default: Option<TypeRefId>,
pub provenance: TypeParamProvenance,
diff --git a/crates/hir-def/src/hir/type_ref.rs b/crates/hir-def/src/hir/type_ref.rs
index ad8535413d..b64199fa26 100644
--- a/crates/hir-def/src/hir/type_ref.rs
+++ b/crates/hir-def/src/hir/type_ref.rs
@@ -1,8 +1,6 @@
//! HIR for references to types. Paths in these are not yet resolved. They can
//! be directly created from an ast::TypeRef, without further queries.
-use std::fmt::Write;
-
use hir_expand::name::Name;
use intern::Symbol;
use la_arena::Idx;
@@ -10,12 +8,11 @@ use thin_vec::ThinVec;
use crate::{
LifetimeParamId, TypeParamId,
- builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
expr_store::{
ExpressionStore,
path::{GenericArg, Path},
},
- hir::{ExprId, Literal},
+ hir::ExprId,
};
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
@@ -275,56 +272,3 @@ impl TypeBound {
pub struct ConstRef {
pub expr: ExprId,
}
-
-/// A literal constant value
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub enum LiteralConstRef {
- Int(i128),
- UInt(u128),
- Bool(bool),
- Char(char),
-
- /// Case of an unknown value that rustc might know but we don't
- // FIXME: this is a hack to get around chalk not being able to represent unevaluatable
- // constants
- // https://github.com/rust-lang/rust-analyzer/pull/8813#issuecomment-840679177
- // https://rust-lang.zulipchat.com/#narrow/stream/144729-wg-traits/topic/Handling.20non.20evaluatable.20constants'.20equality/near/238386348
- Unknown,
-}
-
-impl LiteralConstRef {
- pub fn builtin_type(&self) -> BuiltinType {
- match self {
- LiteralConstRef::UInt(_) | LiteralConstRef::Unknown => {
- BuiltinType::Uint(BuiltinUint::U128)
- }
- LiteralConstRef::Int(_) => BuiltinType::Int(BuiltinInt::I128),
- LiteralConstRef::Char(_) => BuiltinType::Char,
- LiteralConstRef::Bool(_) => BuiltinType::Bool,
- }
- }
-}
-
-impl From<Literal> for LiteralConstRef {
- fn from(literal: Literal) -> Self {
- match literal {
- Literal::Char(c) => Self::Char(c),
- Literal::Bool(flag) => Self::Bool(flag),
- Literal::Int(num, _) => Self::Int(num),
- Literal::Uint(num, _) => Self::UInt(num),
- _ => Self::Unknown,
- }
- }
-}
-
-impl std::fmt::Display for LiteralConstRef {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
- match self {
- LiteralConstRef::Int(num) => num.fmt(f),
- LiteralConstRef::UInt(num) => num.fmt(f),
- LiteralConstRef::Bool(flag) => flag.fmt(f),
- LiteralConstRef::Char(c) => write!(f, "'{c}'"),
- LiteralConstRef::Unknown => f.write_char('_'),
- }
- }
-}
diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs
index 9e7868b273..a3278dd76c 100644
--- a/crates/hir-def/src/item_scope.rs
+++ b/crates/hir-def/src/item_scope.rs
@@ -158,7 +158,7 @@ pub struct ItemScope {
/// declared.
declarations: ThinVec<ModuleDefId>,
- impls: ThinVec<ImplId>,
+ impls: ThinVec<(ImplId, /* trait impl */ bool)>,
builtin_derive_impls: ThinVec<BuiltinDeriveImplId>,
extern_blocks: ThinVec<ExternBlockId>,
unnamed_consts: ThinVec<ConstId>,
@@ -327,7 +327,15 @@ impl ItemScope {
}
pub fn impls(&self) -> impl ExactSizeIterator<Item = ImplId> + '_ {
- self.impls.iter().copied()
+ self.impls.iter().map(|&(id, _)| id)
+ }
+
+ pub fn trait_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
+ self.impls.iter().filter(|&&(_, is_trait_impl)| is_trait_impl).map(|&(id, _)| id)
+ }
+
+ pub fn inherent_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
+ self.impls.iter().filter(|&&(_, is_trait_impl)| !is_trait_impl).map(|&(id, _)| id)
}
pub fn builtin_derive_impls(&self) -> impl ExactSizeIterator<Item = BuiltinDeriveImplId> + '_ {
@@ -472,8 +480,8 @@ impl ItemScope {
self.legacy_macros.get(name).map(|it| &**it)
}
- pub(crate) fn define_impl(&mut self, imp: ImplId) {
- self.impls.push(imp);
+ pub(crate) fn define_impl(&mut self, imp: ImplId, is_trait_impl: bool) {
+ self.impls.push((imp, is_trait_impl));
}
pub(crate) fn define_builtin_derive_impl(&mut self, imp: BuiltinDeriveImplId) {
diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs
index 2e838fad2e..a1707f17be 100644
--- a/crates/hir-def/src/item_tree.rs
+++ b/crates/hir-def/src/item_tree.rs
@@ -614,7 +614,9 @@ pub struct Trait {
}
#[derive(Debug, Clone, Eq, PartialEq)]
-pub struct Impl {}
+pub struct Impl {
+ pub is_trait_impl: bool,
+}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TypeAlias {
diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs
index d8519f7393..3f19e00154 100644
--- a/crates/hir-def/src/item_tree/lower.rs
+++ b/crates/hir-def/src/item_tree/lower.rs
@@ -271,7 +271,7 @@ impl<'a> Ctx<'a> {
let ast_id = self.source_ast_id_map.ast_id(impl_def);
// Note that trait impls don't get implicit `Self` unlike traits, because here they are a
// type alias rather than a type parameter, so this is handled by the resolver.
- let res = Impl {};
+ let res = Impl { is_trait_impl: impl_def.trait_().is_some() };
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Impl(res));
ast_id
}
diff --git a/crates/hir-def/src/item_tree/pretty.rs b/crates/hir-def/src/item_tree/pretty.rs
index c89299e6d8..4113a778ea 100644
--- a/crates/hir-def/src/item_tree/pretty.rs
+++ b/crates/hir-def/src/item_tree/pretty.rs
@@ -258,7 +258,7 @@ impl Printer<'_> {
w!(self, "trait {} {{ ... }}", name.display(self.db, self.edition));
}
ModItemId::Impl(ast_id) => {
- let Impl {} = &self.tree[ast_id];
+ let Impl { is_trait_impl: _ } = &self.tree[ast_id];
self.print_ast_id(ast_id.erase());
w!(self, "impl {{ ... }}");
}
diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs
index 41d69c1fd6..eba4d87ec9 100644
--- a/crates/hir-def/src/lang_item.rs
+++ b/crates/hir-def/src/lang_item.rs
@@ -40,8 +40,12 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option<Box<LangIt
let crate_def_map = crate_def_map(db, krate);
+ if !crate_def_map.is_unstable_feature_enabled(&sym::lang_items) {
+ return None;
+ }
+
for (_, module_data) in crate_def_map.modules() {
- for impl_def in module_data.scope.impls() {
+ for impl_def in module_data.scope.inherent_impls() {
lang_items.collect_lang_item(db, impl_def);
for &(_, assoc) in impl_def.impl_items(db).items.iter() {
match assoc {
diff --git a/crates/hir-def/src/macro_expansion_tests/mod.rs b/crates/hir-def/src/macro_expansion_tests/mod.rs
index 3f136bc591..c63f2c1d78 100644
--- a/crates/hir-def/src/macro_expansion_tests/mod.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mod.rs
@@ -16,7 +16,7 @@ mod proc_macros;
use std::{any::TypeId, iter, ops::Range, sync};
-use base_db::{RootQueryDb, SourceDatabase};
+use base_db::RootQueryDb;
use expect_test::Expect;
use hir_expand::{
AstId, ExpansionInfo, InFile, MacroCallId, MacroCallKind, MacroKind,
@@ -387,7 +387,7 @@ struct IdentityWhenValidProcMacroExpander;
impl ProcMacroExpander for IdentityWhenValidProcMacroExpander {
fn expand(
&self,
- _: &dyn SourceDatabase,
+ _: &dyn ExpandDatabase,
subtree: &TopSubtree,
_: Option<&TopSubtree>,
_: &base_db::Env,
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index 4740e3b99e..87ade06517 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -2028,7 +2028,9 @@ impl ModCollector<'_, '_> {
let impl_id =
ImplLoc { container: module_id, id: InFile::new(self.file_id(), imp) }
.intern(db);
- self.def_collector.def_map.modules[self.module_id].scope.define_impl(impl_id)
+ self.def_collector.def_map.modules[self.module_id]
+ .scope
+ .define_impl(impl_id, self.item_tree[imp].is_trait_impl)
}
ModItemId::Function(id) => {
let it = &self.item_tree[id];
diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs
index e4b1d2a987..cf33cecf5f 100644
--- a/crates/hir-def/src/nameres/path_resolution.rs
+++ b/crates/hir-def/src/nameres/path_resolution.rs
@@ -267,7 +267,6 @@ impl DefMap {
// plain import or absolute path in 2015: crate-relative with
// fallback to extern prelude (with the simplification in
// rust-lang/rust#57745)
- // FIXME there must be a nicer way to write this condition
PathKind::Plain | PathKind::Abs
if self.data.edition == Edition::Edition2015
&& (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
@@ -383,7 +382,6 @@ impl DefMap {
// plain import or absolute path in 2015: crate-relative with
// fallback to extern prelude (with the simplification in
// rust-lang/rust#57745)
- // FIXME there must be a nicer way to write this condition
PathKind::Plain | PathKind::Abs
if self.data.edition == Edition::Edition2015
&& (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs
index 263f603a0b..f643ed31ad 100644
--- a/crates/hir-def/src/resolver.rs
+++ b/crates/hir-def/src/resolver.rs
@@ -950,7 +950,7 @@ fn hygiene_info(
hygiene_id: HygieneId,
) -> Option<(SyntaxContext, MacroDefId)> {
if !hygiene_id.is_root() {
- let ctx = hygiene_id.lookup();
+ let ctx = hygiene_id.syntax_context();
ctx.outer_expn(db).map(|expansion| {
let expansion = db.lookup_intern_macro_call(expansion.into());
(ctx.parent(db), expansion.def)
diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs
index 40d44cd1db..51767f87ff 100644
--- a/crates/hir-expand/src/db.rs
+++ b/crates/hir-expand/src/db.rs
@@ -9,8 +9,8 @@ use triomphe::Arc;
use crate::{
AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallInfo,
- EagerExpander, EditionedFileId, ExpandError, ExpandResult, ExpandTo, HirFileId, MacroCallId,
- MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind,
+ EagerExpander, EditionedFileId, ExpandError, ExpandResult, ExpandTo, FileRange, HirFileId,
+ MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind,
attrs::Meta,
builtin::pseudo_derive_attr_expansion,
cfg_process::attr_macro_input_to_token_tree,
@@ -62,6 +62,9 @@ pub trait ExpandDatabase: RootQueryDb {
fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>;
#[salsa::transparent]
+ fn resolve_span(&self, span: Span) -> FileRange;
+
+ #[salsa::transparent]
fn parse_or_expand(&self, file_id: HirFileId) -> SyntaxNode;
/// Implementation for the macro case.
@@ -158,6 +161,13 @@ fn syntax_context(db: &dyn ExpandDatabase, file: HirFileId, edition: Edition) ->
}
}
+fn resolve_span(db: &dyn ExpandDatabase, Span { range, anchor, ctx: _ }: Span) -> FileRange {
+ let file_id = EditionedFileId::from_span_guess_origin(db, anchor.file_id);
+ let anchor_offset =
+ db.ast_id_map(file_id.into()).get_erased(anchor.ast_id).text_range().start();
+ FileRange { file_id, range: range + anchor_offset }
+}
+
/// This expands the given macro call, but with different arguments. This is
/// used for completion, where we want to see what 'would happen' if we insert a
/// token. The `token_to_map` mapped down into the expansion, with the mapped
diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs
index 7b6a6135b3..05541e782e 100644
--- a/crates/hir-expand/src/lib.rs
+++ b/crates/hir-expand/src/lib.rs
@@ -901,11 +901,8 @@ impl ExpansionInfo {
let span = self.exp_map.span_at(token.start());
match &self.arg_map {
SpanMap::RealSpanMap(_) => {
- let file_id =
- EditionedFileId::from_span_guess_origin(db, span.anchor.file_id).into();
- let anchor_offset =
- db.ast_id_map(file_id).get_erased(span.anchor.ast_id).text_range().start();
- InFile { file_id, value: smallvec::smallvec![span.range + anchor_offset] }
+ let range = db.resolve_span(span);
+ InFile { file_id: range.file_id.into(), value: smallvec::smallvec![range.range] }
}
SpanMap::ExpansionSpanMap(arg_map) => {
let Some(arg_node) = &self.arg.value else {
@@ -947,7 +944,7 @@ pub fn map_node_range_up_rooted(
range: TextRange,
) -> Option<FileRange> {
let mut spans = exp_map.spans_for_range(range).filter(|span| span.ctx.is_root());
- let Span { range, anchor, ctx: _ } = spans.next()?;
+ let Span { range, anchor, ctx } = spans.next()?;
let mut start = range.start();
let mut end = range.end();
@@ -958,10 +955,7 @@ pub fn map_node_range_up_rooted(
start = start.min(span.range.start());
end = end.max(span.range.end());
}
- let file_id = EditionedFileId::from_span_guess_origin(db, anchor.file_id);
- let anchor_offset =
- db.ast_id_map(file_id.into()).get_erased(anchor.ast_id).text_range().start();
- Some(FileRange { file_id, range: TextRange::new(start, end) + anchor_offset })
+ Some(db.resolve_span(Span { range: TextRange::new(start, end), anchor, ctx }))
}
/// Maps up the text range out of the expansion hierarchy back into the original file its from.
@@ -984,10 +978,7 @@ pub fn map_node_range_up(
start = start.min(span.range.start());
end = end.max(span.range.end());
}
- let file_id = EditionedFileId::from_span_guess_origin(db, anchor.file_id);
- let anchor_offset =
- db.ast_id_map(file_id.into()).get_erased(anchor.ast_id).text_range().start();
- Some((FileRange { file_id, range: TextRange::new(start, end) + anchor_offset }, ctx))
+ Some((db.resolve_span(Span { range: TextRange::new(start, end), anchor, ctx }), ctx))
}
/// Looks up the span at the given offset.
@@ -997,10 +988,7 @@ pub fn span_for_offset(
offset: TextSize,
) -> (FileRange, SyntaxContext) {
let span = exp_map.span_at(offset);
- let file_id = EditionedFileId::from_span_guess_origin(db, span.anchor.file_id);
- let anchor_offset =
- db.ast_id_map(file_id.into()).get_erased(span.anchor.ast_id).text_range().start();
- (FileRange { file_id, range: span.range + anchor_offset }, span.ctx)
+ (db.resolve_span(span), span.ctx)
}
/// In Rust, macros expand token trees to token trees. When we want to turn a
diff --git a/crates/hir-expand/src/proc_macro.rs b/crates/hir-expand/src/proc_macro.rs
index d2614aa5f1..467eae3122 100644
--- a/crates/hir-expand/src/proc_macro.rs
+++ b/crates/hir-expand/src/proc_macro.rs
@@ -4,7 +4,7 @@ use core::fmt;
use std::any::Any;
use std::{panic::RefUnwindSafe, sync};
-use base_db::{Crate, CrateBuilderId, CratesIdMap, Env, ProcMacroLoadingError, SourceDatabase};
+use base_db::{Crate, CrateBuilderId, CratesIdMap, Env, ProcMacroLoadingError};
use intern::Symbol;
use rustc_hash::FxHashMap;
use span::Span;
@@ -25,7 +25,7 @@ pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe + Any {
/// [`ProcMacroKind::Attr`]), environment variables, and span information.
fn expand(
&self,
- db: &dyn SourceDatabase,
+ db: &dyn ExpandDatabase,
subtree: &tt::TopSubtree,
attrs: Option<&tt::TopSubtree>,
env: &Env,
diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs
index f11240e0f7..5bc2446fdd 100644
--- a/crates/hir-ty/src/consteval.rs
+++ b/crates/hir-ty/src/consteval.rs
@@ -7,9 +7,9 @@ use base_db::Crate;
use hir_def::{
ConstId, EnumVariantId, GeneralConstId, HasModule, StaticId,
attrs::AttrFlags,
+ builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
expr_store::Body,
- hir::{Expr, ExprId},
- type_ref::LiteralConstRef,
+ hir::{Expr, ExprId, Literal},
};
use hir_expand::Lookup;
use rustc_type_ir::inherent::IntoKind;
@@ -23,7 +23,7 @@ use crate::{
mir::{MirEvalError, MirLowerError},
next_solver::{
Const, ConstBytes, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs,
- ParamEnv, StoredConst, StoredGenericArgs, Ty, ValueConst,
+ StoredConst, StoredGenericArgs, Ty, ValueConst,
},
traits::StoredParamEnvAndCrate,
};
@@ -81,47 +81,122 @@ impl From<MirEvalError> for ConstEvalError {
/// Interns a constant scalar with the given type
pub fn intern_const_ref<'a>(
db: &'a dyn HirDatabase,
- value: &LiteralConstRef,
+ value: &Literal,
ty: Ty<'a>,
- krate: Crate,
+ _krate: Crate,
) -> Const<'a> {
let interner = DbInterner::new_no_crate(db);
- let layout = db
- .layout_of_ty(ty.store(), ParamEnvAndCrate { param_env: ParamEnv::empty(), krate }.store());
let kind = match value {
- LiteralConstRef::Int(i) => {
- // FIXME: We should handle failure of layout better.
- let size = layout.map(|it| it.size.bytes_usize()).unwrap_or(16);
+ &Literal::Uint(i, builtin_ty)
+ if builtin_ty.is_none() || ty.as_builtin() == builtin_ty.map(BuiltinType::Uint) =>
+ {
+ let memory = match ty.as_builtin() {
+ Some(BuiltinType::Uint(builtin_uint)) => match builtin_uint {
+ BuiltinUint::U8 => Box::new([i as u8]) as Box<[u8]>,
+ BuiltinUint::U16 => Box::new((i as u16).to_le_bytes()),
+ BuiltinUint::U32 => Box::new((i as u32).to_le_bytes()),
+ BuiltinUint::U64 => Box::new((i as u64).to_le_bytes()),
+ BuiltinUint::U128 => Box::new((i).to_le_bytes()),
+ BuiltinUint::Usize => Box::new((i as usize).to_le_bytes()),
+ },
+ _ => return Const::new(interner, rustc_type_ir::ConstKind::Error(ErrorGuaranteed)),
+ };
rustc_type_ir::ConstKind::Value(ValueConst::new(
ty,
- ConstBytes {
- memory: i.to_le_bytes()[0..size].into(),
- memory_map: MemoryMap::default(),
+ ConstBytes { memory, memory_map: MemoryMap::default() },
+ ))
+ }
+ &Literal::Int(i, None)
+ if ty
+ .as_builtin()
+ .is_some_and(|builtin_ty| matches!(builtin_ty, BuiltinType::Uint(_))) =>
+ {
+ let memory = match ty.as_builtin() {
+ Some(BuiltinType::Uint(builtin_uint)) => match builtin_uint {
+ BuiltinUint::U8 => Box::new([i as u8]) as Box<[u8]>,
+ BuiltinUint::U16 => Box::new((i as u16).to_le_bytes()),
+ BuiltinUint::U32 => Box::new((i as u32).to_le_bytes()),
+ BuiltinUint::U64 => Box::new((i as u64).to_le_bytes()),
+ BuiltinUint::U128 => Box::new((i as u128).to_le_bytes()),
+ BuiltinUint::Usize => Box::new((i as usize).to_le_bytes()),
},
+ _ => return Const::new(interner, rustc_type_ir::ConstKind::Error(ErrorGuaranteed)),
+ };
+ rustc_type_ir::ConstKind::Value(ValueConst::new(
+ ty,
+ ConstBytes { memory, memory_map: MemoryMap::default() },
))
}
- LiteralConstRef::UInt(i) => {
- let size = layout.map(|it| it.size.bytes_usize()).unwrap_or(16);
+ &Literal::Int(i, builtin_ty)
+ if builtin_ty.is_none() || ty.as_builtin() == builtin_ty.map(BuiltinType::Int) =>
+ {
+ let memory = match ty.as_builtin() {
+ Some(BuiltinType::Int(builtin_int)) => match builtin_int {
+ BuiltinInt::I8 => Box::new([i as u8]) as Box<[u8]>,
+ BuiltinInt::I16 => Box::new((i as i16).to_le_bytes()),
+ BuiltinInt::I32 => Box::new((i as i32).to_le_bytes()),
+ BuiltinInt::I64 => Box::new((i as i64).to_le_bytes()),
+ BuiltinInt::I128 => Box::new((i).to_le_bytes()),
+ BuiltinInt::Isize => Box::new((i as isize).to_le_bytes()),
+ },
+ _ => return Const::new(interner, rustc_type_ir::ConstKind::Error(ErrorGuaranteed)),
+ };
rustc_type_ir::ConstKind::Value(ValueConst::new(
ty,
- ConstBytes {
- memory: i.to_le_bytes()[0..size].into(),
- memory_map: MemoryMap::default(),
+ ConstBytes { memory, memory_map: MemoryMap::default() },
+ ))
+ }
+ Literal::Float(float_type_wrapper, builtin_float)
+ if builtin_float.is_none()
+ || ty.as_builtin() == builtin_float.map(BuiltinType::Float) =>
+ {
+ let memory = match ty.as_builtin().unwrap() {
+ BuiltinType::Float(builtin_float) => match builtin_float {
+ // FIXME:
+ hir_def::builtin_type::BuiltinFloat::F16 => Box::new([0u8; 2]) as Box<[u8]>,
+ hir_def::builtin_type::BuiltinFloat::F32 => {
+ Box::new(float_type_wrapper.to_f32().to_le_bytes())
+ }
+ hir_def::builtin_type::BuiltinFloat::F64 => {
+ Box::new(float_type_wrapper.to_f64().to_le_bytes())
+ }
+ // FIXME:
+ hir_def::builtin_type::BuiltinFloat::F128 => Box::new([0; 16]),
},
+ _ => unreachable!(),
+ };
+ rustc_type_ir::ConstKind::Value(ValueConst::new(
+ ty,
+ ConstBytes { memory, memory_map: MemoryMap::default() },
))
}
- LiteralConstRef::Bool(b) => rustc_type_ir::ConstKind::Value(ValueConst::new(
+ Literal::Bool(b) if ty.is_bool() => rustc_type_ir::ConstKind::Value(ValueConst::new(
ty,
ConstBytes { memory: Box::new([*b as u8]), memory_map: MemoryMap::default() },
)),
- LiteralConstRef::Char(c) => rustc_type_ir::ConstKind::Value(ValueConst::new(
+ Literal::Char(c) if ty.is_char() => rustc_type_ir::ConstKind::Value(ValueConst::new(
ty,
ConstBytes {
memory: (*c as u32).to_le_bytes().into(),
memory_map: MemoryMap::default(),
},
)),
- LiteralConstRef::Unknown => rustc_type_ir::ConstKind::Error(ErrorGuaranteed),
+ Literal::String(symbol) if ty.is_str() => rustc_type_ir::ConstKind::Value(ValueConst::new(
+ ty,
+ ConstBytes {
+ memory: symbol.as_str().as_bytes().into(),
+ memory_map: MemoryMap::default(),
+ },
+ )),
+ Literal::ByteString(items) if ty.as_slice().is_some_and(|ty| ty.is_u8()) => {
+ rustc_type_ir::ConstKind::Value(ValueConst::new(
+ ty,
+ ConstBytes { memory: items.clone(), memory_map: MemoryMap::default() },
+ ))
+ }
+ // FIXME
+ Literal::CString(_items) => rustc_type_ir::ConstKind::Error(ErrorGuaranteed),
+ _ => rustc_type_ir::ConstKind::Error(ErrorGuaranteed),
};
Const::new(interner, kind)
}
@@ -130,7 +205,15 @@ pub fn intern_const_ref<'a>(
pub fn usize_const<'db>(db: &'db dyn HirDatabase, value: Option<u128>, krate: Crate) -> Const<'db> {
intern_const_ref(
db,
- &value.map_or(LiteralConstRef::Unknown, LiteralConstRef::UInt),
+ &match value {
+ Some(value) => Literal::Uint(value, Some(BuiltinUint::Usize)),
+ None => {
+ return Const::new(
+ DbInterner::new_no_crate(db),
+ rustc_type_ir::ConstKind::Error(ErrorGuaranteed),
+ );
+ }
+ },
Ty::new_uint(DbInterner::new_no_crate(db), rustc_type_ir::UintTy::Usize),
krate,
)
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index 08f201fea9..5f6bcb4a60 100644
--- a/crates/hir-ty/src/consteval/tests.rs
+++ b/crates/hir-ty/src/consteval/tests.rs
@@ -2209,6 +2209,7 @@ fn boxes() {
check_number(
r#"
//- minicore: coerce_unsized, deref_mut, slice
+#![feature(lang_items)]
use core::ops::{Deref, DerefMut};
use core::{marker::Unsize, ops::CoerceUnsized};
@@ -2346,6 +2347,7 @@ fn c_string() {
check_number(
r#"
//- minicore: index, slice
+#![feature(lang_items)]
#[lang = "CStr"]
pub struct CStr {
inner: [u8]
@@ -2360,6 +2362,7 @@ const GOAL: u8 = {
check_number(
r#"
//- minicore: index, slice
+#![feature(lang_items)]
#[lang = "CStr"]
pub struct CStr {
inner: [u8]
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index 44bbd84003..43b428c3fa 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -10,7 +10,8 @@ use std::{
use base_db::{Crate, FxIndexMap};
use either::Either;
use hir_def::{
- FindPathConfig, GenericDefId, HasModule, LocalFieldId, Lookup, ModuleDefId, ModuleId, TraitId,
+ FindPathConfig, GenericDefId, GenericParamId, HasModule, LocalFieldId, Lookup, ModuleDefId,
+ ModuleId, TraitId,
db::DefDatabase,
expr_store::{ExpressionStore, path::Path},
find_path::{self, PrefixKind},
@@ -66,6 +67,7 @@ pub type Result<T = (), E = HirDisplayError> = std::result::Result<T, E>;
pub trait HirWrite: fmt::Write {
fn start_location_link(&mut self, _location: ModuleDefId) {}
+ fn start_location_link_generic(&mut self, _location: GenericParamId) {}
fn end_location_link(&mut self) {}
}
@@ -147,6 +149,10 @@ impl<'db> HirFormatter<'_, 'db> {
self.fmt.start_location_link(location);
}
+ pub fn start_location_link_generic(&mut self, location: GenericParamId) {
+ self.fmt.start_location_link_generic(location);
+ }
+
pub fn end_location_link(&mut self) {
self.fmt.end_location_link();
}
@@ -686,7 +692,9 @@ impl<'db> HirDisplay<'db> for Const<'db> {
ConstKind::Param(param) => {
let generics = generics(f.db, param.id.parent());
let param_data = &generics[param.id.local_id()];
+ f.start_location_link_generic(param.id.into());
write!(f, "{}", param_data.name().unwrap().display(f.db, f.edition()))?;
+ f.end_location_link();
Ok(())
}
ConstKind::Value(const_bytes) => render_const_scalar(
@@ -1489,6 +1497,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
match param_data {
TypeOrConstParamData::TypeParamData(p) => match p.provenance {
TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
+ f.start_location_link_generic(param.id.into());
write!(
f,
"{}",
@@ -1496,7 +1505,8 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
.clone()
.unwrap_or_else(Name::missing)
.display(f.db, f.edition())
- )?
+ )?;
+ f.end_location_link();
}
TypeParamProvenance::ArgumentImplTrait => {
let bounds = GenericPredicates::query_all(f.db, param.id.parent())
@@ -1519,7 +1529,9 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
}
},
TypeOrConstParamData::ConstParamData(p) => {
+ f.start_location_link_generic(param.id.into());
write!(f, "{}", p.name.display(f.db, f.edition()))?;
+ f.end_location_link();
}
}
}
@@ -2031,7 +2043,9 @@ impl<'db> HirDisplay<'db> for Region<'db> {
RegionKind::ReEarlyParam(param) => {
let generics = generics(f.db, param.id.parent);
let param_data = &generics[param.id.local_id];
+ f.start_location_link_generic(param.id.into());
write!(f, "{}", param_data.name.display(f.db, f.edition()))?;
+ f.end_location_link();
Ok(())
}
RegionKind::ReBound(BoundVarIndexKind::Bound(db), idx) => {
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 9307868f39..46ec554e0a 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -27,8 +27,8 @@ use hir_def::{
resolver::{HasResolver, LifetimeNs, Resolver, TypeNs, ValueNs},
signatures::{FunctionSignature, TraitFlags, TypeAliasFlags},
type_ref::{
- ConstRef, LifetimeRefId, LiteralConstRef, PathId, TraitBoundModifier,
- TraitRef as HirTraitRef, TypeBound, TypeRef, TypeRefId,
+ ConstRef, LifetimeRefId, PathId, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound,
+ TypeRef, TypeRefId,
},
};
use hir_expand::name::Name;
@@ -281,21 +281,9 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
hir_def::hir::Expr::Path(path) => {
self.path_to_const(path).unwrap_or_else(|| unknown_const(const_type))
}
- hir_def::hir::Expr::Literal(literal) => intern_const_ref(
- self.db,
- &match *literal {
- hir_def::hir::Literal::Float(_, _)
- | hir_def::hir::Literal::String(_)
- | hir_def::hir::Literal::ByteString(_)
- | hir_def::hir::Literal::CString(_) => LiteralConstRef::Unknown,
- hir_def::hir::Literal::Char(c) => LiteralConstRef::Char(c),
- hir_def::hir::Literal::Bool(b) => LiteralConstRef::Bool(b),
- hir_def::hir::Literal::Int(val, _) => LiteralConstRef::Int(val),
- hir_def::hir::Literal::Uint(val, _) => LiteralConstRef::UInt(val),
- },
- const_type,
- self.resolver.krate(),
- ),
+ hir_def::hir::Expr::Literal(literal) => {
+ intern_const_ref(self.db, literal, const_type, self.resolver.krate())
+ }
hir_def::hir::Expr::UnaryOp { expr: inner_expr, op: hir_def::hir::UnaryOp::Neg } => {
if let hir_def::hir::Expr::Literal(literal) = &self.store[*inner_expr] {
// Only handle negation for signed integers and floats
@@ -304,7 +292,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
if let Some(negated_literal) = literal.clone().negate() {
intern_const_ref(
self.db,
- &negated_literal.into(),
+ &negated_literal,
const_type,
self.resolver.krate(),
)
@@ -1319,7 +1307,7 @@ fn type_for_struct_constructor(
db: &dyn HirDatabase,
def: StructId,
) -> Option<StoredEarlyBinder<StoredTy>> {
- let struct_data = def.fields(db);
+ let struct_data = db.struct_signature(def);
match struct_data.shape {
FieldsShape::Record => None,
FieldsShape::Unit => Some(type_for_adt(db, def.into())),
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index 50dbd87d69..e4681b464f 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -609,12 +609,7 @@ impl InherentImpls {
map: &mut FxHashMap<SimplifiedType, Vec<ImplId>>,
) {
for (_module_id, module_data) in def_map.modules() {
- for impl_id in module_data.scope.impls() {
- let data = db.impl_signature(impl_id);
- if data.target_trait.is_some() {
- continue;
- }
-
+ for impl_id in module_data.scope.inherent_impls() {
let interner = DbInterner::new_no_crate(db);
let self_ty = db.impl_self_ty(impl_id);
let self_ty = self_ty.instantiate_identity();
@@ -730,7 +725,11 @@ impl TraitImpls {
map: &mut FxHashMap<TraitId, OneTraitImplsBuilder>,
) {
for (_module_id, module_data) in def_map.modules() {
- for impl_id in module_data.scope.impls() {
+ for impl_id in module_data.scope.trait_impls() {
+ let trait_ref = match db.impl_trait(impl_id) {
+ Some(tr) => tr.instantiate_identity(),
+ None => continue,
+ };
// Reservation impls should be ignored during trait resolution, so we never need
// them during type analysis. See rust-lang/rust#64631 for details.
//
@@ -742,10 +741,6 @@ impl TraitImpls {
{
continue;
}
- let trait_ref = match db.impl_trait(impl_id) {
- Some(tr) => tr.instantiate_identity(),
- None => continue,
- };
let self_ty = trait_ref.self_ty();
let interner = DbInterner::new_no_crate(db);
let entry = map.entry(trait_ref.def_id.0).or_default();
diff --git a/crates/hir-ty/src/next_solver/infer/mod.rs b/crates/hir-ty/src/next_solver/infer/mod.rs
index 2926dc30de..7d291f7ddb 100644
--- a/crates/hir-ty/src/next_solver/infer/mod.rs
+++ b/crates/hir-ty/src/next_solver/infer/mod.rs
@@ -878,9 +878,11 @@ impl<'db> InferCtxt<'db> {
self.tainted_by_errors.set(Some(e));
}
- #[instrument(level = "debug", skip(self), ret)]
- pub fn take_opaque_types(&self) -> Vec<(OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)> {
- self.inner.borrow_mut().opaque_type_storage.take_opaque_types().collect()
+ #[instrument(level = "debug", skip(self))]
+ pub fn take_opaque_types(
+ &self,
+ ) -> impl IntoIterator<Item = (OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)> + use<'db> {
+ self.inner.borrow_mut().opaque_type_storage.take_opaque_types()
}
#[instrument(level = "debug", skip(self), ret)]
diff --git a/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs b/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs
index 00177d21ac..894fe5eb7b 100644
--- a/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs
+++ b/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs
@@ -61,7 +61,7 @@ impl<'db> OpaqueTypeStorage<'db> {
pub(crate) fn take_opaque_types(
&mut self,
- ) -> impl Iterator<Item = (OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)> {
+ ) -> impl IntoIterator<Item = (OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)> + use<'db> {
let OpaqueTypeStorage { opaque_types, duplicate_entries } = self;
std::mem::take(opaque_types).into_iter().chain(std::mem::take(duplicate_entries))
}
diff --git a/crates/hir-ty/src/next_solver/ty.rs b/crates/hir-ty/src/next_solver/ty.rs
index 030ba37015..66a24d3949 100644
--- a/crates/hir-ty/src/next_solver/ty.rs
+++ b/crates/hir-ty/src/next_solver/ty.rs
@@ -383,6 +383,11 @@ impl<'db> Ty<'db> {
matches!(self.kind(), TyKind::Bool)
}
+ #[inline]
+ pub fn is_char(self) -> bool {
+ matches!(self.kind(), TyKind::Char)
+ }
+
/// A scalar type is one that denotes an atomic datum, with no sub-components.
/// (A RawPtr is scalar because it represents a non-managed pointer, so its
/// contents are abstract to rustc.)
@@ -423,6 +428,11 @@ impl<'db> Ty<'db> {
}
#[inline]
+ pub fn is_u8(self) -> bool {
+ matches!(self.kind(), TyKind::Uint(UintTy::U8))
+ }
+
+ #[inline]
pub fn is_raw_ptr(self) -> bool {
matches!(self.kind(), TyKind::RawPtr(..))
}
@@ -457,6 +467,14 @@ impl<'db> Ty<'db> {
}
#[inline]
+ pub fn as_slice(self) -> Option<Ty<'db>> {
+ match self.kind() {
+ TyKind::Slice(ty) => Some(ty),
+ _ => None,
+ }
+ }
+
+ #[inline]
pub fn ty_vid(self) -> Option<TyVid> {
match self.kind() {
TyKind::Infer(rustc_type_ir::TyVar(vid)) => Some(vid),
diff --git a/crates/hir-ty/src/tests/incremental.rs b/crates/hir-ty/src/tests/incremental.rs
index 1457bb2e10..cf7ff6f7ec 100644
--- a/crates/hir-ty/src/tests/incremental.rs
+++ b/crates/hir-ty/src/tests/incremental.rs
@@ -132,14 +132,13 @@ fn baz() -> i32 {
"trait_environment_query",
"lang_items",
"crate_lang_items",
- "AttrFlags::query_",
- "AttrFlags::query_",
"GenericPredicates::query_with_diagnostics_",
"ImplTraits::return_type_impl_traits_",
"expr_scopes_shim",
"InferenceResult::for_body_",
"function_signature_shim",
"function_signature_with_source_map_shim",
+ "AttrFlags::query_",
"body_shim",
"body_with_source_map_shim",
"trait_environment_query",
@@ -149,6 +148,7 @@ fn baz() -> i32 {
"InferenceResult::for_body_",
"function_signature_shim",
"function_signature_with_source_map_shim",
+ "AttrFlags::query_",
"body_shim",
"body_with_source_map_shim",
"trait_environment_query",
@@ -197,13 +197,13 @@ fn baz() -> i32 {
"body_with_source_map_shim",
"body_shim",
"AttrFlags::query_",
- "AttrFlags::query_",
"function_signature_with_source_map_shim",
"function_signature_shim",
"body_with_source_map_shim",
"body_shim",
"InferenceResult::for_body_",
"expr_scopes_shim",
+ "AttrFlags::query_",
"function_signature_with_source_map_shim",
"function_signature_shim",
"body_with_source_map_shim",
@@ -245,8 +245,6 @@ $0",
"TraitImpls::for_crate_",
"lang_items",
"crate_lang_items",
- "AttrFlags::query_",
- "AttrFlags::query_",
]
"#]],
);
@@ -284,9 +282,6 @@ pub struct NewStruct {
"crate_local_def_map",
"TraitImpls::for_crate_",
"crate_lang_items",
- "AttrFlags::query_",
- "AttrFlags::query_",
- "AttrFlags::query_",
]
"#]],
);
@@ -324,8 +319,6 @@ $0",
"TraitImpls::for_crate_",
"lang_items",
"crate_lang_items",
- "AttrFlags::query_",
- "AttrFlags::query_",
]
"#]],
);
@@ -364,12 +357,6 @@ pub enum SomeEnum {
"crate_local_def_map",
"TraitImpls::for_crate_",
"crate_lang_items",
- "AttrFlags::query_",
- "AttrFlags::query_",
- "AttrFlags::query_",
- "EnumVariants::of_",
- "AttrFlags::query_",
- "AttrFlags::query_",
]
"#]],
);
@@ -407,8 +394,6 @@ $0",
"TraitImpls::for_crate_",
"lang_items",
"crate_lang_items",
- "AttrFlags::query_",
- "AttrFlags::query_",
]
"#]],
);
@@ -444,8 +429,6 @@ fn bar() -> f32 {
"crate_local_def_map",
"TraitImpls::for_crate_",
"crate_lang_items",
- "AttrFlags::query_",
- "AttrFlags::query_",
]
"#]],
);
@@ -487,9 +470,6 @@ $0",
"TraitImpls::for_crate_",
"lang_items",
"crate_lang_items",
- "AttrFlags::query_",
- "AttrFlags::query_",
- "AttrFlags::query_",
]
"#]],
);
@@ -533,18 +513,6 @@ impl SomeStruct {
"crate_local_def_map",
"TraitImpls::for_crate_",
"crate_lang_items",
- "AttrFlags::query_",
- "ImplItems::of_",
- "AttrFlags::query_",
- "AttrFlags::query_",
- "AttrFlags::query_",
- "AttrFlags::query_",
- "impl_trait_with_diagnostics_query",
- "impl_signature_shim",
- "impl_signature_with_source_map_shim",
- "impl_self_ty_with_diagnostics_query",
- "struct_signature_shim",
- "struct_signature_with_source_map_shim",
]
"#]],
);
@@ -616,8 +584,6 @@ fn main() {
"trait_environment_query",
"lang_items",
"crate_lang_items",
- "AttrFlags::query_",
- "AttrFlags::query_",
"GenericPredicates::query_with_diagnostics_",
"GenericPredicates::query_with_diagnostics_",
"ImplTraits::return_type_impl_traits_",
@@ -630,18 +596,18 @@ fn main() {
"expr_scopes_shim",
"struct_signature_shim",
"struct_signature_with_source_map_shim",
+ "AttrFlags::query_",
"GenericPredicates::query_with_diagnostics_",
"value_ty_query",
- "VariantFields::firewall_",
- "VariantFields::query_",
"InherentImpls::for_crate_",
- "impl_signature_shim",
- "impl_signature_with_source_map_shim",
"callable_item_signature_query",
"TraitImpls::for_crate_and_deps_",
"TraitImpls::for_crate_",
"impl_trait_with_diagnostics_query",
+ "impl_signature_shim",
+ "impl_signature_with_source_map_shim",
"impl_self_ty_with_diagnostics_query",
+ "AttrFlags::query_",
"GenericPredicates::query_with_diagnostics_",
]
"#]],
@@ -710,9 +676,6 @@ fn main() {
"body_with_source_map_shim",
"body_shim",
"crate_lang_items",
- "AttrFlags::query_",
- "AttrFlags::query_",
- "AttrFlags::query_",
"GenericPredicates::query_with_diagnostics_",
"GenericPredicates::query_with_diagnostics_",
"ImplTraits::return_type_impl_traits_",
@@ -722,15 +685,16 @@ fn main() {
"ImplTraits::return_type_impl_traits_",
"expr_scopes_shim",
"struct_signature_with_source_map_shim",
+ "AttrFlags::query_",
"GenericPredicates::query_with_diagnostics_",
- "VariantFields::query_",
"InherentImpls::for_crate_",
- "impl_signature_with_source_map_shim",
- "impl_signature_shim",
"callable_item_signature_query",
"TraitImpls::for_crate_",
+ "impl_signature_with_source_map_shim",
+ "impl_signature_shim",
"impl_trait_with_diagnostics_query",
"impl_self_ty_with_diagnostics_query",
+ "AttrFlags::query_",
"GenericPredicates::query_with_diagnostics_",
]
"#]],
diff --git a/crates/hir-ty/src/tests/patterns.rs b/crates/hir-ty/src/tests/patterns.rs
index c312b16759..0b776938c5 100644
--- a/crates/hir-ty/src/tests/patterns.rs
+++ b/crates/hir-ty/src/tests/patterns.rs
@@ -794,6 +794,8 @@ fn slice_tail_pattern() {
fn box_pattern() {
check_infer(
r#"
+ #![feature(lang_items)]
+
pub struct Global;
#[lang = "owned_box"]
pub struct Box<T, A = Global>(T);
@@ -805,13 +807,13 @@ fn box_pattern() {
}
"#,
expect![[r#"
- 83..89 'params': Box<i32, Global>
- 101..155 '{ ... } }': ()
- 107..153 'match ... }': ()
- 113..119 'params': Box<i32, Global>
- 130..141 'box integer': Box<i32, Global>
- 134..141 'integer': i32
- 145..147 '{}': ()
+ 108..114 'params': Box<i32, Global>
+ 126..180 '{ ... } }': ()
+ 132..178 'match ... }': ()
+ 138..144 'params': Box<i32, Global>
+ 155..166 'box integer': Box<i32, Global>
+ 159..166 'integer': i32
+ 170..172 '{}': ()
"#]],
);
check_infer(
@@ -831,7 +833,6 @@ fn box_pattern() {
76..122 'match ... }': ()
82..88 'params': Box<i32>
99..110 'box integer': Box<i32>
- 103..110 'integer': i32
114..116 '{}': ()
"#]],
);
@@ -1142,6 +1143,7 @@ fn my_fn(#[cfg(feature = "feature")] u8: u8, u32: u32) {}
fn var_args() {
check_types(
r#"
+#![feature(lang_items)]
#[lang = "va_list"]
pub struct VaListImpl<'f>;
fn my_fn(foo: ...) {}
@@ -1156,6 +1158,7 @@ fn my_fn2(bar: u32, foo: ...) {}
fn var_args_cond() {
check_types(
r#"
+#![feature(lang_items)]
#[lang = "va_list"]
pub struct VaListImpl<'f>;
fn my_fn(bar: u32, #[cfg(FALSE)] foo: ..., #[cfg(not(FALSE))] foo: u32) {
diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs
index f03f8d754f..c805f03044 100644
--- a/crates/hir-ty/src/tests/regression.rs
+++ b/crates/hir-ty/src/tests/regression.rs
@@ -2374,6 +2374,7 @@ fn rust_destruct_option_clone() {
check_types(
r#"
//- minicore: option, drop
+#![feature(lang_items)]
fn test(o: &Option<i32>) {
o.my_clone();
//^^^^^^^^^^^^ Option<i32>
diff --git a/crates/hir-ty/src/tests/regression/new_solver.rs b/crates/hir-ty/src/tests/regression/new_solver.rs
index e11cc85e7f..a4554673cd 100644
--- a/crates/hir-ty/src/tests/regression/new_solver.rs
+++ b/crates/hir-ty/src/tests/regression/new_solver.rs
@@ -234,6 +234,7 @@ fn main() {
// toolchains <= 1.88.0, before sized-hierarchy.
check_no_mismatches(
r#"
+#![feature(lang_items)]
#[lang = "sized"]
pub trait Sized {}
diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs
index db557b7507..6367521841 100644
--- a/crates/hir-ty/src/tests/simple.rs
+++ b/crates/hir-ty/src/tests/simple.rs
@@ -2702,6 +2702,8 @@ fn box_into_vec() {
check_infer(
r#"
//- /core.rs crate:core
+#![feature(lang_items)]
+
#[lang = "sized"]
pub trait Sized {}
@@ -2745,22 +2747,22 @@ struct Astruct;
impl B for Astruct {}
"#,
expect![[r#"
- 614..618 'self': Box<[T], A>
- 647..679 '{ ... }': Vec<T, A>
- 693..863 '{ ...])); }': ()
- 703..706 'vec': Vec<i32, Global>
- 709..724 '<[_]>::into_vec': fn into_vec<i32, Global>(Box<[i32], Global>) -> Vec<i32, Global>
- 709..755 '<[_]>:...i32]))': Vec<i32, Global>
- 725..754 '#[rust...1i32])': Box<[i32; 1], Global>
- 747..753 '[1i32]': [i32; 1]
- 748..752 '1i32': i32
- 765..766 'v': Vec<Box<dyn B + 'static, Global>, Global>
- 786..803 '<[_]> ...to_vec': fn into_vec<Box<dyn B + '?, Global>, Global>(Box<[Box<dyn B + '?, Global>], Global>) -> Vec<Box<dyn B + '?, Global>, Global>
- 786..860 '<[_]> ...ct)]))': Vec<Box<dyn B + '?, Global>, Global>
- 804..859 '#[rust...uct)])': Box<[Box<dyn B + '?, Global>; 1], Global>
- 826..858 '[#[rus...ruct)]': [Box<dyn B + '?, Global>; 1]
- 827..857 '#[rust...truct)': Box<Astruct, Global>
- 849..856 'Astruct': Astruct
+ 639..643 'self': Box<[T], A>
+ 672..704 '{ ... }': Vec<T, A>
+ 718..888 '{ ...])); }': ()
+ 728..731 'vec': Vec<i32, Global>
+ 734..749 '<[_]>::into_vec': fn into_vec<i32, Global>(Box<[i32], Global>) -> Vec<i32, Global>
+ 734..780 '<[_]>:...i32]))': Vec<i32, Global>
+ 750..779 '#[rust...1i32])': Box<[i32; 1], Global>
+ 772..778 '[1i32]': [i32; 1]
+ 773..777 '1i32': i32
+ 790..791 'v': Vec<Box<dyn B + 'static, Global>, Global>
+ 811..828 '<[_]> ...to_vec': fn into_vec<Box<dyn B + '?, Global>, Global>(Box<[Box<dyn B + '?, Global>], Global>) -> Vec<Box<dyn B + '?, Global>, Global>
+ 811..885 '<[_]> ...ct)]))': Vec<Box<dyn B + '?, Global>, Global>
+ 829..884 '#[rust...uct)])': Box<[Box<dyn B + '?, Global>; 1], Global>
+ 851..883 '[#[rus...ruct)]': [Box<dyn B + '?, Global>; 1]
+ 852..882 '#[rust...truct)': Box<Astruct, Global>
+ 874..881 'Astruct': Astruct
"#]],
)
}
@@ -3647,6 +3649,8 @@ fn main() {
fn cstring_literals() {
check_types(
r#"
+#![feature(lang_items)]
+
#[lang = "CStr"]
pub struct CStr;
diff --git a/crates/hir-ty/src/variance.rs b/crates/hir-ty/src/variance.rs
index e5cfe85573..6f415a5289 100644
--- a/crates/hir-ty/src/variance.rs
+++ b/crates/hir-ty/src/variance.rs
@@ -41,7 +41,6 @@ pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> Variances
)]
fn variances_of_query(db: &dyn HirDatabase, def: GenericDefId) -> StoredVariancesOf {
tracing::debug!("variances_of(def={:?})", def);
- let interner = DbInterner::new_no_crate(db);
match def {
GenericDefId::FunctionId(_) => (),
GenericDefId::AdtId(adt) => {
@@ -55,15 +54,17 @@ fn variances_of_query(db: &dyn HirDatabase, def: GenericDefId) -> StoredVariance
}
}
}
- _ => return VariancesOf::empty(interner).store(),
+ _ => return VariancesOf::empty(DbInterner::new_no_crate(db)).store(),
}
let generics = generics(db, def);
let count = generics.len();
if count == 0 {
- return VariancesOf::empty(interner).store();
+ return VariancesOf::empty(DbInterner::new_no_crate(db)).store();
}
- let variances = Context { generics, variances: vec![Variance::Bivariant; count], db }.solve();
+ let variances =
+ Context { generics, variances: vec![Variance::Bivariant; count].into_boxed_slice(), db }
+ .solve();
VariancesOf::new_from_slice(&variances).store()
}
@@ -113,11 +114,11 @@ pub(crate) fn variances_of_cycle_initial(
struct Context<'db> {
db: &'db dyn HirDatabase,
generics: Generics,
- variances: Vec<Variance>,
+ variances: Box<[Variance]>,
}
impl<'db> Context<'db> {
- fn solve(mut self) -> Vec<Variance> {
+ fn solve(mut self) -> Box<[Variance]> {
tracing::debug!("solve(generics={:?})", self.generics);
match self.generics.def() {
GenericDefId::AdtId(adt) => {
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs
index 09c5b1cca7..e032a16989 100644
--- a/crates/hir/src/has_source.rs
+++ b/crates/hir/src/has_source.rs
@@ -330,7 +330,7 @@ impl HasSource for Label {
let (_body, source_map) = db.body_with_source_map(self.parent);
let src = source_map.label_syntax(self.label_id);
let root = src.file_syntax(db);
- Some(src.map(|ast| ast.to_node(&root)))
+ src.map(|ast| ast.to_node(&root).left()).transpose()
}
}
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 1ab57c4489..78be5a7e8f 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -50,9 +50,9 @@ use either::Either;
use hir_def::{
AdtId, AssocItemId, AssocItemLoc, BuiltinDeriveImplId, CallableDefId, ConstId, ConstParamId,
DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, GenericDefId,
- GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup,
- MacroExpander, MacroId, StaticId, StructId, SyntheticSyntax, TupleId, TypeAliasId,
- TypeOrConstParamId, TypeParamId, UnionId,
+ HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, MacroExpander,
+ MacroId, StaticId, StructId, SyntheticSyntax, TupleId, TypeAliasId, TypeOrConstParamId,
+ TypeParamId, UnionId,
attrs::AttrFlags,
builtin_derive::BuiltinDeriveImplMethod,
expr_store::{ExpressionStoreDiagnostics, ExpressionStoreSourceMap},
@@ -150,7 +150,7 @@ pub use {
visibility::Visibility,
// FIXME: This is here since some queries take it as input that are used
// outside of hir.
- {ModuleDefId, TraitId},
+ {GenericParamId, ModuleDefId, TraitId},
},
hir_expand::{
EditionedFileId, ExpandResult, HirFileId, MacroCallId, MacroKind,
@@ -803,22 +803,21 @@ impl Module {
emit_def_diagnostic(db, acc, diag, edition, loc.container.krate(db));
}
- if impl_signature.target_trait.is_none()
- && !is_inherent_impl_coherent(db, def_map, impl_id)
- {
+ let trait_impl = impl_signature.target_trait.is_some();
+ if !trait_impl && !is_inherent_impl_coherent(db, def_map, impl_id) {
acc.push(IncoherentImpl { impl_: ast_id_map.get(loc.id.value), file_id }.into())
}
- if !impl_def.check_orphan_rules(db) {
+ if trait_impl && !impl_def.check_orphan_rules(db) {
acc.push(TraitImplOrphan { impl_: ast_id_map.get(loc.id.value), file_id }.into())
}
- let trait_ = impl_def.trait_(db);
+ let trait_ = trait_impl.then(|| impl_def.trait_(db)).flatten();
let mut trait_is_unsafe = trait_.is_some_and(|t| t.is_unsafe(db));
let impl_is_negative = impl_def.is_negative(db);
let impl_is_unsafe = impl_def.is_unsafe(db);
- let trait_is_unresolved = trait_.is_none() && impl_signature.target_trait.is_some();
+ let trait_is_unresolved = trait_.is_none() && trait_impl;
if trait_is_unresolved {
// Ignore trait safety errors when the trait is unresolved, as otherwise we'll treat it as safe,
// which may not be correct.
@@ -921,6 +920,48 @@ impl Module {
}
}
+ // HACK: When specialization is enabled in the current crate, and there exists
+ // *any* blanket impl that provides a default implementation for the missing item,
+ // suppress the missing associated item diagnostic.
+ // This can lead to false negatives when the impl in question does not actually
+ // specialize that blanket impl, but determining the exact specialization
+ // relationship here would be significantly more expensive.
+ if !missing.is_empty() {
+ let krate = self.krate(db).id;
+ let def_map = crate_def_map(db, krate);
+ if def_map.is_unstable_feature_enabled(&sym::specialization)
+ || def_map.is_unstable_feature_enabled(&sym::min_specialization)
+ {
+ missing.retain(|(assoc_name, assoc_item)| {
+ let AssocItem::Function(_) = assoc_item else {
+ return true;
+ };
+
+ for &impl_ in TraitImpls::for_crate(db, krate).blanket_impls(trait_.id)
+ {
+ if impl_ == impl_id {
+ continue;
+ }
+
+ for (name, item) in &impl_.impl_items(db).items {
+ let AssocItemId::FunctionId(fn_) = item else {
+ continue;
+ };
+ if name != assoc_name {
+ continue;
+ }
+
+ if db.function_signature(*fn_).is_default() {
+ return false;
+ }
+ }
+ }
+
+ true
+ });
+ }
+ }
+
if !missing.is_empty() {
acc.push(
TraitImplMissingAssocItems {
diff --git a/crates/ide-assists/src/handlers/move_guard.rs b/crates/ide-assists/src/handlers/move_guard.rs
index 8daf86923d..1c0c6e43d5 100644
--- a/crates/ide-assists/src/handlers/move_guard.rs
+++ b/crates/ide-assists/src/handlers/move_guard.rs
@@ -1,6 +1,11 @@
+use itertools::Itertools;
use syntax::{
SyntaxKind::WHITESPACE,
- ast::{AstNode, BlockExpr, ElseBranch, Expr, IfExpr, MatchArm, Pat, edit::AstNodeEdit, make},
+ ast::{
+ AstNode, BlockExpr, ElseBranch, Expr, IfExpr, MatchArm, Pat, edit::AstNodeEdit, make,
+ syntax_factory::SyntaxFactory,
+ },
+ syntax_editor::Element,
};
use crate::{AssistContext, AssistId, Assists};
@@ -131,8 +136,10 @@ pub(crate) fn move_arm_cond_to_match_guard(
AssistId::refactor_rewrite("move_arm_cond_to_match_guard"),
"Move condition to match guard",
replace_node.text_range(),
- |edit| {
- edit.delete(match_arm.syntax().text_range());
+ |builder| {
+ let make = SyntaxFactory::without_mappings();
+ let mut replace_arms = vec![];
+
// Dedent if if_expr is in a BlockExpr
let dedent = if needs_dedent {
cov_mark::hit!(move_guard_ifelse_in_block);
@@ -141,47 +148,30 @@ pub(crate) fn move_arm_cond_to_match_guard(
cov_mark::hit!(move_guard_ifelse_else_block);
0
};
- let then_arm_end = match_arm.syntax().text_range().end();
let indent_level = match_arm.indent_level();
- let spaces = indent_level;
- let mut first = true;
for (cond, block) in conds_blocks {
- if !first {
- edit.insert(then_arm_end, format!("\n{spaces}"));
- } else {
- first = false;
- }
- let guard = format!("{match_pat} if {cond} => ");
- edit.insert(then_arm_end, guard);
let only_expr = block.statements().next().is_none();
- match &block.tail_expr() {
- Some(then_expr) if only_expr => {
- edit.insert(then_arm_end, then_expr.syntax().text());
- edit.insert(then_arm_end, ",");
- }
- _ => {
- let to_insert = block.dedent(dedent.into()).syntax().text();
- edit.insert(then_arm_end, to_insert)
- }
- }
+ let expr = match block.tail_expr() {
+ Some(then_expr) if only_expr => then_expr,
+ _ => block.dedent(dedent.into()).into(),
+ };
+ let guard = make.match_guard(cond);
+ let new_arm = make.match_arm(match_pat.clone(), Some(guard), expr);
+ replace_arms.push(new_arm);
}
- if let Some(e) = tail {
+ if let Some(block) = tail {
cov_mark::hit!(move_guard_ifelse_else_tail);
- let guard = format!("\n{spaces}{match_pat} => ");
- edit.insert(then_arm_end, guard);
- let only_expr = e.statements().next().is_none();
- match &e.tail_expr() {
+ let only_expr = block.statements().next().is_none();
+ let expr = match block.tail_expr() {
Some(expr) if only_expr => {
cov_mark::hit!(move_guard_ifelse_expr_only);
- edit.insert(then_arm_end, expr.syntax().text());
- edit.insert(then_arm_end, ",");
- }
- _ => {
- let to_insert = e.dedent(dedent.into()).syntax().text();
- edit.insert(then_arm_end, to_insert)
+ expr
}
- }
+ _ => block.dedent(dedent.into()).into(),
+ };
+ let new_arm = make.match_arm(match_pat, None, expr);
+ replace_arms.push(new_arm);
} else {
// There's no else branch. Add a pattern without guard, unless the following match
// arm is `_ => ...`
@@ -193,9 +183,21 @@ pub(crate) fn move_arm_cond_to_match_guard(
{
cov_mark::hit!(move_guard_ifelse_has_wildcard);
}
- _ => edit.insert(then_arm_end, format!("\n{spaces}{match_pat} => {{}}")),
+ _ => {
+ let block_expr = make.expr_empty_block().into();
+ replace_arms.push(make.match_arm(match_pat, None, block_expr));
+ }
}
}
+
+ let mut edit = builder.make_editor(match_arm.syntax());
+
+ let newline = make.whitespace(&format!("\n{indent_level}"));
+ let replace_arms = replace_arms.iter().map(|it| it.syntax().syntax_element());
+ let replace_arms = Itertools::intersperse(replace_arms, newline.syntax_element());
+ edit.replace_with_many(match_arm.syntax(), replace_arms.collect());
+
+ builder.add_file_edits(ctx.vfs_file_id(), edit);
},
)
}
diff --git a/crates/ide-completion/src/tests/flyimport.rs b/crates/ide-completion/src/tests/flyimport.rs
index aad881f8ce..797df3f163 100644
--- a/crates/ide-completion/src/tests/flyimport.rs
+++ b/crates/ide-completion/src/tests/flyimport.rs
@@ -781,8 +781,8 @@ fn main() {
}
"#,
expect![[r#"
- fn weird_function() (use dep::test_mod::TestTrait) fn() 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
"#]],
);
diff --git a/crates/ide-db/src/syntax_helpers/suggest_name.rs b/crates/ide-db/src/syntax_helpers/suggest_name.rs
index 273328a8d2..b8b9a7a768 100644
--- a/crates/ide-db/src/syntax_helpers/suggest_name.rs
+++ b/crates/ide-db/src/syntax_helpers/suggest_name.rs
@@ -44,7 +44,7 @@ const SEQUENCE_TYPES: &[&str] = &["Vec", "VecDeque", "LinkedList"];
/// `vec.as_slice()` -> `slice`
/// `args.into_config()` -> `config`
/// `bytes.to_vec()` -> `vec`
-const USELESS_METHOD_PREFIXES: &[&str] = &["into_", "as_", "to_"];
+const USELESS_METHOD_PREFIXES: &[&str] = &["try_into_", "into_", "as_", "to_"];
/// Useless methods that are stripped from expression
///
diff --git a/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs b/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs
index 3414e972d5..c5b2f499d3 100644
--- a/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs
+++ b/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs
@@ -64,6 +64,7 @@ unsafe trait Unsafe {}
fn drop_may_dangle() {
check_diagnostics(
r#"
+#![feature(lang_items)]
#[lang = "drop"]
trait Drop {}
struct S<T>;
diff --git a/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs b/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs
index 0e18ce9674..2c05544701 100644
--- a/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs
+++ b/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs
@@ -156,4 +156,22 @@ impl Trait for dyn OtherTrait {}
"#,
)
}
+
+ #[test]
+ fn no_false_positive_on_specialization() {
+ check_diagnostics(
+ r#"
+#![feature(specialization)]
+
+pub trait Foo {
+ fn foo();
+}
+
+impl<T> Foo for T {
+ default fn foo() {}
+}
+impl Foo for bool {}
+"#,
+ );
+ }
}
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index f42d3cf0dc..0b518021e3 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -4089,6 +4089,7 @@ fn foo() {
let fo$0o = async { S };
}
//- /core.rs crate:core
+#![feature(lang_items)]
pub mod future {
#[lang = "future_trait"]
pub trait Future {}
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 06ae0b1d73..a58dc6f030 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -5,8 +5,8 @@ use std::{
use either::Either;
use hir::{
- ClosureStyle, DisplayTarget, EditionedFileId, HasVisibility, HirDisplay, HirDisplayError,
- HirWrite, InRealFile, ModuleDef, ModuleDefId, Semantics, sym,
+ ClosureStyle, DisplayTarget, EditionedFileId, GenericParam, GenericParamId, HasVisibility,
+ HirDisplay, HirDisplayError, HirWrite, InRealFile, ModuleDef, ModuleDefId, Semantics, sym,
};
use ide_db::{
FileRange, MiniCore, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder,
@@ -709,6 +709,21 @@ impl HirWrite for InlayHintLabelBuilder<'_> {
});
}
+ fn start_location_link_generic(&mut self, def: GenericParamId) {
+ never!(self.location.is_some(), "location link is already started");
+ self.make_new_part();
+
+ self.location = Some(if self.resolve {
+ LazyProperty::Lazy
+ } else {
+ LazyProperty::Computed({
+ let Some(location) = GenericParam::from(def).try_to_nav(self.sema) else { return };
+ let location = location.call_site();
+ FileRange { file_id: location.file_id, range: location.focus_or_full_range() }
+ })
+ });
+ }
+
fn end_location_link(&mut self) {
self.make_new_part();
}
diff --git a/crates/ide/src/inlay_hints/bind_pat.rs b/crates/ide/src/inlay_hints/bind_pat.rs
index 547004687c..c74e3104c1 100644
--- a/crates/ide/src/inlay_hints/bind_pat.rs
+++ b/crates/ide/src/inlay_hints/bind_pat.rs
@@ -183,7 +183,8 @@ mod tests {
use crate::{ClosureReturnTypeHints, fixture, inlay_hints::InlayHintsConfig};
use crate::inlay_hints::tests::{
- DISABLED_CONFIG, TEST_CONFIG, check, check_edit, check_no_edit, check_with_config,
+ DISABLED_CONFIG, TEST_CONFIG, check, check_edit, check_expect, check_no_edit,
+ check_with_config,
};
#[track_caller]
@@ -1255,4 +1256,130 @@ where
"#,
);
}
+
+ #[test]
+ fn type_param_inlay_hint_has_location_link() {
+ check_expect(
+ InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG },
+ r#"
+fn identity<T>(t: T) -> T {
+ let x = t;
+ x
+}
+"#,
+ expect![[r#"
+ [
+ (
+ 36..37,
+ [
+ InlayHintLabelPart {
+ text: "T",
+ linked_location: Some(
+ Computed(
+ FileRangeWrapper {
+ file_id: FileId(
+ 0,
+ ),
+ range: 12..13,
+ },
+ ),
+ ),
+ tooltip: "",
+ },
+ ],
+ ),
+ ]
+ "#]],
+ );
+ }
+
+ #[test]
+ fn const_param_inlay_hint_has_location_link() {
+ check_expect(
+ InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG },
+ r#"
+fn f<const N: usize>() {
+ let x = [0; N];
+}
+"#,
+ expect![[r#"
+ [
+ (
+ 33..34,
+ [
+ "[i32; ",
+ InlayHintLabelPart {
+ text: "N",
+ linked_location: Some(
+ Computed(
+ FileRangeWrapper {
+ file_id: FileId(
+ 0,
+ ),
+ range: 11..12,
+ },
+ ),
+ ),
+ tooltip: "",
+ },
+ "]",
+ ],
+ ),
+ ]
+ "#]],
+ );
+ }
+
+ #[test]
+ fn lifetime_param_inlay_hint_has_location_link() {
+ check_expect(
+ InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG },
+ r#"
+struct S<'lt>(*mut &'lt ());
+
+fn f<'a>() {
+ let x = S::<'a>(loop {});
+}
+"#,
+ expect![[r#"
+ [
+ (
+ 51..52,
+ [
+ InlayHintLabelPart {
+ text: "S",
+ linked_location: Some(
+ Computed(
+ FileRangeWrapper {
+ file_id: FileId(
+ 0,
+ ),
+ range: 7..8,
+ },
+ ),
+ ),
+ tooltip: "",
+ },
+ "<",
+ InlayHintLabelPart {
+ text: "'a",
+ linked_location: Some(
+ Computed(
+ FileRangeWrapper {
+ file_id: FileId(
+ 0,
+ ),
+ range: 35..37,
+ },
+ ),
+ ),
+ tooltip: "",
+ },
+ ">",
+ ],
+ ),
+ ]
+ "#]],
+ );
+ }
}
diff --git a/crates/ide/src/inlay_hints/bounds.rs b/crates/ide/src/inlay_hints/bounds.rs
index c9fbdf3ae7..045559fd7f 100644
--- a/crates/ide/src/inlay_hints/bounds.rs
+++ b/crates/ide/src/inlay_hints/bounds.rs
@@ -143,7 +143,7 @@ fn foo<T>() {}
file_id: FileId(
1,
),
- range: 446..451,
+ range: 470..475,
},
),
),
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index ffae7bf6c7..4918fe4ff9 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -38,7 +38,8 @@ use syntax::{
};
use crate::{
- Analysis, FilePosition, HighlightedRange, NavigationTarget, TryToNav, highlight_related,
+ Analysis, FilePosition, HighlightedRange, NavigationTarget, TryToNav,
+ doc_links::token_as_doc_comment, highlight_related,
};
/// Result of a reference search operation.
@@ -211,6 +212,13 @@ pub(crate) fn find_defs(
syntax: &SyntaxNode,
offset: TextSize,
) -> Option<Vec<Definition>> {
+ if let Some(token) = syntax.token_at_offset(offset).left_biased()
+ && let Some(doc_comment) = token_as_doc_comment(&token)
+ {
+ return doc_comment
+ .get_definition_with_descend_at(sema, offset, |def, _, _| Some(vec![def]));
+ }
+
let token = syntax.token_at_offset(offset).find(|t| {
matches!(
t.kind(),
@@ -786,6 +794,23 @@ fn main() {
}
#[test]
+ fn test_find_all_refs_in_comments() {
+ check(
+ r#"
+struct Foo;
+
+/// $0[`Foo`] is just above
+struct Bar;
+"#,
+ expect![[r#"
+ Foo Struct FileId(0) 0..11 7..10
+
+ (no references)
+ "#]],
+ );
+ }
+
+ #[test]
fn search_filters_by_range() {
check(
r#"
diff --git a/crates/intern/src/intern.rs b/crates/intern/src/intern.rs
index b7acd6624b..a96dfcfa9f 100644
--- a/crates/intern/src/intern.rs
+++ b/crates/intern/src/intern.rs
@@ -334,7 +334,7 @@ impl<T: ?Sized> InternStorage<T> {
impl<T: Internable + ?Sized> InternStorage<T> {
pub(crate) fn get(&self) -> &InternMap<T> {
- self.map.get_or_init(DashMap::default)
+ self.map.get_or_init(|| DashMap::with_capacity_and_hasher(1024, Default::default()))
}
}
diff --git a/crates/intern/src/intern_slice.rs b/crates/intern/src/intern_slice.rs
index 58de6e17bd..8857771d2e 100644
--- a/crates/intern/src/intern_slice.rs
+++ b/crates/intern/src/intern_slice.rs
@@ -292,7 +292,12 @@ impl<T: SliceInternable> InternSliceStorage<T> {
impl<T: SliceInternable> InternSliceStorage<T> {
pub(crate) fn get(&self) -> &InternMap<T> {
- self.map.get_or_init(DashMap::default)
+ self.map.get_or_init(|| {
+ DashMap::with_capacity_and_hasher(
+ (64 * 1024) / std::mem::size_of::<T::SliceType>(),
+ Default::default(),
+ )
+ })
}
}
diff --git a/crates/intern/src/symbol/symbols.rs b/crates/intern/src/symbol/symbols.rs
index 3e325b2f99..b6efc599f1 100644
--- a/crates/intern/src/symbol/symbols.rs
+++ b/crates/intern/src/symbol/symbols.rs
@@ -297,6 +297,7 @@ define_symbols! {
iterator,
keyword,
lang,
+ lang_items,
le,
Left,
len,
diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs
index 5122051fb3..e8d98b1ce6 100644
--- a/crates/load-cargo/src/lib.rs
+++ b/crates/load-cargo/src/lib.rs
@@ -11,15 +11,16 @@ extern crate rustc_driver as _;
use std::{any::Any, collections::hash_map::Entry, mem, path::Path, sync};
use crossbeam_channel::{Receiver, unbounded};
-use hir_expand::proc_macro::{
- ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind, ProcMacroLoadResult,
- ProcMacrosBuilder,
+use hir_expand::{
+ db::ExpandDatabase,
+ proc_macro::{
+ ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind, ProcMacroLoadResult,
+ ProcMacrosBuilder,
+ },
};
use ide_db::{
ChangeWithProcMacros, FxHashMap, RootDatabase,
- base_db::{
- CrateGraphBuilder, Env, ProcMacroLoadingError, SourceDatabase, SourceRoot, SourceRootId,
- },
+ base_db::{CrateGraphBuilder, Env, ProcMacroLoadingError, SourceRoot, SourceRootId},
prime_caches,
};
use itertools::Itertools;
@@ -31,7 +32,8 @@ use proc_macro_api::{
},
};
use project_model::{CargoConfig, PackageRoot, ProjectManifest, ProjectWorkspace};
-use span::Span;
+use span::{Span, SpanAnchor, SyntaxContext};
+use tt::{TextRange, TextSize};
use vfs::{
AbsPath, AbsPathBuf, FileId, VfsPath,
file_set::FileSetConfig,
@@ -530,7 +532,7 @@ struct Expander(proc_macro_api::ProcMacro);
impl ProcMacroExpander for Expander {
fn expand(
&self,
- db: &dyn SourceDatabase,
+ db: &dyn ExpandDatabase,
subtree: &tt::TopSubtree,
attrs: Option<&tt::TopSubtree>,
env: &Env,
@@ -540,11 +542,44 @@ impl ProcMacroExpander for Expander {
current_dir: String,
) -> Result<tt::TopSubtree, ProcMacroExpansionError> {
let mut cb = |req| match req {
- SubRequest::SourceText { file_id, start, end } => {
- let file = FileId::from_raw(file_id);
- let text = db.file_text(file).text(db);
- let slice = text.get(start as usize..end as usize).map(ToOwned::to_owned);
- Ok(SubResponse::SourceTextResult { text: slice })
+ SubRequest::LocalFilePath { file_id } => {
+ let file_id = FileId::from_raw(file_id);
+ let source_root_id = db.file_source_root(file_id).source_root_id(db);
+ let source_root = db.source_root(source_root_id).source_root(db);
+ let name = source_root
+ .path_for_file(&file_id)
+ .and_then(|path| path.as_path())
+ .map(|path| path.to_string());
+
+ Ok(SubResponse::LocalFilePathResult { name })
+ }
+ SubRequest::SourceText { file_id, ast_id, start, end } => {
+ let ast_id = span::ErasedFileAstId::from_raw(ast_id);
+ let editioned_file_id = span::EditionedFileId::from_raw(file_id);
+ let span = Span {
+ range: TextRange::new(TextSize::from(start), TextSize::from(end)),
+ anchor: SpanAnchor { file_id: editioned_file_id, ast_id },
+ ctx: SyntaxContext::root(editioned_file_id.edition()),
+ };
+ let range = db.resolve_span(span);
+ let source = db.file_text(range.file_id.file_id(db)).text(db);
+ let text = source
+ .get(usize::from(range.range.start())..usize::from(range.range.end()))
+ .map(ToOwned::to_owned);
+
+ Ok(SubResponse::SourceTextResult { text })
+ }
+ SubRequest::FilePath { file_id } => {
+ let file_id = FileId::from_raw(file_id);
+ let source_root_id = db.file_source_root(file_id).source_root_id(db);
+ let source_root = db.source_root(source_root_id).source_root(db);
+ let name = source_root
+ .path_for_file(&file_id)
+ .and_then(|path| path.as_path())
+ .map(|path| path.to_string())
+ .unwrap_or_default();
+
+ Ok(SubResponse::FilePathResult { name })
}
};
match self.0.expand(
diff --git a/crates/proc-macro-api/src/bidirectional_protocol/msg.rs b/crates/proc-macro-api/src/bidirectional_protocol/msg.rs
index cf8becd922..e41f8a5d7d 100644
--- a/crates/proc-macro-api/src/bidirectional_protocol/msg.rs
+++ b/crates/proc-macro-api/src/bidirectional_protocol/msg.rs
@@ -10,12 +10,16 @@ use crate::{
#[derive(Debug, Serialize, Deserialize)]
pub enum SubRequest {
- SourceText { file_id: u32, start: u32, end: u32 },
+ FilePath { file_id: u32 },
+ SourceText { file_id: u32, ast_id: u32, start: u32, end: u32 },
+ LocalFilePath { file_id: u32 },
}
#[derive(Debug, Serialize, Deserialize)]
pub enum SubResponse {
+ FilePathResult { name: String },
SourceTextResult { text: Option<String> },
+ LocalFilePathResult { name: Option<String> },
}
#[derive(Debug, Serialize, Deserialize)]
diff --git a/crates/proc-macro-srv-cli/Cargo.toml b/crates/proc-macro-srv-cli/Cargo.toml
index 2c6e5a16ee..6b2db0b269 100644
--- a/crates/proc-macro-srv-cli/Cargo.toml
+++ b/crates/proc-macro-srv-cli/Cargo.toml
@@ -18,6 +18,7 @@ clap = {version = "4.5.42", default-features = false, features = ["std"]}
[features]
default = []
+# default = ["sysroot-abi"]
sysroot-abi = ["proc-macro-srv/sysroot-abi", "proc-macro-api/sysroot-abi"]
in-rust-tree = ["proc-macro-srv/in-rust-tree", "sysroot-abi"]
diff --git a/crates/proc-macro-srv-cli/README.md b/crates/proc-macro-srv-cli/README.md
new file mode 100644
index 0000000000..02a67ac3ec
--- /dev/null
+++ b/crates/proc-macro-srv-cli/README.md
@@ -0,0 +1,65 @@
+# proc-macro-srv-cli
+
+A standalone binary for the `proc-macro-srv` crate that provides procedural macro expansion for rust-analyzer.
+
+## Overview
+
+rust-analyzer uses a RPC (via stdio) client-server architecture for procedural macro expansion. This is necessary because:
+
+1. Proc macros are dynamic libraries that can segfault, bringing down the entire process, so running them out of process allows rust-analyzer to recover from fatal errors.
+2. Proc macro dylibs are compiled against a specific rustc version and require matching internal APIs to load and execute, as such having this binary shipped as a rustup component allows us to always match the rustc version irrespective of the rust-analyzer version used.
+
+## The `sysroot-abi` Feature
+
+**The `sysroot-abi` feature is required for the binary to actually function.** Without it, the binary will return an error:
+
+```
+proc-macro-srv-cli needs to be compiled with the `sysroot-abi` feature to function
+```
+
+This feature is necessary because the proc-macro server needs access to unstable rustc internals (`proc_macro_internals`, `proc_macro_diagnostic`, `proc_macro_span`) which are only available on nightly or with `RUSTC_BOOTSTRAP=1`.
+rust-analyzer is a stable toolchain project though, so the feature flag is used to have it remain compilable on stable by default.
+
+### Building
+
+```bash
+# Using nightly toolchain
+cargo build -p proc-macro-srv-cli --features sysroot-abi
+
+# Or with RUSTC_BOOTSTRAP on stable
+RUSTC_BOOTSTRAP=1 cargo build -p proc-macro-srv-cli --features sysroot-abi
+```
+
+### Installing the proc-macro server
+
+For local testing purposes, you can install the proc-macro server using the xtask command:
+
+```bash
+# Recommended: use the xtask command
+cargo xtask install --proc-macro-server
+```
+
+## Testing
+
+```bash
+cargo test --features sysroot-abi -p proc-macro-srv -p proc-macro-srv-cli -p proc-macro-api
+```
+
+The tests use a test proc macro dylib built by the `proc-macro-test` crate, which compiles a small proc macro implementation during build time.
+
+**Note**: Tests only compile on nightly toolchains (or with `RUSTC_BOOTSTRAP=1`).
+
+## Usage
+
+The binary requires the `RUST_ANALYZER_INTERNALS_DO_NOT_USE` environment variable to be set. This is intentional—the binary is an implementation detail of rust-analyzer and its API is still unstable:
+
+```bash
+RUST_ANALYZER_INTERNALS_DO_NOT_USE=1 rust-analyzer-proc-macro-srv --version
+```
+
+## Related Crates
+
+- `proc-macro-srv`: The core server library that handles loading dylibs and expanding macros, but not the RPC protocol.
+- `proc-macro-api`: The client library used by rust-analyzer to communicate with this server as well as the protocol definitions.
+- `proc-macro-test`: Test harness with sample proc macros for testing
+- `proc-macro-srv-cli`: The actual server binary that handles the RPC protocol.
diff --git a/crates/proc-macro-srv-cli/src/main_loop.rs b/crates/proc-macro-srv-cli/src/main_loop.rs
index 25a5104c5d..b2f4b96bd2 100644
--- a/crates/proc-macro-srv-cli/src/main_loop.rs
+++ b/crates/proc-macro-srv-cli/src/main_loop.rs
@@ -81,7 +81,6 @@ fn run_new<C: Codec>() -> io::Result<()> {
}
bidirectional::Request::ApiVersionCheck {} => {
- // bidirectional::Response::ApiVersionCheck(CURRENT_API_VERSION).write::<_, C>(stdout)
send_response::<C>(
&stdout,
bidirectional::Response::ApiVersionCheck(CURRENT_API_VERSION),
@@ -167,28 +166,57 @@ struct ProcMacroClientHandle<'a, C: Codec> {
buf: &'a mut C::Buf,
}
-impl<C: Codec> proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandle<'_, C> {
- fn source_text(&mut self, file_id: u32, start: u32, end: u32) -> Option<String> {
- let req = bidirectional::BidirectionalMessage::SubRequest(
- bidirectional::SubRequest::SourceText { file_id, start, end },
- );
+impl<'a, C: Codec> ProcMacroClientHandle<'a, C> {
+ fn roundtrip(
+ &mut self,
+ req: bidirectional::SubRequest,
+ ) -> Option<bidirectional::BidirectionalMessage> {
+ let msg = bidirectional::BidirectionalMessage::SubRequest(req);
- if req.write::<_, C>(&mut self.stdout.lock()).is_err() {
+ if msg.write::<_, C>(&mut self.stdout.lock()).is_err() {
return None;
}
- let msg = match bidirectional::BidirectionalMessage::read::<_, C>(
- &mut self.stdin.lock(),
- self.buf,
- ) {
- Ok(Some(msg)) => msg,
- _ => return None,
- };
+ match bidirectional::BidirectionalMessage::read::<_, C>(&mut self.stdin.lock(), self.buf) {
+ Ok(Some(msg)) => Some(msg),
+ _ => None,
+ }
+ }
+}
+
+impl<C: Codec> proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandle<'_, C> {
+ fn file(&mut self, file_id: proc_macro_srv::span::FileId) -> String {
+ match self.roundtrip(bidirectional::SubRequest::FilePath { file_id: file_id.index() }) {
+ Some(bidirectional::BidirectionalMessage::SubResponse(
+ bidirectional::SubResponse::FilePathResult { name },
+ )) => name,
+ _ => String::new(),
+ }
+ }
- match msg {
- bidirectional::BidirectionalMessage::SubResponse(
+ fn source_text(
+ &mut self,
+ proc_macro_srv::span::Span { range, anchor, ctx: _ }: proc_macro_srv::span::Span,
+ ) -> Option<String> {
+ match self.roundtrip(bidirectional::SubRequest::SourceText {
+ file_id: anchor.file_id.as_u32(),
+ ast_id: anchor.ast_id.into_raw(),
+ start: range.start().into(),
+ end: range.end().into(),
+ }) {
+ Some(bidirectional::BidirectionalMessage::SubResponse(
bidirectional::SubResponse::SourceTextResult { text },
- ) => text,
+ )) => text,
+ _ => None,
+ }
+ }
+
+ fn local_file(&mut self, file_id: proc_macro_srv::span::FileId) -> Option<String> {
+ match self.roundtrip(bidirectional::SubRequest::LocalFilePath { file_id: file_id.index() })
+ {
+ Some(bidirectional::BidirectionalMessage::SubResponse(
+ bidirectional::SubResponse::LocalFilePathResult { name },
+ )) => name,
_ => None,
}
}
diff --git a/crates/proc-macro-srv/src/lib.rs b/crates/proc-macro-srv/src/lib.rs
index 17ffa29ce1..f2d1dfbba4 100644
--- a/crates/proc-macro-srv/src/lib.rs
+++ b/crates/proc-macro-srv/src/lib.rs
@@ -53,6 +53,7 @@ use temp_dir::TempDir;
pub use crate::server_impl::token_id::SpanId;
pub use proc_macro::Delimiter;
+pub use span;
pub use crate::bridge::*;
pub use crate::server_impl::literal_from_str;
@@ -94,7 +95,9 @@ impl<'env> ProcMacroSrv<'env> {
pub type ProcMacroClientHandle<'a> = &'a mut (dyn ProcMacroClientInterface + Sync + Send);
pub trait ProcMacroClientInterface {
- fn source_text(&mut self, file_id: u32, start: u32, end: u32) -> Option<String>;
+ fn file(&mut self, file_id: span::FileId) -> String;
+ fn source_text(&mut self, span: Span) -> Option<String>;
+ fn local_file(&mut self, file_id: span::FileId) -> Option<String>;
}
const EXPANDER_STACK_SIZE: usize = 8 * 1024 * 1024;
diff --git a/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
index 5d9090c060..32725afc55 100644
--- a/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
+++ b/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
@@ -127,13 +127,11 @@ impl server::Span for RaSpanServer<'_> {
fn debug(&mut self, span: Self::Span) -> String {
format!("{:?}", span)
}
- fn file(&mut self, _: Self::Span) -> String {
- // FIXME
- String::new()
+ fn file(&mut self, span: Self::Span) -> String {
+ self.callback.as_mut().map(|cb| cb.file(span.anchor.file_id.file_id())).unwrap_or_default()
}
- fn local_file(&mut self, _: Self::Span) -> Option<String> {
- // FIXME
- None
+ fn local_file(&mut self, span: Self::Span) -> Option<String> {
+ self.callback.as_mut().and_then(|cb| cb.local_file(span.anchor.file_id.file_id()))
}
fn save_span(&mut self, _span: Self::Span) -> usize {
// FIXME, quote is incompatible with third-party tools
@@ -152,11 +150,7 @@ impl server::Span for RaSpanServer<'_> {
/// See PR:
/// https://github.com/rust-lang/rust/pull/55780
fn source_text(&mut self, span: Self::Span) -> Option<String> {
- let file_id = span.anchor.file_id;
- let start: u32 = span.range.start().into();
- let end: u32 = span.range.end().into();
-
- self.callback.as_mut()?.source_text(file_id.file_id().index(), start, end)
+ self.callback.as_mut()?.source_text(span)
}
fn parent(&mut self, _span: Self::Span) -> Option<Self::Span> {
diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs
index 971ae2a601..4a37bb34ab 100644
--- a/crates/rust-analyzer/src/lib.rs
+++ b/crates/rust-analyzer/src/lib.rs
@@ -16,6 +16,9 @@ extern crate rustc_driver as _;
extern crate ra_ap_rustc_type_ir as rustc_type_ir;
+/*
+ If you bump this, grep for `FIXME(MINIMUM_SUPPORTED_TOOLCHAIN_VERSION)` to check for old support code we can drop
+*/
/// Any toolchain less than this version will likely not work with rust-analyzer built from this revision.
pub const MINIMUM_SUPPORTED_TOOLCHAIN_VERSION: semver::Version = semver::Version {
major: 1,
diff --git a/crates/span/src/hygiene.rs b/crates/span/src/hygiene.rs
index 6805417177..ea4f4c5efb 100644
--- a/crates/span/src/hygiene.rs
+++ b/crates/span/src/hygiene.rs
@@ -19,9 +19,8 @@
//! # The Call-site Hierarchy
//!
//! `ExpnData::call_site` in rustc, [`MacroCallLoc::call_site`] in rust-analyzer.
-use std::fmt;
-
use crate::Edition;
+use std::fmt;
/// A syntax context describes a hierarchy tracking order of macro definitions.
#[cfg(feature = "salsa")]
diff --git a/crates/test-fixture/src/lib.rs b/crates/test-fixture/src/lib.rs
index b9c389c769..d81f27d7c3 100644
--- a/crates/test-fixture/src/lib.rs
+++ b/crates/test-fixture/src/lib.rs
@@ -738,7 +738,7 @@ struct IdentityProcMacroExpander;
impl ProcMacroExpander for IdentityProcMacroExpander {
fn expand(
&self,
- _: &dyn SourceDatabase,
+ _: &dyn ExpandDatabase,
subtree: &TopSubtree,
_: Option<&TopSubtree>,
_: &Env,
@@ -761,7 +761,7 @@ struct Issue18089ProcMacroExpander;
impl ProcMacroExpander for Issue18089ProcMacroExpander {
fn expand(
&self,
- _: &dyn SourceDatabase,
+ _: &dyn ExpandDatabase,
subtree: &TopSubtree,
_: Option<&TopSubtree>,
_: &Env,
@@ -797,7 +797,7 @@ struct AttributeInputReplaceProcMacroExpander;
impl ProcMacroExpander for AttributeInputReplaceProcMacroExpander {
fn expand(
&self,
- _: &dyn SourceDatabase,
+ _: &dyn ExpandDatabase,
_: &TopSubtree,
attrs: Option<&TopSubtree>,
_: &Env,
@@ -821,7 +821,7 @@ struct Issue18840ProcMacroExpander;
impl ProcMacroExpander for Issue18840ProcMacroExpander {
fn expand(
&self,
- _: &dyn SourceDatabase,
+ _: &dyn ExpandDatabase,
fn_: &TopSubtree,
_: Option<&TopSubtree>,
_: &Env,
@@ -858,7 +858,7 @@ struct MirrorProcMacroExpander;
impl ProcMacroExpander for MirrorProcMacroExpander {
fn expand(
&self,
- _: &dyn SourceDatabase,
+ _: &dyn ExpandDatabase,
input: &TopSubtree,
_: Option<&TopSubtree>,
_: &Env,
@@ -897,7 +897,7 @@ struct ShortenProcMacroExpander;
impl ProcMacroExpander for ShortenProcMacroExpander {
fn expand(
&self,
- _: &dyn SourceDatabase,
+ _: &dyn ExpandDatabase,
input: &TopSubtree,
_: Option<&TopSubtree>,
_: &Env,
@@ -942,7 +942,7 @@ struct Issue17479ProcMacroExpander;
impl ProcMacroExpander for Issue17479ProcMacroExpander {
fn expand(
&self,
- _: &dyn SourceDatabase,
+ _: &dyn ExpandDatabase,
subtree: &TopSubtree,
_: Option<&TopSubtree>,
_: &Env,
@@ -973,7 +973,7 @@ struct Issue18898ProcMacroExpander;
impl ProcMacroExpander for Issue18898ProcMacroExpander {
fn expand(
&self,
- _: &dyn SourceDatabase,
+ _: &dyn ExpandDatabase,
subtree: &TopSubtree,
_: Option<&TopSubtree>,
_: &Env,
@@ -1027,7 +1027,7 @@ struct DisallowCfgProcMacroExpander;
impl ProcMacroExpander for DisallowCfgProcMacroExpander {
fn expand(
&self,
- _: &dyn SourceDatabase,
+ _: &dyn ExpandDatabase,
subtree: &TopSubtree,
_: Option<&TopSubtree>,
_: &Env,
@@ -1059,7 +1059,7 @@ struct GenerateSuffixedTypeProcMacroExpander;
impl ProcMacroExpander for GenerateSuffixedTypeProcMacroExpander {
fn expand(
&self,
- _: &dyn SourceDatabase,
+ _: &dyn ExpandDatabase,
subtree: &TopSubtree,
_attrs: Option<&TopSubtree>,
_env: &Env,
diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs
index b7c09391ec..01274a9835 100644
--- a/crates/test-utils/src/minicore.rs
+++ b/crates/test-utils/src/minicore.rs
@@ -80,6 +80,7 @@
//! offset_of:
#![rustc_coherence_is_core]
+#![feature(lang_items)]
pub mod marker {
// region:sized
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index 00d83e9068..57f6bf69be 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -5584,9 +5584,9 @@
}
},
"node_modules/qs": {
- "version": "6.14.0",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
- "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
+ "version": "6.14.1",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
+ "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {