Merge pull request #4338 from RalfJung/FileDescription
FileDescription: improve read/write docs
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index f48a571..e98d6c5 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -70,44 +70,32 @@ fn with_lctx(
}
}
- pub(super) fn lower_node(&mut self, def_id: LocalDefId) -> hir::MaybeOwner<'hir> {
+ pub(super) fn lower_node(&mut self, def_id: LocalDefId) {
let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
if let hir::MaybeOwner::Phantom = owner {
let node = self.ast_index[def_id];
match node {
AstOwner::NonOwner => {}
- AstOwner::Crate(c) => self.lower_crate(c),
- AstOwner::Item(item) => self.lower_item(item),
- AstOwner::AssocItem(item, ctxt) => self.lower_assoc_item(item, ctxt),
- AstOwner::ForeignItem(item) => self.lower_foreign_item(item),
+ AstOwner::Crate(c) => {
+ debug_assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID);
+ self.with_lctx(CRATE_NODE_ID, |lctx| {
+ let module = lctx.lower_mod(&c.items, &c.spans);
+ // FIXME(jdonszelman): is dummy span ever a problem here?
+ lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs, DUMMY_SP);
+ hir::OwnerNode::Crate(module)
+ })
+ }
+ AstOwner::Item(item) => {
+ self.with_lctx(item.id, |lctx| hir::OwnerNode::Item(lctx.lower_item(item)))
+ }
+ AstOwner::AssocItem(item, ctxt) => {
+ self.with_lctx(item.id, |lctx| lctx.lower_assoc_item(item, ctxt))
+ }
+ AstOwner::ForeignItem(item) => self.with_lctx(item.id, |lctx| {
+ hir::OwnerNode::ForeignItem(lctx.lower_foreign_item(item))
+ }),
}
}
-
- self.owners[def_id]
- }
-
- #[instrument(level = "debug", skip(self, c))]
- fn lower_crate(&mut self, c: &Crate) {
- debug_assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID);
- self.with_lctx(CRATE_NODE_ID, |lctx| {
- let module = lctx.lower_mod(&c.items, &c.spans);
- // FIXME(jdonszelman): is dummy span ever a problem here?
- lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs, DUMMY_SP);
- hir::OwnerNode::Crate(module)
- })
- }
-
- #[instrument(level = "debug", skip(self))]
- fn lower_item(&mut self, item: &Item) {
- self.with_lctx(item.id, |lctx| hir::OwnerNode::Item(lctx.lower_item(item)))
- }
-
- fn lower_assoc_item(&mut self, item: &AssocItem, ctxt: AssocCtxt) {
- self.with_lctx(item.id, |lctx| lctx.lower_assoc_item(item, ctxt))
- }
-
- fn lower_foreign_item(&mut self, item: &ForeignItem) {
- self.with_lctx(item.id, |lctx| hir::OwnerNode::ForeignItem(lctx.lower_foreign_item(item)))
}
}
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 19095f2..422e79c 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -444,14 +444,14 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
tcx.definitions_untracked().def_index_count(),
);
+ let mut lowerer = item::ItemLowerer {
+ tcx,
+ resolver: &mut resolver,
+ ast_index: &ast_index,
+ owners: &mut owners,
+ };
for def_id in ast_index.indices() {
- item::ItemLowerer {
- tcx,
- resolver: &mut resolver,
- ast_index: &ast_index,
- owners: &mut owners,
- }
- .lower_node(def_id);
+ lowerer.lower_node(def_id);
}
drop(ast_index);
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index a1386b4..d13e17a 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -147,6 +147,12 @@ pub trait Machine<'tcx>: Sized {
/// already been checked before.
const ALL_CONSTS_ARE_PRECHECKED: bool = true;
+ /// Determines whether rustc_const_eval functions that make use of the [Machine] should make
+ /// tracing calls (to the `tracing` library). By default this is `false`, meaning the tracing
+ /// calls will supposedly be optimized out. This flag is set to `true` inside Miri, to allow
+ /// tracing the interpretation steps, among other things.
+ const TRACING_ENABLED: bool = false;
+
/// Whether memory accesses should be alignment-checked.
fn enforce_alignment(ecx: &InterpCx<'tcx, Self>) -> bool;
diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs
index ba579e2..847905e 100644
--- a/compiler/rustc_const_eval/src/interpret/util.rs
+++ b/compiler/rustc_const_eval/src/interpret/util.rs
@@ -45,3 +45,22 @@ pub(crate) fn create_static_alloc<'tcx>(
assert!(ecx.memory.alloc_map.insert(alloc_id, (MemoryKind::Stack, alloc)).is_none());
interp_ok(ecx.ptr_to_mplace(Pointer::from(alloc_id).into(), layout))
}
+
+/// This struct is needed to enforce `#[must_use]` on [tracing::span::EnteredSpan]
+/// while wrapping them in an `Option`.
+#[must_use]
+pub enum MaybeEnteredSpan {
+ Some(tracing::span::EnteredSpan),
+ None,
+}
+
+#[macro_export]
+macro_rules! enter_trace_span {
+ ($machine:ident, $($tt:tt)*) => {
+ if $machine::TRACING_ENABLED {
+ $crate::interpret::tracing_utils::MaybeEnteredSpan::Some(tracing::info_span!($($tt)*).entered())
+ } else {
+ $crate::interpret::tracing_utils::MaybeEnteredSpan::None
+ }
+ }
+}
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index d1bc54e..8182851 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -84,7 +84,7 @@ pub(crate) fn emit_coerce_suggestions(
self.annotate_expected_due_to_let_ty(err, expr, error);
self.annotate_loop_expected_due_to_inference(err, expr, error);
- if self.annotate_mut_binding_to_immutable_binding(err, expr, error) {
+ if self.annotate_mut_binding_to_immutable_binding(err, expr, expr_ty, expected, error) {
return;
}
@@ -799,17 +799,17 @@ fn annotate_expected_due_to_let_ty(
/// Detect the following case
///
/// ```text
- /// fn change_object(mut a: &Ty) {
+ /// fn change_object(mut b: &Ty) {
/// let a = Ty::new();
/// b = a;
/// }
/// ```
///
- /// where the user likely meant to modify the value behind there reference, use `a` as an out
+ /// where the user likely meant to modify the value behind there reference, use `b` as an out
/// parameter, instead of mutating the local binding. When encountering this we suggest:
///
/// ```text
- /// fn change_object(a: &'_ mut Ty) {
+ /// fn change_object(b: &'_ mut Ty) {
/// let a = Ty::new();
/// *b = a;
/// }
@@ -818,13 +818,15 @@ fn annotate_mut_binding_to_immutable_binding(
&self,
err: &mut Diag<'_>,
expr: &hir::Expr<'_>,
+ expr_ty: Ty<'tcx>,
+ expected: Ty<'tcx>,
error: Option<TypeError<'tcx>>,
) -> bool {
- if let Some(TypeError::Sorts(ExpectedFound { expected, found })) = error
+ if let Some(TypeError::Sorts(ExpectedFound { .. })) = error
&& let ty::Ref(_, inner, hir::Mutability::Not) = expected.kind()
// The difference between the expected and found values is one level of borrowing.
- && self.can_eq(self.param_env, *inner, found)
+ && self.can_eq(self.param_env, *inner, expr_ty)
// We have an `ident = expr;` assignment.
&& let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(lhs, rhs, _), .. }) =
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 9be041f..b2497cb 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -9,17 +9,21 @@
//! which creates a new `TypeckResults` which doesn't contain any inference variables.
use std::mem;
+use std::ops::ControlFlow;
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_data_structures::unord::ExtendUnord;
-use rustc_errors::ErrorGuaranteed;
+use rustc_errors::{E0720, ErrorGuaranteed};
+use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, InferKind, Visitor};
use rustc_hir::{self as hir, AmbigArg, HirId};
use rustc_infer::traits::solve::Goal;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
use rustc_middle::ty::{
- self, DefiningScopeKind, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
- TypeVisitableExt, fold_regions,
+ self, DefiningScopeKind, OpaqueHiddenType, Ty, TyCtxt, TypeFoldable, TypeFolder,
+ TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
+ fold_regions,
};
use rustc_span::{Span, sym};
use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
@@ -595,6 +599,35 @@ fn visit_opaque_types(&mut self) {
entry.span = prev.span.substitute_dummy(hidden_type.span);
}
}
+
+ let recursive_opaques: Vec<_> = self
+ .typeck_results
+ .concrete_opaque_types
+ .iter()
+ .filter(|&(&def_id, hidden_ty)| {
+ hidden_ty
+ .ty
+ .visit_with(&mut HasRecursiveOpaque {
+ def_id,
+ seen: Default::default(),
+ opaques: &self.typeck_results.concrete_opaque_types,
+ tcx,
+ })
+ .is_break()
+ })
+ .map(|(def_id, hidden_ty)| (*def_id, hidden_ty.span))
+ .collect();
+ for (def_id, span) in recursive_opaques {
+ let guar = self
+ .fcx
+ .dcx()
+ .struct_span_err(span, "cannot resolve opaque type")
+ .with_code(E0720)
+ .emit();
+ self.typeck_results
+ .concrete_opaque_types
+ .insert(def_id, OpaqueHiddenType { span, ty: Ty::new_error(tcx, guar) });
+ }
}
fn visit_field_id(&mut self, hir_id: HirId) {
@@ -959,3 +992,34 @@ fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
self.tcx.try_normalize_erasing_regions(self.typing_env, ct).unwrap_or(ct)
}
}
+
+struct HasRecursiveOpaque<'a, 'tcx> {
+ def_id: LocalDefId,
+ seen: FxHashSet<LocalDefId>,
+ opaques: &'a FxIndexMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>,
+ tcx: TyCtxt<'tcx>,
+}
+
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasRecursiveOpaque<'_, 'tcx> {
+ type Result = ControlFlow<()>;
+
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
+ if let ty::Alias(ty::Opaque, alias_ty) = *t.kind()
+ && let Some(def_id) = alias_ty.def_id.as_local()
+ {
+ if self.def_id == def_id {
+ return ControlFlow::Break(());
+ }
+
+ if self.seen.insert(def_id)
+ && let Some(hidden_ty) = self.opaques.get(&def_id)
+ {
+ ty::EarlyBinder::bind(hidden_ty.ty)
+ .instantiate(self.tcx, alias_ty.args)
+ .visit_with(self)?;
+ }
+ }
+
+ t.super_visit_with(self)
+ }
+}
diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl
index cac8f34..bccffe3 100644
--- a/compiler/rustc_metadata/messages.ftl
+++ b/compiler/rustc_metadata/messages.ftl
@@ -2,7 +2,7 @@
linking modifier `as-needed` is only compatible with `dylib` and `framework` linking kinds
metadata_async_drop_types_in_dependency =
- found async drop types in dependecy `{$extern_crate}`, but async_drop feature is disabled for `{$local_crate}`
+ found async drop types in dependency `{$extern_crate}`, but async_drop feature is disabled for `{$local_crate}`
.help = if async drop type will be dropped in a crate without `feature(async_drop)`, sync Drop will be used
metadata_bad_panic_strategy =
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index a89d01d..d9f1888 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -1,6 +1,5 @@
use std::fmt;
use std::iter::once;
-use std::ops::ControlFlow;
use rustc_abi::{FIRST_VARIANT, FieldIdx, Integer, VariantIdx};
use rustc_arena::DroplessArena;
@@ -12,8 +11,7 @@
use rustc_middle::thir::{self, Pat, PatKind, PatRange, PatRangeBoundary};
use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::{
- self, FieldDef, OpaqueTypeKey, ScalarInt, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
- TypeVisitableExt, TypeVisitor, VariantDef,
+ self, FieldDef, OpaqueTypeKey, ScalarInt, Ty, TyCtxt, TypeVisitableExt, VariantDef,
};
use rustc_middle::{bug, span_bug};
use rustc_session::lint;
@@ -137,22 +135,11 @@ fn reveal_inner<'tcx>(cx: &RustcPatCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> RevealedTy<'
/// Returns the hidden type corresponding to this key if the body under analysis is allowed to
/// know it.
fn reveal_opaque_key(&self, key: OpaqueTypeKey<'tcx>) -> Option<Ty<'tcx>> {
- if let Some(hidden_ty) = self.typeck_results.concrete_opaque_types.get(&key.def_id) {
- let ty = ty::EarlyBinder::bind(hidden_ty.ty).instantiate(self.tcx, key.args);
- if ty.visit_with(&mut RecursiveOpaque { def_id: key.def_id.into() }).is_continue() {
- Some(ty)
- } else {
- // HACK: We skip revealing opaque types which recursively expand
- // to themselves. This is because we may infer hidden types like
- // `Opaque<T> = Opaque<Opaque<T>>` or `Opaque<T> = Opaque<(T,)>`
- // in hir typeck.
- None
- }
- } else {
- None
- }
+ self.typeck_results
+ .concrete_opaque_types
+ .get(&key.def_id)
+ .map(|x| ty::EarlyBinder::bind(x.ty).instantiate(self.tcx, key.args))
}
-
// This can take a non-revealed `Ty` because it reveals opaques itself.
pub fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
!ty.inhabited_predicate(self.tcx).apply_revealing_opaque(
@@ -1177,20 +1164,3 @@ fn detect_mixed_deref_pat_ctors<'p, 'tcx>(
}
Ok(())
}
-
-struct RecursiveOpaque {
- def_id: DefId,
-}
-impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for RecursiveOpaque {
- type Result = ControlFlow<()>;
-
- fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
- if let ty::Alias(ty::Opaque, alias_ty) = t.kind() {
- if alias_ty.def_id == self.def_id {
- return ControlFlow::Break(());
- }
- }
-
- if t.has_opaque_types() { t.super_visit_with(self) } else { ControlFlow::Continue(()) }
- }
-}
diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs
index eae3213..1b5d04e 100644
--- a/compiler/rustc_type_ir/src/region_kind.rs
+++ b/compiler/rustc_type_ir/src/region_kind.rs
@@ -193,7 +193,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
ReVar(vid) => write!(f, "{vid:?}"),
- RePlaceholder(placeholder) => write!(f, "{placeholder:?}"),
+ RePlaceholder(placeholder) => write!(f, "'{placeholder:?}"),
// Use `'{erased}` as the output instead of `'erased` so that its more obviously distinct from
// a `ReEarlyParam` named `'erased`. Technically that would print as `'erased/#IDX` so this is
diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs
index 24c5d4c..8766fd9 100644
--- a/library/alloc/src/str.rs
+++ b/library/alloc/src/str.rs
@@ -234,7 +234,7 @@ impl str {
#[stable(feature = "str_box_extras", since = "1.20.0")]
#[must_use = "`self` will be dropped if the result is not used"]
#[inline]
- pub fn into_boxed_bytes(self: Box<str>) -> Box<[u8]> {
+ pub fn into_boxed_bytes(self: Box<Self>) -> Box<[u8]> {
self.into()
}
@@ -501,7 +501,7 @@ pub fn to_uppercase(&self) -> String {
#[rustc_allow_incoherent_impl]
#[must_use = "`self` will be dropped if the result is not used"]
#[inline]
- pub fn into_string(self: Box<str>) -> String {
+ pub fn into_string(self: Box<Self>) -> String {
let slice = Box::<[u8]>::from(self);
unsafe { String::from_utf8_unchecked(slice.into_vec()) }
}
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index effdc3c..23bafa7 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -62,8 +62,7 @@
#![allow(missing_docs)]
use crate::marker::{DiscriminantKind, Tuple};
-use crate::mem::SizedTypeProperties;
-use crate::{ptr, ub_checks};
+use crate::ptr;
pub mod fallback;
pub mod mir;
@@ -3317,7 +3316,7 @@ pub const fn is_val_statically_known<T: Copy>(_arg: T) -> bool {
/// `#[inline]`), gating assertions on `ub_checks()` rather than `cfg!(ub_checks)` means that
/// assertions are enabled whenever the *user crate* has UB checks enabled. However, if the
/// user has UB checks disabled, the checks will still get optimized out. This intrinsic is
-/// primarily used by [`ub_checks::assert_unsafe_precondition`].
+/// primarily used by [`crate::ub_checks::assert_unsafe_precondition`].
#[rustc_intrinsic_const_stable_indirect] // just for UB checks
#[inline(always)]
#[rustc_intrinsic]
@@ -3595,306 +3594,38 @@ impl<P: ?Sized, T: ptr::Thin> AggregateRawPtr<*mut T> for *mut P {
#[rustc_intrinsic]
pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + ?Sized, M>(ptr: *const P) -> M;
-// Some functions are defined here because they accidentally got made
-// available in this module on stable. See <https://github.com/rust-lang/rust/issues/15702>.
-// (`transmute` also falls into this category, but it cannot be wrapped due to the
-// check that `T` and `U` have the same size.)
-
-/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
-/// and destination must *not* overlap.
-///
-/// For regions of memory which might overlap, use [`copy`] instead.
-///
-/// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but
-/// with the source and destination arguments swapped,
-/// and `count` counting the number of `T`s instead of bytes.
-///
-/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the
-/// requirements of `T`. The initialization state is preserved exactly.
-///
-/// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy
-///
-/// # Safety
-///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
-///
-/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
-///
-/// * Both `src` and `dst` must be properly aligned.
-///
-/// * The region of memory beginning at `src` with a size of `count *
-/// size_of::<T>()` bytes must *not* overlap with the region of memory
-/// beginning at `dst` with the same size.
-///
-/// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of
-/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values
-/// in the region beginning at `*src` and the region beginning at `*dst` can
-/// [violate memory safety][read-ownership].
-///
-/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
-/// `0`, the pointers must be properly aligned.
-///
-/// [`read`]: crate::ptr::read
-/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
-/// [valid]: crate::ptr#safety
-///
-/// # Examples
-///
-/// Manually implement [`Vec::append`]:
-///
-/// ```
-/// use std::ptr;
-///
-/// /// Moves all the elements of `src` into `dst`, leaving `src` empty.
-/// fn append<T>(dst: &mut Vec<T>, src: &mut Vec<T>) {
-/// let src_len = src.len();
-/// let dst_len = dst.len();
-///
-/// // Ensure that `dst` has enough capacity to hold all of `src`.
-/// dst.reserve(src_len);
-///
-/// unsafe {
-/// // The call to add is always safe because `Vec` will never
-/// // allocate more than `isize::MAX` bytes.
-/// let dst_ptr = dst.as_mut_ptr().add(dst_len);
-/// let src_ptr = src.as_ptr();
-///
-/// // Truncate `src` without dropping its contents. We do this first,
-/// // to avoid problems in case something further down panics.
-/// src.set_len(0);
-///
-/// // The two regions cannot overlap because mutable references do
-/// // not alias, and two different vectors cannot own the same
-/// // memory.
-/// ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len);
-///
-/// // Notify `dst` that it now holds the contents of `src`.
-/// dst.set_len(dst_len + src_len);
-/// }
-/// }
-///
-/// let mut a = vec!['r'];
-/// let mut b = vec!['u', 's', 't'];
-///
-/// append(&mut a, &mut b);
-///
-/// assert_eq!(a, &['r', 'u', 's', 't']);
-/// assert!(b.is_empty());
-/// ```
-///
-/// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append
-#[doc(alias = "memcpy")]
+/// This is an accidentally-stable alias to [`ptr::copy_nonoverlapping`]; use that instead.
+// Note (intentionally not in the doc comment): `ptr::copy_nonoverlapping` adds some extra
+// debug assertions; if you are writing compiler tests or code inside the standard library
+// that wants to avoid those debug assertions, directly call this intrinsic instead.
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")]
-#[inline(always)]
-#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
-#[rustc_diagnostic_item = "ptr_copy_nonoverlapping"]
-pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
- #[rustc_intrinsic_const_stable_indirect]
- #[rustc_nounwind]
- #[rustc_intrinsic]
- const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
+#[rustc_nounwind]
+#[rustc_intrinsic]
+pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
- ub_checks::assert_unsafe_precondition!(
- check_language_ub,
- "ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null \
- and the specified memory ranges do not overlap",
- (
- src: *const () = src as *const (),
- dst: *mut () = dst as *mut (),
- size: usize = size_of::<T>(),
- align: usize = align_of::<T>(),
- count: usize = count,
- ) => {
- let zero_size = count == 0 || size == 0;
- ub_checks::maybe_is_aligned_and_not_null(src, align, zero_size)
- && ub_checks::maybe_is_aligned_and_not_null(dst, align, zero_size)
- && ub_checks::maybe_is_nonoverlapping(src, dst, size, count)
- }
- );
-
- // SAFETY: the safety contract for `copy_nonoverlapping` must be
- // upheld by the caller.
- unsafe { copy_nonoverlapping(src, dst, count) }
-}
-
-/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
-/// and destination may overlap.
-///
-/// If the source and destination will *never* overlap,
-/// [`copy_nonoverlapping`] can be used instead.
-///
-/// `copy` is semantically equivalent to C's [`memmove`], but
-/// with the source and destination arguments swapped,
-/// and `count` counting the number of `T`s instead of bytes.
-/// Copying takes place as if the bytes were copied from `src`
-/// to a temporary array and then copied from the array to `dst`.
-///
-/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the
-/// requirements of `T`. The initialization state is preserved exactly.
-///
-/// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove
-///
-/// # Safety
-///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
-///
-/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes, and must remain valid even
-/// when `src` is read for `count * size_of::<T>()` bytes. (This means if the memory ranges
-/// overlap, the `dst` pointer must not be invalidated by `src` reads.)
-///
-/// * Both `src` and `dst` must be properly aligned.
-///
-/// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of
-/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values
-/// in the region beginning at `*src` and the region beginning at `*dst` can
-/// [violate memory safety][read-ownership].
-///
-/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
-/// `0`, the pointers must be properly aligned.
-///
-/// [`read`]: crate::ptr::read
-/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
-/// [valid]: crate::ptr#safety
-///
-/// # Examples
-///
-/// Efficiently create a Rust vector from an unsafe buffer:
-///
-/// ```
-/// use std::ptr;
-///
-/// /// # Safety
-/// ///
-/// /// * `ptr` must be correctly aligned for its type and non-zero.
-/// /// * `ptr` must be valid for reads of `elts` contiguous elements of type `T`.
-/// /// * Those elements must not be used after calling this function unless `T: Copy`.
-/// # #[allow(dead_code)]
-/// unsafe fn from_buf_raw<T>(ptr: *const T, elts: usize) -> Vec<T> {
-/// let mut dst = Vec::with_capacity(elts);
-///
-/// // SAFETY: Our precondition ensures the source is aligned and valid,
-/// // and `Vec::with_capacity` ensures that we have usable space to write them.
-/// unsafe { ptr::copy(ptr, dst.as_mut_ptr(), elts); }
-///
-/// // SAFETY: We created it with this much capacity earlier,
-/// // and the previous `copy` has initialized these elements.
-/// unsafe { dst.set_len(elts); }
-/// dst
-/// }
-/// ```
-#[doc(alias = "memmove")]
+/// This is an accidentally-stable alias to [`ptr::copy`]; use that instead.
+// Note (intentionally not in the doc comment): `ptr::copy` adds some extra
+// debug assertions; if you are writing compiler tests or code inside the standard library
+// that wants to avoid those debug assertions, directly call this intrinsic instead.
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"]
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")]
-#[inline(always)]
-#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
-#[rustc_diagnostic_item = "ptr_copy"]
-pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
- #[rustc_intrinsic_const_stable_indirect]
- #[rustc_nounwind]
- #[rustc_intrinsic]
- const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize);
+#[rustc_nounwind]
+#[rustc_intrinsic]
+pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize);
- // SAFETY: the safety contract for `copy` must be upheld by the caller.
- unsafe {
- ub_checks::assert_unsafe_precondition!(
- check_language_ub,
- "ptr::copy requires that both pointer arguments are aligned and non-null",
- (
- src: *const () = src as *const (),
- dst: *mut () = dst as *mut (),
- align: usize = align_of::<T>(),
- zero_size: bool = T::IS_ZST || count == 0,
- ) =>
- ub_checks::maybe_is_aligned_and_not_null(src, align, zero_size)
- && ub_checks::maybe_is_aligned_and_not_null(dst, align, zero_size)
- );
- copy(src, dst, count)
- }
-}
-
-/// Sets `count * size_of::<T>()` bytes of memory starting at `dst` to
-/// `val`.
-///
-/// `write_bytes` is similar to C's [`memset`], but sets `count *
-/// size_of::<T>()` bytes to `val`.
-///
-/// [`memset`]: https://en.cppreference.com/w/c/string/byte/memset
-///
-/// # Safety
-///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
-///
-/// * `dst` must be properly aligned.
-///
-/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
-/// `0`, the pointer must be properly aligned.
-///
-/// Additionally, note that changing `*dst` in this way can easily lead to undefined behavior (UB)
-/// later if the written bytes are not a valid representation of some `T`. For instance, the
-/// following is an **incorrect** use of this function:
-///
-/// ```rust,no_run
-/// unsafe {
-/// let mut value: u8 = 0;
-/// let ptr: *mut bool = &mut value as *mut u8 as *mut bool;
-/// let _bool = ptr.read(); // This is fine, `ptr` points to a valid `bool`.
-/// ptr.write_bytes(42u8, 1); // This function itself does not cause UB...
-/// let _bool = ptr.read(); // ...but it makes this operation UB! ⚠️
-/// }
-/// ```
-///
-/// [valid]: crate::ptr#safety
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```
-/// use std::ptr;
-///
-/// let mut vec = vec![0u32; 4];
-/// unsafe {
-/// let vec_ptr = vec.as_mut_ptr();
-/// ptr::write_bytes(vec_ptr, 0xfe, 2);
-/// }
-/// assert_eq!(vec, [0xfefefefe, 0xfefefefe, 0, 0]);
-/// ```
-#[doc(alias = "memset")]
+/// This is an accidentally-stable alias to [`ptr::write_bytes`]; use that instead.
+// Note (intentionally not in the doc comment): `ptr::write_bytes` adds some extra
+// debug assertions; if you are writing compiler tests or code inside the standard library
+// that wants to avoid those debug assertions, directly call this intrinsic instead.
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"]
-#[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")]
-#[inline(always)]
-#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
-#[rustc_diagnostic_item = "ptr_write_bytes"]
-pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
- #[rustc_intrinsic_const_stable_indirect]
- #[rustc_nounwind]
- #[rustc_intrinsic]
- const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
-
- // SAFETY: the safety contract for `write_bytes` must be upheld by the caller.
- unsafe {
- ub_checks::assert_unsafe_precondition!(
- check_language_ub,
- "ptr::write_bytes requires that the destination pointer is aligned and non-null",
- (
- addr: *const () = dst as *const (),
- align: usize = align_of::<T>(),
- zero_size: bool = T::IS_ZST || count == 0,
- ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, zero_size)
- );
- write_bytes(dst, val, count)
- }
-}
+#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")]
+#[rustc_nounwind]
+#[rustc_intrinsic]
+pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
/// Returns the minimum (IEEE 754-2008 minNum) of two `f16` values.
///
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index 2738775..0a5f3ee 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -21,6 +21,8 @@
#[unstable(feature = "transmutability", issue = "99571")]
pub use transmutability::{Assume, TransmuteFrom};
+// This one has to be a re-export (rather than wrapping the underlying intrinsic) so that we can do
+// the special magic "types have equal size" check at the call site.
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(inline)]
pub use crate::intrinsics::transmute;
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index 257424b..aad073c 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -1419,7 +1419,7 @@ pub fn as_mut(&mut self) -> Pin<&mut Ptr::Target> {
#[stable(feature = "pin_deref_mut", since = "1.84.0")]
#[must_use = "`self` will be dropped if the result is not used"]
#[inline(always)]
- pub fn as_deref_mut(self: Pin<&mut Pin<Ptr>>) -> Pin<&mut Ptr::Target> {
+ pub fn as_deref_mut(self: Pin<&mut Self>) -> Pin<&mut Ptr::Target> {
// SAFETY: What we're asserting here is that going from
//
// Pin<&mut Pin<Ptr>>
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index bd6c4daa..35a909f6 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -405,16 +405,6 @@
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
pub use alignment::Alignment;
-#[stable(feature = "rust1", since = "1.0.0")]
-#[doc(inline)]
-pub use crate::intrinsics::copy;
-#[stable(feature = "rust1", since = "1.0.0")]
-#[doc(inline)]
-pub use crate::intrinsics::copy_nonoverlapping;
-#[stable(feature = "rust1", since = "1.0.0")]
-#[doc(inline)]
-pub use crate::intrinsics::write_bytes;
-
mod metadata;
#[unstable(feature = "ptr_metadata", issue = "81513")]
pub use metadata::{DynMetadata, Pointee, Thin, from_raw_parts, from_raw_parts_mut, metadata};
@@ -430,6 +420,289 @@
mod const_ptr;
mod mut_ptr;
+// Some functions are defined here because they accidentally got made
+// available in this module on stable. See <https://github.com/rust-lang/rust/issues/15702>.
+// (`transmute` also falls into this category, but it cannot be wrapped due to the
+// check that `T` and `U` have the same size.)
+
+/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
+/// and destination must *not* overlap.
+///
+/// For regions of memory which might overlap, use [`copy`] instead.
+///
+/// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but
+/// with the source and destination arguments swapped,
+/// and `count` counting the number of `T`s instead of bytes.
+///
+/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the
+/// requirements of `T`. The initialization state is preserved exactly.
+///
+/// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy
+///
+/// # Safety
+///
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
+///
+/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
+///
+/// * Both `src` and `dst` must be properly aligned.
+///
+/// * The region of memory beginning at `src` with a size of `count *
+/// size_of::<T>()` bytes must *not* overlap with the region of memory
+/// beginning at `dst` with the same size.
+///
+/// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of
+/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values
+/// in the region beginning at `*src` and the region beginning at `*dst` can
+/// [violate memory safety][read-ownership].
+///
+/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
+/// `0`, the pointers must be properly aligned.
+///
+/// [`read`]: crate::ptr::read
+/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
+/// [valid]: crate::ptr#safety
+///
+/// # Examples
+///
+/// Manually implement [`Vec::append`]:
+///
+/// ```
+/// use std::ptr;
+///
+/// /// Moves all the elements of `src` into `dst`, leaving `src` empty.
+/// fn append<T>(dst: &mut Vec<T>, src: &mut Vec<T>) {
+/// let src_len = src.len();
+/// let dst_len = dst.len();
+///
+/// // Ensure that `dst` has enough capacity to hold all of `src`.
+/// dst.reserve(src_len);
+///
+/// unsafe {
+/// // The call to add is always safe because `Vec` will never
+/// // allocate more than `isize::MAX` bytes.
+/// let dst_ptr = dst.as_mut_ptr().add(dst_len);
+/// let src_ptr = src.as_ptr();
+///
+/// // Truncate `src` without dropping its contents. We do this first,
+/// // to avoid problems in case something further down panics.
+/// src.set_len(0);
+///
+/// // The two regions cannot overlap because mutable references do
+/// // not alias, and two different vectors cannot own the same
+/// // memory.
+/// ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len);
+///
+/// // Notify `dst` that it now holds the contents of `src`.
+/// dst.set_len(dst_len + src_len);
+/// }
+/// }
+///
+/// let mut a = vec!['r'];
+/// let mut b = vec!['u', 's', 't'];
+///
+/// append(&mut a, &mut b);
+///
+/// assert_eq!(a, &['r', 'u', 's', 't']);
+/// assert!(b.is_empty());
+/// ```
+///
+/// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append
+#[doc(alias = "memcpy")]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")]
+#[inline(always)]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
+#[rustc_diagnostic_item = "ptr_copy_nonoverlapping"]
+pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
+ ub_checks::assert_unsafe_precondition!(
+ check_language_ub,
+ "ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null \
+ and the specified memory ranges do not overlap",
+ (
+ src: *const () = src as *const (),
+ dst: *mut () = dst as *mut (),
+ size: usize = size_of::<T>(),
+ align: usize = align_of::<T>(),
+ count: usize = count,
+ ) => {
+ let zero_size = count == 0 || size == 0;
+ ub_checks::maybe_is_aligned_and_not_null(src, align, zero_size)
+ && ub_checks::maybe_is_aligned_and_not_null(dst, align, zero_size)
+ && ub_checks::maybe_is_nonoverlapping(src, dst, size, count)
+ }
+ );
+
+ // SAFETY: the safety contract for `copy_nonoverlapping` must be
+ // upheld by the caller.
+ unsafe { crate::intrinsics::copy_nonoverlapping(src, dst, count) }
+}
+
+/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
+/// and destination may overlap.
+///
+/// If the source and destination will *never* overlap,
+/// [`copy_nonoverlapping`] can be used instead.
+///
+/// `copy` is semantically equivalent to C's [`memmove`], but
+/// with the source and destination arguments swapped,
+/// and `count` counting the number of `T`s instead of bytes.
+/// Copying takes place as if the bytes were copied from `src`
+/// to a temporary array and then copied from the array to `dst`.
+///
+/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the
+/// requirements of `T`. The initialization state is preserved exactly.
+///
+/// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove
+///
+/// # Safety
+///
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
+///
+/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes, and must remain valid even
+/// when `src` is read for `count * size_of::<T>()` bytes. (This means if the memory ranges
+/// overlap, the `dst` pointer must not be invalidated by `src` reads.)
+///
+/// * Both `src` and `dst` must be properly aligned.
+///
+/// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of
+/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values
+/// in the region beginning at `*src` and the region beginning at `*dst` can
+/// [violate memory safety][read-ownership].
+///
+/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
+/// `0`, the pointers must be properly aligned.
+///
+/// [`read`]: crate::ptr::read
+/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
+/// [valid]: crate::ptr#safety
+///
+/// # Examples
+///
+/// Efficiently create a Rust vector from an unsafe buffer:
+///
+/// ```
+/// use std::ptr;
+///
+/// /// # Safety
+/// ///
+/// /// * `ptr` must be correctly aligned for its type and non-zero.
+/// /// * `ptr` must be valid for reads of `elts` contiguous elements of type `T`.
+/// /// * Those elements must not be used after calling this function unless `T: Copy`.
+/// # #[allow(dead_code)]
+/// unsafe fn from_buf_raw<T>(ptr: *const T, elts: usize) -> Vec<T> {
+/// let mut dst = Vec::with_capacity(elts);
+///
+/// // SAFETY: Our precondition ensures the source is aligned and valid,
+/// // and `Vec::with_capacity` ensures that we have usable space to write them.
+/// unsafe { ptr::copy(ptr, dst.as_mut_ptr(), elts); }
+///
+/// // SAFETY: We created it with this much capacity earlier,
+/// // and the previous `copy` has initialized these elements.
+/// unsafe { dst.set_len(elts); }
+/// dst
+/// }
+/// ```
+#[doc(alias = "memmove")]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")]
+#[inline(always)]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
+#[rustc_diagnostic_item = "ptr_copy"]
+pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
+ // SAFETY: the safety contract for `copy` must be upheld by the caller.
+ unsafe {
+ ub_checks::assert_unsafe_precondition!(
+ check_language_ub,
+ "ptr::copy requires that both pointer arguments are aligned and non-null",
+ (
+ src: *const () = src as *const (),
+ dst: *mut () = dst as *mut (),
+ align: usize = align_of::<T>(),
+ zero_size: bool = T::IS_ZST || count == 0,
+ ) =>
+ ub_checks::maybe_is_aligned_and_not_null(src, align, zero_size)
+ && ub_checks::maybe_is_aligned_and_not_null(dst, align, zero_size)
+ );
+ crate::intrinsics::copy(src, dst, count)
+ }
+}
+
+/// Sets `count * size_of::<T>()` bytes of memory starting at `dst` to
+/// `val`.
+///
+/// `write_bytes` is similar to C's [`memset`], but sets `count *
+/// size_of::<T>()` bytes to `val`.
+///
+/// [`memset`]: https://en.cppreference.com/w/c/string/byte/memset
+///
+/// # Safety
+///
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
+///
+/// * `dst` must be properly aligned.
+///
+/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
+/// `0`, the pointer must be properly aligned.
+///
+/// Additionally, note that changing `*dst` in this way can easily lead to undefined behavior (UB)
+/// later if the written bytes are not a valid representation of some `T`. For instance, the
+/// following is an **incorrect** use of this function:
+///
+/// ```rust,no_run
+/// unsafe {
+/// let mut value: u8 = 0;
+/// let ptr: *mut bool = &mut value as *mut u8 as *mut bool;
+/// let _bool = ptr.read(); // This is fine, `ptr` points to a valid `bool`.
+/// ptr.write_bytes(42u8, 1); // This function itself does not cause UB...
+/// let _bool = ptr.read(); // ...but it makes this operation UB! ⚠️
+/// }
+/// ```
+///
+/// [valid]: crate::ptr#safety
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use std::ptr;
+///
+/// let mut vec = vec![0u32; 4];
+/// unsafe {
+/// let vec_ptr = vec.as_mut_ptr();
+/// ptr::write_bytes(vec_ptr, 0xfe, 2);
+/// }
+/// assert_eq!(vec, [0xfefefefe, 0xfefefefe, 0, 0]);
+/// ```
+#[doc(alias = "memset")]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")]
+#[inline(always)]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
+#[rustc_diagnostic_item = "ptr_write_bytes"]
+pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
+ // SAFETY: the safety contract for `write_bytes` must be upheld by the caller.
+ unsafe {
+ ub_checks::assert_unsafe_precondition!(
+ check_language_ub,
+ "ptr::write_bytes requires that the destination pointer is aligned and non-null",
+ (
+ addr: *const () = dst as *const (),
+ align: usize = align_of::<T>(),
+ zero_size: bool = T::IS_ZST || count == 0,
+ ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, zero_size)
+ );
+ crate::intrinsics::write_bytes(dst, val, count)
+ }
+}
+
/// Executes the destructor (if any) of the pointed-to value.
///
/// This is almost the same as calling [`ptr::read`] and discarding
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index 72bdf03..ead4877 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -1040,7 +1040,7 @@ pub fn len(&self) -> usize {
/// Converts a <code>[Box]<[OsStr]></code> into an [`OsString`] without copying or allocating.
#[stable(feature = "into_boxed_os_str", since = "1.20.0")]
#[must_use = "`self` will be dropped if the result is not used"]
- pub fn into_os_string(self: Box<OsStr>) -> OsString {
+ pub fn into_os_string(self: Box<Self>) -> OsString {
let boxed = unsafe { Box::from_raw(Box::into_raw(self) as *mut Slice) };
OsString { inner: Buf::from_box(boxed) }
}
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 1a4a7aa..7959c63 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -3163,7 +3163,7 @@ pub fn is_symlink(&self) -> bool {
/// allocating.
#[stable(feature = "into_boxed_path", since = "1.20.0")]
#[must_use = "`self` will be dropped if the result is not used"]
- pub fn into_path_buf(self: Box<Path>) -> PathBuf {
+ pub fn into_path_buf(self: Box<Self>) -> PathBuf {
let rw = Box::into_raw(self) as *mut OsStr;
let inner = unsafe { Box::from_raw(rw) };
PathBuf { inner: OsString::from(inner) }
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 67daf81..d5ea96b 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -1984,17 +1984,20 @@ fn run(self, builder: &Builder<'_>) -> Compiler {
trace!("installing `{tool}`");
let tool_exe = exe(tool, target_compiler.host);
let src_path = llvm_bin_dir.join(&tool_exe);
- // When using `download-ci-llvm`, some of the tools
- // may not exist, so skip trying to copy them.
- if src_path.exists() {
- // There is a chance that these tools are being installed from an external LLVM.
- // Use `Builder::resolve_symlink_and_copy` instead of `Builder::copy_link` to ensure
- // we are copying the original file not the symlinked path, which causes issues for
- // tarball distribution.
- //
- // See https://github.com/rust-lang/rust/issues/135554.
- builder.resolve_symlink_and_copy(&src_path, &libdir_bin.join(&tool_exe));
+
+ // When using `download-ci-llvm`, some of the tools may not exist, so skip trying to copy them.
+ if !src_path.exists() && builder.config.llvm_from_ci {
+ eprintln!("{} does not exist; skipping copy", src_path.display());
+ continue;
}
+
+ // There is a chance that these tools are being installed from an external LLVM.
+ // Use `Builder::resolve_symlink_and_copy` instead of `Builder::copy_link` to ensure
+ // we are copying the original file not the symlinked path, which causes issues for
+ // tarball distribution.
+ //
+ // See https://github.com/rust-lang/rust/issues/135554.
+ builder.resolve_symlink_and_copy(&src_path, &libdir_bin.join(&tool_exe));
}
}
}
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index aa2c750..253fa22 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -2274,9 +2274,9 @@ fn tools_to_install(paths: &[PathBuf]) -> Vec<&'static str> {
let target = self.target;
- /* run only if llvm-config isn't used */
+ // Run only if a custom llvm-config is not used
if let Some(config) = builder.config.target_config.get(&target) {
- if let Some(ref _s) = config.llvm_config {
+ if !builder.config.llvm_from_ci && config.llvm_config.is_some() {
builder.info(&format!("Skipping LlvmTools ({target}): external LLVM"));
return None;
}
@@ -2294,6 +2294,12 @@ fn tools_to_install(paths: &[PathBuf]) -> Vec<&'static str> {
let dst_bindir = format!("lib/rustlib/{}/bin", target.triple);
for tool in tools_to_install(&builder.paths) {
let exe = src_bindir.join(exe(tool, target));
+ // When using `download-ci-llvm`, some of the tools may not exist, so skip trying to copy them.
+ if !exe.exists() && builder.config.llvm_from_ci {
+ eprintln!("{} does not exist; skipping copy", exe.display());
+ continue;
+ }
+
tarball.add_file(&exe, &dst_bindir, FileType::Executable);
}
}
diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs
index c31c40e..585adf9 100644
--- a/src/bootstrap/src/core/build_steps/install.rs
+++ b/src/bootstrap/src/core/build_steps/install.rs
@@ -244,7 +244,7 @@ fn run($sel, $builder: &Builder<'_>) {
);
}
};
- LlvmTools, alias = "llvm-tools", Self::should_build(_config), only_hosts: true, {
+ LlvmTools, alias = "llvm-tools", _config.llvm_tools_enabled && _config.llvm_enabled(_config.build), only_hosts: true, {
if let Some(tarball) = builder.ensure(dist::LlvmTools { target: self.target }) {
install_sh(builder, "llvm-tools", self.compiler.stage, Some(self.target), &tarball);
} else {
diff --git a/src/ci/scripts/install-clang.sh b/src/ci/scripts/install-clang.sh
index 5522095..a9528e9 100755
--- a/src/ci/scripts/install-clang.sh
+++ b/src/ci/scripts/install-clang.sh
@@ -10,8 +10,8 @@
source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
# Update both macOS's and Windows's tarballs when bumping the version here.
-# Try to keep this in sync with src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh
-LLVM_VERSION="18.1.4"
+# Try to keep this in sync with src/ci/docker/scripts/build-clang.sh
+LLVM_VERSION="20.1.3"
if isMacOS; then
# FIXME: This is the latest pre-built version of LLVM that's available for
diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version
index 5e4266f..0d889a5 100644
--- a/src/doc/rustc-dev-guide/rust-version
+++ b/src/doc/rustc-dev-guide/rust-version
@@ -1 +1 @@
-414482f6a0d4e7290f614300581a0b55442552a3
+e42bbfe1f7c26f8760a99c4b1f27d33aba1040bb
diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md
index 3111949..a7b7623 100644
--- a/src/doc/rustc-dev-guide/src/SUMMARY.md
+++ b/src/doc/rustc-dev-guide/src/SUMMARY.md
@@ -134,9 +134,9 @@
- [Command-line arguments](./cli.md)
- [rustc_driver and rustc_interface](./rustc-driver/intro.md)
+ - [Remarks on perma-unstable features](./rustc-driver/remarks-on-perma-unstable-features.md)
- [Example: Type checking](./rustc-driver/interacting-with-the-ast.md)
- [Example: Getting diagnostics](./rustc-driver/getting-diagnostics.md)
- - [Remarks on perma-unstable features](./rustc-driver/remarks-on-perma-unstable-features.md)
- [Errors and lints](diagnostics.md)
- [Diagnostic and subdiagnostic structs](./diagnostics/diagnostic-structs.md)
- [Translation](./diagnostics/translation.md)
diff --git a/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md b/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md
index 513df16..eeb2af5 100644
--- a/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md
+++ b/src/doc/rustc-dev-guide/src/backend/libs-and-metadata.md
@@ -28,8 +28,8 @@
[`-C embed-bitcode=no`][embed-bitcode] CLI option to improve compile times
and reduce disk space if LTO is not needed.
* `rustc` [metadata], in a file named `lib.rmeta`.
-* A symbol table, which is generally a list of symbols with offsets to the
- object file that contain that symbol. This is pretty standard for archive
+* A symbol table, which is essentially a list of symbols with offsets to the
+ object files that contain that symbol. This is pretty standard for archive
files.
[archive file]: https://en.wikipedia.org/wiki/Ar_(Unix)
@@ -46,12 +46,11 @@
### rmeta
-An `rmeta` file is custom binary format that contains the [metadata] for the
-crate. This file can be used for fast "checks" of a project by skipping all
-code generation (as is done with `cargo check`), collecting enough information
-for documentation (as is done with `cargo doc`), or for
-[pipelining](#pipelining). This file is created if the
-[`--emit=metadata`][emit] CLI option is used.
+An `rmeta` file is a custom binary format that contains the [metadata] for the
+crate. This file can be used for fast "checks" of a project by skipping all code
+generation (as is done with `cargo check`), collecting enough information for
+documentation (as is done with `cargo doc`), or for [pipelining](#pipelining).
+This file is created if the [`--emit=metadata`][emit] CLI option is used.
`rmeta` files do not support linking, since they do not contain compiled
object files.
@@ -60,8 +59,8 @@
## Metadata
-The metadata contains a wide swath of different elements. This guide will not
-go into detail of every field it contains. You are encouraged to browse the
+The metadata contains a wide swath of different elements. This guide will not go
+into detail about every field it contains. You are encouraged to browse the
[`CrateRoot`] definition to get a sense of the different elements it contains.
Everything about metadata encoding and decoding is in the [`rustc_metadata`]
package.
@@ -122,9 +121,9 @@
By default, all Rust symbols are mangled and incorporate the stable crate id.
This allows multiple versions of the same crate to be included together. Cargo
-automatically generates `-C metadata` hashes based on a variety of factors,
-like the package version, source, and the target kind (a lib and test can have
-the same crate name, so they need to be disambiguated).
+automatically generates `-C metadata` hashes based on a variety of factors, like
+the package version, source, and target kind (a lib and test can have the same
+crate name, so they need to be disambiguated).
[`StableCrateId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/def_id/struct.StableCrateId.html
[`StableCrateId::new`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/def_id/struct.StableCrateId.html#method.new
@@ -154,7 +153,7 @@
As crates are loaded, they are kept in the [`CStore`] with the crate metadata
wrapped in the [`CrateMetadata`] struct. After resolution and expansion, the
-`CStore` will make its way into the [`GlobalCtxt`] for the rest of
+`CStore` will make its way into the [`GlobalCtxt`] for the rest of the
compilation.
[name resolution]: ../name-resolution.md
diff --git a/src/doc/rustc-dev-guide/src/cli.md b/src/doc/rustc-dev-guide/src/cli.md
index 408ae20..4c77007 100644
--- a/src/doc/rustc-dev-guide/src/cli.md
+++ b/src/doc/rustc-dev-guide/src/cli.md
@@ -28,6 +28,6 @@
unstable-options` flag.
[cli-docs]: https://doc.rust-lang.org/rustc/command-line-arguments.html
-[forge guide for new options]: https://forge.rust-lang.org/compiler/new_option.html
+[forge guide for new options]: https://forge.rust-lang.org/compiler/proposals-and-stabilization.html#compiler-flags
[unstable book]: https://doc.rust-lang.org/nightly/unstable-book/
[`parse_bool`]: https://github.com/rust-lang/rust/blob/e5335592e78354e33d798d20c04bcd677c1df62d/src/librustc_session/options.rs#L307-L313
diff --git a/src/doc/rustc-dev-guide/src/getting-started.md b/src/doc/rustc-dev-guide/src/getting-started.md
index 8bf14be..0e5b32a 100644
--- a/src/doc/rustc-dev-guide/src/getting-started.md
+++ b/src/doc/rustc-dev-guide/src/getting-started.md
@@ -89,7 +89,7 @@
Not all important or beginner work has issue labels.
See below for how to find work that isn't labelled.
-[help-wanted-search]: https://github.com/issues?q=is%3Aopen+is%3Aissue+org%3Arust-lang+no%3Aassignee+label%3AE-easy%2C%22good+first+issue%22%2Cgood-first-issue%2CE-medium%2CEasy%2CE-help-wanted%2CE-mentor+-label%3AS-blocked+
+[help-wanted-search]: https://github.com/issues?q=is%3Aopen+is%3Aissue+org%3Arust-lang+no%3Aassignee+label%3AE-easy%2C%22good+first+issue%22%2Cgood-first-issue%2CE-medium%2CEasy%2CE-help-wanted%2CE-mentor+-label%3AS-blocked+-linked:pr+
[Triage]: ./contributing.md#issue-triage
### Recurring work
diff --git a/src/doc/rustc-dev-guide/src/rustc-driver/intro.md b/src/doc/rustc-dev-guide/src/rustc-driver/intro.md
index 40500e6..a368439 100644
--- a/src/doc/rustc-dev-guide/src/rustc-driver/intro.md
+++ b/src/doc/rustc-dev-guide/src/rustc-driver/intro.md
@@ -7,8 +7,8 @@
using the interface defined in the [`rustc_interface`] crate. Where possible, using [`rustc_driver`] rather than [`rustc_interface`] is recommended.
The main entry point of [`rustc_driver`] is [`rustc_driver::run_compiler`][rd_rc].
-This builder accepts the same command-line args as rustc as well as an implementation of [`Callbacks`][cb] and a couple of other optional options.
-[`Callbacks`][cb] is a `trait` that allows for custom compiler configuration,
+This builder accepts the same command-line args as rustc as well as an implementation of [`Callbacks`] and a couple of other optional options.
+[`Callbacks`] is a `trait` that allows for custom compiler configuration,
as well as allowing custom code to run after different phases of the compilation.
## `rustc_interface`
@@ -33,14 +33,8 @@
[`Compiler`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/interface/struct.Compiler.html
[`rustc_driver`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/
[`rustc_interface`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/index.html
-[`Session`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/struct.Session.html
-[`SourceMap`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/source_map/struct.SourceMap.html
-[`TyCtxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html
-[Appendix A]: appendix/stupid-stats.html
-[cb]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/trait.Callbacks.html
+[`Callbacks`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/trait.Callbacks.html
[example]: https://github.com/rust-lang/rustc-dev-guide/blob/master/examples/rustc-interface-example.rs
[i_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/interface/fn.run_compiler.html
[rd_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/fn.run_compiler.html
[rdi_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver_impl/fn.run_compiler.html
-[stupid-stats]: https://github.com/nrc/stupid-stats
-[`nightly-rustc`]: https://doc.rust-lang.org/nightly/nightly-rustc/
diff --git a/src/doc/rustc/theme/pagetoc.css b/src/doc/rustc/theme/pagetoc.css
index 58ca1f8..fa70919 100644
--- a/src/doc/rustc/theme/pagetoc.css
+++ b/src/doc/rustc/theme/pagetoc.css
@@ -49,7 +49,7 @@
}
#pagetoc a {
border-left: 1px solid var(--sidebar-bg);
- color: var(--sidebar-fg) !important;
+ color: var(--fg);
display: block;
padding-bottom: 5px;
padding-top: 5px;
diff --git a/src/doc/unstable-book/src/language-features/explicit-extern-abis.md b/src/doc/unstable-book/src/language-features/explicit-extern-abis.md
index ba62246..7728f67 100644
--- a/src/doc/unstable-book/src/language-features/explicit-extern-abis.md
+++ b/src/doc/unstable-book/src/language-features/explicit-extern-abis.md
@@ -1,6 +1,6 @@
# `explicit_extern_abis`
-The tracking issue for this feature is: #134986
+The tracking issue for this feature is: [#134986]
------
@@ -21,3 +21,5 @@
extern "aapcs" fn function3() {} // compiles
```
+
+[#134986]: https://github.com/rust-lang/rust/issues/134986
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index 44b3be2..3b5f9b5 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -1,4 +1,4 @@
-use std::fmt::{self, Display};
+use std::fmt::Display;
use std::path::PathBuf;
use askama::Template;
@@ -71,23 +71,6 @@ struct PageLayout<'a> {
pub(crate) use crate::html::render::sidebar::filters;
-/// Implements [`Display`] for a function that accepts a mutable reference to a [`String`], and (optionally) writes to it.
-///
-/// The wrapped function will receive an empty string, and can modify it,
-/// and the `Display` implementation will write the contents of the string after the function has finished.
-pub(crate) struct BufDisplay<F>(pub F);
-
-impl<F> Display for BufDisplay<F>
-where
- F: Fn(&mut String),
-{
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let mut buf = String::new();
- self.0(&mut buf);
- f.write_str(&buf)
- }
-}
-
pub(crate) fn render<T: Display, S: Display>(
layout: &Layout,
page: &Page<'_>,
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index f22935d..1f7201b 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -28,11 +28,10 @@
use crate::formats::item_type::ItemType;
use crate::html::escape::Escape;
use crate::html::format::join_with_double_colon;
-use crate::html::layout::{self, BufDisplay};
use crate::html::markdown::{self, ErrorCodes, IdMap, plain_text_summary};
use crate::html::render::write_shared::write_shared;
use crate::html::url_parts_builder::UrlPartsBuilder;
-use crate::html::{sources, static_files};
+use crate::html::{layout, sources, static_files};
use crate::scrape_examples::AllCallLocations;
use crate::{DOC_RUST_LANG_ORG_VERSION, try_err};
@@ -250,9 +249,7 @@ fn render_item(&mut self, it: &clean::Item, is_module: bool) -> String {
layout::render(
&self.shared.layout,
&page,
- BufDisplay(|buf: &mut String| {
- print_sidebar(self, it, buf);
- }),
+ fmt::from_fn(|f| print_sidebar(self, it, f)),
content,
&self.shared.style_files,
)
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 3492df9..06cb926 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -538,7 +538,7 @@ fn document(
}
fmt::from_fn(move |f| {
- document_item_info(cx, item, parent).render_into(f).unwrap();
+ document_item_info(cx, item, parent).render_into(f)?;
if parent.is_none() {
write!(f, "{}", document_full_collapsible(item, cx, heading_offset))
} else {
@@ -582,7 +582,7 @@ fn document_short(
show_def_docs: bool,
) -> impl fmt::Display {
fmt::from_fn(move |f| {
- document_item_info(cx, item, Some(parent)).render_into(f).unwrap();
+ document_item_info(cx, item, Some(parent)).render_into(f)?;
if !show_def_docs {
return Ok(());
}
@@ -661,7 +661,7 @@ fn document_full_inner(
};
if let clean::ItemKind::FunctionItem(..) | clean::ItemKind::MethodItem(..) = kind {
- render_call_locations(f, cx, item);
+ render_call_locations(f, cx, item)?;
}
Ok(())
})
@@ -2584,11 +2584,15 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec<String> {
const NUM_VISIBLE_LINES: usize = 10;
/// Generates the HTML for example call locations generated via the --scrape-examples flag.
-fn render_call_locations<W: fmt::Write>(mut w: W, cx: &Context<'_>, item: &clean::Item) {
+fn render_call_locations<W: fmt::Write>(
+ mut w: W,
+ cx: &Context<'_>,
+ item: &clean::Item,
+) -> fmt::Result {
let tcx = cx.tcx();
let def_id = item.item_id.expect_def_id();
let key = tcx.def_path_hash(def_id);
- let Some(call_locations) = cx.shared.call_locations.get(&key) else { return };
+ let Some(call_locations) = cx.shared.call_locations.get(&key) else { return Ok(()) };
// Generate a unique ID so users can link to this section for a given method
let id = cx.derive_id("scraped-examples");
@@ -2602,8 +2606,7 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &Context<'_>, item: &clean
</h5>",
root_path = cx.root_path(),
id = id
- )
- .unwrap();
+ )?;
// Create a URL to a particular location in a reverse-dependency's source file
let link_to_loc = |call_data: &CallData, loc: &CallLocation| -> (String, String) {
@@ -2705,7 +2708,8 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &Context<'_>, item: &clean
title: init_title,
locations: locations_encoded,
}),
- );
+ )
+ .unwrap();
true
};
@@ -2761,8 +2765,7 @@ fn sort_criterion<'a>(
<div class=\"hide-more\">Hide additional examples</div>\
<div class=\"more-scraped-examples\">\
<div class=\"toggle-line\"><div class=\"toggle-line-inner\"></div></div>"
- )
- .unwrap();
+ )?;
// Only generate inline code for MAX_FULL_EXAMPLES number of examples. Otherwise we could
// make the page arbitrarily huge!
@@ -2774,9 +2777,8 @@ fn sort_criterion<'a>(
if it.peek().is_some() {
w.write_str(
r#"<div class="example-links">Additional examples can be found in:<br><ul>"#,
- )
- .unwrap();
- it.for_each(|(_, call_data)| {
+ )?;
+ it.try_for_each(|(_, call_data)| {
let (url, _) = link_to_loc(call_data, &call_data.locations[0]);
write!(
w,
@@ -2784,13 +2786,12 @@ fn sort_criterion<'a>(
url = url,
name = call_data.display_name
)
- .unwrap();
- });
- w.write_str("</ul></div>").unwrap();
+ })?;
+ w.write_str("</ul></div>")?;
}
- w.write_str("</div></details>").unwrap();
+ w.write_str("</div></details>")?;
}
- w.write_str("</div>").unwrap();
+ w.write_str("</div>")
}
diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs
index cd0c977..a902997 100644
--- a/src/librustdoc/html/render/sidebar.rs
+++ b/src/librustdoc/html/render/sidebar.rs
@@ -1,5 +1,6 @@
use std::borrow::Cow;
use std::cmp::Ordering;
+use std::fmt;
use askama::Template;
use rustc_data_structures::fx::FxHashSet;
@@ -135,7 +136,11 @@ pub(crate) fn wrapped<T>(v: T) -> askama::Result<Safe<impl Display>>
}
}
-pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut String) {
+pub(super) fn print_sidebar(
+ cx: &Context<'_>,
+ it: &clean::Item,
+ mut buffer: impl fmt::Write,
+) -> fmt::Result {
let mut ids = IdMap::new();
let mut blocks: Vec<LinkBlock<'_>> = docblock_toc(cx, it, &mut ids).into_iter().collect();
let deref_id_map = cx.deref_id_map.borrow();
@@ -195,7 +200,8 @@ pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Str
blocks,
path,
};
- sidebar.render_into(buffer).unwrap();
+ sidebar.render_into(&mut buffer)?;
+ Ok(())
}
fn get_struct_fields_name<'a>(fields: &'a [clean::Item]) -> Vec<Link<'a>> {
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index 095795c..1fa6b5a 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -11,9 +11,8 @@
use rustc_span::{FileName, FileNameDisplayPreference, RealFileName, sym};
use tracing::info;
-use super::highlight;
-use super::layout::{self, BufDisplay};
use super::render::Context;
+use super::{highlight, layout};
use crate::clean;
use crate::clean::utils::has_doc_flag;
use crate::docfs::PathError;
@@ -243,16 +242,16 @@ fn emit_source(
&shared.layout,
&page,
"",
- BufDisplay(|buf: &mut String| {
+ fmt::from_fn(|f| {
print_src(
- buf,
+ f,
contents,
file_span,
self.cx,
&root_path,
&highlight::DecorationInfo::default(),
&source_context,
- );
+ )
}),
&shared.style_files,
);
@@ -331,7 +330,7 @@ pub(crate) fn print_src(
root_path: &str,
decoration_info: &highlight::DecorationInfo,
source_context: &SourceContext<'_>,
-) {
+) -> fmt::Result {
let mut lines = s.lines().count();
let line_info = if let SourceContext::Embedded(info) = source_context {
highlight::LineInfo::new_scraped(lines as u32, info.offset as u32)
@@ -367,12 +366,10 @@ pub(crate) fn print_src(
},
max_nb_digits,
}
- .render_into(&mut writer)
- .unwrap(),
+ .render_into(&mut writer),
SourceContext::Embedded(info) => {
- ScrapedSource { info, code_html: code, max_nb_digits }
- .render_into(&mut writer)
- .unwrap();
+ ScrapedSource { info, code_html: code, max_nb_digits }.render_into(&mut writer)
}
- };
+ }?;
+ Ok(())
}
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 5b47d1b..4698969 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-a8e4c68dcb4dc1e48a0db294c5323cab0227fcb9
+2b96ddca1272960623e41829439df8dae82d20af
diff --git a/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.rs b/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.rs
deleted file mode 100644
index 3ef194c5..0000000
--- a/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ignore-target: windows # No libc IO on Windows
-
-fn main() -> std::io::Result<()> {
- let mut bytes = [0u8; 512];
- unsafe {
- libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); //~ ERROR: `read` from stdin not available when isolation is enabled
- }
- Ok(())
-}
diff --git a/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr b/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr
deleted file mode 100644
index bb7e8ce..0000000
--- a/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error: unsupported operation: `read` from stdin not available when isolation is enabled
- --> tests/fail-dep/libc/fs/isolated_stdin.rs:LL:CC
- |
-LL | libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `read` from stdin not available when isolation is enabled
- |
- = help: set `MIRIFLAGS=-Zmiri-disable-isolation` to disable isolation;
- = help: or set `MIRIFLAGS=-Zmiri-isolation-error=warn` to make Miri return an error code from isolated operations (if supported for that operation) and continue with a warning
- = note: BACKTRACE:
- = note: inside `main` at tests/fail-dep/libc/fs/isolated_stdin.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs b/src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs
index e628261..ff16ac6 100644
--- a/src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs
+++ b/src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs
@@ -1,14 +1,11 @@
-#![feature(intrinsics)]
-
-// Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
+#![feature(core_intrinsics)]
fn main() {
let mut data = [0u8; 16];
unsafe {
let a = data.as_mut_ptr();
let b = a.wrapping_offset(1) as *mut _;
- copy_nonoverlapping(a, b, 2); //~ ERROR: `copy_nonoverlapping` called on overlapping ranges
+ // Directly call intrinsic to avoid debug assertions in the `std::ptr` version.
+ std::intrinsics::copy_nonoverlapping(a, b, 2); //~ ERROR: `copy_nonoverlapping` called on overlapping ranges
}
}
diff --git a/src/tools/miri/tests/fail/intrinsics/copy_overlapping.stderr b/src/tools/miri/tests/fail/intrinsics/copy_overlapping.stderr
index fef5a0a..9b60a48 100644
--- a/src/tools/miri/tests/fail/intrinsics/copy_overlapping.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/copy_overlapping.stderr
@@ -1,8 +1,8 @@
error: Undefined Behavior: `copy_nonoverlapping` called on overlapping ranges
--> tests/fail/intrinsics/copy_overlapping.rs:LL:CC
|
-LL | copy_nonoverlapping(a, b, 2);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `copy_nonoverlapping` called on overlapping ranges
+LL | std::intrinsics::copy_nonoverlapping(a, b, 2);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `copy_nonoverlapping` called on overlapping ranges
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs b/src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs
index ded9d0b..311789c 100644
--- a/src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs
+++ b/src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs
@@ -1,14 +1,11 @@
-#![feature(intrinsics)]
-
-// Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
+#![feature(core_intrinsics)]
fn main() {
let mut data = [0u16; 8];
let ptr = (&mut data[0] as *mut u16 as *mut u8).wrapping_add(1) as *mut u16;
// Even copying 0 elements to something unaligned should error
unsafe {
- copy_nonoverlapping(&data[5], ptr, 0); //~ ERROR: accessing memory with alignment 1, but alignment 2 is required
+ // Directly call intrinsic to avoid debug assertions in the `std::ptr` version.
+ std::intrinsics::copy_nonoverlapping(&data[5], ptr, 0); //~ ERROR: accessing memory with alignment 1, but alignment 2 is required
}
}
diff --git a/src/tools/miri/tests/fail/intrinsics/copy_unaligned.stderr b/src/tools/miri/tests/fail/intrinsics/copy_unaligned.stderr
index 2d0edd4..65dbdb3 100644
--- a/src/tools/miri/tests/fail/intrinsics/copy_unaligned.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/copy_unaligned.stderr
@@ -1,8 +1,8 @@
error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required
--> tests/fail/intrinsics/copy_unaligned.rs:LL:CC
|
-LL | copy_nonoverlapping(&data[5], ptr, 0);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required
+LL | std::intrinsics::copy_nonoverlapping(&data[5], ptr, 0);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/shims/isolated_stdin.rs b/src/tools/miri/tests/fail/shims/isolated_stdin.rs
new file mode 100644
index 0000000..040c3cc
--- /dev/null
+++ b/src/tools/miri/tests/fail/shims/isolated_stdin.rs
@@ -0,0 +1,12 @@
+//@ignore-target: windows # FIXME: stdin does not work on Windows
+//@error-in-other-file: `read` from stdin not available when isolation is enabled
+//@normalize-stderr-test: "src/sys/.*\.rs" -> "$$FILE"
+//@normalize-stderr-test: "\nLL \| .*" -> ""
+//@normalize-stderr-test: "\| +[|_^]+" -> "| ^"
+//@normalize-stderr-test: "\n *= note:.*" -> ""
+use std::io::{self, Read};
+
+fn main() {
+ let mut bytes = [0u8; 512];
+ io::stdin().read(&mut bytes).unwrap();
+}
diff --git a/src/tools/miri/tests/fail/shims/isolated_stdin.stderr b/src/tools/miri/tests/fail/shims/isolated_stdin.stderr
new file mode 100644
index 0000000..1a4d7e9
--- /dev/null
+++ b/src/tools/miri/tests/fail/shims/isolated_stdin.stderr
@@ -0,0 +1,16 @@
+error: unsupported operation: `read` from stdin not available when isolation is enabled
+ --> RUSTLIB/std/$FILE:LL:CC
+ |
+ | ^ `read` from stdin not available when isolation is enabled
+ |
+ = help: set `MIRIFLAGS=-Zmiri-disable-isolation` to disable isolation;
+ = help: or set `MIRIFLAGS=-Zmiri-isolation-error=warn` to make Miri return an error code from isolated operations (if supported for that operation) and continue with a warning
+note: inside `main`
+ --> tests/fail/shims/isolated_stdin.rs:LL:CC
+ |
+ | ^
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/pass/shims/io.rs b/src/tools/miri/tests/pass/shims/io.rs
index 420ef95..a96b98c 100644
--- a/src/tools/miri/tests/pass/shims/io.rs
+++ b/src/tools/miri/tests/pass/shims/io.rs
@@ -1,8 +1,10 @@
-use std::io::{self, IsTerminal};
+use std::io::{self, IsTerminal, Write};
fn main() {
- // We can't really assume that this is truly a terminal, and anyway on Windows Miri will always
- // return `false` here, but we can check that the call succeeds.
+ io::stdout().write_all(b"stdout\n").unwrap();
+ io::stderr().write_all(b"stderr\n").unwrap();
+
+ // We can't assume that this is truly a terminal, but we can check that the call succeeds.
io::stdout().is_terminal();
// Ensure we can format `io::Error` created from OS errors
diff --git a/src/tools/miri/tests/pass/shims/io.stderr b/src/tools/miri/tests/pass/shims/io.stderr
new file mode 100644
index 0000000..af6415d
--- /dev/null
+++ b/src/tools/miri/tests/pass/shims/io.stderr
@@ -0,0 +1 @@
+stderr
diff --git a/src/tools/miri/tests/pass/shims/io.stdout b/src/tools/miri/tests/pass/shims/io.stdout
new file mode 100644
index 0000000..faa3a15
--- /dev/null
+++ b/src/tools/miri/tests/pass/shims/io.stdout
@@ -0,0 +1 @@
+stdout
diff --git a/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/config.yml b/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000..466672e
--- /dev/null
+++ b/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,4 @@
+contact_links:
+ - name: Questions regarding rust-analyzer
+ url: https://github.com/rust-lang/rust-analyzer/discussions
+ about: Please ask and answer questions here instead of opening an issue
diff --git a/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/critical_nightly_regression.md b/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/critical_nightly_regression.md
index 23c4344..2b44bdc 100644
--- a/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/critical_nightly_regression.md
+++ b/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/critical_nightly_regression.md
@@ -12,5 +12,3 @@
Please try to provide information which will help us to fix the issue faster. Minimal reproducible examples with few dependencies are especially lovely <3.
-->
-
-This is a serious regression in nightly and it's important to fix it before the next release.
diff --git a/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/question.md b/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/question.md
deleted file mode 100644
index a90ade8..0000000
--- a/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/question.md
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: Support Question
-about: A question regarding functionality of rust-analyzer.
-title: ''
-labels: 'C-support'
-assignees: ''
-
----
diff --git a/src/tools/rust-analyzer/.github/workflows/metrics.yaml b/src/tools/rust-analyzer/.github/workflows/metrics.yaml
index a4146d6..dc2f432 100644
--- a/src/tools/rust-analyzer/.github/workflows/metrics.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/metrics.yaml
@@ -18,9 +18,9 @@
steps:
- name: Install Rust toolchain
run: |
- rustup update --no-self-update stable
- rustup default stable
- rustup component add --toolchain stable rust-src
+ rustup update --no-self-update beta
+ rustup default beta
+ rustup component add --toolchain beta rust-src
- name: Checkout repository
uses: actions/checkout@v4
@@ -61,9 +61,9 @@
steps:
- name: Install Rust toolchain
run: |
- rustup update --no-self-update stable
- rustup default stable
- rustup component add --toolchain stable rust-src
+ rustup update --no-self-update beta
+ rustup default beta
+ rustup component add --toolchain beta rust-src
- name: Checkout repository
uses: actions/checkout@v4
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 8d6c828..bd8146d 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -61,9 +61,9 @@
[[package]]
name = "backtrace"
-version = "0.3.74"
+version = "0.3.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
+checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
dependencies = [
"addr2line",
"cfg-if",
@@ -80,6 +80,7 @@
dependencies = [
"cfg",
"dashmap",
+ "indexmap",
"intern",
"la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"query-group-macro",
@@ -316,9 +317,9 @@
[[package]]
name = "ctrlc"
-version = "3.4.5"
+version = "3.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3"
+checksum = "46f93780a459b7d656ef7f071fe699c4d3d2cb201c4b24d085b6ddc505276e73"
dependencies = [
"nix",
"windows-sys 0.59.0",
@@ -472,9 +473,9 @@
[[package]]
name = "flate2"
-version = "1.1.0"
+version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc"
+checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
dependencies = [
"crc32fast",
"miniz_oxide",
@@ -1010,9 +1011,9 @@
[[package]]
name = "indexmap"
-version = "2.8.0"
+version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
+checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
dependencies = [
"equivalent",
"hashbrown 0.15.2",
@@ -1123,12 +1124,12 @@
[[package]]
name = "libloading"
-version = "0.8.6"
+version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
+checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c"
dependencies = [
"cfg-if",
- "windows-targets 0.52.6",
+ "windows-targets 0.53.0",
]
[[package]]
@@ -1358,9 +1359,9 @@
[[package]]
name = "nix"
-version = "0.29.0"
+version = "0.30.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
+checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
dependencies = [
"bitflags 2.9.0",
"cfg-if",
@@ -1640,14 +1641,14 @@
[[package]]
name = "process-wrap"
-version = "8.2.0"
+version = "8.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d35f4dc9988d1326b065b4def5e950c3ed727aa03e3151b86cc9e2aec6b03f54"
+checksum = "a3ef4f2f0422f23a82ec9f628ea2acd12871c81a9362b02c43c1aa86acfc3ba1"
dependencies = [
"indexmap",
"nix",
"tracing",
- "windows 0.59.0",
+ "windows 0.61.1",
]
[[package]]
@@ -1749,9 +1750,9 @@
[[package]]
name = "ra-ap-rustc_abi"
-version = "0.110.0"
+version = "0.113.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "912228bd8ed3beff1f6f9e5e2d4b37c0827ba3e2070060bf3858a311d0e29e30"
+checksum = "c33b8fa229789975647ca5426be432c7c327ebde89ab15889928185dbcee3230"
dependencies = [
"bitflags 2.9.0",
"ra-ap-rustc_hashes",
@@ -1761,18 +1762,18 @@
[[package]]
name = "ra-ap-rustc_hashes"
-version = "0.110.0"
+version = "0.113.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba520764daf057a9d963fa769f4762eaf87ac5d4900ae76195eeead64cd35afd"
+checksum = "0d68a3e389927002f552938a90b04787f6435f55b46fc5691360470d1cb2e99d"
dependencies = [
"rustc-stable-hash",
]
[[package]]
name = "ra-ap-rustc_index"
-version = "0.110.0"
+version = "0.113.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b76b5f9ee55f2d0e5a65bea23f6d738893349ce8d3d17a6720933e647ab04978"
+checksum = "32502273df2838d0ca13f1c67e2a48feef940e591f9771869f07e2db2acede53"
dependencies = [
"ra-ap-rustc_index_macros",
"smallvec",
@@ -1780,9 +1781,9 @@
[[package]]
name = "ra-ap-rustc_index_macros"
-version = "0.110.0"
+version = "0.113.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ddd972eb1face2fcaa0d94c01d97862fb955b5561d4f5932003bce8a6cadd8c6"
+checksum = "8a32f081864ae34c7ae6634edfa7a95ab9260ba85015e8b1d347580eda79d14f"
dependencies = [
"proc-macro2",
"quote",
@@ -1791,9 +1792,9 @@
[[package]]
name = "ra-ap-rustc_lexer"
-version = "0.110.0"
+version = "0.113.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba3a9876456fb2521097deef33ddeac1c18260c8eafb68054d986f8b9d6ce9fa"
+checksum = "ed34c51974718c5bd90d876d1364d9725159fc8030c2382b9cb837034152ed68"
dependencies = [
"memchr",
"unicode-properties",
@@ -1802,9 +1803,9 @@
[[package]]
name = "ra-ap-rustc_parse_format"
-version = "0.110.0"
+version = "0.113.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e85de58dfcc60a5f9d5ec0157a657e3f84abd8f22c8a0c4d707cfb42c9011f4"
+checksum = "ff0440e5d27facbf4ff13ea651e48c2f6e360b3dbfc56251b41d60719b965fb8"
dependencies = [
"ra-ap-rustc_lexer",
"rustc-literal-escaper",
@@ -1812,9 +1813,9 @@
[[package]]
name = "ra-ap-rustc_pattern_analysis"
-version = "0.110.0"
+version = "0.113.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ceadf9db550db67deff7eff2e2765109b860c9d7e5bdfca144863020289c823d"
+checksum = "a6056efa57aba3aa0cc69a0bf1a8281624c23ad25b05748d11ebcd4668037bfc"
dependencies = [
"ra-ap-rustc_index",
"rustc-hash 2.1.1",
@@ -2228,6 +2229,7 @@
dependencies = [
"backtrace",
"crossbeam-channel",
+ "crossbeam-utils",
"itertools 0.14.0",
"jod-thread",
"libc",
@@ -2750,12 +2752,24 @@
[[package]]
name = "windows"
-version = "0.59.0"
+version = "0.61.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f919aee0a93304be7f62e8e5027811bbba96bcb1de84d6618be56e43f8a32a1"
+checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419"
dependencies = [
- "windows-core 0.59.0",
- "windows-targets 0.53.0",
+ "windows-collections",
+ "windows-core 0.61.0",
+ "windows-future",
+ "windows-link",
+ "windows-numerics",
+]
+
+[[package]]
+name = "windows-collections"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8"
+dependencies = [
+ "windows-core 0.61.0",
]
[[package]]
@@ -2773,15 +2787,25 @@
[[package]]
name = "windows-core"
-version = "0.59.0"
+version = "0.61.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "810ce18ed2112484b0d4e15d022e5f598113e220c53e373fb31e67e21670c1ce"
+checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
dependencies = [
- "windows-implement 0.59.0",
- "windows-interface 0.59.0",
- "windows-result 0.3.1",
- "windows-strings 0.3.1",
- "windows-targets 0.53.0",
+ "windows-implement 0.60.0",
+ "windows-interface 0.59.1",
+ "windows-link",
+ "windows-result 0.3.2",
+ "windows-strings 0.4.0",
+]
+
+[[package]]
+name = "windows-future"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32"
+dependencies = [
+ "windows-core 0.61.0",
+ "windows-link",
]
[[package]]
@@ -2797,9 +2821,9 @@
[[package]]
name = "windows-implement"
-version = "0.59.0"
+version = "0.60.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1"
+checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
dependencies = [
"proc-macro2",
"quote",
@@ -2819,9 +2843,9 @@
[[package]]
name = "windows-interface"
-version = "0.59.0"
+version = "0.59.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb26fd936d991781ea39e87c3a27285081e3c0da5ca0fcbc02d368cc6f52ff01"
+checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
dependencies = [
"proc-macro2",
"quote",
@@ -2830,9 +2854,19 @@
[[package]]
name = "windows-link"
-version = "0.1.0"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3"
+checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
+
+[[package]]
+name = "windows-numerics"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
+dependencies = [
+ "windows-core 0.61.0",
+ "windows-link",
+]
[[package]]
name = "windows-result"
@@ -2845,9 +2879,9 @@
[[package]]
name = "windows-result"
-version = "0.3.1"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06374efe858fab7e4f881500e6e86ec8bc28f9462c47e5a9941a0142ad86b189"
+checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
dependencies = [
"windows-link",
]
@@ -2864,9 +2898,9 @@
[[package]]
name = "windows-strings"
-version = "0.3.1"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319"
+checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
dependencies = [
"windows-link",
]
@@ -3230,17 +3264,14 @@
[[package]]
name = "zip"
-version = "2.4.2"
+version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fabe6324e908f85a1c52063ce7aa26b68dcb7eb6dbc83a2d148403c9bc3eba50"
+checksum = "12598812502ed0105f607f941c386f43d441e00148fce9dec3ca5ffb0bde9308"
dependencies = [
"arbitrary",
"crc32fast",
- "crossbeam-utils",
- "displaydoc",
"flate2",
"indexmap",
"memchr",
- "thiserror 2.0.12",
"time",
]
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index c4c2fdf..07731ba 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -85,11 +85,11 @@
vfs = { path = "./crates/vfs", version = "0.0.0" }
edition = { path = "./crates/edition", version = "0.0.0" }
-ra-ap-rustc_lexer = { version = "0.110", default-features = false }
-ra-ap-rustc_parse_format = { version = "0.110", default-features = false }
-ra-ap-rustc_index = { version = "0.110", default-features = false }
-ra-ap-rustc_abi = { version = "0.110", default-features = false }
-ra-ap-rustc_pattern_analysis = { version = "0.110", default-features = false }
+ra-ap-rustc_lexer = { version = "0.113", default-features = false }
+ra-ap-rustc_parse_format = { version = "0.113", default-features = false }
+ra-ap-rustc_index = { version = "0.113", default-features = false }
+ra-ap-rustc_abi = { version = "0.113", default-features = false }
+ra-ap-rustc_pattern_analysis = { version = "0.113", default-features = false }
# local crates that aren't published to crates.io. These should not have versions.
@@ -132,7 +132,10 @@
pulldown-cmark = { version = "0.9.6", default-features = false }
rayon = "1.10.0"
rowan = "=0.15.15"
-salsa = { version = "0.21.1", default-features = false, features = ["rayon","salsa_unstable"] }
+salsa = { version = "0.21.1", default-features = false, features = [
+ "rayon",
+ "salsa_unstable",
+] }
salsa-macros = "0.21.1"
semver = "1.0.26"
serde = { version = "1.0.219" }
diff --git a/src/tools/rust-analyzer/crates/base-db/Cargo.toml b/src/tools/rust-analyzer/crates/base-db/Cargo.toml
index e2e3253..3b423a8 100644
--- a/src/tools/rust-analyzer/crates/base-db/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/base-db/Cargo.toml
@@ -21,6 +21,7 @@
triomphe.workspace = true
semver.workspace = true
tracing.workspace = true
+indexmap.workspace = true
# local deps
cfg.workspace = true
diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs
index 9660e6e..d42d7e5 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/input.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs
@@ -14,7 +14,7 @@
use dashmap::mapref::entry::Entry;
use intern::Symbol;
use la_arena::{Arena, Idx, RawIdx};
-use rustc_hash::{FxHashMap, FxHashSet, FxHasher};
+use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet, FxHasher};
use salsa::{Durability, Setter};
use span::Edition;
use triomphe::Arc;
@@ -24,6 +24,8 @@
pub type ProcMacroPaths = FxHashMap<CrateBuilderId, Result<(String, AbsPathBuf), String>>;
+type FxIndexSet<T> = indexmap::IndexSet<T, FxBuildHasher>;
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct SourceRootId(pub u32);
@@ -474,7 +476,9 @@ pub fn add_dep(
}
pub fn set_in_db(self, db: &mut dyn RootQueryDb) -> CratesIdMap {
- let mut all_crates = Vec::with_capacity(self.arena.len());
+ // For some reason in some repositories we have duplicate crates, so we use a set and not `Vec`.
+ // We use an `IndexSet` because the list needs to be topologically sorted.
+ let mut all_crates = FxIndexSet::with_capacity_and_hasher(self.arena.len(), FxBuildHasher);
let mut visited = FxHashMap::default();
let mut visited_root_files = FxHashSet::default();
@@ -494,9 +498,11 @@ pub fn set_in_db(self, db: &mut dyn RootQueryDb) -> CratesIdMap {
);
}
- if **old_all_crates != *all_crates {
+ if old_all_crates.len() != all_crates.len()
+ || old_all_crates.iter().any(|&krate| !all_crates.contains(&krate))
+ {
db.set_all_crates_with_durability(
- Arc::new(all_crates.into_boxed_slice()),
+ Arc::new(Vec::from_iter(all_crates).into_boxed_slice()),
Durability::MEDIUM,
);
}
@@ -509,7 +515,7 @@ fn go(
crates_map: &CratesMap,
visited: &mut FxHashMap<CrateBuilderId, Crate>,
visited_root_files: &mut FxHashSet<FileId>,
- all_crates: &mut Vec<Crate>,
+ all_crates: &mut FxIndexSet<Crate>,
source: CrateBuilderId,
) -> Crate {
if let Some(&crate_id) = visited.get(&source) {
@@ -597,7 +603,7 @@ fn go(
input
}
};
- all_crates.push(crate_input);
+ all_crates.insert(crate_input);
visited.insert(source, crate_input);
crate_input
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
index 2cbdbe1..4a9a3b1 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
@@ -24,8 +24,8 @@
item_tree::{AttrOwner, ItemTree},
lang_item::{self, LangItem},
nameres::{
- DefMap, LocalDefMap,
assoc::{ImplItems, TraitItems},
+ crate_def_map,
diagnostics::DefDiagnostics,
},
signatures::{
@@ -111,16 +111,6 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase {
#[salsa::invoke(ItemTree::block_item_tree_query)]
fn block_item_tree(&self, block_id: BlockId) -> Arc<ItemTree>;
- #[salsa::invoke(DefMap::crate_local_def_map_query)]
- fn crate_local_def_map(&self, krate: Crate) -> (Arc<DefMap>, Arc<LocalDefMap>);
-
- #[salsa::invoke(DefMap::crate_def_map_query)]
- fn crate_def_map(&self, krate: Crate) -> Arc<DefMap>;
-
- /// Computes the block-level `DefMap`.
- #[salsa::invoke(DefMap::block_def_map_query)]
- fn block_def_map(&self, block: BlockId) -> Arc<DefMap>;
-
/// Turns a MacroId into a MacroDefId, describing the macro's definition post name resolution.
#[salsa::invoke(macro_def)]
fn macro_def(&self, m: MacroId) -> MacroDefId;
@@ -363,7 +353,7 @@ fn include_macro_invoc(
db: &dyn DefDatabase,
krate: Crate,
) -> Arc<[(MacroCallId, EditionedFileId)]> {
- db.crate_def_map(krate)
+ crate_def_map(db, krate)
.modules
.values()
.flat_map(|m| m.scope.iter_macro_invoc())
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
index e3775c4..f617c32 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
@@ -19,7 +19,6 @@
use smallvec::SmallVec;
use span::{Edition, SyntaxContext};
use syntax::{AstPtr, SyntaxNodePtr, ast};
-use triomphe::Arc;
use tt::TextRange;
use crate::{
@@ -30,7 +29,7 @@
Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, Label, LabelId, Pat,
PatId, RecordFieldPat, Statement,
},
- nameres::DefMap,
+ nameres::{DefMap, block_def_map},
type_ref::{LifetimeRef, LifetimeRefId, PathId, TypeRef, TypeRefId},
};
@@ -225,8 +224,8 @@ impl ExpressionStore {
pub fn blocks<'a>(
&'a self,
db: &'a dyn DefDatabase,
- ) -> impl Iterator<Item = (BlockId, Arc<DefMap>)> + 'a {
- self.block_scopes.iter().map(move |&block| (block, db.block_def_map(block)))
+ ) -> impl Iterator<Item = (BlockId, &'a DefMap)> + 'a {
+ self.block_scopes.iter().map(move |&block| (block, block_def_map(db, block)))
}
pub fn walk_bindings_in_pat(&self, pat_id: PatId, mut f: impl FnMut(BindingId)) {
@@ -299,17 +298,16 @@ pub fn walk_child_exprs(&self, expr_id: ExprId, mut f: impl FnMut(ExprId)) {
Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op {
AsmOperand::In { expr, .. }
| AsmOperand::Out { expr: Some(expr), .. }
- | AsmOperand::InOut { expr, .. } => f(*expr),
+ | AsmOperand::InOut { expr, .. }
+ | AsmOperand::Const(expr)
+ | AsmOperand::Label(expr) => f(*expr),
AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
f(*in_expr);
if let Some(out_expr) = out_expr {
f(*out_expr);
}
}
- AsmOperand::Out { expr: None, .. }
- | AsmOperand::Const(_)
- | AsmOperand::Label(_)
- | AsmOperand::Sym(_) => (),
+ AsmOperand::Out { expr: None, .. } | AsmOperand::Sym(_) => (),
}),
Expr::If { condition, then_branch, else_branch } => {
f(*condition);
@@ -436,17 +434,16 @@ pub fn walk_child_exprs_without_pats(&self, expr_id: ExprId, mut f: impl FnMut(E
Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op {
AsmOperand::In { expr, .. }
| AsmOperand::Out { expr: Some(expr), .. }
- | AsmOperand::InOut { expr, .. } => f(*expr),
+ | AsmOperand::InOut { expr, .. }
+ | AsmOperand::Const(expr)
+ | AsmOperand::Label(expr) => f(*expr),
AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
f(*in_expr);
if let Some(out_expr) = out_expr {
f(*out_expr);
}
}
- AsmOperand::Out { expr: None, .. }
- | AsmOperand::Const(_)
- | AsmOperand::Label(_)
- | AsmOperand::Sym(_) => (),
+ AsmOperand::Out { expr: None, .. } | AsmOperand::Sym(_) => (),
}),
Expr::If { condition, then_branch, else_branch } => {
f(*condition);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
index 50505d5..29871f5 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
@@ -56,7 +56,7 @@
item_scope::BuiltinShadowMode,
item_tree::FieldsShape,
lang_item::LangItem,
- nameres::{DefMap, LocalDefMap, MacroSubNs},
+ nameres::{DefMap, LocalDefMap, MacroSubNs, block_def_map},
type_ref::{
ArrayType, ConstRef, FnType, LifetimeRef, LifetimeRefId, Mutability, PathId, Rawness,
RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId, UseArgRef,
@@ -436,8 +436,8 @@ pub struct ExprCollector<'db> {
db: &'db dyn DefDatabase,
cfg_options: &'db CfgOptions,
expander: Expander,
- def_map: Arc<DefMap>,
- local_def_map: Arc<LocalDefMap>,
+ def_map: &'db DefMap,
+ local_def_map: &'db LocalDefMap,
module: ModuleId,
pub store: ExpressionStoreBuilder,
pub(crate) source_map: ExpressionStoreSourceMap,
@@ -544,7 +544,7 @@ pub fn new(
current_file_id: HirFileId,
) -> ExprCollector<'_> {
let (def_map, local_def_map) = module.local_def_map(db);
- let expander = Expander::new(db, current_file_id, &def_map);
+ let expander = Expander::new(db, current_file_id, def_map);
ExprCollector {
db,
cfg_options: module.krate().cfg_options(db),
@@ -1947,7 +1947,7 @@ fn collect_macro_call<T, U>(
let resolver = |path: &_| {
self.def_map
.resolve_path(
- &self.local_def_map,
+ self.local_def_map,
self.db,
module,
path,
@@ -2163,12 +2163,12 @@ fn collect_block_(
};
let (module, def_map) =
- match block_id.map(|block_id| (self.db.block_def_map(block_id), block_id)) {
+ match block_id.map(|block_id| (block_def_map(self.db, block_id), block_id)) {
Some((def_map, block_id)) => {
self.store.block_scopes.push(block_id);
(def_map.module_id(DefMap::ROOT), def_map)
}
- None => (self.module, self.def_map.clone()),
+ None => (self.module, self.def_map),
};
let prev_def_map = mem::replace(&mut self.def_map, def_map);
let prev_local_module = mem::replace(&mut self.module, module);
@@ -2247,7 +2247,7 @@ fn collect_pat(&mut self, pat: ast::Pat, binding_list: &mut BindingList) -> PatI
// This could also be a single-segment path pattern. To
// decide that, we need to try resolving the name.
let (resolved, _) = self.def_map.resolve_path(
- &self.local_def_map,
+ self.local_def_map,
self.db,
self.module.local_id,
&name.clone().into(),
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path.rs
index 629d1f2..be006c9 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path.rs
@@ -232,6 +232,14 @@ pub(super) fn lower_path(
.with_borrow_mut(|map| map.extend(ast_segments.into_iter().zip(ast_segments_offset..)));
}
+ if let Some(last_segment_args @ Some(GenericArgs { has_self_type: true, .. })) =
+ generic_args.last_mut()
+ {
+ // Well-formed code cannot have `<T as Trait>` without an associated item after,
+ // and this causes panics in hir-ty lowering.
+ *last_segment_args = None;
+ }
+
let mod_path = Interned::new(ModPath::from_segments(kind, segments));
if type_anchor.is_none() && generic_args.is_empty() {
return Some(Path::BarePath(mod_path));
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path/tests.rs
index 337cb10..8fd81c7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path/tests.rs
@@ -4,7 +4,6 @@
use test_fixture::WithFixture;
use crate::{
- db::DefDatabase,
expr_store::{
ExpressionStore,
lower::{
@@ -14,13 +13,15 @@
path::Path,
pretty,
},
+ nameres::crate_def_map,
test_db::TestDB,
};
fn lower_path(path: ast::Path) -> (TestDB, ExpressionStore, Option<Path>) {
let (db, file_id) = TestDB::with_single_file("");
let krate = db.fetch_test_crate();
- let mut ctx = ExprCollector::new(&db, db.crate_def_map(krate).root_module_id(), file_id.into());
+ let mut ctx =
+ ExprCollector::new(&db, crate_def_map(&db, krate).root_module_id(), file_id.into());
let lowered_path = ctx.lower_path(path, &mut ExprCollector::impl_trait_allocator);
let store = ctx.store.finish();
(db, store, lowered_path)
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs
index 431ea9e..a46711c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs
@@ -324,11 +324,13 @@ mod tests {
use test_fixture::WithFixture;
use test_utils::{assert_eq_text, extract_offset};
- use crate::{FunctionId, ModuleDefId, db::DefDatabase, test_db::TestDB};
+ use crate::{
+ FunctionId, ModuleDefId, db::DefDatabase, nameres::crate_def_map, test_db::TestDB,
+ };
fn find_function(db: &TestDB, file_id: FileId) -> FunctionId {
let krate = db.test_crate();
- let crate_def_map = db.crate_def_map(krate);
+ let crate_def_map = crate_def_map(db, krate);
let module = crate_def_map.modules_for_file(db, file_id).next().unwrap();
let (_, def) = crate_def_map[module].scope.entries().next().unwrap();
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs
index d6645dc..29e249b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs
@@ -1,9 +1,10 @@
mod block;
-use crate::{DefWithBodyId, ModuleDefId, hir::MatchArm, test_db::TestDB};
+use crate::{DefWithBodyId, ModuleDefId, hir::MatchArm, nameres::crate_def_map, test_db::TestDB};
use expect_test::{Expect, expect};
use la_arena::RawIdx;
use test_fixture::WithFixture;
+use triomphe::Arc;
use super::super::*;
@@ -11,7 +12,7 @@ fn lower(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (TestDB, Arc<Body>,
let db = TestDB::with_files(ra_fixture);
let krate = db.fetch_test_crate();
- let def_map = db.crate_def_map(krate);
+ let def_map = crate_def_map(&db, krate);
let mut fn_def = None;
'outer: for (_, module) in def_map.modules() {
for decl in module.scope.declarations() {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs
index da3b65d..5f7b510 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs
@@ -189,8 +189,8 @@ fn f() {
}
"#,
expect![[r#"
- BlockId(3801) in BlockRelativeModuleId { block: Some(BlockId(3800)), local_id: Idx::<ModuleData>(1) }
- BlockId(3800) in BlockRelativeModuleId { block: None, local_id: Idx::<ModuleData>(0) }
+ BlockId(3c01) in BlockRelativeModuleId { block: Some(BlockId(3c00)), local_id: Idx::<ModuleData>(1) }
+ BlockId(3c00) in BlockRelativeModuleId { block: None, local_id: Idx::<ModuleData>(0) }
crate scope
"#]],
);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/signatures.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/signatures.rs
index 80561d6..efb558a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/signatures.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/signatures.rs
@@ -1,6 +1,7 @@
use crate::{
GenericDefId, ModuleDefId,
expr_store::pretty::{print_function, print_struct},
+ nameres::crate_def_map,
test_db::TestDB,
};
use expect_test::{Expect, expect};
@@ -12,7 +13,7 @@ fn lower_and_print(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expe
let db = TestDB::with_files(ra_fixture);
let krate = db.fetch_test_crate();
- let def_map = db.crate_def_map(krate);
+ let def_map = crate_def_map(&db, krate);
let mut defs = vec![];
for (_, module) in def_map.modules() {
for decl in module.scope.declarations() {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
index 9d62d9c..bb75621 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
@@ -52,7 +52,7 @@ pub fn find_path(
ignore_local_imports,
is_std_item: item_module.krate().data(db).origin.is_lang(),
from,
- from_def_map: &from.def_map(db),
+ from_def_map: from.def_map(db),
fuel: Cell::new(FIND_PATH_FUEL),
},
item,
@@ -691,7 +691,7 @@ fn check_found_path_(
let (def_map, local_def_map) = module.local_def_map(&db);
let resolved = def_map
.resolve_path(
- &local_def_map,
+ local_def_map,
&db,
module.local_id,
&mod_path,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs
index f27a406..271484d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs
@@ -297,7 +297,8 @@ enum ArgRef<'a> {
unfinished_literal.clear();
}
- let span = parser.arg_places.get(placeholder_index).and_then(|s| to_span(s.clone()));
+ let span =
+ parser.arg_places.get(placeholder_index).and_then(|s| to_span(s.clone()));
placeholder_index += 1;
let position_span = to_span(position_span);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
index db571f0..a6138fb 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
@@ -16,7 +16,7 @@
AssocItemId, AttrDefId, Complete, FxIndexMap, ModuleDefId, ModuleId, TraitId,
db::DefDatabase,
item_scope::{ImportOrExternCrate, ItemInNs},
- nameres::DefMap,
+ nameres::{DefMap, crate_def_map},
visibility::Visibility,
};
@@ -129,7 +129,7 @@ pub fn import_info_for(&self, item: ItemInNs) -> Option<&[ImportInfo]> {
fn collect_import_map(db: &dyn DefDatabase, krate: Crate) -> ImportMapIndex {
let _p = tracing::info_span!("collect_import_map").entered();
- let def_map = db.crate_def_map(krate);
+ let def_map = crate_def_map(db, krate);
let mut map = FxIndexMap::default();
// We look only into modules that are public(ly reexported), starting with the crate root.
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
index 51a833b..5934464 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
@@ -10,6 +10,7 @@
use crate::{
AdtId, AssocItemId, AttrDefId, Crate, EnumId, EnumVariantId, FunctionId, ImplId, ModuleDefId,
StaticId, StructId, TraitId, TypeAliasId, UnionId, db::DefDatabase, expr_store::path::Path,
+ nameres::crate_def_map,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -90,7 +91,7 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option<Box<LangIt
let mut lang_items = LangItems::default();
- let crate_def_map = db.crate_def_map(krate);
+ let crate_def_map = crate_def_map(db, krate);
for (_, module_data) in crate_def_map.modules() {
for impl_def in module_data.scope.impls() {
@@ -209,7 +210,7 @@ pub(crate) fn crate_notable_traits(db: &dyn DefDatabase, krate: Crate) -> Option
let mut traits = Vec::new();
- let crate_def_map = db.crate_def_map(krate);
+ let crate_def_map = crate_def_map(db, krate);
for (_, module_data) in crate_def_map.modules() {
for def in module_data.scope.declarations() {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
index 28011bd..b41ff02 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -92,7 +92,7 @@
Const, Enum, ExternCrate, Function, Impl, ItemTreeId, ItemTreeNode, Macro2, MacroRules,
Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use, Variant,
},
- nameres::LocalDefMap,
+ nameres::{LocalDefMap, block_def_map, crate_def_map, crate_local_def_map},
signatures::VariantFields,
};
@@ -324,12 +324,13 @@ pub struct CrateRootModuleId {
}
impl CrateRootModuleId {
- pub fn def_map(&self, db: &dyn DefDatabase) -> Arc<DefMap> {
- db.crate_def_map(self.krate)
+ pub fn def_map(self, db: &dyn DefDatabase) -> &DefMap {
+ crate_def_map(db, self.krate)
}
- pub(crate) fn local_def_map(&self, db: &dyn DefDatabase) -> (Arc<DefMap>, Arc<LocalDefMap>) {
- db.crate_local_def_map(self.krate)
+ pub(crate) fn local_def_map(self, db: &dyn DefDatabase) -> (&DefMap, &LocalDefMap) {
+ let def_map = crate_local_def_map(db, self.krate);
+ (def_map.def_map(db), def_map.local(db))
}
pub fn krate(self) -> Crate {
@@ -390,26 +391,29 @@ pub struct ModuleId {
}
impl ModuleId {
- pub fn def_map(self, db: &dyn DefDatabase) -> Arc<DefMap> {
+ pub fn def_map(self, db: &dyn DefDatabase) -> &DefMap {
match self.block {
- Some(block) => db.block_def_map(block),
- None => db.crate_def_map(self.krate),
+ Some(block) => block_def_map(db, block),
+ None => crate_def_map(db, self.krate),
}
}
- pub(crate) fn local_def_map(self, db: &dyn DefDatabase) -> (Arc<DefMap>, Arc<LocalDefMap>) {
+ pub(crate) fn local_def_map(self, db: &dyn DefDatabase) -> (&DefMap, &LocalDefMap) {
match self.block {
- Some(block) => (db.block_def_map(block), self.only_local_def_map(db)),
- None => db.crate_local_def_map(self.krate),
+ Some(block) => (block_def_map(db, block), self.only_local_def_map(db)),
+ None => {
+ let def_map = crate_local_def_map(db, self.krate);
+ (def_map.def_map(db), def_map.local(db))
+ }
}
}
- pub(crate) fn only_local_def_map(self, db: &dyn DefDatabase) -> Arc<LocalDefMap> {
- db.crate_local_def_map(self.krate).1
+ pub(crate) fn only_local_def_map(self, db: &dyn DefDatabase) -> &LocalDefMap {
+ crate_local_def_map(db, self.krate).local(db)
}
- pub fn crate_def_map(self, db: &dyn DefDatabase) -> Arc<DefMap> {
- db.crate_def_map(self.krate)
+ pub fn crate_def_map(self, db: &dyn DefDatabase) -> &DefMap {
+ crate_def_map(db, self.krate)
}
pub fn krate(self) -> Crate {
@@ -701,6 +705,16 @@ pub enum AssocItemId {
// casting them, and somehow making the constructors private, which would be annoying.
impl_from!(FunctionId, ConstId, TypeAliasId for AssocItemId);
+impl From<AssocItemId> for ModuleDefId {
+ fn from(item: AssocItemId) -> Self {
+ match item {
+ AssocItemId::FunctionId(f) => f.into(),
+ AssocItemId::ConstId(c) => c.into(),
+ AssocItemId::TypeAliasId(t) => t.into(),
+ }
+ }
+}
+
#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)]
pub enum GenericDefId {
AdtId(AdtId),
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
index e21d141..3027aff 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
@@ -454,13 +454,13 @@ fn test_concat_expand() {
#[rustc_builtin_macro]
macro_rules! concat {}
-fn main() { concat!("fo", "o", 0, r#""bar""#, "\n", false, '"', '\0'); }
+fn main() { concat!("fo", "o", 0, r#""bar""#, "\n", false, '"', -4, - 4, '\0'); }
"##,
expect![[r##"
#[rustc_builtin_macro]
macro_rules! concat {}
-fn main() { "foo0\"bar\"\nfalse\"\u{0}"; }
+fn main() { "foo0\"bar\"\nfalse\"-4-4\u{0}"; }
"##]],
);
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
index 800c96e..dc4334e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
@@ -39,7 +39,7 @@
use crate::{
AdtId, Lookup, ModuleDefId,
db::DefDatabase,
- nameres::{DefMap, ModuleSource},
+ nameres::{DefMap, ModuleSource, crate_def_map},
src::HasSource,
test_db::TestDB,
tt::TopSubtree,
@@ -49,7 +49,7 @@
fn check_errors(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
let db = TestDB::with_files(ra_fixture);
let krate = db.fetch_test_crate();
- let def_map = db.crate_def_map(krate);
+ let def_map = crate_def_map(&db, krate);
let errors = def_map
.modules()
.flat_map(|module| module.1.scope.all_macro_calls())
@@ -113,7 +113,7 @@ fn resolve(
let (body, sm) = db.body_with_source_map(body);
if let Some(it) =
- body.blocks(db).find_map(|block| resolve(db, &block.1, ast_id, ast_ptr))
+ body.blocks(db).find_map(|block| resolve(db, block.1, ast_id, ast_ptr))
{
return Some(it);
}
@@ -127,7 +127,7 @@ fn resolve(
let db = TestDB::with_files_extra_proc_macros(ra_fixture, extra_proc_macros);
let krate = db.fetch_test_crate();
- let def_map = db.crate_def_map(krate);
+ let def_map = crate_def_map(&db, krate);
let local_id = DefMap::ROOT;
let source = def_map[local_id].definition_source(&db);
let source_file = match source.value {
@@ -142,7 +142,7 @@ fn resolve(
let ast_id = db.ast_id_map(source.file_id).ast_id(¯o_call_node);
let ast_id = InFile::new(source.file_id, ast_id);
let ptr = InFile::new(source.file_id, AstPtr::new(¯o_call_node));
- let macro_call_id = resolve(&db, &def_map, ast_id, ptr)
+ let macro_call_id = resolve(&db, def_map, ast_id, ptr)
.unwrap_or_else(|| panic!("unable to find semantic macro call {macro_call_node}"));
let expansion_result = db.parse_macro_expansion(macro_call_id);
expansions.push((macro_call_node.clone(), expansion_result));
@@ -380,8 +380,4 @@ fn expand(
panic!("got invalid macro input: {:?}", parse.errors());
}
}
-
- fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
- other.as_any().type_id() == std::any::TypeId::of::<Self>()
- }
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
index fc66d8e..d4b30a1 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
@@ -112,6 +112,18 @@ pub struct LocalDefMap {
extern_prelude: FxIndexMap<Name, (CrateRootModuleId, Option<ExternCrateId>)>,
}
+impl std::hash::Hash for LocalDefMap {
+ fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+ let LocalDefMap { extern_prelude } = self;
+ extern_prelude.len().hash(state);
+ for (name, (crate_root, extern_crate)) in extern_prelude {
+ name.hash(state);
+ crate_root.hash(state);
+ extern_crate.hash(state);
+ }
+ }
+}
+
impl LocalDefMap {
pub(crate) const EMPTY: &Self =
&Self { extern_prelude: FxIndexMap::with_hasher(rustc_hash::FxBuildHasher) };
@@ -250,7 +262,7 @@ struct BlockRelativeModuleId {
}
impl BlockRelativeModuleId {
- fn def_map(self, db: &dyn DefDatabase, krate: Crate) -> Arc<DefMap> {
+ fn def_map(self, db: &dyn DefDatabase, krate: Crate) -> &DefMap {
self.into_module(krate).def_map(db)
}
@@ -358,6 +370,87 @@ pub struct ModuleData {
pub scope: ItemScope,
}
+#[inline]
+pub fn crate_def_map(db: &dyn DefDatabase, crate_id: Crate) -> &DefMap {
+ crate_local_def_map(db, crate_id).def_map(db)
+}
+
+#[allow(unused_lifetimes)]
+mod __ {
+ use super::*;
+ #[salsa_macros::tracked]
+ pub(crate) struct DefMapPair<'db> {
+ #[tracked]
+ #[return_ref]
+ pub(crate) def_map: DefMap,
+ #[return_ref]
+ pub(crate) local: LocalDefMap,
+ }
+}
+pub(crate) use __::DefMapPair;
+
+#[salsa_macros::tracked(return_ref)]
+pub(crate) fn crate_local_def_map(db: &dyn DefDatabase, crate_id: Crate) -> DefMapPair<'_> {
+ let krate = crate_id.data(db);
+ let _p = tracing::info_span!(
+ "crate_def_map_query",
+ name=?crate_id
+ .extra_data(db)
+ .display_name
+ .as_ref()
+ .map(|it| it.crate_name().to_smolstr())
+ .unwrap_or_default()
+ )
+ .entered();
+
+ let module_data = ModuleData::new(
+ ModuleOrigin::CrateRoot { definition: krate.root_file_id(db) },
+ Visibility::Public,
+ );
+
+ let def_map =
+ DefMap::empty(crate_id, Arc::new(DefMapCrateData::new(krate.edition)), module_data, None);
+ let (def_map, local_def_map) = collector::collect_defs(
+ db,
+ def_map,
+ TreeId::new(krate.root_file_id(db).into(), None),
+ None,
+ );
+
+ DefMapPair::new(db, def_map, local_def_map)
+}
+
+#[salsa_macros::tracked(return_ref)]
+pub fn block_def_map(db: &dyn DefDatabase, block_id: BlockId) -> DefMap {
+ let BlockLoc { ast_id, module } = block_id.lookup(db);
+
+ let visibility = Visibility::Module(
+ ModuleId { krate: module.krate, local_id: DefMap::ROOT, block: module.block },
+ VisibilityExplicitness::Implicit,
+ );
+ let module_data =
+ ModuleData::new(ModuleOrigin::BlockExpr { block: ast_id, id: block_id }, visibility);
+
+ let local_def_map = crate_local_def_map(db, module.krate);
+ let def_map = DefMap::empty(
+ module.krate,
+ local_def_map.def_map(db).data.clone(),
+ module_data,
+ Some(BlockInfo {
+ block: block_id,
+ parent: BlockRelativeModuleId { block: module.block, local_id: module.local_id },
+ }),
+ );
+
+ let (def_map, _) = collector::collect_defs(
+ db,
+ def_map,
+ TreeId::new(ast_id.file_id, Some(block_id)),
+ Some(local_def_map.local(db)),
+ );
+ def_map
+}
+
impl DefMap {
/// The module id of a crate or block root.
pub const ROOT: LocalModuleId = LocalModuleId::from_raw(la_arena::RawIdx::from_u32(0));
@@ -366,77 +459,6 @@ pub fn edition(&self) -> Edition {
self.data.edition
}
- pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, crate_id: Crate) -> Arc<DefMap> {
- db.crate_local_def_map(crate_id).0
- }
-
- pub(crate) fn crate_local_def_map_query(
- db: &dyn DefDatabase,
- crate_id: Crate,
- ) -> (Arc<DefMap>, Arc<LocalDefMap>) {
- let krate = crate_id.data(db);
- let _p = tracing::info_span!(
- "crate_def_map_query",
- name=?crate_id
- .extra_data(db)
- .display_name
- .as_ref()
- .map(|it| it.crate_name().to_smolstr())
- .unwrap_or_default()
- )
- .entered();
-
- let module_data = ModuleData::new(
- ModuleOrigin::CrateRoot { definition: krate.root_file_id(db) },
- Visibility::Public,
- );
-
- let def_map = DefMap::empty(
- crate_id,
- Arc::new(DefMapCrateData::new(krate.edition)),
- module_data,
- None,
- );
- let (def_map, local_def_map) = collector::collect_defs(
- db,
- def_map,
- TreeId::new(krate.root_file_id(db).into(), None),
- None,
- );
-
- (Arc::new(def_map), Arc::new(local_def_map))
- }
-
- pub(crate) fn block_def_map_query(db: &dyn DefDatabase, block_id: BlockId) -> Arc<DefMap> {
- let BlockLoc { ast_id, module } = block_id.lookup(db);
-
- let visibility = Visibility::Module(
- ModuleId { krate: module.krate, local_id: Self::ROOT, block: module.block },
- VisibilityExplicitness::Implicit,
- );
- let module_data =
- ModuleData::new(ModuleOrigin::BlockExpr { block: ast_id, id: block_id }, visibility);
-
- let (crate_map, crate_local_map) = db.crate_local_def_map(module.krate);
- let def_map = DefMap::empty(
- module.krate,
- crate_map.data.clone(),
- module_data,
- Some(BlockInfo {
- block: block_id,
- parent: BlockRelativeModuleId { block: module.block, local_id: module.local_id },
- }),
- );
-
- let (def_map, _) = collector::collect_defs(
- db,
- def_map,
- TreeId::new(ast_id.file_id, Some(block_id)),
- Some(crate_local_map),
- );
- Arc::new(def_map)
- }
-
fn empty(
krate: Crate,
crate_data: Arc<DefMapCrateData>,
@@ -595,7 +617,7 @@ pub fn dump(&self, db: &dyn DefDatabase) -> String {
go(&mut buf, db, current_map, "block scope", Self::ROOT);
buf.push('\n');
arc = block.parent.def_map(db, self.krate);
- current_map = &arc;
+ current_map = arc;
}
go(&mut buf, db, current_map, "crate", Self::ROOT);
return buf;
@@ -628,7 +650,7 @@ pub fn dump_block_scopes(&self, db: &dyn DefDatabase) -> String {
while let Some(block) = current_map.block {
format_to!(buf, "{:?} in {:?}\n", block.block, block.parent);
arc = block.parent.def_map(db, self.krate);
- current_map = &arc;
+ current_map = arc;
}
format_to!(buf, "crate scope\n");
@@ -708,7 +730,7 @@ pub(crate) fn with_ancestor_maps<T>(
let mut block = self.block;
while let Some(block_info) = block {
let parent = block_info.parent.def_map(db, self.krate);
- if let Some(it) = f(&parent, block_info.parent.local_id) {
+ if let Some(it) = f(parent, block_info.parent.local_id) {
return Some(it);
}
block = parent.block;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs
index 448b908..d45709b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs
@@ -66,6 +66,15 @@ pub fn method_by_name(&self, name: &Name) -> Option<FunctionId> {
})
}
+ pub fn assoc_item_by_name(&self, name: &Name) -> Option<AssocItemId> {
+ self.items.iter().find_map(|&(ref item_name, item)| match item {
+ AssocItemId::FunctionId(_) if item_name == name => Some(item),
+ AssocItemId::TypeAliasId(_) if item_name == name => Some(item),
+ AssocItemId::ConstId(_) if item_name == name => Some(item),
+ _ => None,
+ })
+ }
+
pub fn attribute_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
self.macro_calls.iter().flat_map(|it| it.iter()).copied()
}
@@ -108,8 +117,8 @@ pub fn attribute_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCa
struct AssocItemCollector<'a> {
db: &'a dyn DefDatabase,
module_id: ModuleId,
- def_map: Arc<DefMap>,
- local_def_map: Arc<LocalDefMap>,
+ def_map: &'a DefMap,
+ local_def_map: &'a LocalDefMap,
diagnostics: Vec<DefDiagnostic>,
container: ItemContainerId,
@@ -174,7 +183,7 @@ fn collect_item(&mut self, item_tree: &ItemTree, tree_id: TreeId, item: AssocIte
let ast_id_with_path = AstIdWithPath { path: attr.path.clone(), ast_id };
match self.def_map.resolve_attr_macro(
- &self.local_def_map,
+ self.local_def_map,
self.db,
self.module_id.local_id,
ast_id_with_path,
@@ -246,7 +255,7 @@ fn record_item(&mut self, item_tree: &ItemTree, tree_id: TreeId, item: AssocItem
let resolver = |path: &_| {
self.def_map
.resolve_path(
- &self.local_def_map,
+ self.local_def_map,
self.db,
self.module_id.local_id,
path,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
index 8df0f09..350c97c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
@@ -26,7 +26,7 @@
use triomphe::Arc;
use crate::{
- AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, ExternBlockLoc,
+ AdtId, AssocItemId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, ExternBlockLoc,
ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, ImplLoc, Intern, ItemContainerId,
LocalModuleId, Lookup, Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId,
MacroRulesLoc, MacroRulesLocFlags, ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc,
@@ -43,9 +43,10 @@
nameres::{
BuiltinShadowMode, DefMap, LocalDefMap, MacroSubNs, ModuleData, ModuleOrigin, ResolveMode,
attr_resolution::{attr_macro_as_call_id, derive_macro_as_call_id},
+ crate_def_map,
diagnostics::DefDiagnostic,
mod_resolution::ModDir,
- path_resolution::ReachedFixedPoint,
+ path_resolution::{ReachedFixedPoint, ResolvePathResult},
proc_macro::{ProcMacroDef, ProcMacroKind, parse_macro_name_and_helper_attrs},
sub_namespace_match,
},
@@ -61,7 +62,7 @@ pub(super) fn collect_defs(
db: &dyn DefDatabase,
def_map: DefMap,
tree_id: TreeId,
- crate_local_def_map: Option<Arc<LocalDefMap>>,
+ crate_local_def_map: Option<&LocalDefMap>,
) -> (DefMap, LocalDefMap) {
let krate = &def_map.krate.data(db);
let cfg_options = def_map.krate.cfg_options(db);
@@ -216,7 +217,7 @@ struct DefCollector<'a> {
def_map: DefMap,
local_def_map: LocalDefMap,
/// Set only in case of blocks.
- crate_local_def_map: Option<Arc<LocalDefMap>>,
+ crate_local_def_map: Option<&'a LocalDefMap>,
// The dependencies of the current crate, including optional deps like `test`.
deps: FxHashMap<Name, BuiltDependency>,
glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility, GlobId)>>,
@@ -533,7 +534,7 @@ fn inject_prelude(&mut self) {
);
let (per_ns, _) = self.def_map.resolve_path(
- self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map),
+ self.crate_local_def_map.unwrap_or(&self.local_def_map),
self.db,
DefMap::ROOT,
&path,
@@ -556,7 +557,7 @@ fn inject_prelude(&mut self) {
}
fn local_def_map(&mut self) -> &LocalDefMap {
- self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map)
+ self.crate_local_def_map.unwrap_or(&self.local_def_map)
}
/// Adds a definition of procedural macro `name` to the root module.
@@ -688,7 +689,7 @@ fn define_macro_def(
let vis = self
.def_map
.resolve_visibility(
- self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map),
+ self.crate_local_def_map.unwrap_or(&self.local_def_map),
self.db,
module_id,
vis,
@@ -731,7 +732,7 @@ fn import_macros_from_extern_crate(
names: Option<Vec<Name>>,
extern_crate: Option<ExternCrateId>,
) {
- let def_map = self.db.crate_def_map(krate);
+ let def_map = crate_def_map(self.db, krate);
// `#[macro_use]` brings macros into macro_use prelude. Yes, even non-`macro_rules!`
// macros.
let root_scope = &def_map[DefMap::ROOT].scope;
@@ -811,32 +812,35 @@ fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialRe
let _p = tracing::info_span!("resolve_import", import_path = %import.path.display(self.db, Edition::LATEST))
.entered();
tracing::debug!("resolving import: {:?} ({:?})", import, self.def_map.data.edition);
- let res = self.def_map.resolve_path_fp_with_macro(
- self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map),
- self.db,
- ResolveMode::Import,
- module_id,
- &import.path,
- BuiltinShadowMode::Module,
- None, // An import may resolve to any kind of macro.
- );
+ let ResolvePathResult { resolved_def, segment_index, reached_fixedpoint, prefix_info } =
+ self.def_map.resolve_path_fp_with_macro(
+ self.crate_local_def_map.unwrap_or(&self.local_def_map),
+ self.db,
+ ResolveMode::Import,
+ module_id,
+ &import.path,
+ BuiltinShadowMode::Module,
+ None, // An import may resolve to any kind of macro.
+ );
- let def = res.resolved_def;
- if res.reached_fixedpoint == ReachedFixedPoint::No || def.is_none() {
+ if reached_fixedpoint == ReachedFixedPoint::No
+ || resolved_def.is_none()
+ || segment_index.is_some()
+ {
return PartialResolvedImport::Unresolved;
}
- if res.prefix_info.differing_crate {
+ if prefix_info.differing_crate {
return PartialResolvedImport::Resolved(
- def.filter_visibility(|v| matches!(v, Visibility::Public)),
+ resolved_def.filter_visibility(|v| matches!(v, Visibility::Public)),
);
}
// Check whether all namespaces are resolved.
- if def.is_full() {
- PartialResolvedImport::Resolved(def)
+ if resolved_def.is_full() {
+ PartialResolvedImport::Resolved(resolved_def)
} else {
- PartialResolvedImport::Indeterminate(def)
+ PartialResolvedImport::Indeterminate(resolved_def)
}
}
@@ -849,7 +853,7 @@ fn record_resolved_import(&mut self, directive: &ImportDirective) {
let vis = self
.def_map
.resolve_visibility(
- self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map),
+ self.crate_local_def_map.unwrap_or(&self.local_def_map),
self.db,
module_id,
&directive.import.visibility,
@@ -986,6 +990,43 @@ fn record_resolved_import(&mut self, directive: &ImportDirective) {
Some(ImportOrExternCrate::Glob(glob)),
);
}
+ Some(ModuleDefId::TraitId(it)) => {
+ // FIXME: Implement this correctly
+ // We can't actually call `trait_items`, the reason being that if macro calls
+ // occur, they will call back into the def map which we might be computing right
+ // now resulting in a cycle.
+ // To properly implement this, trait item collection needs to be done in def map
+ // collection...
+ let resolutions = if true {
+ vec![]
+ } else {
+ self.db
+ .trait_items(it)
+ .items
+ .iter()
+ .map(|&(ref name, variant)| {
+ let res = match variant {
+ AssocItemId::FunctionId(it) => {
+ PerNs::values(it.into(), vis, None)
+ }
+ AssocItemId::ConstId(it) => {
+ PerNs::values(it.into(), vis, None)
+ }
+ AssocItemId::TypeAliasId(it) => {
+ PerNs::types(it.into(), vis, None)
+ }
+ };
+ (Some(name.clone()), res)
+ })
+ .collect::<Vec<_>>()
+ };
+ self.update(
+ module_id,
+ &resolutions,
+ vis,
+ Some(ImportOrExternCrate::Glob(glob)),
+ );
+ }
Some(d) => {
tracing::debug!("glob import {:?} from non-module/enum {:?}", import, d);
}
@@ -1240,7 +1281,7 @@ enum Resolved {
};
let resolver = |path: &_| {
let resolved_res = self.def_map.resolve_path_fp_with_macro(
- self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map),
+ self.crate_local_def_map.unwrap_or(&self.local_def_map),
self.db,
ResolveMode::Other,
directive.module_id,
@@ -1307,7 +1348,7 @@ enum Resolved {
);
// Record its helper attributes.
if def_id.krate != self.def_map.krate {
- let def_map = self.db.crate_def_map(def_id.krate);
+ let def_map = crate_def_map(self.db, def_id.krate);
if let Some(helpers) = def_map.data.exported_derives.get(&def_id) {
self.def_map
.derive_helpers_in_scope
@@ -1553,7 +1594,7 @@ fn finish(mut self) -> (DefMap, LocalDefMap) {
self.def_map.krate,
|path| {
let resolved_res = self.def_map.resolve_path_fp_with_macro(
- self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map),
+ self.crate_local_def_map.unwrap_or(&self.local_def_map),
self.db,
ResolveMode::Other,
directive.module_id,
@@ -1702,11 +1743,8 @@ fn collect(&mut self, items: &[ModItem], container: ItemContainerId) {
let module = self.def_collector.def_map.module_id(module_id);
let def_map = &mut self.def_collector.def_map;
- let local_def_map = self
- .def_collector
- .crate_local_def_map
- .as_deref()
- .unwrap_or(&self.def_collector.local_def_map);
+ let local_def_map =
+ self.def_collector.crate_local_def_map.unwrap_or(&self.def_collector.local_def_map);
match item {
ModItem::Mod(m) => self.collect_module(m, &attrs),
@@ -2133,10 +2171,7 @@ fn push_child_module(
let def_map = &mut self.def_collector.def_map;
let vis = def_map
.resolve_visibility(
- self.def_collector
- .crate_local_def_map
- .as_deref()
- .unwrap_or(&self.def_collector.local_def_map),
+ self.def_collector.crate_local_def_map.unwrap_or(&self.def_collector.local_def_map),
self.def_collector.db,
self.module_id,
visibility,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
index a49155d..74ce33a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
@@ -17,14 +17,17 @@
name::Name,
};
use span::Edition;
-use triomphe::Arc;
+use stdx::TupleExt;
use crate::{
AdtId, LocalModuleId, ModuleDefId,
db::DefDatabase,
item_scope::{BUILTIN_SCOPE, ImportOrExternCrate},
item_tree::FieldsShape,
- nameres::{BlockInfo, BuiltinShadowMode, DefMap, LocalDefMap, MacroSubNs, sub_namespace_match},
+ nameres::{
+ BlockInfo, BuiltinShadowMode, DefMap, LocalDefMap, MacroSubNs, crate_def_map,
+ sub_namespace_match,
+ },
per_ns::PerNs,
visibility::{RawVisibility, Visibility},
};
@@ -44,6 +47,7 @@ pub(super) enum ReachedFixedPoint {
#[derive(Debug, Clone)]
pub(super) struct ResolvePathResult {
pub(super) resolved_def: PerNs,
+ /// The index of the last resolved segment, or `None` if the full path has been resolved.
pub(super) segment_index: Option<usize>,
pub(super) reached_fixedpoint: ReachedFixedPoint,
pub(super) prefix_info: ResolvePathResultPrefixInfo,
@@ -173,7 +177,6 @@ pub(super) fn resolve_path_fp_with_macro(
return result;
}
- let mut arc;
let mut current_map = self;
let mut merge = |new: ResolvePathResult| {
@@ -195,8 +198,7 @@ pub(super) fn resolve_path_fp_with_macro(
Some(block) if original_module == Self::ROOT => {
// Block modules "inherit" names from its parent module.
original_module = block.parent.local_id;
- arc = block.parent.def_map(db, current_map.krate);
- current_map = &arc;
+ current_map = block.parent.def_map(db, current_map.krate);
}
// Proper (non-block) modules, including those in block `DefMap`s, don't.
_ => {
@@ -204,8 +206,7 @@ pub(super) fn resolve_path_fp_with_macro(
// A module inside a block. Do not resolve items declared in upper blocks, but we do need to get
// the prelude items (which are not inserted into blocks because they can be overridden there).
original_module = Self::ROOT;
- arc = db.crate_def_map(self.krate);
- current_map = &arc;
+ current_map = crate_def_map(db, self.krate);
let new = current_map.resolve_path_fp_in_all_preludes(
local_def_map,
@@ -253,7 +254,7 @@ pub(super) fn resolve_path_fp_with_macro_single(
cov_mark::hit!(macro_dollar_crate_self);
PerNs::types(self.crate_root().into(), Visibility::Public, None)
} else {
- let def_map = db.crate_def_map(krate);
+ let def_map = crate_def_map(db, krate);
let module = def_map.module_id(Self::ROOT);
cov_mark::hit!(macro_dollar_crate_other);
PerNs::types(module.into(), Visibility::Public, None)
@@ -312,7 +313,7 @@ pub(super) fn resolve_path_fp_with_macro_single(
// Adjust `local_id` to `self`, i.e. the nearest non-block module.
if def_map.module_id(local_id).is_block_module() {
(ext, local_id) = adjust_to_nearest_non_block_module(db, def_map, local_id);
- def_map = &ext;
+ def_map = ext;
}
// Go up the module tree but skip block modules as `super` always refers to the
@@ -325,7 +326,7 @@ pub(super) fn resolve_path_fp_with_macro_single(
if def_map.module_id(local_id).is_block_module() {
(ext, local_id) =
adjust_to_nearest_non_block_module(db, def_map, local_id);
- def_map = &ext;
+ def_map = ext;
}
} else {
stdx::always!(def_map.block.is_none());
@@ -364,7 +365,15 @@ pub(super) fn resolve_path_fp_with_macro_single(
},
};
- self.resolve_remaining_segments(segments, curr_per_ns, path, db, shadow, original_module)
+ self.resolve_remaining_segments(
+ db,
+ mode,
+ segments,
+ curr_per_ns,
+ path,
+ shadow,
+ original_module,
+ )
}
/// Resolves a path only in the preludes, without accounting for item scopes.
@@ -413,7 +422,15 @@ pub(super) fn resolve_path_fp_in_all_preludes(
}
};
- self.resolve_remaining_segments(segments, curr_per_ns, path, db, shadow, original_module)
+ self.resolve_remaining_segments(
+ db,
+ mode,
+ segments,
+ curr_per_ns,
+ path,
+ shadow,
+ original_module,
+ )
}
/// 2018-style absolute path -- only extern prelude
@@ -441,10 +458,11 @@ fn resolve_path_abs<'a>(
fn resolve_remaining_segments<'a>(
&self,
+ db: &dyn DefDatabase,
+ mode: ResolveMode,
mut segments: impl Iterator<Item = (usize, &'a Name)>,
mut curr_per_ns: PerNs,
path: &ModPath,
- db: &dyn DefDatabase,
shadow: BuiltinShadowMode,
original_module: LocalModuleId,
) -> ResolvePathResult {
@@ -465,6 +483,7 @@ fn resolve_remaining_segments<'a>(
curr_per_ns = match curr.def {
ModuleDefId::ModuleId(module) => {
if module.krate != self.krate {
+ // FIXME: Inefficient
let path = ModPath::from_segments(
PathKind::SELF,
path.segments()[i..].iter().cloned(),
@@ -478,7 +497,7 @@ fn resolve_remaining_segments<'a>(
let resolution = defp_map.resolve_path_fp_with_macro(
LocalDefMap::EMPTY,
db,
- ResolveMode::Other,
+ mode,
module.local_id,
&path,
shadow,
@@ -553,6 +572,44 @@ fn resolve_remaining_segments<'a>(
),
};
}
+ def @ ModuleDefId::TraitId(t) if mode == ResolveMode::Import => {
+ // FIXME: Implement this correctly
+ // We can't actually call `trait_items`, the reason being that if macro calls
+ // occur, they will call back into the def map which we might be computing right
+ // now resulting in a cycle.
+ // To properly implement this, trait item collection needs to be done in def map
+ // collection...
+ let item =
+ if true { None } else { db.trait_items(t).assoc_item_by_name(segment) };
+ return match item {
+ Some(item) => ResolvePathResult::new(
+ match item {
+ crate::AssocItemId::FunctionId(function_id) => PerNs::values(
+ function_id.into(),
+ curr.vis,
+ curr.import.and_then(|it| it.import_or_glob()),
+ ),
+ crate::AssocItemId::ConstId(const_id) => PerNs::values(
+ const_id.into(),
+ curr.vis,
+ curr.import.and_then(|it| it.import_or_glob()),
+ ),
+ crate::AssocItemId::TypeAliasId(type_alias_id) => {
+ PerNs::types(type_alias_id.into(), curr.vis, curr.import)
+ }
+ },
+ ReachedFixedPoint::Yes,
+ segments.next().map(TupleExt::head),
+ ResolvePathResultPrefixInfo::default(),
+ ),
+ None => ResolvePathResult::new(
+ PerNs::types(def, curr.vis, curr.import),
+ ReachedFixedPoint::Yes,
+ Some(i),
+ ResolvePathResultPrefixInfo::default(),
+ ),
+ };
+ }
s => {
// could be an inherent method call in UFCS form
// (`Struct::method`), or some other kind of associated item
@@ -715,7 +772,7 @@ fn resolve_in_prelude(&self, db: &dyn DefDatabase, name: &Name) -> PerNs {
} else {
// Extend lifetime
keep = prelude.def_map(db);
- &keep
+ keep
};
def_map[prelude.local_id].scope.get(name)
} else {
@@ -725,25 +782,23 @@ fn resolve_in_prelude(&self, db: &dyn DefDatabase, name: &Name) -> PerNs {
}
/// Given a block module, returns its nearest non-block module and the `DefMap` it belongs to.
-fn adjust_to_nearest_non_block_module(
- db: &dyn DefDatabase,
- def_map: &DefMap,
+fn adjust_to_nearest_non_block_module<'db>(
+ db: &'db dyn DefDatabase,
+ def_map: &'db DefMap,
mut local_id: LocalModuleId,
-) -> (Arc<DefMap>, LocalModuleId) {
+) -> (&'db DefMap, LocalModuleId) {
// INVARIANT: `local_id` in `def_map` must be a block module.
stdx::always!(def_map.module_id(local_id).is_block_module());
- let mut ext;
// This needs to be a local variable due to our mighty lifetime.
let mut def_map = def_map;
loop {
let BlockInfo { parent, .. } = def_map.block.expect("block module without parent module");
- ext = parent.def_map(db, def_map.krate);
- def_map = &ext;
+ def_map = parent.def_map(db, def_map.krate);
local_id = parent.local_id;
if !parent.is_block_module() {
- return (ext, local_id);
+ return (def_map, local_id);
}
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
index 3fd095a..4a7974c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
@@ -7,20 +7,25 @@
use base_db::RootQueryDb;
use expect_test::{Expect, expect};
use test_fixture::WithFixture;
-use triomphe::Arc;
-use crate::{db::DefDatabase, nameres::DefMap, test_db::TestDB};
+use crate::{
+ nameres::{DefMap, crate_def_map},
+ test_db::TestDB,
+};
-fn compute_crate_def_map(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> Arc<DefMap> {
+fn compute_crate_def_map(
+ #[rust_analyzer::rust_fixture] ra_fixture: &str,
+ cb: impl FnOnce(&DefMap),
+) {
let db = TestDB::with_files(ra_fixture);
let krate = db.fetch_test_crate();
- db.crate_def_map(krate)
+ cb(crate_def_map(&db, krate));
}
fn render_crate_def_map(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String {
let db = TestDB::with_files(ra_fixture);
let krate = db.fetch_test_crate();
- db.crate_def_map(krate).dump(&db)
+ crate_def_map(&db, krate).dump(&db)
}
fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
index 179a9c8..948e8be 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
@@ -7,24 +7,37 @@
use test_fixture::WithFixture;
use triomphe::Arc;
-use crate::{AdtId, ModuleDefId, db::DefDatabase, nameres::tests::TestDB};
+use crate::{
+ AdtId, ModuleDefId,
+ db::DefDatabase,
+ nameres::{crate_def_map, tests::TestDB},
+};
-fn check_def_map_is_not_recomputed(ra_fixture_initial: &str, ra_fixture_change: &str) {
+fn check_def_map_is_not_recomputed(
+ #[rust_analyzer::rust_fixture] ra_fixture_initial: &str,
+ #[rust_analyzer::rust_fixture] ra_fixture_change: &str,
+) {
let (mut db, pos) = TestDB::with_position(ra_fixture_initial);
let krate = db.fetch_test_crate();
{
let events = db.log_executed(|| {
- db.crate_def_map(krate);
+ crate_def_map(&db, krate);
});
- assert!(format!("{events:?}").contains("crate_def_map"), "{events:#?}")
+ assert!(
+ format!("{events:?}").contains("crate_local_def_map"),
+ "no crate def map computed:\n{events:#?}",
+ )
}
db.set_file_text(pos.file_id.file_id(&db), ra_fixture_change);
{
let events = db.log_executed(|| {
- db.crate_def_map(krate);
+ crate_def_map(&db, krate);
});
- assert!(!format!("{events:?}").contains("crate_def_map"), "{events:#?}")
+ assert!(
+ !format!("{events:?}").contains("crate_local_def_map"),
+ "crate def map invalidated:\n{events:#?}",
+ )
}
}
@@ -44,7 +57,7 @@ pub fn foo() {}
);
for &krate in db.all_crates().iter() {
- db.crate_def_map(krate);
+ crate_def_map(&db, krate);
}
let all_crates_before = db.all_crates();
@@ -94,11 +107,11 @@ pub fn foo() {}
let events = db.log_executed(|| {
for &krate in db.all_crates().iter() {
- db.crate_def_map(krate);
+ crate_def_map(&db, krate);
}
});
let invalidated_def_maps =
- events.iter().filter(|event| event.contains("crate_def_map")).count();
+ events.iter().filter(|event| event.contains("crate_local_def_map")).count();
assert_eq!(invalidated_def_maps, 1, "{events:#?}")
}
@@ -330,7 +343,7 @@ fn quux() { 1$0 }
let krate = db.test_crate();
{
let events = db.log_executed(|| {
- let crate_def_map = db.crate_def_map(krate);
+ let crate_def_map = crate_def_map(&db, krate);
let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
assert_eq!(module_data.scope.resolutions().count(), 4);
});
@@ -352,7 +365,7 @@ fn quux() { 92 }
{
let events = db.log_executed(|| {
- let crate_def_map = db.crate_def_map(krate);
+ let crate_def_map = crate_def_map(&db, krate);
let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
assert_eq!(module_data.scope.resolutions().count(), 4);
});
@@ -403,7 +416,7 @@ impl Tr for () {}
{
let events = db.log_executed(|| {
- let crate_def_map = db.crate_def_map(krate);
+ let crate_def_map = crate_def_map(&db, krate);
let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
assert_eq!(module_data.scope.resolutions().count(), 8);
assert_eq!(module_data.scope.impls().count(), 1);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
index 5f8a015..3cba88e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
@@ -736,7 +736,7 @@ macro_rules! foo {
#[test]
fn macro_dollar_crate_is_correct_in_derive_meta() {
- let map = compute_crate_def_map(
+ compute_crate_def_map(
r#"
//- minicore: derive, clone
//- /main.rs crate:main deps:lib
@@ -753,13 +753,13 @@ macro_rules! foo {
pub use core::clone::Clone;
"#,
+ |map| assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1),
);
- assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1);
}
#[test]
fn expand_derive() {
- let map = compute_crate_def_map(
+ compute_crate_def_map(
r#"
//- /main.rs crate:main deps:core
use core::Copy;
@@ -775,8 +775,8 @@ fn expand_derive() {
#[rustc_builtin_macro]
pub macro Clone {}
"#,
+ |map| assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 2),
);
- assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 2);
}
#[test]
@@ -803,7 +803,7 @@ pub trait Clone {}
fn builtin_derive_with_unresolved_attributes_fall_back() {
// Tests that we still resolve derives after ignoring an unresolved attribute.
cov_mark::check!(unresolved_attribute_fallback);
- let map = compute_crate_def_map(
+ compute_crate_def_map(
r#"
//- /main.rs crate:main deps:core
use core::{Clone, derive};
@@ -818,8 +818,8 @@ fn builtin_derive_with_unresolved_attributes_fall_back() {
#[rustc_builtin_macro]
pub macro Clone {}
"#,
+ |map| assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1),
);
- assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1);
}
#[test]
@@ -1096,7 +1096,7 @@ pub fn derive_macro_2(_item: TokenStream) -> TokenStream {
"#,
);
let krate = *db.all_crates().last().expect("no crate graph present");
- let def_map = db.crate_def_map(krate);
+ let def_map = crate_def_map(&db, krate);
assert_eq!(def_map.data.exported_derives.len(), 1);
match def_map.data.exported_derives.values().next() {
@@ -1446,7 +1446,7 @@ fn proc_attr(a: TokenStream, b: TokenStream) -> TokenStream { a }
"#,
);
let krate = *db.all_crates().last().expect("no crate graph present");
- let def_map = db.crate_def_map(krate);
+ let def_map = crate_def_map(&db, krate);
let root_module = &def_map[DefMap::ROOT].scope;
assert!(
@@ -1544,7 +1544,7 @@ macro_rules! foo {
#[test]
fn macro_sub_namespace() {
- let map = compute_crate_def_map(
+ compute_crate_def_map(
r#"
//- minicore: derive, clone
macro_rules! Clone { () => {} }
@@ -1553,8 +1553,8 @@ macro_rules! derive { () => {} }
#[derive(Clone)]
struct S;
"#,
+ |map| assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1),
);
- assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1);
}
#[test]
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs
index 071b55c..9c97e42 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs
@@ -839,6 +839,7 @@ fn circular_mods() {
#[path = "./foo.rs"]
mod foo;
"#,
+ |_| (),
);
compute_crate_def_map(
@@ -852,6 +853,7 @@ fn circular_mods() {
#[path = "./foo.rs"]
mod foo;
"#,
+ |_| (),
);
}
@@ -894,3 +896,149 @@ fn cfg_in_module_file() {
"#]],
)
}
+
+#[test]
+fn invalid_imports() {
+ check(
+ r#"
+//- /main.rs
+mod module;
+
+use self::module::S::new;
+use self::module::unresolved;
+use self::module::C::const_based;
+use self::module::Enum::Variant::NoAssoc;
+
+//- /module.rs
+pub struct S;
+impl S {
+ pub fn new() {}
+}
+pub const C: () = ();
+pub enum Enum {
+ Variant,
+}
+ "#,
+ expect![[r#"
+ crate
+ NoAssoc: _
+ const_based: _
+ module: t
+ new: _
+ unresolved: _
+
+ crate::module
+ C: v
+ Enum: t
+ S: t v
+ "#]],
+ );
+}
+
+#[test]
+fn trait_item_imports_same_crate() {
+ check(
+ r#"
+//- /main.rs
+mod module;
+
+use self::module::Trait::{AssocType, ASSOC_CONST, MACRO_CONST, method};
+
+//- /module.rs
+macro_rules! m {
+ ($name:ident) => { const $name: () = (); };
+}
+pub trait Trait {
+ type AssocType;
+ const ASSOC_CONST: ();
+ fn method(&self);
+ m!(MACRO_CONST);
+}
+ "#,
+ expect![[r#"
+ crate
+ ASSOC_CONST: _
+ AssocType: _
+ MACRO_CONST: _
+ method: _
+ module: t
+
+ crate::module
+ Trait: t
+ "#]],
+ );
+ check(
+ r#"
+//- /main.rs
+mod module;
+
+use self::module::Trait::*;
+
+//- /module.rs
+macro_rules! m {
+ ($name:ident) => { const $name: () = (); };
+}
+pub trait Trait {
+ type AssocType;
+ const ASSOC_CONST: ();
+ fn method(&self);
+ m!(MACRO_CONST);
+}
+ "#,
+ expect![[r#"
+ crate
+ module: t
+
+ crate::module
+ Trait: t
+ "#]],
+ );
+}
+
+#[test]
+fn trait_item_imports_differing_crate() {
+ check(
+ r#"
+//- /main.rs deps:lib crate:main
+use lib::Trait::{AssocType, ASSOC_CONST, MACRO_CONST, method};
+
+//- /lib.rs crate:lib
+macro_rules! m {
+ ($name:ident) => { const $name: () = (); };
+}
+pub trait Trait {
+ type AssocType;
+ const ASSOC_CONST: ();
+ fn method(&self);
+ m!(MACRO_CONST);
+}
+ "#,
+ expect![[r#"
+ crate
+ ASSOC_CONST: _
+ AssocType: _
+ MACRO_CONST: _
+ method: _
+ "#]],
+ );
+ check(
+ r#"
+//- /main.rs deps:lib crate:main
+use lib::Trait::*;
+
+//- /lib.rs crate:lib
+macro_rules! m {
+ ($name:ident) => { const $name: () = (); };
+}
+pub trait Trait {
+ type AssocType;
+ const ASSOC_CONST: ();
+ fn method(&self);
+ m!(MACRO_CONST);
+}
+ "#,
+ expect![[r#"
+ crate
+ "#]],
+ );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
index 8a8d170..16988dd 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -34,30 +34,30 @@
item_scope::{BUILTIN_SCOPE, BuiltinShadowMode, ImportOrExternCrate, ImportOrGlob, ItemScope},
item_tree::ImportAlias,
lang_item::LangItemTarget,
- nameres::{DefMap, LocalDefMap, MacroSubNs, ResolvePathResultPrefixInfo},
+ nameres::{DefMap, LocalDefMap, MacroSubNs, ResolvePathResultPrefixInfo, block_def_map},
per_ns::PerNs,
type_ref::LifetimeRef,
visibility::{RawVisibility, Visibility},
};
#[derive(Debug, Clone)]
-pub struct Resolver {
+pub struct Resolver<'db> {
/// The stack of scopes, where the inner-most scope is the last item.
///
/// When using, you generally want to process the scopes in reverse order,
/// there's `scopes` *method* for that.
- scopes: Vec<Scope>,
- module_scope: ModuleItemMap,
+ scopes: Vec<Scope<'db>>,
+ module_scope: ModuleItemMap<'db>,
}
#[derive(Clone)]
-struct ModuleItemMap {
- def_map: Arc<DefMap>,
- local_def_map: Arc<LocalDefMap>,
+struct ModuleItemMap<'db> {
+ def_map: &'db DefMap,
+ local_def_map: &'db LocalDefMap,
module_id: LocalModuleId,
}
-impl fmt::Debug for ModuleItemMap {
+impl fmt::Debug for ModuleItemMap<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ModuleItemMap").field("module_id", &self.module_id).finish()
}
@@ -80,9 +80,9 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
#[derive(Debug, Clone)]
-enum Scope {
+enum Scope<'db> {
/// All the items and imported names of a module
- BlockScope(ModuleItemMap),
+ BlockScope(ModuleItemMap<'db>),
/// Brings the generic parameters of an item into scope as well as the `Self` type alias /
/// generic for ADTs and impls.
GenericParams { def: GenericDefId, params: Arc<GenericParams> },
@@ -133,7 +133,7 @@ pub enum LifetimeNs {
LifetimeParam(LifetimeParamId),
}
-impl Resolver {
+impl<'db> Resolver<'db> {
/// Resolve known trait from std, like `std::futures::Future`
pub fn resolve_known_trait(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<TraitId> {
let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
@@ -580,7 +580,7 @@ pub fn names_in_scope(
for scope in self.scopes() {
scope.process_names(&mut res, db);
}
- let ModuleItemMap { ref def_map, module_id, ref local_def_map } = self.module_scope;
+ let ModuleItemMap { def_map, module_id, local_def_map } = self.module_scope;
// FIXME: should we provide `self` here?
// f(
// Name::self_param(),
@@ -842,14 +842,14 @@ pub fn rename_will_conflict_with_renamed(
#[must_use]
pub fn update_to_inner_scope(
&mut self,
- db: &dyn DefDatabase,
+ db: &'db dyn DefDatabase,
owner: DefWithBodyId,
expr_id: ExprId,
) -> UpdateGuard {
#[inline(always)]
- fn append_expr_scope(
- db: &dyn DefDatabase,
- resolver: &mut Resolver,
+ fn append_expr_scope<'db>(
+ db: &'db dyn DefDatabase,
+ resolver: &mut Resolver<'db>,
owner: DefWithBodyId,
expr_scopes: &Arc<ExprScopes>,
scope_id: ScopeId,
@@ -863,7 +863,7 @@ fn append_expr_scope(
scope_id,
}));
if let Some(block) = expr_scopes.block(scope_id) {
- let def_map = db.block_def_map(block);
+ let def_map = block_def_map(db, block);
let local_def_map = block.lookup(db).module.only_local_def_map(db);
resolver.scopes.push(Scope::BlockScope(ModuleItemMap {
def_map,
@@ -945,8 +945,8 @@ fn hygiene_info(
pub struct UpdateGuard(usize);
-impl Resolver {
- fn scopes(&self) -> impl Iterator<Item = &Scope> {
+impl<'db> Resolver<'db> {
+ fn scopes(&self) -> impl Iterator<Item = &Scope<'db>> {
self.scopes.iter().rev()
}
@@ -970,12 +970,12 @@ fn resolve_module_path(
fn item_scope_(&self) -> (&DefMap, &LocalDefMap, LocalModuleId) {
self.scopes()
.find_map(|scope| match scope {
- Scope::BlockScope(m) => Some((&*m.def_map, &*m.local_def_map, m.module_id)),
+ Scope::BlockScope(m) => Some((m.def_map, m.local_def_map, m.module_id)),
_ => None,
})
.unwrap_or((
- &self.module_scope.def_map,
- &self.module_scope.local_def_map,
+ self.module_scope.def_map,
+ self.module_scope.local_def_map,
self.module_scope.module_id,
))
}
@@ -992,8 +992,8 @@ pub enum ScopeDef {
Label(LabelId),
}
-impl Scope {
- fn process_names(&self, acc: &mut ScopeNames, db: &dyn DefDatabase) {
+impl<'db> Scope<'db> {
+ fn process_names(&self, acc: &mut ScopeNames, db: &'db dyn DefDatabase) {
match self {
Scope::BlockScope(m) => {
m.def_map[m.module_id].scope.entries().for_each(|(name, def)| {
@@ -1047,7 +1047,11 @@ fn process_names(&self, acc: &mut ScopeNames, db: &dyn DefDatabase) {
}
}
-pub fn resolver_for_expr(db: &dyn DefDatabase, owner: DefWithBodyId, expr_id: ExprId) -> Resolver {
+pub fn resolver_for_expr(
+ db: &dyn DefDatabase,
+ owner: DefWithBodyId,
+ expr_id: ExprId,
+) -> Resolver<'_> {
let r = owner.resolver(db);
let scopes = db.expr_scopes(owner);
let scope_id = scopes.scope_for(expr_id);
@@ -1058,25 +1062,25 @@ pub fn resolver_for_scope(
db: &dyn DefDatabase,
owner: DefWithBodyId,
scope_id: Option<ScopeId>,
-) -> Resolver {
+) -> Resolver<'_> {
let r = owner.resolver(db);
let scopes = db.expr_scopes(owner);
resolver_for_scope_(db, scopes, scope_id, r, owner)
}
-fn resolver_for_scope_(
- db: &dyn DefDatabase,
+fn resolver_for_scope_<'db>(
+ db: &'db dyn DefDatabase,
scopes: Arc<ExprScopes>,
scope_id: Option<ScopeId>,
- mut r: Resolver,
+ mut r: Resolver<'db>,
owner: DefWithBodyId,
-) -> Resolver {
+) -> Resolver<'db> {
let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>();
r.scopes.reserve(scope_chain.len());
for scope in scope_chain.into_iter().rev() {
if let Some(block) = scopes.block(scope) {
- let def_map = db.block_def_map(block);
+ let def_map = block_def_map(db, block);
let local_def_map = block.lookup(db).module.only_local_def_map(db);
r = r.push_block_scope(def_map, local_def_map);
// FIXME: This adds as many module scopes as there are blocks, but resolving in each
@@ -1092,18 +1096,26 @@ fn resolver_for_scope_(
r
}
-impl Resolver {
- fn push_scope(mut self, scope: Scope) -> Resolver {
+impl<'db> Resolver<'db> {
+ fn push_scope(mut self, scope: Scope<'db>) -> Resolver<'db> {
self.scopes.push(scope);
self
}
- fn push_generic_params_scope(self, db: &dyn DefDatabase, def: GenericDefId) -> Resolver {
+ fn push_generic_params_scope(
+ self,
+ db: &'db dyn DefDatabase,
+ def: GenericDefId,
+ ) -> Resolver<'db> {
let params = db.generic_params(def);
self.push_scope(Scope::GenericParams { def, params })
}
- fn push_block_scope(self, def_map: Arc<DefMap>, local_def_map: Arc<LocalDefMap>) -> Resolver {
+ fn push_block_scope(
+ self,
+ def_map: &'db DefMap,
+ local_def_map: &'db LocalDefMap,
+ ) -> Resolver<'db> {
self.push_scope(Scope::BlockScope(ModuleItemMap {
def_map,
local_def_map,
@@ -1116,19 +1128,19 @@ fn push_expr_scope(
owner: DefWithBodyId,
expr_scopes: Arc<ExprScopes>,
scope_id: ScopeId,
- ) -> Resolver {
+ ) -> Resolver<'db> {
self.push_scope(Scope::ExprScope(ExprScope { owner, expr_scopes, scope_id }))
}
}
-impl ModuleItemMap {
+impl<'db> ModuleItemMap<'db> {
fn resolve_path_in_value_ns(
&self,
- db: &dyn DefDatabase,
+ db: &'db dyn DefDatabase,
path: &ModPath,
) -> Option<(ResolveValueResult, ResolvePathResultPrefixInfo)> {
let (module_def, unresolved_idx, prefix_info) = self.def_map.resolve_path_locally(
- &self.local_def_map,
+ self.local_def_map,
db,
self.module_id,
path,
@@ -1167,7 +1179,7 @@ fn resolve_path_in_type_ns(
) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>, ResolvePathResultPrefixInfo)>
{
let (module_def, idx, prefix_info) = self.def_map.resolve_path_locally(
- &self.local_def_map,
+ self.local_def_map,
db,
self.module_id,
path,
@@ -1263,11 +1275,11 @@ fn add_local(&mut self, name: &Name, binding: BindingId) {
pub trait HasResolver: Copy {
/// Builds a resolver for type references inside this def.
- fn resolver(self, db: &dyn DefDatabase) -> Resolver;
+ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_>;
}
impl HasResolver for ModuleId {
- fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
let (mut def_map, local_def_map) = self.local_def_map(db);
let mut module_id = self.local_id;
@@ -1289,21 +1301,17 @@ fn resolver(self, db: &dyn DefDatabase) -> Resolver {
}
let mut resolver = Resolver {
scopes: Vec::with_capacity(modules.len()),
- module_scope: ModuleItemMap {
- def_map,
- local_def_map: local_def_map.clone(),
- module_id,
- },
+ module_scope: ModuleItemMap { def_map, local_def_map, module_id },
};
for def_map in modules.into_iter().rev() {
- resolver = resolver.push_block_scope(def_map, local_def_map.clone());
+ resolver = resolver.push_block_scope(def_map, local_def_map);
}
resolver
}
}
impl HasResolver for CrateRootModuleId {
- fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
let (def_map, local_def_map) = self.local_def_map(db);
Resolver {
scopes: vec![],
@@ -1313,75 +1321,75 @@ fn resolver(self, db: &dyn DefDatabase) -> Resolver {
}
impl HasResolver for TraitId {
- fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
lookup_resolver(db, self).push_generic_params_scope(db, self.into())
}
}
impl HasResolver for TraitAliasId {
- fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
lookup_resolver(db, self).push_generic_params_scope(db, self.into())
}
}
impl<T: Into<AdtId> + Copy> HasResolver for T {
- fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
let def = self.into();
def.module(db).resolver(db).push_generic_params_scope(db, def.into())
}
}
impl HasResolver for FunctionId {
- fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
lookup_resolver(db, self).push_generic_params_scope(db, self.into())
}
}
impl HasResolver for ConstId {
- fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
lookup_resolver(db, self)
}
}
impl HasResolver for StaticId {
- fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
lookup_resolver(db, self)
}
}
impl HasResolver for TypeAliasId {
- fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
lookup_resolver(db, self).push_generic_params_scope(db, self.into())
}
}
impl HasResolver for ImplId {
- fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into())
}
}
impl HasResolver for ExternBlockId {
- fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
// Same as parent's
lookup_resolver(db, self)
}
}
impl HasResolver for ExternCrateId {
- fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
lookup_resolver(db, self)
}
}
impl HasResolver for UseId {
- fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
lookup_resolver(db, self)
}
}
impl HasResolver for DefWithBodyId {
- fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
match self {
DefWithBodyId::ConstId(c) => c.resolver(db),
DefWithBodyId::FunctionId(f) => f.resolver(db),
@@ -1392,7 +1400,7 @@ fn resolver(self, db: &dyn DefDatabase) -> Resolver {
}
impl HasResolver for ItemContainerId {
- fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
match self {
ItemContainerId::ModuleId(it) => it.resolver(db),
ItemContainerId::TraitId(it) => it.resolver(db),
@@ -1403,7 +1411,7 @@ fn resolver(self, db: &dyn DefDatabase) -> Resolver {
}
impl HasResolver for GenericDefId {
- fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
match self {
GenericDefId::FunctionId(inner) => inner.resolver(db),
GenericDefId::AdtId(adt) => adt.resolver(db),
@@ -1418,13 +1426,13 @@ fn resolver(self, db: &dyn DefDatabase) -> Resolver {
}
impl HasResolver for EnumVariantId {
- fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
self.lookup(db).parent.resolver(db)
}
}
impl HasResolver for VariantId {
- fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
match self {
VariantId::EnumVariantId(it) => it.resolver(db),
VariantId::StructId(it) => it.resolver(db),
@@ -1434,7 +1442,7 @@ fn resolver(self, db: &dyn DefDatabase) -> Resolver {
}
impl HasResolver for MacroId {
- fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
match self {
MacroId::Macro2Id(it) => it.resolver(db),
MacroId::MacroRulesId(it) => it.resolver(db),
@@ -1444,29 +1452,29 @@ fn resolver(self, db: &dyn DefDatabase) -> Resolver {
}
impl HasResolver for Macro2Id {
- fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
lookup_resolver(db, self)
}
}
impl HasResolver for ProcMacroId {
- fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
lookup_resolver(db, self)
}
}
impl HasResolver for MacroRulesId {
- fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
lookup_resolver(db, self)
}
}
-fn lookup_resolver<'db>(
- db: &(dyn DefDatabase + 'db),
+fn lookup_resolver(
+ db: &dyn DefDatabase,
lookup: impl Lookup<
Database = dyn DefDatabase,
Data = impl ItemTreeLoc<Container = impl HasResolver>,
>,
-) -> Resolver {
+) -> Resolver<'_> {
lookup.lookup(db).container().resolver(db)
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
index 4709754..6c995ab 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
@@ -15,7 +15,7 @@
use crate::{
LocalModuleId, Lookup, ModuleDefId, ModuleId,
db::DefDatabase,
- nameres::{DefMap, ModuleSource},
+ nameres::{DefMap, ModuleSource, block_def_map, crate_def_map},
src::HasSource,
};
@@ -133,7 +133,7 @@ pub(crate) fn fetch_test_crate(&self) -> Crate {
pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId {
for &krate in self.relevant_crates(file_id).iter() {
- let crate_def_map = self.crate_def_map(krate);
+ let crate_def_map = crate_def_map(self, krate);
for (local_id, data) in crate_def_map.modules() {
if data.origin.file_id().map(|file_id| file_id.file_id(self)) == Some(file_id) {
return crate_def_map.module_id(local_id);
@@ -146,16 +146,16 @@ pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId {
pub(crate) fn module_at_position(&self, position: FilePosition) -> ModuleId {
let file_module = self.module_for_file(position.file_id.file_id(self));
let mut def_map = file_module.def_map(self);
- let module = self.mod_at_position(&def_map, position);
+ let module = self.mod_at_position(def_map, position);
- def_map = match self.block_at_position(&def_map, position) {
+ def_map = match self.block_at_position(def_map, position) {
Some(it) => it,
None => return def_map.module_id(module),
};
loop {
- let new_map = self.block_at_position(&def_map, position);
+ let new_map = self.block_at_position(def_map, position);
match new_map {
- Some(new_block) if !Arc::ptr_eq(&new_block, &def_map) => {
+ Some(new_block) if !std::ptr::eq(&new_block, &def_map) => {
def_map = new_block;
}
_ => {
@@ -206,7 +206,7 @@ fn mod_at_position(&self, def_map: &DefMap, position: FilePosition) -> LocalModu
res
}
- fn block_at_position(&self, def_map: &DefMap, position: FilePosition) -> Option<Arc<DefMap>> {
+ fn block_at_position(&self, def_map: &DefMap, position: FilePosition) -> Option<&DefMap> {
// Find the smallest (innermost) function in `def_map` containing the cursor.
let mut size = None;
let mut fn_def = None;
@@ -263,7 +263,7 @@ fn block_at_position(&self, def_map: &DefMap, position: FilePosition) -> Option<
let mut containing_blocks =
scopes.scope_chain(Some(scope)).filter_map(|scope| scopes.block(scope));
- if let Some(block) = containing_blocks.next().map(|block| self.block_def_map(block)) {
+ if let Some(block) = containing_blocks.next().map(|block| block_def_map(self, block)) {
return Some(block);
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
index b42c8d3..3c67ee9 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
@@ -28,7 +28,7 @@ pub enum Visibility {
impl Visibility {
pub fn resolve(
db: &dyn DefDatabase,
- resolver: &crate::resolver::Resolver,
+ resolver: &crate::resolver::Resolver<'_>,
raw_vis: &RawVisibility,
) -> Self {
// we fall back to public visibility (i.e. fail open) if the path can't be resolved
@@ -50,7 +50,7 @@ pub fn is_visible_from(self, db: &dyn DefDatabase, from_module: ModuleId) -> boo
return false;
}
let def_map = from_module.def_map(db);
- Self::is_visible_from_def_map_(db, &def_map, to_module, from_module.local_id)
+ Self::is_visible_from_def_map_(db, def_map, to_module, from_module.local_id)
}
pub(crate) fn is_visible_from_def_map(
@@ -116,7 +116,7 @@ fn is_visible_from_def_map_(
match def_map.parent() {
Some(module) => {
parent_arc = module.def_map(db);
- def_map = &*parent_arc;
+ def_map = parent_arc;
from_module = module.local_id;
}
// Reached the root module, nothing left to check.
@@ -257,7 +257,7 @@ pub(crate) fn type_alias_visibility_query(db: &dyn DefDatabase, def: TypeAliasId
}
#[inline]
-fn trait_vis(db: &dyn DefDatabase, resolver: &Resolver, trait_id: TraitId) -> Visibility {
+fn trait_vis(db: &dyn DefDatabase, resolver: &Resolver<'_>, trait_id: TraitId) -> Visibility {
let ItemLoc { id: tree_id, .. } = trait_id.lookup(db);
let item_tree = tree_id.item_tree(db);
let tr_def = &item_tree[tree_id.value];
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
index bb17eb0..94c9771 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
@@ -1,4 +1,5 @@
//! A higher level attributes based on TokenTree, with also some shortcuts.
+use std::iter;
use std::{borrow::Cow, fmt, ops};
use base_db::Crate;
@@ -122,16 +123,15 @@ pub fn merge(&self, other: Self) -> Self {
(None, entries @ Some(_)) => Self { entries },
(Some(entries), None) => Self { entries: Some(entries.clone()) },
(Some(a), Some(b)) => {
- let last_ast_index = a.slice.last().map_or(0, |it| it.id.ast_index() + 1) as u32;
+ let last_ast_index = a.slice.last().map_or(0, |it| it.id.ast_index() + 1);
let items = a
.slice
.iter()
.cloned()
.chain(b.slice.iter().map(|it| {
let mut it = it.clone();
- it.id.id = (it.id.ast_index() as u32 + last_ast_index)
- | ((it.id.cfg_attr_index().unwrap_or(0) as u32)
- << AttrId::AST_INDEX_BITS);
+ let id = it.id.ast_index() + last_ast_index;
+ it.id = AttrId::new(id, it.id.is_inner_attr());
it
}))
.collect::<Vec<_>>();
@@ -175,25 +175,20 @@ pub struct AttrId {
// FIXME: This only handles a single level of cfg_attr nesting
// that is `#[cfg_attr(all(), cfg_attr(all(), cfg(any())))]` breaks again
impl AttrId {
- const CFG_ATTR_BITS: usize = 7;
- const AST_INDEX_MASK: usize = 0x00FF_FFFF;
- const AST_INDEX_BITS: usize = Self::AST_INDEX_MASK.count_ones() as usize;
- const CFG_ATTR_SET_BITS: u32 = 1 << 31;
+ const INNER_ATTR_SET_BIT: u32 = 1 << 31;
+
+ pub fn new(id: usize, is_inner: bool) -> Self {
+ assert!(id <= !Self::INNER_ATTR_SET_BIT as usize);
+ let id = id as u32;
+ Self { id: if is_inner { id | Self::INNER_ATTR_SET_BIT } else { id } }
+ }
pub fn ast_index(&self) -> usize {
- self.id as usize & Self::AST_INDEX_MASK
+ (self.id & !Self::INNER_ATTR_SET_BIT) as usize
}
- pub fn cfg_attr_index(&self) -> Option<usize> {
- if self.id & Self::CFG_ATTR_SET_BITS == 0 {
- None
- } else {
- Some(self.id as usize >> Self::AST_INDEX_BITS)
- }
- }
-
- pub fn with_cfg_attr(self, idx: usize) -> AttrId {
- AttrId { id: self.id | ((idx as u32) << Self::AST_INDEX_BITS) | Self::CFG_ATTR_SET_BITS }
+ pub fn is_inner_attr(&self) -> bool {
+ self.id & Self::INNER_ATTR_SET_BIT != 0
}
}
@@ -333,10 +328,7 @@ pub fn expand_cfg_attr(
None => return smallvec![self.clone()],
};
let index = self.id;
- let attrs = parts
- .enumerate()
- .take(1 << AttrId::CFG_ATTR_BITS)
- .filter_map(|(idx, attr)| Attr::from_tt(db, attr, index.with_cfg_attr(idx)));
+ let attrs = parts.filter_map(|attr| Attr::from_tt(db, attr, index));
let cfg = TopSubtree::from_token_trees(subtree.top_subtree().delimiter, cfg);
let cfg = CfgExpr::parse(&cfg);
@@ -467,13 +459,18 @@ fn unescape(s: &str) -> Option<Cow<'_, str>> {
pub fn collect_attrs(
owner: &dyn ast::HasAttrs,
) -> impl Iterator<Item = (AttrId, Either<ast::Attr, ast::Comment>)> {
- let inner_attrs = inner_attributes(owner.syntax()).into_iter().flatten();
- let outer_attrs =
- ast::AttrDocCommentIter::from_syntax_node(owner.syntax()).filter(|el| match el {
+ let inner_attrs =
+ inner_attributes(owner.syntax()).into_iter().flatten().zip(iter::repeat(true));
+ let outer_attrs = ast::AttrDocCommentIter::from_syntax_node(owner.syntax())
+ .filter(|el| match el {
Either::Left(attr) => attr.kind().is_outer(),
Either::Right(comment) => comment.is_outer(),
- });
- outer_attrs.chain(inner_attrs).enumerate().map(|(id, attr)| (AttrId { id: id as u32 }, attr))
+ })
+ .zip(iter::repeat(false));
+ outer_attrs
+ .chain(inner_attrs)
+ .enumerate()
+ .map(|(id, (attr, is_inner))| (AttrId::new(id, is_inner), attr))
}
fn inner_attributes(
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs
index 68283b9..d135584 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs
@@ -1,5 +1,6 @@
//! Builtin derives.
+use either::Either;
use intern::sym;
use itertools::{Itertools, izip};
use parser::SyntaxKind;
@@ -1179,10 +1180,10 @@ fn coerce_pointee_expand(
};
new_predicates.push(
make::where_pred(
- make::ty_path(make::path_from_segments(
+ Either::Right(make::ty_path(make::path_from_segments(
[make::path_segment(new_bounds_target)],
false,
- )),
+ ))),
new_bounds,
)
.clone_for_update(),
@@ -1245,7 +1246,9 @@ fn coerce_pointee_expand(
substitute_type_in_bound(ty, &pointee_param_name.text(), ADDED_PARAM)
})
});
- new_predicates.push(make::where_pred(pred_target, new_bounds).clone_for_update());
+ new_predicates.push(
+ make::where_pred(Either::Right(pred_target), new_bounds).clone_for_update(),
+ );
}
}
@@ -1260,10 +1263,10 @@ fn coerce_pointee_expand(
// Find the `#[pointee]` parameter and add an `Unsize<__S>` bound to it.
where_clause.add_predicate(
make::where_pred(
- make::ty_path(make::path_from_segments(
+ Either::Right(make::ty_path(make::path_from_segments(
[make::path_segment(make::name_ref(&pointee_param_name.text()))],
false,
- )),
+ ))),
[make::type_bound(make::ty_path(make::path_from_segments(
[
make::path_segment(make::name_ref("core")),
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
index 621e174..539c727 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
@@ -452,7 +452,10 @@ fn concat_expand(
Some(_) => (),
None => span = Some(s),
};
- for (i, mut t) in tt.iter().enumerate() {
+
+ let mut i = 0;
+ let mut iter = tt.iter();
+ while let Some(mut t) = iter.next() {
// FIXME: hack on top of a hack: `$e:expr` captures get surrounded in parentheses
// to ensure the right parsing order, so skip the parentheses here. Ideally we'd
// implement rustc's model. cc https://github.com/rust-lang/rust-analyzer/pull/10623
@@ -504,10 +507,40 @@ fn concat_expand(
record_span(id.span);
}
TtElement::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (),
+ // handle negative numbers
+ TtElement::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 0 && punct.char == '-' => {
+ let t = match iter.next() {
+ Some(t) => t,
+ None => {
+ err.get_or_insert(ExpandError::other(
+ call_site,
+ "unexpected end of input after '-'",
+ ));
+ break;
+ }
+ };
+
+ match t {
+ TtElement::Leaf(tt::Leaf::Literal(it))
+ if matches!(it.kind, tt::LitKind::Integer | tt::LitKind::Float) =>
+ {
+ format_to!(text, "-{}", it.symbol.as_str());
+ record_span(punct.span.cover(it.span));
+ }
+ _ => {
+ err.get_or_insert(ExpandError::other(
+ call_site,
+ "expected integer or floating pointer number after '-'",
+ ));
+ break;
+ }
+ }
+ }
_ => {
err.get_or_insert(ExpandError::other(call_site, "unexpected token"));
}
}
+ i += 1;
}
let span = span.unwrap_or_else(|| tt.top_subtree().delimiter.open);
ExpandResult { value: quote!(span =>#text), err }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
index 8a1a33d..1cd975b 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
@@ -19,18 +19,8 @@ pub enum ProcMacroKind {
Attr,
}
-pub trait AsAny: Any {
- fn as_any(&self) -> &dyn Any;
-}
-
-impl<T: Any> AsAny for T {
- fn as_any(&self) -> &dyn Any {
- self
- }
-}
-
/// A proc-macro expander implementation.
-pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe + AsAny {
+pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe + Any {
/// Run the expander with the given input subtree, optional attribute input subtree (for
/// [`ProcMacroKind::Attr`]), environment variables, and span information.
fn expand(
@@ -44,7 +34,9 @@ fn expand(
current_dir: String,
) -> Result<tt::TopSubtree, ProcMacroExpansionError>;
- fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool;
+ fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
+ other.type_id() == self.type_id()
+ }
}
impl PartialEq for dyn ProcMacroExpander {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
index d1a1e13..f903b06 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
@@ -91,7 +91,7 @@ fn from(value: MirEvalError) -> Self {
pub(crate) fn path_to_const<'g>(
db: &dyn HirDatabase,
- resolver: &Resolver,
+ resolver: &Resolver<'_>,
path: &Path,
mode: ParamLoweringMode,
args: impl FnOnce() -> &'g Generics,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
index 5710641..e4a23cb 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
@@ -480,7 +480,7 @@ struct FilterMapNextChecker {
}
impl FilterMapNextChecker {
- fn new(resolver: &hir_def::resolver::Resolver, db: &dyn HirDatabase) -> Self {
+ fn new(resolver: &hir_def::resolver::Resolver<'_>, db: &dyn HirDatabase) -> Self {
// Find and store the FunctionIds for Iterator::filter_map and Iterator::next
let (next_function_id, filter_map_function_id) = match LangItem::IteratorNext
.resolve_function(db, resolver.krate())
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
index 068fc22..785277d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
@@ -73,7 +73,7 @@ pub(crate) struct MatchCheckCtx<'db> {
impl<'db> MatchCheckCtx<'db> {
pub(crate) fn new(module: ModuleId, body: DefWithBodyId, db: &'db dyn HirDatabase) -> Self {
- let def_map = db.crate_def_map(module.krate());
+ let def_map = module.crate_def_map(db);
let exhaustive_patterns = def_map.is_unstable_feature_enabled(&sym::exhaustive_patterns);
Self { module, body, db, exhaustive_patterns }
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
index 73b99db..20cf3c7 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
@@ -7,7 +7,7 @@
use hir_def::{
AdtId, DefWithBodyId, FieldId, FunctionId, VariantId,
expr_store::{Body, path::Path},
- hir::{Expr, ExprId, ExprOrPatId, Pat, PatId, Statement, UnaryOp},
+ hir::{AsmOperand, Expr, ExprId, ExprOrPatId, Pat, PatId, Statement, UnaryOp},
resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs},
signatures::StaticFlags,
type_ref::Rawness,
@@ -131,28 +131,28 @@ pub fn unsafe_operations(
visitor.walk_expr(current);
}
-struct UnsafeVisitor<'a> {
- db: &'a dyn HirDatabase,
- infer: &'a InferenceResult,
- body: &'a Body,
- resolver: Resolver,
+struct UnsafeVisitor<'db> {
+ db: &'db dyn HirDatabase,
+ infer: &'db InferenceResult,
+ body: &'db Body,
+ resolver: Resolver<'db>,
def: DefWithBodyId,
inside_unsafe_block: InsideUnsafeBlock,
inside_assignment: bool,
inside_union_destructure: bool,
- callback: &'a mut dyn FnMut(UnsafeDiagnostic),
+ callback: &'db mut dyn FnMut(UnsafeDiagnostic),
def_target_features: TargetFeatures,
// FIXME: This needs to be the edition of the span of each call.
edition: Edition,
}
-impl<'a> UnsafeVisitor<'a> {
+impl<'db> UnsafeVisitor<'db> {
fn new(
- db: &'a dyn HirDatabase,
- infer: &'a InferenceResult,
- body: &'a Body,
+ db: &'db dyn HirDatabase,
+ infer: &'db InferenceResult,
+ body: &'db Body,
def: DefWithBodyId,
- unsafe_expr_cb: &'a mut dyn FnMut(UnsafeDiagnostic),
+ unsafe_expr_cb: &'db mut dyn FnMut(UnsafeDiagnostic),
) -> Self {
let resolver = def.resolver(db);
let def_target_features = match def {
@@ -199,6 +199,17 @@ fn check_call(&mut self, node: ExprId, func: FunctionId) {
}
}
+ fn with_inside_unsafe_block<R>(
+ &mut self,
+ inside_unsafe_block: InsideUnsafeBlock,
+ f: impl FnOnce(&mut Self) -> R,
+ ) -> R {
+ let old = mem::replace(&mut self.inside_unsafe_block, inside_unsafe_block);
+ let result = f(self);
+ self.inside_unsafe_block = old;
+ result
+ }
+
fn walk_pats_top(&mut self, pats: impl Iterator<Item = PatId>, parent_expr: ExprId) {
let guard = self.resolver.update_to_inner_scope(self.db, self.def, parent_expr);
pats.for_each(|pat| self.walk_pat(pat));
@@ -303,7 +314,29 @@ fn walk_expr(&mut self, current: ExprId) {
self.walk_pats_top(std::iter::once(target), current);
self.inside_assignment = old_inside_assignment;
}
- Expr::InlineAsm(_) => self.on_unsafe_op(current.into(), UnsafetyReason::InlineAsm),
+ Expr::InlineAsm(asm) => {
+ self.on_unsafe_op(current.into(), UnsafetyReason::InlineAsm);
+ asm.operands.iter().for_each(|(_, op)| match op {
+ AsmOperand::In { expr, .. }
+ | AsmOperand::Out { expr: Some(expr), .. }
+ | AsmOperand::InOut { expr, .. }
+ | AsmOperand::Const(expr) => self.walk_expr(*expr),
+ AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
+ self.walk_expr(*in_expr);
+ if let Some(out_expr) = out_expr {
+ self.walk_expr(*out_expr);
+ }
+ }
+ AsmOperand::Out { expr: None, .. } | AsmOperand::Sym(_) => (),
+ AsmOperand::Label(expr) => {
+ // Inline asm labels are considered safe even when inside unsafe blocks.
+ self.with_inside_unsafe_block(InsideUnsafeBlock::No, |this| {
+ this.walk_expr(*expr)
+ });
+ }
+ });
+ return;
+ }
// rustc allows union assignment to propagate through field accesses and casts.
Expr::Cast { .. } => self.inside_assignment = inside_assignment,
Expr::Field { .. } => {
@@ -317,17 +350,16 @@ fn walk_expr(&mut self, current: ExprId) {
}
}
Expr::Unsafe { statements, .. } => {
- let old_inside_unsafe_block =
- mem::replace(&mut self.inside_unsafe_block, InsideUnsafeBlock::Yes);
- self.walk_pats_top(
- statements.iter().filter_map(|statement| match statement {
- &Statement::Let { pat, .. } => Some(pat),
- _ => None,
- }),
- current,
- );
- self.body.walk_child_exprs_without_pats(current, |child| self.walk_expr(child));
- self.inside_unsafe_block = old_inside_unsafe_block;
+ self.with_inside_unsafe_block(InsideUnsafeBlock::Yes, |this| {
+ this.walk_pats_top(
+ statements.iter().filter_map(|statement| match statement {
+ &Statement::Let { pat, .. } => Some(pat),
+ _ => None,
+ }),
+ current,
+ );
+ this.body.walk_child_exprs_without_pats(current, |child| this.walk_expr(child));
+ });
return;
}
Expr::Block { statements, .. } | Expr::Async { statements, .. } => {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
index 106b996..ed8d8dc 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
@@ -9,8 +9,8 @@
};
use chalk_solve::rust_ir::InlineBound;
use hir_def::{
- AssocItemId, ConstId, FunctionId, GenericDefId, HasModule, TraitId, TypeAliasId,
- lang_item::LangItem, signatures::TraitFlags,
+ AssocItemId, ConstId, CrateRootModuleId, FunctionId, GenericDefId, HasModule, TraitId,
+ TypeAliasId, lang_item::LangItem, signatures::TraitFlags,
};
use rustc_hash::FxHashSet;
use smallvec::SmallVec;
@@ -343,7 +343,7 @@ fn dyn_compatibility_violation_for_assoc_item<F>(
})
}
AssocItemId::TypeAliasId(it) => {
- let def_map = db.crate_def_map(trait_.krate(db));
+ let def_map = CrateRootModuleId::from(trait_.krate(db)).def_map(db);
if def_map.is_unstable_feature_enabled(&intern::sym::generic_associated_type_extended) {
ControlFlow::Continue(())
} else {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
index f0ec31d..e698fb2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -594,16 +594,16 @@ fn index(&self, b: BindingId) -> &Ty {
/// The inference context contains all information needed during type inference.
#[derive(Clone, Debug)]
-pub(crate) struct InferenceContext<'a> {
- pub(crate) db: &'a dyn HirDatabase,
+pub(crate) struct InferenceContext<'db> {
+ pub(crate) db: &'db dyn HirDatabase,
pub(crate) owner: DefWithBodyId,
- pub(crate) body: &'a Body,
+ pub(crate) body: &'db Body,
/// Generally you should not resolve things via this resolver. Instead create a TyLoweringContext
/// and resolve the path via its methods. This will ensure proper error reporting.
- pub(crate) resolver: Resolver,
+ pub(crate) resolver: Resolver<'db>,
generic_def: GenericDefId,
generics: OnceCell<Generics>,
- table: unify::InferenceTable<'a>,
+ table: unify::InferenceTable<'db>,
/// The traits in scope, disregarding block modules. This is used for caching purposes.
traits_in_scope: FxHashSet<TraitId>,
pub(crate) result: InferenceResult,
@@ -695,12 +695,12 @@ enum ImplTraitReplacingMode {
TypeAlias,
}
-impl<'a> InferenceContext<'a> {
+impl<'db> InferenceContext<'db> {
fn new(
- db: &'a dyn HirDatabase,
+ db: &'db dyn HirDatabase,
owner: DefWithBodyId,
- body: &'a Body,
- resolver: Resolver,
+ body: &'db Body,
+ resolver: Resolver<'db>,
) -> Self {
let trait_env = db.trait_environment_for_body(owner);
InferenceContext {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs
index e3c4f55..003364d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs
@@ -61,7 +61,7 @@ impl<'a> InferenceTyLoweringContext<'a> {
#[inline]
pub(super) fn new(
db: &'a dyn HirDatabase,
- resolver: &'a Resolver,
+ resolver: &'a Resolver<'_>,
store: &'a ExpressionStore,
diagnostics: &'a Diagnostics,
source: InferenceTyDiagnosticSource,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
index 8084b39..87b7f34 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
@@ -959,8 +959,8 @@ fn infer_expr_inner(
}
Expr::OffsetOf(_) => TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner),
Expr::InlineAsm(asm) => {
- let mut check_expr_asm_operand = |expr, is_input: bool| {
- let ty = self.infer_expr_no_expect(expr, ExprIsRead::Yes);
+ let check_expr_asm_operand = |this: &mut Self, expr, is_input: bool| {
+ let ty = this.infer_expr_no_expect(expr, ExprIsRead::Yes);
// If this is an input value, we require its type to be fully resolved
// at this point. This allows us to provide helpful coercions which help
@@ -970,18 +970,18 @@ fn infer_expr_inner(
// allows them to be inferred based on how they are used later in the
// function.
if is_input {
- let ty = self.resolve_ty_shallow(&ty);
+ let ty = this.resolve_ty_shallow(&ty);
match ty.kind(Interner) {
TyKind::FnDef(def, parameters) => {
let fnptr_ty = TyKind::Function(
- CallableSig::from_def(self.db, *def, parameters).to_fn_ptr(),
+ CallableSig::from_def(this.db, *def, parameters).to_fn_ptr(),
)
.intern(Interner);
- _ = self.coerce(Some(expr), &ty, &fnptr_ty, CoerceNever::Yes);
+ _ = this.coerce(Some(expr), &ty, &fnptr_ty, CoerceNever::Yes);
}
TyKind::Ref(mutbl, _, base_ty) => {
let ptr_ty = TyKind::Raw(*mutbl, base_ty.clone()).intern(Interner);
- _ = self.coerce(Some(expr), &ty, &ptr_ty, CoerceNever::Yes);
+ _ = this.coerce(Some(expr), &ty, &ptr_ty, CoerceNever::Yes);
}
_ => {}
}
@@ -990,22 +990,28 @@ fn infer_expr_inner(
let diverge = asm.options.contains(AsmOptions::NORETURN);
asm.operands.iter().for_each(|(_, operand)| match *operand {
- AsmOperand::In { expr, .. } => check_expr_asm_operand(expr, true),
+ AsmOperand::In { expr, .. } => check_expr_asm_operand(self, expr, true),
AsmOperand::Out { expr: Some(expr), .. } | AsmOperand::InOut { expr, .. } => {
- check_expr_asm_operand(expr, false)
+ check_expr_asm_operand(self, expr, false)
}
AsmOperand::Out { expr: None, .. } => (),
AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
- check_expr_asm_operand(in_expr, true);
+ check_expr_asm_operand(self, in_expr, true);
if let Some(out_expr) = out_expr {
- check_expr_asm_operand(out_expr, false);
+ check_expr_asm_operand(self, out_expr, false);
}
}
- // FIXME
- AsmOperand::Label(_) => (),
- // FIXME
- AsmOperand::Const(_) => (),
- // FIXME
+ AsmOperand::Label(expr) => {
+ self.infer_expr(
+ expr,
+ &Expectation::HasType(self.result.standard_types.unit.clone()),
+ ExprIsRead::No,
+ );
+ }
+ AsmOperand::Const(expr) => {
+ self.infer_expr(expr, &Expectation::None, ExprIsRead::No);
+ }
+ // FIXME: `sym` should report for things that are not functions or statics.
AsmOperand::Sym(_) => (),
});
if diverge {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index 9def39d..ea8e7cc 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -42,7 +42,6 @@
use hir_expand::name::Name;
use la_arena::{Arena, ArenaMap};
use rustc_hash::FxHashSet;
-use rustc_pattern_analysis::Captures;
use stdx::{impl_from, never};
use triomphe::{Arc, ThinArc};
@@ -151,10 +150,10 @@ pub(crate) fn for_fn_ret() -> LifetimeElisionKind {
}
#[derive(Debug)]
-pub struct TyLoweringContext<'a> {
- pub db: &'a dyn HirDatabase,
- resolver: &'a Resolver,
- store: &'a ExpressionStore,
+pub struct TyLoweringContext<'db> {
+ pub db: &'db dyn HirDatabase,
+ resolver: &'db Resolver<'db>,
+ store: &'db ExpressionStore,
def: GenericDefId,
generics: OnceCell<Generics>,
in_binders: DebruijnIndex,
@@ -170,11 +169,11 @@ pub struct TyLoweringContext<'a> {
lifetime_elision: LifetimeElisionKind,
}
-impl<'a> TyLoweringContext<'a> {
+impl<'db> TyLoweringContext<'db> {
pub fn new(
- db: &'a dyn HirDatabase,
- resolver: &'a Resolver,
- store: &'a ExpressionStore,
+ db: &'db dyn HirDatabase,
+ resolver: &'db Resolver<'db>,
+ store: &'db ExpressionStore,
def: GenericDefId,
lifetime_elision: LifetimeElisionKind,
) -> Self {
@@ -1176,13 +1175,13 @@ fn generic_predicates_filtered_by<F>(
/// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound.
/// Exception is Self of a trait def.
-fn implicitly_sized_clauses<'a, 'subst: 'a>(
- db: &dyn HirDatabase,
+fn implicitly_sized_clauses<'db, 'a, 'subst: 'a>(
+ db: &'db dyn HirDatabase,
def: GenericDefId,
explicitly_unsized_tys: &'a FxHashSet<Ty>,
substitution: &'subst Substitution,
- resolver: &Resolver,
-) -> Option<impl Iterator<Item = WhereClause> + Captures<'a> + Captures<'subst>> {
+ resolver: &Resolver<'db>,
+) -> Option<impl Iterator<Item = WhereClause>> {
let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate()).map(to_chalk_trait_id)?;
let trait_self_idx = trait_self_param_idx(db, def);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
index 8e549ca..3b295d4 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
@@ -10,7 +10,7 @@
use hir_def::{
AssocItemId, BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup,
ModuleId, TraitId,
- nameres::{DefMap, assoc::ImplItems},
+ nameres::{DefMap, assoc::ImplItems, block_def_map, crate_def_map},
signatures::{ConstFlags, EnumFlags, FnFlags, StructFlags, TraitFlags, TypeAliasFlags},
};
use hir_expand::name::Name;
@@ -152,7 +152,7 @@ pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: Crate) ->
let _p = tracing::info_span!("trait_impls_in_crate_query", ?krate).entered();
let mut impls = FxHashMap::default();
- Self::collect_def_map(db, &mut impls, &db.crate_def_map(krate));
+ Self::collect_def_map(db, &mut impls, crate_def_map(db, krate));
Arc::new(Self::finish(impls))
}
@@ -164,7 +164,7 @@ pub(crate) fn trait_impls_in_block_query(
let _p = tracing::info_span!("trait_impls_in_block_query").entered();
let mut impls = FxHashMap::default();
- Self::collect_def_map(db, &mut impls, &db.block_def_map(block));
+ Self::collect_def_map(db, &mut impls, block_def_map(db, block));
if impls.is_empty() { None } else { Some(Arc::new(Self::finish(impls))) }
}
@@ -214,7 +214,7 @@ fn collect_def_map(db: &dyn HirDatabase, map: &mut TraitFpMapCollector, def_map:
for konst in module_data.scope.unnamed_consts() {
let body = db.body(konst.into());
for (_, block_def_map) in body.blocks(db) {
- Self::collect_def_map(db, map, &block_def_map);
+ Self::collect_def_map(db, map, block_def_map);
}
}
}
@@ -280,8 +280,8 @@ pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: Crate)
let _p = tracing::info_span!("inherent_impls_in_crate_query", ?krate).entered();
let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() };
- let crate_def_map = db.crate_def_map(krate);
- impls.collect_def_map(db, &crate_def_map);
+ let crate_def_map = crate_def_map(db, krate);
+ impls.collect_def_map(db, crate_def_map);
impls.shrink_to_fit();
Arc::new(impls)
@@ -294,8 +294,8 @@ pub(crate) fn inherent_impls_in_block_query(
let _p = tracing::info_span!("inherent_impls_in_block_query").entered();
let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() };
- let block_def_map = db.block_def_map(block);
- impls.collect_def_map(db, &block_def_map);
+ let block_def_map = block_def_map(db, block);
+ impls.collect_def_map(db, block_def_map);
impls.shrink_to_fit();
if impls.map.is_empty() && impls.invalid_impls.is_empty() {
@@ -337,7 +337,7 @@ fn collect_def_map(&mut self, db: &dyn HirDatabase, def_map: &DefMap) {
for konst in module_data.scope.unnamed_consts() {
let body = db.body(konst.into());
for (_, block_def_map) in body.blocks(db) {
- self.collect_def_map(db, &block_def_map);
+ self.collect_def_map(db, block_def_map);
}
}
}
@@ -1399,7 +1399,7 @@ fn iterate_inherent_methods(
)?;
}
- block = db.block_def_map(block_id).parent().and_then(|module| module.containing_block());
+ block = block_def_map(db, block_id).parent().and_then(|module| module.containing_block());
}
for krate in def_crates {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
index 26ef95d..7cf948b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
@@ -5,6 +5,7 @@
use chalk_ir::TyKind;
use hir_def::{
+ CrateRootModuleId,
builtin_type::{BuiltinInt, BuiltinUint},
resolver::HasResolver,
};
@@ -153,7 +154,7 @@ pub(super) fn detect_and_redirect_special_function(
) -> Result<Option<FunctionId>> {
// `PanicFmt` is redirected to `ConstPanicFmt`
if let Some(LangItem::PanicFmt) = self.db.lang_attr(def.into()) {
- let resolver = self.db.crate_def_map(self.crate_id).crate_root().resolver(self.db);
+ let resolver = CrateRootModuleId::from(self.crate_id).resolver(self.db);
let Some(const_panic_fmt) =
LangItem::ConstPanicFmt.resolve_function(self.db, resolver.krate())
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
index 7b48b15..7fcc89e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
@@ -68,16 +68,16 @@ struct DropScope {
locals: Vec<LocalId>,
}
-struct MirLowerCtx<'a> {
+struct MirLowerCtx<'db> {
result: MirBody,
owner: DefWithBodyId,
current_loop_blocks: Option<LoopBlocks>,
labeled_loop_blocks: FxHashMap<LabelId, LoopBlocks>,
discr_temp: Option<Place>,
- db: &'a dyn HirDatabase,
- body: &'a Body,
- infer: &'a InferenceResult,
- resolver: Resolver,
+ db: &'db dyn HirDatabase,
+ body: &'db Body,
+ infer: &'db InferenceResult,
+ resolver: Resolver<'db>,
drop_scopes: Vec<DropScope>,
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs
index bcd8aa6..8f0d17c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs
@@ -7,7 +7,7 @@
SourceRoot, SourceRootId, SourceRootInput,
};
-use hir_def::{ModuleId, db::DefDatabase};
+use hir_def::{ModuleId, db::DefDatabase, nameres::crate_def_map};
use hir_expand::EditionedFileId;
use rustc_hash::FxHashMap;
use salsa::{AsDynDatabase, Durability};
@@ -118,7 +118,7 @@ impl TestDB {
pub(crate) fn module_for_file_opt(&self, file_id: impl Into<FileId>) -> Option<ModuleId> {
let file_id = file_id.into();
for &krate in self.relevant_crates(file_id).iter() {
- let crate_def_map = self.crate_def_map(krate);
+ let crate_def_map = crate_def_map(self, krate);
for (local_id, data) in crate_def_map.modules() {
if data.origin.file_id().map(|file_id| file_id.file_id(self)) == Some(file_id) {
return Some(crate_def_map.module_id(local_id));
@@ -137,7 +137,7 @@ pub(crate) fn extract_annotations(
) -> FxHashMap<EditionedFileId, Vec<(TextRange, String)>> {
let mut files = Vec::new();
for &krate in self.all_crates().iter() {
- let crate_def_map = self.crate_def_map(krate);
+ let crate_def_map = crate_def_map(self, krate);
for (module_id, _) in crate_def_map.modules() {
let file_id = crate_def_map[module_id].origin.file_id();
files.extend(file_id)
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
index cc37f65..2b75bd6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
@@ -132,7 +132,7 @@ fn check_impl(
None => continue,
};
let def_map = module.def_map(&db);
- visit_module(&db, &def_map, module.local_id, &mut |it| {
+ visit_module(&db, def_map, module.local_id, &mut |it| {
let def = match it {
ModuleDefId::FunctionId(it) => it.into(),
ModuleDefId::EnumVariantId(it) => it.into(),
@@ -391,7 +391,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
let def_map = module.def_map(&db);
let mut defs: Vec<(DefWithBodyId, Crate)> = Vec::new();
- visit_module(&db, &def_map, module.local_id, &mut |it| {
+ visit_module(&db, def_map, module.local_id, &mut |it| {
let def = match it {
ModuleDefId::FunctionId(it) => it.into(),
ModuleDefId::EnumVariantId(it) => it.into(),
@@ -504,7 +504,7 @@ fn visit_scope(
fn visit_body(db: &TestDB, body: &Body, cb: &mut dyn FnMut(ModuleDefId)) {
for (_, def_map) in body.blocks(db) {
for (mod_id, _) in def_map.modules() {
- visit_module(db, &def_map, mod_id, cb);
+ visit_module(db, def_map, mod_id, cb);
}
}
}
@@ -570,7 +570,7 @@ fn main() {
let module = db.module_for_file(pos.file_id.file_id(&db));
let crate_def_map = module.def_map(&db);
- visit_module(&db, &crate_def_map, module.local_id, &mut |def| {
+ visit_module(&db, crate_def_map, module.local_id, &mut |def| {
db.infer(match def {
ModuleDefId::FunctionId(it) => it.into(),
ModuleDefId::EnumVariantId(it) => it.into(),
@@ -609,7 +609,7 @@ fn main() {
let module = db.module_for_file(pos.file_id.file_id(&db));
let crate_def_map = module.def_map(&db);
- visit_module(&db, &crate_def_map, module.local_id, &mut |def| {
+ visit_module(&db, crate_def_map, module.local_id, &mut |def| {
db.infer(match def {
ModuleDefId::FunctionId(it) => it.into(),
ModuleDefId::EnumVariantId(it) => it.into(),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs
index 73f1ae5..88d21be 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs
@@ -20,7 +20,7 @@ fn check_closure_captures(#[rust_analyzer::rust_fixture] ra_fixture: &str, expec
let def_map = module.def_map(&db);
let mut defs = Vec::new();
- visit_module(&db, &def_map, module.local_id, &mut |it| defs.push(it));
+ visit_module(&db, def_map, module.local_id, &mut |it| defs.push(it));
let mut captures_info = Vec::new();
for def in defs {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
index 0542be0..48474d2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
@@ -19,7 +19,7 @@ fn foo() -> i32 {
let events = db.log_executed(|| {
let module = db.module_for_file(pos.file_id.file_id(&db));
let crate_def_map = module.def_map(&db);
- visit_module(&db, &crate_def_map, module.local_id, &mut |def| {
+ visit_module(&db, crate_def_map, module.local_id, &mut |def| {
if let ModuleDefId::FunctionId(it) = def {
db.infer(it.into());
}
@@ -41,7 +41,7 @@ fn foo() -> i32 {
let events = db.log_executed(|| {
let module = db.module_for_file(pos.file_id.file_id(&db));
let crate_def_map = module.def_map(&db);
- visit_module(&db, &crate_def_map, module.local_id, &mut |def| {
+ visit_module(&db, crate_def_map, module.local_id, &mut |def| {
if let ModuleDefId::FunctionId(it) = def {
db.infer(it.into());
}
@@ -70,7 +70,7 @@ fn baz() -> i32 {
let events = db.log_executed(|| {
let module = db.module_for_file(pos.file_id.file_id(&db));
let crate_def_map = module.def_map(&db);
- visit_module(&db, &crate_def_map, module.local_id, &mut |def| {
+ visit_module(&db, crate_def_map, module.local_id, &mut |def| {
if let ModuleDefId::FunctionId(it) = def {
db.infer(it.into());
}
@@ -97,7 +97,7 @@ fn baz() -> i32 {
let events = db.log_executed(|| {
let module = db.module_for_file(pos.file_id.file_id(&db));
let crate_def_map = module.def_map(&db);
- visit_module(&db, &crate_def_map, module.local_id, &mut |def| {
+ visit_module(&db, crate_def_map, module.local_id, &mut |def| {
if let ModuleDefId::FunctionId(it) = def {
db.infer(it.into());
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
index 446f0b2..ea7a113 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
@@ -1505,6 +1505,10 @@ fn main() {
!119..120 'o': i32
293..294 'o': i32
308..317 'thread_id': usize
+ !314..320 'OffPtr': usize
+ !333..338 'OffFn': usize
+ !354..355 '0': i32
+ !371..382 'MEM_RELEASE': usize
"#]],
)
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
index eeebe38..cf51671 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
@@ -3902,3 +3902,66 @@ fn main() {
"#]],
);
}
+
+#[test]
+fn regression_19734() {
+ check_infer(
+ r#"
+trait Foo {
+ type Gat<'o>;
+}
+
+trait Bar {
+ fn baz() -> <Self::Xyz as Foo::Gat<'_>>;
+}
+
+fn foo<T: Bar>() {
+ T::baz();
+}
+ "#,
+ expect![[r#"
+ 110..127 '{ ...z(); }': ()
+ 116..122 'T::baz': fn baz<T>() -> <{unknown} as Foo>::Gat<'?>
+ 116..124 'T::baz()': Foo::Gat<'?, {unknown}>
+ "#]],
+ );
+}
+
+#[test]
+fn asm_const_label() {
+ check_infer(
+ r#"
+//- minicore: asm
+const fn bar() -> i32 { 123 }
+fn baz(s: &str) {}
+
+fn foo() {
+ unsafe {
+ core::arch::asm!(
+ "mov eax, {}",
+ "jmp {}",
+ const bar(),
+ label {
+ baz("hello");
+ },
+ );
+ }
+}
+ "#,
+ expect![[r#"
+ 22..29 '{ 123 }': i32
+ 24..27 '123': i32
+ 37..38 's': &'? str
+ 46..48 '{}': ()
+ !0..68 'builti...");},)': ()
+ !40..43 'bar': fn bar() -> i32
+ !40..45 'bar()': i32
+ !51..66 '{baz("hello");}': ()
+ !52..55 'baz': fn baz(&'? str)
+ !52..64 'baz("hello")': ()
+ !56..63 '"hello"': &'static str
+ 59..257 '{ ... } }': ()
+ 65..255 'unsafe... }': ()
+ "#]],
+ );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
index 1413760..2b527a4 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
@@ -4884,3 +4884,22 @@ async fn baz<T: AsyncFnOnce(u32) -> i32>(c: T) {
"#]],
);
}
+
+#[test]
+fn import_trait_items() {
+ check_infer(
+ r#"
+//- minicore: default
+use core::default::Default::default;
+fn main() {
+ let a: i32 = default();
+}
+ "#,
+ expect![[r#"
+ 47..78 '{ ...t(); }': ()
+ 57..58 'a': i32
+ 66..73 'default': {unknown}
+ 66..75 'default()': i32
+ "#]],
+ );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs
index 6e1cd9a..d6b43ae 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs
@@ -984,7 +984,7 @@ fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected: Expect) {
let mut defs: Vec<GenericDefId> = Vec::new();
let module = db.module_for_file_opt(file_id.file_id(&db)).unwrap();
let def_map = module.def_map(&db);
- crate::tests::visit_module(&db, &def_map, module.local_id, &mut |it| {
+ crate::tests::visit_module(&db, def_map, module.local_id, &mut |it| {
defs.push(match it {
ModuleDefId::FunctionId(it) => it.into(),
ModuleDefId::AdtId(it) => it.into(),
diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs
index b1c478d..b1cf30b 100644
--- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs
@@ -105,11 +105,12 @@ fn attr_id(self) -> AttrDefId {
/// Resolves the item `link` points to in the scope of `def`.
pub fn resolve_doc_path_on(
db: &dyn HirDatabase,
- def: impl HasAttrs,
+ def: impl HasAttrs + Copy,
link: &str,
ns: Option<Namespace>,
+ is_inner_doc: bool,
) -> Option<DocLinkDef> {
- resolve_doc_path_on_(db, link, def.attr_id(), ns)
+ resolve_doc_path_on_(db, link, def.attr_id(), ns, is_inner_doc)
}
fn resolve_doc_path_on_(
@@ -117,9 +118,18 @@ fn resolve_doc_path_on_(
link: &str,
attr_id: AttrDefId,
ns: Option<Namespace>,
+ is_inner_doc: bool,
) -> Option<DocLinkDef> {
let resolver = match attr_id {
- AttrDefId::ModuleId(it) => it.resolver(db),
+ AttrDefId::ModuleId(it) => {
+ if is_inner_doc {
+ it.resolver(db)
+ } else if let Some(parent) = Module::from(it).parent(db) {
+ parent.id.resolver(db)
+ } else {
+ it.resolver(db)
+ }
+ }
AttrDefId::FieldId(it) => it.parent.resolver(db),
AttrDefId::AdtId(it) => it.resolver(db),
AttrDefId::FunctionId(it) => it.resolver(db),
@@ -160,7 +170,7 @@ fn resolve_doc_path_on_(
fn resolve_assoc_or_field(
db: &dyn HirDatabase,
- resolver: Resolver,
+ resolver: Resolver<'_>,
path: ModPath,
name: Name,
ns: Option<Namespace>,
@@ -248,7 +258,7 @@ fn resolve_assoc_item(
fn resolve_impl_trait_item(
db: &dyn HirDatabase,
- resolver: Resolver,
+ resolver: Resolver<'_>,
ty: &Type,
name: &Name,
ns: Option<Namespace>,
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index 3f1d5bb..3a91050 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -97,7 +97,8 @@
diagnostics::*,
has_source::HasSource,
semantics::{
- PathResolution, Semantics, SemanticsImpl, SemanticsScope, TypeInfo, VisibleTraits,
+ PathResolution, PathResolutionPerNs, Semantics, SemanticsImpl, SemanticsScope, TypeInfo,
+ VisibleTraits,
},
};
@@ -119,7 +120,7 @@
find_path::PrefixKind,
import_map,
lang_item::LangItem,
- nameres::{DefMap, ModuleSource},
+ nameres::{DefMap, ModuleSource, crate_def_map},
per_ns::Namespace,
type_ref::{Mutability, TypeRef},
visibility::Visibility,
@@ -227,7 +228,7 @@ pub fn root_module(self) -> Module {
}
pub fn modules(self, db: &dyn HirDatabase) -> Vec<Module> {
- let def_map = db.crate_def_map(self.id);
+ let def_map = crate_def_map(db, self.id);
def_map.modules().map(|(id, _)| def_map.module_id(id).into()).collect()
}
@@ -528,7 +529,7 @@ pub fn krate(self) -> Crate {
/// might be missing `krate`. This can happen if a module's file is not included
/// in the module tree of any target in `Cargo.toml`.
pub fn crate_root(self, db: &dyn HirDatabase) -> Module {
- let def_map = db.crate_def_map(self.id.krate());
+ let def_map = crate_def_map(db, self.id.krate());
Module { id: def_map.crate_root().into() }
}
@@ -2468,7 +2469,7 @@ pub fn as_proc_macro(self, db: &dyn HirDatabase) -> Option<Macro> {
{
return None;
}
- let def_map = db.crate_def_map(HasModule::krate(&self.id, db));
+ let def_map = crate_def_map(db, HasModule::krate(&self.id, db));
def_map.fn_as_proc_macro(self.id).map(|id| Macro { id: id.into() })
}
@@ -4015,8 +4016,7 @@ pub(crate) fn by_name(db: &dyn HirDatabase, krate: Crate, name: &str) -> Option<
if let builtin @ Some(_) = Self::builtin(name) {
return builtin;
}
- let idx = db
- .crate_def_map(krate.id)
+ let idx = crate_def_map(db, krate.id)
.registered_attrs()
.iter()
.position(|it| it.as_str() == name)? as u32;
@@ -4031,7 +4031,7 @@ fn builtin(name: &str) -> Option<Self> {
pub fn name(&self, db: &dyn HirDatabase) -> Name {
match self.krate {
Some(krate) => Name::new_symbol_root(
- db.crate_def_map(krate).registered_attrs()[self.idx as usize].clone(),
+ crate_def_map(db, krate).registered_attrs()[self.idx as usize].clone(),
),
None => Name::new_symbol_root(Symbol::intern(
hir_expand::inert_attr_macro::INERT_ATTRIBUTES[self.idx as usize].name,
@@ -4059,14 +4059,14 @@ impl ToolModule {
pub(crate) fn by_name(db: &dyn HirDatabase, krate: Crate, name: &str) -> Option<Self> {
let krate = krate.id;
let idx =
- db.crate_def_map(krate).registered_tools().iter().position(|it| it.as_str() == name)?
+ crate_def_map(db, krate).registered_tools().iter().position(|it| it.as_str() == name)?
as u32;
Some(ToolModule { krate, idx })
}
pub fn name(&self, db: &dyn HirDatabase) -> Name {
Name::new_symbol_root(
- db.crate_def_map(self.krate).registered_tools()[self.idx as usize].clone(),
+ crate_def_map(db, self.krate).registered_tools()[self.idx as usize].clone(),
)
}
@@ -4488,7 +4488,7 @@ pub fn as_builtin_derive_path(self, db: &dyn HirDatabase) -> Option<InMacroFile<
MacroCallKind::Derive { ast_id, derive_attr_index, derive_index, .. } => {
let module_id = self.id.lookup(db).container;
(
- db.crate_def_map(module_id.krate())[module_id.local_id]
+ crate_def_map(db, module_id.krate())[module_id.local_id]
.scope
.derive_macro_invoc(ast_id, derive_attr_index)?,
derive_index,
@@ -4530,7 +4530,7 @@ pub struct TraitRef {
impl TraitRef {
pub(crate) fn new_with_resolver(
db: &dyn HirDatabase,
- resolver: &Resolver,
+ resolver: &Resolver<'_>,
trait_ref: hir_ty::TraitRef,
) -> TraitRef {
let env = resolver
@@ -4752,13 +4752,13 @@ pub struct Type {
}
impl Type {
- pub(crate) fn new_with_resolver(db: &dyn HirDatabase, resolver: &Resolver, ty: Ty) -> Type {
+ pub(crate) fn new_with_resolver(db: &dyn HirDatabase, resolver: &Resolver<'_>, ty: Ty) -> Type {
Type::new_with_resolver_inner(db, resolver, ty)
}
pub(crate) fn new_with_resolver_inner(
db: &dyn HirDatabase,
- resolver: &Resolver,
+ resolver: &Resolver<'_>,
ty: Ty,
) -> Type {
let environment = resolver
@@ -6400,7 +6400,7 @@ pub fn resolve_absolute_path<'a, I: Iterator<Item = Symbol> + Clone + 'a>(
})
.filter_map(|&krate| {
let segments = segments.clone();
- let mut def_map = db.crate_def_map(krate);
+ let mut def_map = crate_def_map(db, krate);
let mut module = &def_map[DefMap::ROOT];
let mut segments = segments.with_position().peekable();
while let Some((_, segment)) = segments.next_if(|&(position, _)| {
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index 4d092c1..caa6700 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -15,7 +15,7 @@
DefWithBodyId, FunctionId, MacroId, StructId, TraitId, VariantId,
expr_store::{Body, ExprOrPatSource, path::Path},
hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat},
- nameres::ModuleOrigin,
+ nameres::{ModuleOrigin, crate_def_map},
resolver::{self, HasResolver, Resolver, TypeNs},
type_ref::Mutability,
};
@@ -103,6 +103,26 @@ pub(crate) fn in_type_ns(&self) -> Option<TypeNs> {
}
}
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct PathResolutionPerNs {
+ pub type_ns: Option<PathResolution>,
+ pub value_ns: Option<PathResolution>,
+ pub macro_ns: Option<PathResolution>,
+}
+
+impl PathResolutionPerNs {
+ pub fn new(
+ type_ns: Option<PathResolution>,
+ value_ns: Option<PathResolution>,
+ macro_ns: Option<PathResolution>,
+ ) -> Self {
+ PathResolutionPerNs { type_ns, value_ns, macro_ns }
+ }
+ pub fn any(&self) -> Option<PathResolution> {
+ self.type_ns.or(self.value_ns).or(self.macro_ns)
+ }
+}
+
#[derive(Debug)]
pub struct TypeInfo {
/// The original type of the expression or pattern.
@@ -341,7 +361,7 @@ pub fn find_parent_file(&self, file_id: HirFileId) -> Option<InFile<SyntaxNode>>
match file_id {
HirFileId::FileId(file_id) => {
let module = self.file_to_module_defs(file_id.file_id(self.db)).next()?;
- let def_map = self.db.crate_def_map(module.krate().id);
+ let def_map = crate_def_map(self.db, module.krate().id);
match def_map[module.id.local_id].origin {
ModuleOrigin::CrateRoot { .. } => None,
ModuleOrigin::File { declaration, declaration_tree_id, .. } => {
@@ -1606,6 +1626,10 @@ pub fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> {
self.resolve_path_with_subst(path).map(|(it, _)| it)
}
+ pub fn resolve_path_per_ns(&self, path: &ast::Path) -> Option<PathResolutionPerNs> {
+ self.analyze(path.syntax())?.resolve_hir_path_per_ns(self.db, path)
+ }
+
pub fn resolve_path_with_subst(
&self,
path: &ast::Path,
@@ -1711,13 +1735,13 @@ pub fn body_for(&self, node: InFile<&SyntaxNode>) -> Option<DefWithBody> {
}
/// Returns none if the file of the node is not part of a crate.
- fn analyze(&self, node: &SyntaxNode) -> Option<SourceAnalyzer> {
+ fn analyze(&self, node: &SyntaxNode) -> Option<SourceAnalyzer<'db>> {
let node = self.find_file(node);
self.analyze_impl(node, None, true)
}
/// Returns none if the file of the node is not part of a crate.
- fn analyze_no_infer(&self, node: &SyntaxNode) -> Option<SourceAnalyzer> {
+ fn analyze_no_infer(&self, node: &SyntaxNode) -> Option<SourceAnalyzer<'db>> {
let node = self.find_file(node);
self.analyze_impl(node, None, false)
}
@@ -1726,7 +1750,7 @@ fn analyze_with_offset_no_infer(
&self,
node: &SyntaxNode,
offset: TextSize,
- ) -> Option<SourceAnalyzer> {
+ ) -> Option<SourceAnalyzer<'db>> {
let node = self.find_file(node);
self.analyze_impl(node, Some(offset), false)
}
@@ -1737,7 +1761,7 @@ fn analyze_impl(
offset: Option<TextSize>,
// replace this, just make the inference result a `LazyCell`
infer_body: bool,
- ) -> Option<SourceAnalyzer> {
+ ) -> Option<SourceAnalyzer<'db>> {
let _p = tracing::info_span!("SemanticsImpl::analyze_impl").entered();
let container = self.with_ctx(|ctx| ctx.find_container(node))?;
@@ -1984,13 +2008,13 @@ fn find_root(node: &SyntaxNode) -> SyntaxNode {
/// Note that if you are wondering "what does this specific existing name mean?",
/// you'd better use the `resolve_` family of methods.
#[derive(Debug)]
-pub struct SemanticsScope<'a> {
- pub db: &'a dyn HirDatabase,
+pub struct SemanticsScope<'db> {
+ pub db: &'db dyn HirDatabase,
file_id: HirFileId,
- resolver: Resolver,
+ resolver: Resolver<'db>,
}
-impl SemanticsScope<'_> {
+impl<'db> SemanticsScope<'db> {
pub fn module(&self) -> Module {
Module { id: self.resolver.module() }
}
@@ -2006,7 +2030,7 @@ pub fn containing_function(&self) -> Option<Function> {
})
}
- pub(crate) fn resolver(&self) -> &Resolver {
+ pub(crate) fn resolver(&self) -> &Resolver<'db> {
&self.resolver
}
@@ -2133,7 +2157,7 @@ fn deref(&self) -> &Self::Target {
struct RenameConflictsVisitor<'a> {
db: &'a dyn HirDatabase,
owner: DefWithBodyId,
- resolver: Resolver,
+ resolver: Resolver<'a>,
body: &'a Body,
to_be_renamed: BindingId,
new_name: Symbol,
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
index 587c51d..172af45 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
@@ -96,6 +96,7 @@
keys::{self, Key},
},
hir::{BindingId, Expr, LabelId},
+ nameres::{block_def_map, crate_def_map},
};
use hir_expand::{
EditionedFileId, ExpansionInfo, HirFileId, InMacroFile, MacroCallId, attrs::AttrId,
@@ -180,7 +181,7 @@ impl SourceToDefCtx<'_, '_> {
for &crate_id in self.db.relevant_crates(file).iter() {
// Note: `mod` declarations in block modules cannot be supported here
- let crate_def_map = self.db.crate_def_map(crate_id);
+ let crate_def_map = crate_def_map(self.db, crate_id);
let n_mods = mods.len();
let modules = |file| {
crate_def_map
@@ -226,7 +227,7 @@ pub(super) fn module_to_def(&mut self, src: InFile<&ast::Module>) -> Option<Modu
let parent_module = match parent_declaration {
Some(Either::Right(parent_block)) => self
.block_to_def(parent_block.as_ref())
- .map(|block| self.db.block_def_map(block).root_module_id()),
+ .map(|block| block_def_map(self.db, block).root_module_id()),
Some(Either::Left(parent_declaration)) => {
self.module_to_def(parent_declaration.as_ref())
}
diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
index c1a75ce..ea21546 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -10,7 +10,9 @@
use crate::{
Adt, AssocItem, BindingMode, BuiltinAttr, BuiltinType, Callable, Const, DeriveHelper, Field,
Function, GenericSubstitution, Local, Macro, ModuleDef, Static, Struct, ToolModule, Trait,
- TraitAlias, TupleField, Type, TypeAlias, Variant, db::HirDatabase, semantics::PathResolution,
+ TraitAlias, TupleField, Type, TypeAlias, Variant,
+ db::HirDatabase,
+ semantics::{PathResolution, PathResolutionPerNs},
};
use either::Either;
use hir_def::{
@@ -24,7 +26,7 @@
},
hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat},
lang_item::LangItem,
- nameres::MacroSubNs,
+ nameres::{MacroSubNs, crate_def_map},
resolver::{HasResolver, Resolver, TypeNs, ValueNs, resolver_for_scope},
type_ref::{Mutability, TypeRefId},
};
@@ -57,9 +59,9 @@
/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
/// original source files. It should not be used inside the HIR itself.
#[derive(Debug)]
-pub(crate) struct SourceAnalyzer {
+pub(crate) struct SourceAnalyzer<'db> {
pub(crate) file_id: HirFileId,
- pub(crate) resolver: Resolver,
+ pub(crate) resolver: Resolver<'db>,
pub(crate) body_or_sig: Option<BodyOrSig>,
}
@@ -85,32 +87,32 @@ pub(crate) enum BodyOrSig {
},
}
-impl SourceAnalyzer {
+impl<'db> SourceAnalyzer<'db> {
pub(crate) fn new_for_body(
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
def: DefWithBodyId,
node: InFile<&SyntaxNode>,
offset: Option<TextSize>,
- ) -> SourceAnalyzer {
+ ) -> SourceAnalyzer<'db> {
Self::new_for_body_(db, def, node, offset, Some(db.infer(def)))
}
pub(crate) fn new_for_body_no_infer(
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
def: DefWithBodyId,
node: InFile<&SyntaxNode>,
offset: Option<TextSize>,
- ) -> SourceAnalyzer {
+ ) -> SourceAnalyzer<'db> {
Self::new_for_body_(db, def, node, offset, None)
}
pub(crate) fn new_for_body_(
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
def: DefWithBodyId,
node @ InFile { file_id, .. }: InFile<&SyntaxNode>,
offset: Option<TextSize>,
infer: Option<Arc<InferenceResult>>,
- ) -> SourceAnalyzer {
+ ) -> SourceAnalyzer<'db> {
let (body, source_map) = db.body_with_source_map(def);
let scopes = db.expr_scopes(def);
let scope = match offset {
@@ -134,11 +136,11 @@ pub(crate) fn new_for_body_(
}
pub(crate) fn new_generic_def(
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
def: GenericDefId,
InFile { file_id, .. }: InFile<&SyntaxNode>,
_offset: Option<TextSize>,
- ) -> SourceAnalyzer {
+ ) -> SourceAnalyzer<'db> {
let (_params, store, source_map) = db.generic_params_and_store_and_source_map(def);
let resolver = def.resolver(db);
SourceAnalyzer {
@@ -149,11 +151,11 @@ pub(crate) fn new_generic_def(
}
pub(crate) fn new_variant_body(
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
def: VariantId,
InFile { file_id, .. }: InFile<&SyntaxNode>,
_offset: Option<TextSize>,
- ) -> SourceAnalyzer {
+ ) -> SourceAnalyzer<'db> {
let (fields, source_map) = db.variant_fields_with_source_map(def);
let resolver = def.resolver(db);
SourceAnalyzer {
@@ -168,9 +170,9 @@ pub(crate) fn new_variant_body(
}
pub(crate) fn new_for_resolver(
- resolver: Resolver,
+ resolver: Resolver<'db>,
node: InFile<&SyntaxNode>,
- ) -> SourceAnalyzer {
+ ) -> SourceAnalyzer<'db> {
SourceAnalyzer { resolver, body_or_sig: None, file_id: node.file_id }
}
@@ -220,7 +222,7 @@ pub(crate) fn expansion(&self, node: InFile<&ast::MacroCall>) -> Option<MacroCal
self.store_sm()?.expansion(node)
}
- fn trait_environment(&self, db: &dyn HirDatabase) -> Arc<TraitEnvironment> {
+ fn trait_environment(&self, db: &'db dyn HirDatabase) -> Arc<TraitEnvironment> {
self.body_().map(|(def, ..)| def).map_or_else(
|| TraitEnvironment::empty(self.resolver.krate()),
|def| db.trait_environment_for_body(def),
@@ -259,7 +261,7 @@ pub(crate) fn expr_adjustments(&self, expr: &ast::Expr) -> Option<&[Adjustment]>
infer.expr_adjustments.get(&expr_id).map(|v| &**v)
}
- pub(crate) fn type_of_type(&self, db: &dyn HirDatabase, ty: &ast::Type) -> Option<Type> {
+ pub(crate) fn type_of_type(&self, db: &'db dyn HirDatabase, ty: &ast::Type) -> Option<Type> {
let type_ref = self.type_id(ty)?;
let ty = TyLoweringContext::new(
db,
@@ -277,7 +279,7 @@ pub(crate) fn type_of_type(&self, db: &dyn HirDatabase, ty: &ast::Type) -> Optio
pub(crate) fn type_of_expr(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
expr: &ast::Expr,
) -> Option<(Type, Option<Type>)> {
let expr_id = self.expr_id(expr.clone())?;
@@ -293,7 +295,7 @@ pub(crate) fn type_of_expr(
pub(crate) fn type_of_pat(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
pat: &ast::Pat,
) -> Option<(Type, Option<Type>)> {
let expr_or_pat_id = self.pat_id(pat)?;
@@ -316,7 +318,7 @@ pub(crate) fn type_of_pat(
pub(crate) fn type_of_binding_in_pat(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
pat: &ast::IdentPat,
) -> Option<Type> {
let binding_id = self.binding_id_of_pat(pat)?;
@@ -328,7 +330,7 @@ pub(crate) fn type_of_binding_in_pat(
pub(crate) fn type_of_self(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
_param: &ast::SelfParam,
) -> Option<Type> {
let binding = self.body()?.self_param?;
@@ -338,7 +340,7 @@ pub(crate) fn type_of_self(
pub(crate) fn binding_mode_of_pat(
&self,
- _db: &dyn HirDatabase,
+ _db: &'db dyn HirDatabase,
pat: &ast::IdentPat,
) -> Option<BindingMode> {
let id = self.pat_id(&pat.clone().into())?;
@@ -353,7 +355,7 @@ pub(crate) fn binding_mode_of_pat(
}
pub(crate) fn pattern_adjustments(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
pat: &ast::Pat,
) -> Option<SmallVec<[Type; 1]>> {
let pat_id = self.pat_id(pat)?;
@@ -370,7 +372,7 @@ pub(crate) fn pattern_adjustments(
pub(crate) fn resolve_method_call_as_callable(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
call: &ast::MethodCallExpr,
) -> Option<Callable> {
let expr_id = self.expr_id(call.clone().into())?.as_expr()?;
@@ -384,7 +386,7 @@ pub(crate) fn resolve_method_call_as_callable(
pub(crate) fn resolve_method_call(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
call: &ast::MethodCallExpr,
) -> Option<Function> {
let expr_id = self.expr_id(call.clone().into())?.as_expr()?;
@@ -395,7 +397,7 @@ pub(crate) fn resolve_method_call(
pub(crate) fn resolve_method_call_fallback(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
call: &ast::MethodCallExpr,
) -> Option<(Either<Function, Field>, Option<GenericSubstitution>)> {
let expr_id = self.expr_id(call.clone().into())?.as_expr()?;
@@ -419,7 +421,7 @@ pub(crate) fn resolve_method_call_fallback(
pub(crate) fn resolve_expr_as_callable(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
call: &ast::Expr,
) -> Option<Callable> {
let (orig, adjusted) = self.type_of_expr(db, &call.clone())?;
@@ -441,7 +443,7 @@ fn field_subst(
&self,
field_expr: ExprId,
infer: &InferenceResult,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
) -> Option<GenericSubstitution> {
let body = self.store()?;
if let Expr::Field { expr: object_expr, name: _ } = body[field_expr] {
@@ -457,7 +459,7 @@ fn field_subst(
pub(crate) fn resolve_field_fallback(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
field: &ast::FieldExpr,
) -> Option<(Either<Either<Field, TupleField>, Function>, Option<GenericSubstitution>)> {
let (def, ..) = self.body_()?;
@@ -490,7 +492,7 @@ pub(crate) fn resolve_field_fallback(
pub(crate) fn resolve_range_pat(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
range_pat: &ast::RangePat,
) -> Option<StructId> {
let path: ModPath = match (range_pat.op_kind()?, range_pat.start(), range_pat.end()) {
@@ -509,7 +511,7 @@ pub(crate) fn resolve_range_pat(
pub(crate) fn resolve_range_expr(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
range_expr: &ast::RangeExpr,
) -> Option<StructId> {
let path: ModPath = match (range_expr.op_kind()?, range_expr.start(), range_expr.end()) {
@@ -529,7 +531,7 @@ pub(crate) fn resolve_range_expr(
pub(crate) fn resolve_await_to_poll(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
await_expr: &ast::AwaitExpr,
) -> Option<FunctionId> {
let mut ty = self.ty_of_expr(await_expr.expr()?)?.clone();
@@ -566,7 +568,7 @@ pub(crate) fn resolve_await_to_poll(
pub(crate) fn resolve_prefix_expr(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
prefix_expr: &ast::PrefixExpr,
) -> Option<FunctionId> {
let (op_trait, op_fn) = match prefix_expr.op_kind()? {
@@ -608,7 +610,7 @@ pub(crate) fn resolve_prefix_expr(
pub(crate) fn resolve_index_expr(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
index_expr: &ast::IndexExpr,
) -> Option<FunctionId> {
let base_ty = self.ty_of_expr(index_expr.base()?)?;
@@ -640,7 +642,7 @@ pub(crate) fn resolve_index_expr(
pub(crate) fn resolve_bin_expr(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
binop_expr: &ast::BinExpr,
) -> Option<FunctionId> {
let op = binop_expr.op_kind()?;
@@ -661,7 +663,7 @@ pub(crate) fn resolve_bin_expr(
pub(crate) fn resolve_try_expr(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
try_expr: &ast::TryExpr,
) -> Option<FunctionId> {
let ty = self.ty_of_expr(try_expr.expr()?)?;
@@ -680,7 +682,7 @@ pub(crate) fn resolve_try_expr(
pub(crate) fn resolve_record_field(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
field: &ast::RecordExprField,
) -> Option<(Field, Option<Local>, Type, GenericSubstitution)> {
let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
@@ -724,7 +726,7 @@ pub(crate) fn resolve_record_field(
pub(crate) fn resolve_record_pat_field(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
field: &ast::RecordPatField,
) -> Option<(Field, Type, GenericSubstitution)> {
let field_name = field.field_name()?.as_name();
@@ -745,14 +747,14 @@ pub(crate) fn resolve_record_pat_field(
pub(crate) fn resolve_macro_call(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
macro_call: InFile<&ast::MacroCall>,
) -> Option<Macro> {
let bs = self.store_sm()?;
bs.expansion(macro_call).and_then(|it| {
// FIXME: Block def maps
let def = it.lookup(db).def;
- db.crate_def_map(def.krate)
+ crate_def_map(db, def.krate)
.macro_def_to_macro_id
.get(&def.kind.erased_ast_id())
.map(|it| (*it).into())
@@ -761,7 +763,7 @@ pub(crate) fn resolve_macro_call(
pub(crate) fn resolve_bind_pat_to_const(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
pat: &ast::IdentPat,
) -> Option<ModuleDef> {
let expr_or_pat_id = self.pat_id(&pat.clone().into())?;
@@ -795,7 +797,7 @@ pub(crate) fn resolve_use_type_arg(&self, name: &ast::NameRef) -> Option<crate::
pub(crate) fn resolve_offset_of_field(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
name_ref: &ast::NameRef,
) -> Option<(Either<crate::Variant, crate::Field>, GenericSubstitution)> {
let offset_of_expr = ast::OffsetOfExpr::cast(name_ref.syntax().parent()?)?;
@@ -867,7 +869,7 @@ pub(crate) fn resolve_offset_of_field(
pub(crate) fn resolve_path(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
path: &ast::Path,
) -> Option<(PathResolution, Option<GenericSubstitution>)> {
let parent = path.syntax().parent();
@@ -1159,7 +1161,9 @@ pub(crate) fn resolve_path(
prefer_value_ns,
name_hygiene(db, InFile::new(self.file_id, path.syntax())),
Some(&store),
- )?;
+ false,
+ )
+ .any()?;
let subst = (|| {
let parent = parent()?;
let ty = if let Some(expr) = ast::Expr::cast(parent.clone()) {
@@ -1209,9 +1213,29 @@ pub(crate) fn resolve_path(
}
}
- pub(crate) fn record_literal_missing_fields(
+ pub(crate) fn resolve_hir_path_per_ns(
&self,
db: &dyn HirDatabase,
+ path: &ast::Path,
+ ) -> Option<PathResolutionPerNs> {
+ let mut collector = ExprCollector::new(db, self.resolver.module(), self.file_id);
+ let hir_path =
+ collector.lower_path(path.clone(), &mut ExprCollector::impl_trait_error_allocator)?;
+ let store = collector.store.finish();
+ Some(resolve_hir_path_(
+ db,
+ &self.resolver,
+ &hir_path,
+ false,
+ name_hygiene(db, InFile::new(self.file_id, path.syntax())),
+ Some(&store),
+ true,
+ ))
+ }
+
+ pub(crate) fn record_literal_missing_fields(
+ &self,
+ db: &'db dyn HirDatabase,
literal: &ast::RecordExpr,
) -> Option<Vec<(Field, Type)>> {
let body = self.store()?;
@@ -1234,7 +1258,7 @@ pub(crate) fn record_literal_missing_fields(
pub(crate) fn record_pattern_missing_fields(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
pattern: &ast::RecordPat,
) -> Option<Vec<(Field, Type)>> {
let body = self.store()?;
@@ -1251,7 +1275,7 @@ pub(crate) fn record_pattern_missing_fields(
fn missing_fields(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
substs: &Substitution,
variant: VariantId,
missing_fields: Vec<LocalFieldId>,
@@ -1270,7 +1294,7 @@ fn missing_fields(
pub(crate) fn expand(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
macro_call: InFile<&ast::MacroCall>,
) -> Option<MacroCallId> {
self.store_sm().and_then(|bs| bs.expansion(macro_call)).or_else(|| {
@@ -1288,7 +1312,7 @@ pub(crate) fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<Vari
pub(crate) fn is_unsafe_macro_call_expr(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
macro_expr: InFile<&ast::MacroExpr>,
) -> bool {
if let Some((def, body, sm, Some(infer))) = self.body_() {
@@ -1313,7 +1337,7 @@ pub(crate) fn is_unsafe_macro_call_expr(
pub(crate) fn resolve_offset_in_format_args(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
format_args: InFile<&ast::FormatArgsExpr>,
offset: TextSize,
) -> Option<(TextRange, Option<PathResolution>)> {
@@ -1384,7 +1408,7 @@ pub(crate) fn as_asm_parts(
fn resolve_impl_method_or_trait_def(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
func: FunctionId,
substs: Substitution,
) -> FunctionId {
@@ -1393,7 +1417,7 @@ fn resolve_impl_method_or_trait_def(
fn resolve_impl_method_or_trait_def_with_subst(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
func: FunctionId,
substs: Substitution,
) -> (FunctionId, Substitution) {
@@ -1407,7 +1431,7 @@ fn resolve_impl_method_or_trait_def_with_subst(
fn resolve_impl_const_or_trait_def_with_subst(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
const_id: ConstId,
subs: Substitution,
) -> (ConstId, Substitution) {
@@ -1421,7 +1445,7 @@ fn resolve_impl_const_or_trait_def_with_subst(
fn lang_trait_fn(
&self,
- db: &dyn HirDatabase,
+ db: &'db dyn HirDatabase,
lang_trait: LangItem,
method_name: &Name,
) -> Option<(TraitId, FunctionId)> {
@@ -1527,18 +1551,18 @@ fn adjust(
#[inline]
pub(crate) fn resolve_hir_path(
db: &dyn HirDatabase,
- resolver: &Resolver,
+ resolver: &Resolver<'_>,
path: &Path,
hygiene: HygieneId,
store: Option<&ExpressionStore>,
) -> Option<PathResolution> {
- resolve_hir_path_(db, resolver, path, false, hygiene, store)
+ resolve_hir_path_(db, resolver, path, false, hygiene, store, false).any()
}
#[inline]
pub(crate) fn resolve_hir_path_as_attr_macro(
db: &dyn HirDatabase,
- resolver: &Resolver,
+ resolver: &Resolver<'_>,
path: &Path,
) -> Option<Macro> {
resolver
@@ -1549,12 +1573,13 @@ pub(crate) fn resolve_hir_path_as_attr_macro(
fn resolve_hir_path_(
db: &dyn HirDatabase,
- resolver: &Resolver,
+ resolver: &Resolver<'_>,
path: &Path,
prefer_value_ns: bool,
hygiene: HygieneId,
store: Option<&ExpressionStore>,
-) -> Option<PathResolution> {
+ resolve_per_ns: bool,
+) -> PathResolutionPerNs {
let types = || {
let (ty, unresolved) = match path.type_anchor() {
Some(type_ref) => resolver.generic_def().and_then(|def| {
@@ -1635,14 +1660,36 @@ fn resolve_hir_path_(
.map(|(def, _)| PathResolution::Def(ModuleDef::Macro(def.into())))
};
- if prefer_value_ns { values().or_else(types) } else { types().or_else(values) }
- .or_else(items)
- .or_else(macros)
+ if resolve_per_ns {
+ PathResolutionPerNs {
+ type_ns: types().or_else(items),
+ value_ns: values(),
+ macro_ns: macros(),
+ }
+ } else {
+ let res = if prefer_value_ns {
+ values()
+ .map(|value_ns| PathResolutionPerNs::new(None, Some(value_ns), None))
+ .unwrap_or_else(|| PathResolutionPerNs::new(types(), None, None))
+ } else {
+ types()
+ .map(|type_ns| PathResolutionPerNs::new(Some(type_ns), None, None))
+ .unwrap_or_else(|| PathResolutionPerNs::new(None, values(), None))
+ };
+
+ if res.any().is_some() {
+ res
+ } else if let Some(type_ns) = items() {
+ PathResolutionPerNs::new(Some(type_ns), None, None)
+ } else {
+ PathResolutionPerNs::new(None, None, macros())
+ }
+ }
}
fn resolve_hir_value_path(
db: &dyn HirDatabase,
- resolver: &Resolver,
+ resolver: &Resolver<'_>,
body_owner: Option<DefWithBodyId>,
path: &Path,
hygiene: HygieneId,
@@ -1680,7 +1727,7 @@ fn resolve_hir_value_path(
/// then we know that `foo` in `my::foo::Bar` refers to the module, not the function.
fn resolve_hir_path_qualifier(
db: &dyn HirDatabase,
- resolver: &Resolver,
+ resolver: &Resolver<'_>,
path: &Path,
store: &ExpressionStore,
) -> Option<PathResolution> {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs
index 7e8735b..a9df6f6 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs
@@ -1,3 +1,4 @@
+use either::Either;
use syntax::{
ast::{
self, AstNode, HasName, HasTypeBounds,
@@ -30,10 +31,11 @@ pub(crate) fn move_bounds_to_where_clause(
) -> Option<()> {
let type_param_list = ctx.find_node_at_offset::<ast::GenericParamList>()?;
- let mut type_params = type_param_list.type_or_const_params();
+ let mut type_params = type_param_list.generic_params();
if type_params.all(|p| match p {
- ast::TypeOrConstParam::Type(t) => t.type_bound_list().is_none(),
- ast::TypeOrConstParam::Const(_) => true,
+ ast::GenericParam::TypeParam(t) => t.type_bound_list().is_none(),
+ ast::GenericParam::LifetimeParam(l) => l.type_bound_list().is_none(),
+ ast::GenericParam::ConstParam(_) => true,
}) {
return None;
}
@@ -53,20 +55,23 @@ pub(crate) fn move_bounds_to_where_clause(
match parent {
ast::Fn(it) => it.get_or_create_where_clause(),
ast::Trait(it) => it.get_or_create_where_clause(),
+ ast::TraitAlias(it) => it.get_or_create_where_clause(),
ast::Impl(it) => it.get_or_create_where_clause(),
ast::Enum(it) => it.get_or_create_where_clause(),
ast::Struct(it) => it.get_or_create_where_clause(),
+ ast::TypeAlias(it) => it.get_or_create_where_clause(),
_ => return,
}
};
- for toc_param in type_param_list.type_or_const_params() {
- let type_param = match toc_param {
- ast::TypeOrConstParam::Type(x) => x,
- ast::TypeOrConstParam::Const(_) => continue,
+ for generic_param in type_param_list.generic_params() {
+ let param: &dyn HasTypeBounds = match &generic_param {
+ ast::GenericParam::TypeParam(t) => t,
+ ast::GenericParam::LifetimeParam(l) => l,
+ ast::GenericParam::ConstParam(_) => continue,
};
- if let Some(tbl) = type_param.type_bound_list() {
- if let Some(predicate) = build_predicate(type_param) {
+ if let Some(tbl) = param.type_bound_list() {
+ if let Some(predicate) = build_predicate(generic_param) {
where_clause.add_predicate(predicate)
}
tbl.remove()
@@ -76,9 +81,23 @@ pub(crate) fn move_bounds_to_where_clause(
)
}
-fn build_predicate(param: ast::TypeParam) -> Option<ast::WherePred> {
- let path = make::ext::ident_path(¶m.name()?.syntax().to_string());
- let predicate = make::where_pred(make::ty_path(path), param.type_bound_list()?.bounds());
+fn build_predicate(param: ast::GenericParam) -> Option<ast::WherePred> {
+ let target = match ¶m {
+ ast::GenericParam::TypeParam(t) => {
+ Either::Right(make::ty_path(make::ext::ident_path(&t.name()?.to_string())))
+ }
+ ast::GenericParam::LifetimeParam(l) => Either::Left(l.lifetime()?),
+ ast::GenericParam::ConstParam(_) => return None,
+ };
+ let predicate = make::where_pred(
+ target,
+ match param {
+ ast::GenericParam::TypeParam(t) => t.type_bound_list()?,
+ ast::GenericParam::LifetimeParam(l) => l.type_bound_list()?,
+ ast::GenericParam::ConstParam(_) => return None,
+ }
+ .bounds(),
+ );
Some(predicate.clone_for_update())
}
@@ -123,4 +142,13 @@ fn move_bounds_to_where_clause_tuple_struct() {
r#"struct Pair<T>(T, T) where T: u32;"#,
);
}
+
+ #[test]
+ fn move_bounds_to_where_clause_trait() {
+ check_assist(
+ move_bounds_to_where_clause,
+ r#"trait T<'a: 'static, $0T: u32> {}"#,
+ r#"trait T<'a, T> where 'a: 'static, T: u32 {}"#,
+ );
+ }
}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
index 1baf814..16debc4 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
@@ -1,6 +1,9 @@
use std::collections::hash_map::Entry;
-use hir::{FileRange, InFile, InRealFile, Module, ModuleSource};
+use hir::{
+ FileRange, InFile, InRealFile, Module, ModuleDef, ModuleSource, PathResolution,
+ PathResolutionPerNs,
+};
use ide_db::text_edit::TextRange;
use ide_db::{
FxHashMap, RootDatabase,
@@ -77,22 +80,17 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>)
};
// Get the actual definition associated with this use item.
- let res = match ctx.sema.resolve_path(&path) {
- Some(x) => x,
- None => {
+ let res = match ctx.sema.resolve_path_per_ns(&path) {
+ Some(x) if x.any().is_some() => x,
+ Some(_) | None => {
return None;
}
};
- let def = match res {
- hir::PathResolution::Def(d) => Definition::from(d),
- _ => return None,
- };
-
if u.star_token().is_some() {
// Check if any of the children of this module are used
- let def_mod = match def {
- Definition::Module(module) => module,
+ let def_mod = match res.type_ns {
+ Some(PathResolution::Def(ModuleDef::Module(module))) => module,
_ => return None,
};
@@ -105,21 +103,13 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>)
})
.any(|d| used_once_in_scope(ctx, d, u.rename(), scope))
{
- return Some(u);
+ Some(u)
+ } else {
+ None
}
- } else if let Definition::Trait(ref t) = def {
- // If the trait or any item is used.
- if !std::iter::once((def, u.rename()))
- .chain(t.items(ctx.db()).into_iter().map(|item| (item.into(), None)))
- .any(|(d, rename)| used_once_in_scope(ctx, d, rename, scope))
- {
- return Some(u);
- }
- } else if !used_once_in_scope(ctx, def, u.rename(), scope) {
- return Some(u);
+ } else {
+ is_path_per_ns_unused_in_scope(ctx, &u, scope, &res).then_some(u)
}
-
- None
})
.peekable();
@@ -141,6 +131,52 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>)
}
}
+fn is_path_per_ns_unused_in_scope(
+ ctx: &AssistContext<'_>,
+ u: &ast::UseTree,
+ scope: &mut Vec<SearchScope>,
+ path: &PathResolutionPerNs,
+) -> bool {
+ if let Some(PathResolution::Def(ModuleDef::Trait(ref t))) = path.type_ns {
+ if is_trait_unused_in_scope(ctx, u, scope, t) {
+ let path = [path.value_ns, path.macro_ns];
+ is_path_unused_in_scope(ctx, u, scope, &path)
+ } else {
+ false
+ }
+ } else {
+ let path = [path.type_ns, path.value_ns, path.macro_ns];
+ is_path_unused_in_scope(ctx, u, scope, &path)
+ }
+}
+
+fn is_path_unused_in_scope(
+ ctx: &AssistContext<'_>,
+ u: &ast::UseTree,
+ scope: &mut Vec<SearchScope>,
+ path: &[Option<PathResolution>],
+) -> bool {
+ !path
+ .iter()
+ .filter_map(|path| *path)
+ .filter_map(|res| match res {
+ PathResolution::Def(d) => Some(Definition::from(d)),
+ _ => None,
+ })
+ .any(|def| used_once_in_scope(ctx, def, u.rename(), scope))
+}
+
+fn is_trait_unused_in_scope(
+ ctx: &AssistContext<'_>,
+ u: &ast::UseTree,
+ scope: &mut Vec<SearchScope>,
+ t: &hir::Trait,
+) -> bool {
+ !std::iter::once((Definition::Trait(*t), u.rename()))
+ .chain(t.items(ctx.db()).into_iter().map(|item| (item.into(), None)))
+ .any(|(d, rename)| used_once_in_scope(ctx, d, rename, scope))
+}
+
fn used_once_in_scope(
ctx: &AssistContext<'_>,
def: Definition,
@@ -1012,4 +1048,110 @@ fn test(_: Bar) {
"#,
);
}
+
+ #[test]
+ fn test_unused_macro() {
+ check_assist(
+ remove_unused_imports,
+ r#"
+//- /foo.rs crate:foo
+#[macro_export]
+macro_rules! m { () => {} }
+
+//- /main.rs crate:main deps:foo
+use foo::m;$0
+fn main() {}
+"#,
+ r#"
+fn main() {}
+"#,
+ );
+
+ check_assist_not_applicable(
+ remove_unused_imports,
+ r#"
+//- /foo.rs crate:foo
+#[macro_export]
+macro_rules! m { () => {} }
+
+//- /main.rs crate:main deps:foo
+use foo::m;$0
+fn main() {
+ m!();
+}
+"#,
+ );
+
+ check_assist_not_applicable(
+ remove_unused_imports,
+ r#"
+//- /foo.rs crate:foo
+#[macro_export]
+macro_rules! m { () => {} }
+
+//- /bar.rs crate:bar deps:foo
+pub use foo::m;
+fn m() {}
+
+
+//- /main.rs crate:main deps:bar
+use bar::m;$0
+fn main() {
+ m!();
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn test_conflict_derive_macro() {
+ check_assist_not_applicable(
+ remove_unused_imports,
+ r#"
+//- proc_macros: derive_identity
+//- minicore: derive
+//- /bar.rs crate:bar
+pub use proc_macros::DeriveIdentity;
+pub trait DeriveIdentity {}
+
+//- /main.rs crate:main deps:bar
+$0use bar::DeriveIdentity;$0
+#[derive(DeriveIdentity)]
+struct S;
+"#,
+ );
+
+ check_assist_not_applicable(
+ remove_unused_imports,
+ r#"
+//- proc_macros: derive_identity
+//- minicore: derive
+//- /bar.rs crate:bar
+pub use proc_macros::DeriveIdentity;
+pub fn DeriveIdentity() {}
+
+//- /main.rs crate:main deps:bar
+$0use bar::DeriveIdentity;$0
+#[derive(DeriveIdentity)]
+struct S;
+"#,
+ );
+
+ check_assist_not_applicable(
+ remove_unused_imports,
+ r#"
+//- proc_macros: derive_identity
+//- minicore: derive
+//- /bar.rs crate:bar
+pub use proc_macros::DeriveIdentity;
+pub fn DeriveIdentity() {}
+
+//- /main.rs crate:main deps:bar
+$0use bar::DeriveIdentity;$0
+fn main() {
+ DeriveIdentity();
+}
+"#,
+ );
+ }
}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_type_to_generic_arg.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_type_to_generic_arg.rs
new file mode 100644
index 0000000..7b5adc1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_type_to_generic_arg.rs
@@ -0,0 +1,156 @@
+use ide_db::assists::AssistId;
+use syntax::{
+ AstNode,
+ ast::{self, GenericArg, HasGenericArgs},
+};
+
+use crate::{AssistContext, Assists};
+
+// Assist: unwrap_type_to_generic_arg
+//
+// This assist unwraps a type into its generic type argument.
+//
+// ```
+// fn foo() -> $0Option<i32> {
+// todo!()
+// }
+// ```
+// ->
+// ```
+// fn foo() -> i32 {
+// todo!()
+// }
+// ```
+pub(crate) fn unwrap_type_to_generic_arg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+ let path_type = ctx.find_node_at_offset::<ast::PathType>()?;
+ let path = path_type.path()?;
+ let segment = path.segment()?;
+ let args_list = segment.generic_arg_list()?;
+
+ let mut generic_arg = None;
+
+ for arg in args_list.generic_args() {
+ match arg {
+ GenericArg::ConstArg(_) | GenericArg::LifetimeArg(_) => (),
+ GenericArg::TypeArg(arg) if generic_arg.is_none() => {
+ generic_arg = Some(arg);
+ }
+ _ => return None,
+ }
+ }
+
+ let generic_arg = generic_arg?;
+
+ acc.add(
+ AssistId::refactor_extract("unwrap_type_to_generic_arg"),
+ format!("Unwrap type to type argument {generic_arg}"),
+ path_type.syntax().text_range(),
+ |builder| {
+ let mut editor = builder.make_editor(path_type.syntax());
+ editor.replace(path_type.syntax(), generic_arg.syntax());
+
+ builder.add_file_edits(ctx.vfs_file_id(), editor);
+ },
+ )
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::tests::{check_assist, check_assist_not_applicable};
+
+ #[test]
+ fn test_unwrap_type_to_generic_arg() {
+ check_assist(
+ unwrap_type_to_generic_arg,
+ r#"
+//- minicore: option
+fn foo() -> $0Option<i32> {
+ todo!()
+}
+"#,
+ r#"
+fn foo() -> i32 {
+ todo!()
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn unwrap_type_to_generic_arg_not_applicable_for_non_generic_arg_list() {
+ check_assist_not_applicable(
+ unwrap_type_to_generic_arg,
+ r#"
+fn foo() -> $0i32 {}
+"#,
+ );
+ }
+
+ #[test]
+ fn unwrap_type_to_generic_arg_not_applicable_for_multiple_generic_args() {
+ check_assist_not_applicable(
+ unwrap_type_to_generic_arg,
+ r#"
+//- minicore: result
+fn foo() -> $0Result<i32, ()> {
+ todo!()
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn unwrap_type_to_generic_arg_with_lifetime_and_const() {
+ check_assist(
+ unwrap_type_to_generic_arg,
+ r#"
+enum Foo<'a, T, const N: usize> {
+ Bar(T),
+ Baz(&'a [T; N]),
+}
+
+fn test<'a>() -> $0Foo<'a, i32, 3> {
+ todo!()
+}
+"#,
+ r#"
+enum Foo<'a, T, const N: usize> {
+ Bar(T),
+ Baz(&'a [T; N]),
+}
+
+fn test<'a>() -> i32 {
+ todo!()
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn unwrap_type_to_generic_arg_in_let_stmt() {
+ check_assist(
+ unwrap_type_to_generic_arg,
+ r#"
+enum Foo<T> {
+ Bar(T),
+ Baz,
+}
+
+fn test() {
+ let foo: $0Foo<i32> = todo!();
+}
+"#,
+ r#"
+enum Foo<T> {
+ Bar(T),
+ Baz,
+}
+
+fn test() {
+ let foo: i32 = todo!();
+}
+"#,
+ );
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
index 627ed37..2395091 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
@@ -229,6 +229,7 @@ mod handlers {
mod unwrap_block;
mod unwrap_return_type;
mod unwrap_tuple;
+ mod unwrap_type_to_generic_arg;
mod wrap_return_type;
mod wrap_unwrap_cfg_attr;
@@ -369,6 +370,7 @@ pub(crate) fn all() -> &'static [Handler] {
unwrap_block::unwrap_block,
unwrap_return_type::unwrap_return_type,
unwrap_tuple::unwrap_tuple,
+ unwrap_type_to_generic_arg::unwrap_type_to_generic_arg,
wrap_return_type::wrap_return_type,
wrap_unwrap_cfg_attr::wrap_unwrap_cfg_attr,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
index 01ab0be..76134ac 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
@@ -3482,6 +3482,23 @@ fn main() {
}
#[test]
+fn doctest_unwrap_type_to_generic_arg() {
+ check_doc_test(
+ "unwrap_type_to_generic_arg",
+ r#####"
+fn foo() -> $0Option<i32> {
+ todo!()
+}
+"#####,
+ r#####"
+fn foo() -> i32 {
+ todo!()
+}
+"#####,
+ )
+}
+
+#[test]
fn doctest_wrap_return_type_in_option() {
check_doc_test(
"wrap_return_type_in_option",
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs
index cd18b3d..92cbf41 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs
@@ -13,6 +13,7 @@
const CARGO_DEFINED_VARS: &[(&str, &str)] = &[
("CARGO", "Path to the cargo binary performing the build"),
("CARGO_MANIFEST_DIR", "The directory containing the manifest of your package"),
+ ("CARGO_MANIFEST_PATH", "The path to the manifest of your package"),
("CARGO_PKG_VERSION", "The full version of your package"),
("CARGO_PKG_VERSION_MAJOR", "The major version of your package"),
("CARGO_PKG_VERSION_MINOR", "The minor version of your package"),
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
index 54be7d2..3cdf211 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
@@ -311,6 +311,8 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, String) {
let mut prefix = String::new();
+ let mut found_ref_or_deref = false;
+
while let Some(parent_deref_element) =
resulting_element.syntax().parent().and_then(ast::PrefixExpr::cast)
{
@@ -318,27 +320,26 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, String) {
break;
}
+ found_ref_or_deref = true;
resulting_element = ast::Expr::from(parent_deref_element);
prefix.insert(0, '*');
}
- if let Some(first_ref_expr) = resulting_element.syntax().parent().and_then(ast::RefExpr::cast) {
- if let Some(expr) = first_ref_expr.expr() {
- resulting_element = expr;
- }
+ while let Some(parent_ref_element) =
+ resulting_element.syntax().parent().and_then(ast::RefExpr::cast)
+ {
+ found_ref_or_deref = true;
+ let exclusive = parent_ref_element.mut_token().is_some();
+ resulting_element = ast::Expr::from(parent_ref_element);
- while let Some(parent_ref_element) =
- resulting_element.syntax().parent().and_then(ast::RefExpr::cast)
- {
- let exclusive = parent_ref_element.mut_token().is_some();
- resulting_element = ast::Expr::from(parent_ref_element);
+ prefix.insert_str(0, if exclusive { "&mut " } else { "&" });
+ }
- prefix.insert_str(0, if exclusive { "&mut " } else { "&" });
- }
- } else {
- // If we do not find any ref expressions, restore
+ if !found_ref_or_deref {
+ // If we do not find any ref/deref expressions, restore
// all the progress of tree climbing
+ prefix.clear();
resulting_element = initial_element.clone();
}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
index 391e237..284876f 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
@@ -883,9 +883,10 @@ fn classify_name_ref(
},
ast::MethodCallExpr(method) => {
let receiver = find_opt_node_in_file(original_file, method.receiver());
+ let has_parens = has_parens(&method);
let kind = NameRefKind::DotAccess(DotAccess {
receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)),
- kind: DotAccessKind::Method { has_parens: method.arg_list().is_some_and(|it| it.l_paren_token().is_some()) },
+ kind: DotAccessKind::Method { has_parens },
receiver,
ctx: DotAccessExprCtx { in_block_expr: is_in_block(method.syntax()), in_breakable: is_in_breakable(method.syntax()) }
});
@@ -1372,7 +1373,7 @@ fn classify_name_ref(
}
}
- path_ctx.has_call_parens = it.syntax().parent().is_some_and(|it| ast::CallExpr::can_cast(it.kind()));
+ path_ctx.has_call_parens = it.syntax().parent().is_some_and(|it| ast::CallExpr::cast(it).is_some_and(|it| has_parens(&it)));
make_path_kind_expr(it.into())
},
@@ -1401,7 +1402,7 @@ fn classify_name_ref(
match parent {
ast::PathType(it) => make_path_kind_type(it.into()),
ast::PathExpr(it) => {
- path_ctx.has_call_parens = it.syntax().parent().is_some_and(|it| ast::CallExpr::can_cast(it.kind()));
+ path_ctx.has_call_parens = it.syntax().parent().is_some_and(|it| ast::CallExpr::cast(it).is_some_and(|it| has_parens(&it)));
make_path_kind_expr(it.into())
},
@@ -1559,6 +1560,30 @@ fn classify_name_ref(
Some((NameRefContext { nameref, kind: NameRefKind::Path(path_ctx) }, qualifier_ctx))
}
+/// When writing in the middle of some code the following situation commonly occurs (`|` denotes the cursor):
+/// ```ignore
+/// value.method|
+/// (1, 2, 3)
+/// ```
+/// Here, we want to complete the method parentheses & arguments (if the corresponding settings are on),
+/// but the thing is parsed as a method call with parentheses. Therefore we use heuristics: if the parentheses
+/// are on the next line, consider them non-existent.
+fn has_parens(node: &dyn HasArgList) -> bool {
+ let Some(arg_list) = node.arg_list() else { return false };
+ if arg_list.l_paren_token().is_none() {
+ return false;
+ }
+ let prev_siblings = iter::successors(arg_list.syntax().prev_sibling_or_token(), |it| {
+ it.prev_sibling_or_token()
+ });
+ prev_siblings
+ .take_while(|syntax| syntax.kind().is_trivia())
+ .filter_map(|syntax| {
+ syntax.into_token().filter(|token| token.kind() == SyntaxKind::WHITESPACE)
+ })
+ .all(|whitespace| !whitespace.text().contains('\n'))
+}
+
fn pattern_context_for(
sema: &Semantics<'_, RootDatabase>,
original_file: &SyntaxNode,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
index d513794..e546776 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
@@ -2126,3 +2126,70 @@ fn main() {
"#]],
);
}
+
+#[test]
+fn call_parens_with_newline() {
+ check_edit(
+ "foo",
+ r#"
+fn foo(v: i32) {}
+
+fn bar() {
+ foo$0
+ ()
+}
+ "#,
+ r#"
+fn foo(v: i32) {}
+
+fn bar() {
+ foo(${1:v});$0
+ ()
+}
+ "#,
+ );
+ check_edit(
+ "foo",
+ r#"
+struct Foo;
+impl Foo {
+ fn foo(&self, v: i32) {}
+}
+
+fn bar() {
+ Foo.foo$0
+ ()
+}
+ "#,
+ r#"
+struct Foo;
+impl Foo {
+ fn foo(&self, v: i32) {}
+}
+
+fn bar() {
+ Foo.foo(${1:v});$0
+ ()
+}
+ "#,
+ );
+}
+
+#[test]
+fn dbg_too_many_asterisks() {
+ check_edit(
+ "dbg",
+ r#"
+fn main() {
+ let x = &42;
+ let y = *x.$0;
+}
+ "#,
+ r#"
+fn main() {
+ let x = &42;
+ let y = dbg!(*x);
+}
+ "#,
+ );
+}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
index bf4f541..d5db1c4 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
@@ -6,7 +6,7 @@
// FIXME: this badly needs rename/rewrite (matklad, 2020-02-06).
use crate::RootDatabase;
-use crate::documentation::{Documentation, HasDocs};
+use crate::documentation::{DocsRangeMap, Documentation, HasDocs};
use crate::famous_defs::FamousDefs;
use arrayvec::ArrayVec;
use either::Either;
@@ -21,7 +21,7 @@
use span::Edition;
use stdx::{format_to, impl_from};
use syntax::{
- SyntaxKind, SyntaxNode, SyntaxToken,
+ SyntaxKind, SyntaxNode, SyntaxToken, TextSize,
ast::{self, AstNode},
match_ast,
};
@@ -210,29 +210,40 @@ pub fn docs(
famous_defs: Option<&FamousDefs<'_, '_>>,
display_target: DisplayTarget,
) -> Option<Documentation> {
+ self.docs_with_rangemap(db, famous_defs, display_target).map(|(docs, _)| docs)
+ }
+
+ pub fn docs_with_rangemap(
+ &self,
+ db: &RootDatabase,
+ famous_defs: Option<&FamousDefs<'_, '_>>,
+ display_target: DisplayTarget,
+ ) -> Option<(Documentation, Option<DocsRangeMap>)> {
let docs = match self {
- Definition::Macro(it) => it.docs(db),
- Definition::Field(it) => it.docs(db),
- Definition::Module(it) => it.docs(db),
- Definition::Crate(it) => it.docs(db),
- Definition::Function(it) => it.docs(db),
- Definition::Adt(it) => it.docs(db),
- Definition::Variant(it) => it.docs(db),
- Definition::Const(it) => it.docs(db),
- Definition::Static(it) => it.docs(db),
- Definition::Trait(it) => it.docs(db),
- Definition::TraitAlias(it) => it.docs(db),
+ Definition::Macro(it) => it.docs_with_rangemap(db),
+ Definition::Field(it) => it.docs_with_rangemap(db),
+ Definition::Module(it) => it.docs_with_rangemap(db),
+ Definition::Crate(it) => it.docs_with_rangemap(db),
+ Definition::Function(it) => it.docs_with_rangemap(db),
+ Definition::Adt(it) => it.docs_with_rangemap(db),
+ Definition::Variant(it) => it.docs_with_rangemap(db),
+ Definition::Const(it) => it.docs_with_rangemap(db),
+ Definition::Static(it) => it.docs_with_rangemap(db),
+ Definition::Trait(it) => it.docs_with_rangemap(db),
+ Definition::TraitAlias(it) => it.docs_with_rangemap(db),
Definition::TypeAlias(it) => {
- it.docs(db).or_else(|| {
+ it.docs_with_rangemap(db).or_else(|| {
// docs are missing, try to fall back to the docs of the aliased item.
let adt = it.ty(db).as_adt()?;
- let docs = adt.docs(db)?;
- let docs = format!(
- "*This is the documentation for* `{}`\n\n{}",
- adt.display(db, display_target),
- docs.as_str()
+ let (docs, range_map) = adt.docs_with_rangemap(db)?;
+ let header_docs = format!(
+ "*This is the documentation for* `{}`\n\n",
+ adt.display(db, display_target)
);
- Some(Documentation::new(docs))
+ let offset = TextSize::new(header_docs.len() as u32);
+ let range_map = range_map.shift_docstring_line_range(offset);
+ let docs = header_docs + docs.as_str();
+ Some((Documentation::new(docs), range_map))
})
}
Definition::BuiltinType(it) => {
@@ -241,17 +252,17 @@ pub fn docs(
let primitive_mod =
format!("prim_{}", it.name().display(fd.0.db, display_target.edition));
let doc_owner = find_std_module(fd, &primitive_mod, display_target.edition)?;
- doc_owner.docs(fd.0.db)
+ doc_owner.docs_with_rangemap(fd.0.db)
})
}
Definition::BuiltinLifetime(StaticLifetime) => None,
Definition::Local(_) => None,
Definition::SelfType(impl_def) => {
- impl_def.self_ty(db).as_adt().map(|adt| adt.docs(db))?
+ impl_def.self_ty(db).as_adt().map(|adt| adt.docs_with_rangemap(db))?
}
Definition::GenericParam(_) => None,
Definition::Label(_) => None,
- Definition::ExternCrateDecl(it) => it.docs(db),
+ Definition::ExternCrateDecl(it) => it.docs_with_rangemap(db),
Definition::BuiltinAttr(it) => {
let name = it.name(db);
@@ -276,7 +287,8 @@ pub fn docs(
name_value_str
);
}
- Some(Documentation::new(docs.replace('*', "\\*")))
+
+ return Some((Documentation::new(docs.replace('*', "\\*")), None));
}
Definition::ToolModule(_) => None,
Definition::DeriveHelper(_) => None,
@@ -291,8 +303,9 @@ pub fn docs(
let trait_ = assoc.implemented_trait(db)?;
let name = Some(assoc.name(db)?);
let item = trait_.items(db).into_iter().find(|it| it.name(db) == name)?;
- item.docs(db)
+ item.docs_with_rangemap(db)
})
+ .map(|(docs, range_map)| (docs, Some(range_map)))
}
pub fn label(&self, db: &RootDatabase, display_target: DisplayTarget) -> String {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs
index ef2c839..30c355f 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs
@@ -34,11 +34,13 @@ fn from(Documentation(string): Documentation) -> Self {
pub trait HasDocs: HasAttrs {
fn docs(self, db: &dyn HirDatabase) -> Option<Documentation>;
+ fn docs_with_rangemap(self, db: &dyn HirDatabase) -> Option<(Documentation, DocsRangeMap)>;
fn resolve_doc_path(
self,
db: &dyn HirDatabase,
link: &str,
ns: Option<hir::Namespace>,
+ is_inner_doc: bool,
) -> Option<hir::DocLinkDef>;
}
/// A struct to map text ranges from [`Documentation`] back to TextRanges in the syntax tree.
@@ -53,7 +55,7 @@ pub struct DocsRangeMap {
impl DocsRangeMap {
/// Maps a [`TextRange`] relative to the documentation string back to its AST range
- pub fn map(&self, range: TextRange) -> Option<InFile<TextRange>> {
+ pub fn map(&self, range: TextRange) -> Option<(InFile<TextRange>, AttrId)> {
let found = self.mapping.binary_search_by(|(probe, ..)| probe.ordering(range)).ok()?;
let (line_docs_range, idx, original_line_src_range) = self.mapping[found];
if !line_docs_range.contains_range(range) {
@@ -71,7 +73,7 @@ pub fn map(&self, range: TextRange) -> Option<InFile<TextRange>> {
text_range.end() + original_line_src_range.start() + relative_range.start(),
string.syntax().text_range().len().min(range.len()),
);
- Some(InFile { file_id, value: range })
+ Some((InFile { file_id, value: range }, idx))
}
Either::Right(comment) => {
let text_range = comment.syntax().text_range();
@@ -82,10 +84,22 @@ pub fn map(&self, range: TextRange) -> Option<InFile<TextRange>> {
+ relative_range.start(),
text_range.len().min(range.len()),
);
- Some(InFile { file_id, value: range })
+ Some((InFile { file_id, value: range }, idx))
}
}
}
+
+ pub fn shift_docstring_line_range(self, offset: TextSize) -> DocsRangeMap {
+ let mapping = self
+ .mapping
+ .into_iter()
+ .map(|(buf_offset, id, base_offset)| {
+ let buf_offset = buf_offset.checked_add(offset).unwrap();
+ (buf_offset, id, base_offset)
+ })
+ .collect_vec();
+ DocsRangeMap { source_map: self.source_map, mapping }
+ }
}
pub fn docs_with_rangemap(
@@ -161,13 +175,20 @@ impl HasDocs for hir::$def {
fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
docs_from_attrs(&self.attrs(db)).map(Documentation)
}
+ fn docs_with_rangemap(
+ self,
+ db: &dyn HirDatabase,
+ ) -> Option<(Documentation, DocsRangeMap)> {
+ docs_with_rangemap(db, &self.attrs(db))
+ }
fn resolve_doc_path(
self,
db: &dyn HirDatabase,
link: &str,
- ns: Option<hir::Namespace>
+ ns: Option<hir::Namespace>,
+ is_inner_doc: bool,
) -> Option<hir::DocLinkDef> {
- resolve_doc_path_on(db, self, link, ns)
+ resolve_doc_path_on(db, self, link, ns, is_inner_doc)
}
}
)*};
@@ -184,13 +205,21 @@ impl HasDocs for hir::$variant {
fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
hir::$enum::$variant(self).docs(db)
}
+
+ fn docs_with_rangemap(
+ self,
+ db: &dyn HirDatabase,
+ ) -> Option<(Documentation, DocsRangeMap)> {
+ hir::$enum::$variant(self).docs_with_rangemap(db)
+ }
fn resolve_doc_path(
self,
db: &dyn HirDatabase,
link: &str,
- ns: Option<hir::Namespace>
+ ns: Option<hir::Namespace>,
+ is_inner_doc: bool,
) -> Option<hir::DocLinkDef> {
- hir::$enum::$variant(self).resolve_doc_path(db, link, ns)
+ hir::$enum::$variant(self).resolve_doc_path(db, link, ns, is_inner_doc)
}
}
)*};
@@ -207,16 +236,25 @@ fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
}
}
+ fn docs_with_rangemap(self, db: &dyn HirDatabase) -> Option<(Documentation, DocsRangeMap)> {
+ match self {
+ hir::AssocItem::Function(it) => it.docs_with_rangemap(db),
+ hir::AssocItem::Const(it) => it.docs_with_rangemap(db),
+ hir::AssocItem::TypeAlias(it) => it.docs_with_rangemap(db),
+ }
+ }
+
fn resolve_doc_path(
self,
db: &dyn HirDatabase,
link: &str,
ns: Option<hir::Namespace>,
+ is_inner_doc: bool,
) -> Option<hir::DocLinkDef> {
match self {
- hir::AssocItem::Function(it) => it.resolve_doc_path(db, link, ns),
- hir::AssocItem::Const(it) => it.resolve_doc_path(db, link, ns),
- hir::AssocItem::TypeAlias(it) => it.resolve_doc_path(db, link, ns),
+ hir::AssocItem::Function(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+ hir::AssocItem::Const(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+ hir::AssocItem::TypeAlias(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
}
}
}
@@ -238,13 +276,36 @@ fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
}
.map(Documentation::new)
}
+
+ fn docs_with_rangemap(self, db: &dyn HirDatabase) -> Option<(Documentation, DocsRangeMap)> {
+ let crate_docs = docs_with_rangemap(db, &self.resolved_crate(db)?.root_module().attrs(db));
+ let decl_docs = docs_with_rangemap(db, &self.attrs(db));
+ match (decl_docs, crate_docs) {
+ (None, None) => None,
+ (Some(decl_docs), None) => Some(decl_docs),
+ (None, Some(crate_docs)) => Some(crate_docs),
+ (
+ Some((Documentation(mut decl_docs), mut decl_range_map)),
+ Some((Documentation(crate_docs), crate_range_map)),
+ ) => {
+ decl_docs.push('\n');
+ decl_docs.push('\n');
+ let offset = TextSize::new(decl_docs.len() as u32);
+ decl_docs += &crate_docs;
+ let crate_range_map = crate_range_map.shift_docstring_line_range(offset);
+ decl_range_map.mapping.extend(crate_range_map.mapping);
+ Some((Documentation(decl_docs), decl_range_map))
+ }
+ }
+ }
fn resolve_doc_path(
self,
db: &dyn HirDatabase,
link: &str,
ns: Option<hir::Namespace>,
+ is_inner_doc: bool,
) -> Option<hir::DocLinkDef> {
- resolve_doc_path_on(db, self, link, ns)
+ resolve_doc_path_on(db, self, link, ns, is_inner_doc)
}
}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
index cbe3140..5356614 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
@@ -2,12 +2,10 @@
//! sometimes is counter productive when, for example, the first goto definition
//! request takes longer to compute. This module implements prepopulation of
//! various caches, it's not really advanced at the moment.
-mod topologic_sort;
-
-use std::time::Duration;
+use std::panic::AssertUnwindSafe;
use hir::{Symbol, db::DefDatabase};
-use itertools::Itertools;
+use rustc_hash::FxHashMap;
use salsa::{Cancelled, Database};
use crate::{
@@ -35,59 +33,114 @@ pub fn parallel_prime_caches(
) {
let _p = tracing::info_span!("parallel_prime_caches").entered();
- let mut crates_to_prime = {
- // FIXME: We already have the crate list topologically sorted (but without the things
- // `TopologicalSortIter` gives us). Maybe there is a way to avoid using it and rip it out
- // of the codebase?
- let mut builder = topologic_sort::TopologicalSortIter::builder();
-
- for &crate_id in db.all_crates().iter() {
- builder.add(crate_id, crate_id.data(db).dependencies.iter().map(|d| d.crate_id));
- }
-
- builder.build()
- };
-
enum ParallelPrimeCacheWorkerProgress {
- BeginCrate { crate_id: Crate, crate_name: Symbol },
- EndCrate { crate_id: Crate },
+ BeginCrateDefMap { crate_id: Crate, crate_name: Symbol },
+ EndCrateDefMap { crate_id: Crate },
+ EndCrateImportMap,
+ EndModuleSymbols,
Cancelled(Cancelled),
}
- // We split off def map computation from other work,
- // as the def map is the relevant one. Once the defmaps are computed
- // the project is ready to go, the other indices are just nice to have for some IDE features.
- #[derive(PartialOrd, Ord, PartialEq, Eq, Copy, Clone)]
- enum PrimingPhase {
- DefMap,
- ImportMap,
- CrateSymbols,
- }
+ // The setup here is a bit complicated. We try to make best use of compute resources.
+ // The idea is that if we have a def map available to compute, we should do that first.
+ // This is because def map is a dependency of both import map and symbols. So if we have
+ // e.g. a def map and a symbols, if we compute the def map we can, after it completes,
+ // compute the def maps of dependencies, the existing symbols and the symbols of the
+ // new crate, all in parallel. But if we compute the symbols, after that we will only
+ // have the def map to compute, and the rest of the CPU cores will rest, which is not
+ // good.
+ // However, it's better to compute symbols/import map than to compute a def map that
+ // isn't ready yet, because one of its dependencies hasn't yet completed its def map.
+ // Such def map will just block on the dependency, which is just wasted time. So better
+ // to compute the symbols/import map of an already computed def map in that time.
- let (work_sender, progress_receiver) = {
- let (progress_sender, progress_receiver) = crossbeam_channel::unbounded();
- let (work_sender, work_receiver) = crossbeam_channel::unbounded();
- let prime_caches_worker = move |db: RootDatabase| {
- while let Ok((crate_id, crate_name, kind)) = work_receiver.recv() {
- progress_sender
- .send(ParallelPrimeCacheWorkerProgress::BeginCrate { crate_id, crate_name })?;
-
- let cancelled = Cancelled::catch(|| match kind {
- PrimingPhase::DefMap => _ = db.crate_def_map(crate_id),
- PrimingPhase::ImportMap => _ = db.import_map(crate_id),
- PrimingPhase::CrateSymbols => _ = db.crate_symbols(crate_id.into()),
- });
-
- match cancelled {
- Ok(()) => progress_sender
- .send(ParallelPrimeCacheWorkerProgress::EndCrate { crate_id })?,
- Err(cancelled) => progress_sender
- .send(ParallelPrimeCacheWorkerProgress::Cancelled(cancelled))?,
- }
+ let (reverse_deps, mut to_be_done_deps) = {
+ let all_crates = db.all_crates();
+ let to_be_done_deps = all_crates
+ .iter()
+ .map(|&krate| (krate, krate.data(db).dependencies.len() as u32))
+ .collect::<FxHashMap<_, _>>();
+ let mut reverse_deps =
+ all_crates.iter().map(|&krate| (krate, Vec::new())).collect::<FxHashMap<_, _>>();
+ for &krate in &*all_crates {
+ for dep in &krate.data(db).dependencies {
+ reverse_deps.get_mut(&dep.crate_id).unwrap().push(krate);
}
+ }
+ (reverse_deps, to_be_done_deps)
+ };
- Ok::<_, crossbeam_channel::SendError<_>>(())
- };
+ let (def_map_work_sender, import_map_work_sender, symbols_work_sender, progress_receiver) = {
+ let (progress_sender, progress_receiver) = crossbeam_channel::unbounded();
+ let (def_map_work_sender, def_map_work_receiver) = crossbeam_channel::unbounded();
+ let (import_map_work_sender, import_map_work_receiver) = crossbeam_channel::unbounded();
+ let (symbols_work_sender, symbols_work_receiver) = crossbeam_channel::unbounded();
+ let prime_caches_worker =
+ move |db: RootDatabase| {
+ let handle_def_map = |crate_id, crate_name| {
+ progress_sender.send(ParallelPrimeCacheWorkerProgress::BeginCrateDefMap {
+ crate_id,
+ crate_name,
+ })?;
+
+ let cancelled = Cancelled::catch(|| _ = hir::crate_def_map(&db, crate_id));
+
+ match cancelled {
+ Ok(()) => progress_sender
+ .send(ParallelPrimeCacheWorkerProgress::EndCrateDefMap { crate_id })?,
+ Err(cancelled) => progress_sender
+ .send(ParallelPrimeCacheWorkerProgress::Cancelled(cancelled))?,
+ }
+
+ Ok::<_, crossbeam_channel::SendError<_>>(())
+ };
+ let handle_import_map = |crate_id| {
+ let cancelled = Cancelled::catch(|| _ = db.import_map(crate_id));
+
+ match cancelled {
+ Ok(()) => progress_sender
+ .send(ParallelPrimeCacheWorkerProgress::EndCrateImportMap)?,
+ Err(cancelled) => progress_sender
+ .send(ParallelPrimeCacheWorkerProgress::Cancelled(cancelled))?,
+ }
+
+ Ok::<_, crossbeam_channel::SendError<_>>(())
+ };
+ let handle_symbols = |module| {
+ let cancelled =
+ Cancelled::catch(AssertUnwindSafe(|| _ = db.module_symbols(module)));
+
+ match cancelled {
+ Ok(()) => progress_sender
+ .send(ParallelPrimeCacheWorkerProgress::EndModuleSymbols)?,
+ Err(cancelled) => progress_sender
+ .send(ParallelPrimeCacheWorkerProgress::Cancelled(cancelled))?,
+ }
+
+ Ok::<_, crossbeam_channel::SendError<_>>(())
+ };
+
+ loop {
+ db.unwind_if_revision_cancelled();
+
+ // Biased because we want to prefer def maps.
+ crossbeam_channel::select_biased! {
+ recv(def_map_work_receiver) -> work => {
+ let Ok((crate_id, crate_name)) = work else { break };
+ handle_def_map(crate_id, crate_name)?;
+ }
+ recv(import_map_work_receiver) -> work => {
+ let Ok(crate_id) = work else { break };
+ handle_import_map(crate_id)?;
+ }
+ recv(symbols_work_receiver) -> work => {
+ let Ok(module) = work else { break };
+ handle_symbols(module)?;
+ }
+ }
+ }
+ Ok::<_, crossbeam_channel::SendError<_>>(())
+ };
for id in 0..num_worker_threads {
stdx::thread::Builder::new(
@@ -103,138 +156,121 @@ enum PrimingPhase {
.expect("failed to spawn thread");
}
- (work_sender, progress_receiver)
+ (def_map_work_sender, import_map_work_sender, symbols_work_sender, progress_receiver)
};
- let crates_total = crates_to_prime.pending();
- let mut crates_done = 0;
+ let crate_def_maps_total = db.all_crates().len();
+ let mut crate_def_maps_done = 0;
+ let (mut crate_import_maps_total, mut crate_import_maps_done) = (0usize, 0usize);
+ let (mut module_symbols_total, mut module_symbols_done) = (0usize, 0usize);
// an index map is used to preserve ordering so we can sort the progress report in order of
// "longest crate to index" first
let mut crates_currently_indexing =
FxIndexMap::with_capacity_and_hasher(num_worker_threads, Default::default());
- let mut additional_phases = vec![];
-
- while crates_done < crates_total {
- db.unwind_if_revision_cancelled();
-
- for krate in &mut crates_to_prime {
- let name = krate.extra_data(db).display_name.as_deref().cloned().unwrap_or_else(|| {
- Symbol::integer(salsa::plumbing::AsId::as_id(&krate).as_u32() as usize)
- });
- let origin = &krate.data(db).origin;
- if origin.is_lang() {
- additional_phases.push((krate, name.clone(), PrimingPhase::ImportMap));
- } else if origin.is_local() {
- // Compute the symbol search index.
- // This primes the cache for `ide_db::symbol_index::world_symbols()`.
- //
- // We do this for workspace crates only (members of local_roots), because doing it
- // for all dependencies could be *very* unnecessarily slow in a large project.
- //
- // FIXME: We should do it unconditionally if the configuration is set to default to
- // searching dependencies (rust-analyzer.workspace.symbol.search.scope), but we
- // would need to pipe that configuration information down here.
- additional_phases.push((krate, name.clone(), PrimingPhase::CrateSymbols));
- }
-
- work_sender.send((krate, name, PrimingPhase::DefMap)).ok();
+ for (&krate, &to_be_done_deps) in &to_be_done_deps {
+ if to_be_done_deps != 0 {
+ continue;
}
- // recv_timeout is somewhat a hack, we need a way to from this thread check to see if the current salsa revision
- // is cancelled on a regular basis. workers will only exit if they are processing a task that is cancelled, or
- // if this thread exits, and closes the work channel.
- let worker_progress = match progress_receiver.recv_timeout(Duration::from_millis(10)) {
- Ok(p) => p,
- Err(crossbeam_channel::RecvTimeoutError::Timeout) => {
- continue;
- }
- Err(crossbeam_channel::RecvTimeoutError::Disconnected) => {
- // all our workers have exited, mark us as finished and exit
- cb(ParallelPrimeCachesProgress {
- crates_currently_indexing: vec![],
- crates_done,
- crates_total: crates_done,
- work_type: "Indexing",
- });
- return;
- }
- };
- match worker_progress {
- ParallelPrimeCacheWorkerProgress::BeginCrate { crate_id, crate_name } => {
- crates_currently_indexing.insert(crate_id, crate_name);
- }
- ParallelPrimeCacheWorkerProgress::EndCrate { crate_id } => {
- crates_currently_indexing.swap_remove(&crate_id);
- crates_to_prime.mark_done(crate_id);
- crates_done += 1;
- }
- ParallelPrimeCacheWorkerProgress::Cancelled(cancelled) => {
- // Cancelled::throw should probably be public
- std::panic::resume_unwind(Box::new(cancelled));
- }
- };
+ let name = crate_name(db, krate);
+ def_map_work_sender.send((krate, name)).ok();
+ }
+
+ while crate_def_maps_done < crate_def_maps_total
+ || crate_import_maps_done < crate_import_maps_total
+ || module_symbols_done < module_symbols_total
+ {
+ db.unwind_if_revision_cancelled();
let progress = ParallelPrimeCachesProgress {
crates_currently_indexing: crates_currently_indexing.values().cloned().collect(),
- crates_done,
- crates_total,
+ crates_done: crate_def_maps_done,
+ crates_total: crate_def_maps_total,
work_type: "Indexing",
};
cb(progress);
- }
- let mut crates_done = 0;
- let crates_total = additional_phases.len();
- for w in additional_phases.into_iter().sorted_by_key(|&(_, _, phase)| phase) {
- work_sender.send(w).ok();
- }
-
- while crates_done < crates_total {
- db.unwind_if_revision_cancelled();
-
- // recv_timeout is somewhat a hack, we need a way to from this thread check to see if the current salsa revision
- // is cancelled on a regular basis. workers will only exit if they are processing a task that is cancelled, or
- // if this thread exits, and closes the work channel.
- let worker_progress = match progress_receiver.recv_timeout(Duration::from_millis(10)) {
+ // Biased to prefer progress updates (and because it's faster).
+ let progress = match progress_receiver.recv() {
Ok(p) => p,
- Err(crossbeam_channel::RecvTimeoutError::Timeout) => {
- continue;
- }
- Err(crossbeam_channel::RecvTimeoutError::Disconnected) => {
+ Err(crossbeam_channel::RecvError) => {
// all our workers have exited, mark us as finished and exit
cb(ParallelPrimeCachesProgress {
crates_currently_indexing: vec![],
- crates_done,
- crates_total: crates_done,
- work_type: "Populating symbols",
+ crates_done: crate_def_maps_done,
+ crates_total: crate_def_maps_done,
+ work_type: "Done",
});
return;
}
};
- match worker_progress {
- ParallelPrimeCacheWorkerProgress::BeginCrate { crate_id, crate_name } => {
+
+ match progress {
+ ParallelPrimeCacheWorkerProgress::BeginCrateDefMap { crate_id, crate_name } => {
crates_currently_indexing.insert(crate_id, crate_name);
}
- ParallelPrimeCacheWorkerProgress::EndCrate { crate_id } => {
+ ParallelPrimeCacheWorkerProgress::EndCrateDefMap { crate_id } => {
crates_currently_indexing.swap_remove(&crate_id);
- crates_done += 1;
+ crate_def_maps_done += 1;
+
+ // Fire ready dependencies.
+ for &dep in &reverse_deps[&crate_id] {
+ let to_be_done = to_be_done_deps.get_mut(&dep).unwrap();
+ *to_be_done -= 1;
+ if *to_be_done == 0 {
+ let dep_name = crate_name(db, dep);
+ def_map_work_sender.send((dep, dep_name)).ok();
+ }
+ }
+
+ if crate_def_maps_done == crate_def_maps_total {
+ cb(ParallelPrimeCachesProgress {
+ crates_currently_indexing: vec![],
+ crates_done: crate_def_maps_done,
+ crates_total: crate_def_maps_done,
+ work_type: "Collecting Symbols",
+ });
+ }
+
+ let origin = &crate_id.data(db).origin;
+ if origin.is_lang() {
+ crate_import_maps_total += 1;
+ import_map_work_sender.send(crate_id).ok();
+ } else if origin.is_local() {
+ // Compute the symbol search index.
+ // This primes the cache for `ide_db::symbol_index::world_symbols()`.
+ //
+ // We do this for workspace crates only (members of local_roots), because doing it
+ // for all dependencies could be *very* unnecessarily slow in a large project.
+ //
+ // FIXME: We should do it unconditionally if the configuration is set to default to
+ // searching dependencies (rust-analyzer.workspace.symbol.search.scope), but we
+ // would need to pipe that configuration information down here.
+ let modules = hir::Crate::from(crate_id).modules(db);
+ module_symbols_total += modules.len();
+ for module in modules {
+ symbols_work_sender.send(module).ok();
+ }
+ }
}
+ ParallelPrimeCacheWorkerProgress::EndCrateImportMap => crate_import_maps_done += 1,
+ ParallelPrimeCacheWorkerProgress::EndModuleSymbols => module_symbols_done += 1,
ParallelPrimeCacheWorkerProgress::Cancelled(cancelled) => {
// Cancelled::throw should probably be public
std::panic::resume_unwind(Box::new(cancelled));
}
- };
-
- let progress = ParallelPrimeCachesProgress {
- crates_currently_indexing: crates_currently_indexing.values().cloned().collect(),
- crates_done,
- crates_total,
- work_type: "Populating symbols",
- };
-
- cb(progress);
+ }
}
}
+
+fn crate_name(db: &RootDatabase, krate: Crate) -> Symbol {
+ krate
+ .extra_data(db)
+ .display_name
+ .as_deref()
+ .cloned()
+ .unwrap_or_else(|| Symbol::integer(salsa::plumbing::AsId::as_id(&krate).as_u32() as usize))
+}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches/topologic_sort.rs b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches/topologic_sort.rs
deleted file mode 100644
index c8a0386..0000000
--- a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches/topologic_sort.rs
+++ /dev/null
@@ -1,104 +0,0 @@
-//! helper data structure to schedule work for parallel prime caches.
-use std::{collections::VecDeque, hash::Hash};
-
-use crate::FxHashMap;
-
-pub(crate) struct TopologicSortIterBuilder<T> {
- nodes: FxHashMap<T, Entry<T>>,
-}
-
-// this implementation has different bounds on T than would be implied by #[derive(Default)]
-impl<T> Default for TopologicSortIterBuilder<T>
-where
- T: Copy + Eq + PartialEq + Hash,
-{
- fn default() -> Self {
- Self { nodes: Default::default() }
- }
-}
-
-impl<T> TopologicSortIterBuilder<T>
-where
- T: Copy + Eq + PartialEq + Hash,
-{
- fn get_or_create_entry(&mut self, item: T) -> &mut Entry<T> {
- self.nodes.entry(item).or_default()
- }
-
- pub(crate) fn add(&mut self, item: T, predecessors: impl IntoIterator<Item = T>) {
- let mut num_predecessors = 0;
-
- for predecessor in predecessors.into_iter() {
- self.get_or_create_entry(predecessor).successors.push(item);
- num_predecessors += 1;
- }
-
- let entry = self.get_or_create_entry(item);
- entry.num_predecessors += num_predecessors;
- }
-
- pub(crate) fn build(self) -> TopologicalSortIter<T> {
- let ready = self
- .nodes
- .iter()
- .filter_map(
- |(item, entry)| if entry.num_predecessors == 0 { Some(*item) } else { None },
- )
- .collect();
-
- TopologicalSortIter { nodes: self.nodes, ready }
- }
-}
-
-pub(crate) struct TopologicalSortIter<T> {
- ready: VecDeque<T>,
- nodes: FxHashMap<T, Entry<T>>,
-}
-
-impl<T> TopologicalSortIter<T>
-where
- T: Copy + Eq + PartialEq + Hash,
-{
- pub(crate) fn builder() -> TopologicSortIterBuilder<T> {
- TopologicSortIterBuilder::default()
- }
-
- pub(crate) fn pending(&self) -> usize {
- self.nodes.len()
- }
-
- pub(crate) fn mark_done(&mut self, item: T) {
- let entry = self.nodes.remove(&item).expect("invariant: unknown item marked as done");
-
- for successor in entry.successors {
- let succ_entry = self
- .nodes
- .get_mut(&successor)
- .expect("invariant: unknown successor referenced by entry");
-
- succ_entry.num_predecessors -= 1;
- if succ_entry.num_predecessors == 0 {
- self.ready.push_back(successor);
- }
- }
- }
-}
-
-impl<T> Iterator for TopologicalSortIter<T> {
- type Item = T;
-
- fn next(&mut self) -> Option<Self::Item> {
- self.ready.pop_front()
- }
-}
-
-struct Entry<T> {
- successors: Vec<T>,
- num_predecessors: usize,
-}
-
-impl<T> Default for Entry<T> {
- fn default() -> Self {
- Self { successors: Default::default(), num_predecessors: 0 }
- }
-}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
index b8119e1..fa2a46a 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
@@ -390,11 +390,6 @@ pub fn source_edit_from_references(
let mut edited_ranges = Vec::new();
for &FileReference { range, ref name, .. } in references {
let name_range = name.text_range();
- if name_range.len() != range.len() {
- // This usage comes from a different token kind that was downmapped to a NameLike in a macro
- // Renaming this will most likely break things syntax-wise
- continue;
- }
let has_emitted_edit = match name {
// if the ranges differ then the node is inside a macro call, we can't really attempt
// to make special rewrites like shorthand syntax and such, so just rename the node in
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/await_outside_of_async.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/await_outside_of_async.rs
index 92ca7a7..2a7b009 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/await_outside_of_async.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/await_outside_of_async.rs
@@ -14,6 +14,7 @@ pub(crate) fn await_outside_of_async(
format!("`await` is used inside {}, which is not an `async` context", d.location),
display_range,
)
+ .stable()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/bad_rtn.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/bad_rtn.rs
index 9ed85f9..ae42a88 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/bad_rtn.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/bad_rtn.rs
@@ -12,6 +12,7 @@ pub(crate) fn bad_rtn(ctx: &DiagnosticsContext<'_>, d: &hir::BadRtn) -> Diagnost
"return type notation not allowed in this position yet",
d.rtn.map(Into::into),
)
+ .stable()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs
index c25b0a7..cbcaab6 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs
@@ -19,6 +19,7 @@ pub(crate) fn break_outside_of_loop(
message,
d.expr.map(|it| it.into()),
)
+ .stable()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/elided_lifetimes_in_path.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/elided_lifetimes_in_path.rs
index 438dd2f..b284d9b 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/elided_lifetimes_in_path.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/elided_lifetimes_in_path.rs
@@ -15,7 +15,6 @@ pub(crate) fn elided_lifetimes_in_path(
"implicit elided lifetime not allowed here",
d.generics_or_segment.map(Into::into),
)
- .experimental()
} else {
Diagnostic::new_with_syntax_node_ptr(
ctx,
@@ -23,7 +22,6 @@ pub(crate) fn elided_lifetimes_in_path(
"hidden lifetime parameters in types are deprecated",
d.generics_or_segment.map(Into::into),
)
- .experimental()
}
}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs
index a6da0fd..7d2ac373 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs
@@ -15,7 +15,6 @@ pub(crate) fn expected_function(
format!("expected function, found {}", d.found.display(ctx.sema.db, ctx.display_target)),
d.call.map(|it| it.into()),
)
- .experimental()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs
index b617c09..9ae6f01 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs
@@ -21,6 +21,7 @@ pub(crate) fn generic_args_prohibited(
describe_reason(d.reason),
d.args.map(Into::into),
)
+ .stable()
.with_fixes(fixes(ctx, d))
}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
index 47e1c84..8611ef6 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
@@ -33,6 +33,7 @@ pub(crate) fn inactive_code(
message,
ctx.sema.diagnostics_display_range(d.node),
)
+ .stable()
.with_unused(true);
Some(res)
}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs
index 0b9a2ec..a0c364b 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs
@@ -19,6 +19,7 @@ pub(crate) fn incoherent_impl(ctx: &DiagnosticsContext<'_>, d: &hir::IncoherentI
"cannot define inherent `impl` for foreign type".to_owned(),
display_range,
)
+ .stable()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
index 289a076..38f10c7 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
@@ -29,6 +29,7 @@ pub(crate) fn incorrect_case(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCas
),
InFile::new(d.file, d.ident.into()),
)
+ .stable()
.with_fixes(fixes(ctx, d))
}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs
index 17c7f75..06f3575 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_len.rs
@@ -28,7 +28,6 @@ pub(crate) fn incorrect_generics_len(
message,
d.generics_or_segment.map(Into::into),
)
- .experimental()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_order.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_order.rs
index 84496df..b71586d 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_order.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_generics_order.rs
@@ -28,6 +28,7 @@ pub(crate) fn incorrect_generics_order(
message,
d.provided_arg.map(Into::into),
)
+ .stable()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs
index d72b210..7a6e98f 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs
@@ -100,7 +100,7 @@ pub(crate) fn invalid_cast(ctx: &DiagnosticsContext<'_>, d: &hir::InvalidCast) -
// "cannot cast to a pointer of an unknown kind".to_owned(),
// ),
};
- Diagnostic::new(code, message, display_range)
+ Diagnostic::new(code, message, display_range).stable()
}
// Diagnostic: cast-to-unsized
@@ -113,6 +113,7 @@ pub(crate) fn cast_to_unsized(ctx: &DiagnosticsContext<'_>, d: &hir::CastToUnsiz
format_ty!(ctx, "cast to unsized type: `{}`", d.cast_ty),
display_range,
)
+ .stable()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_derive_target.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_derive_target.rs
index ab0f513..8b708f2 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_derive_target.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_derive_target.rs
@@ -15,6 +15,7 @@ pub(crate) fn invalid_derive_target(
"`derive` may only be applied to `struct`s, `enum`s and `union`s",
display_range,
)
+ .stable()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
index a2648a1..546512a 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
@@ -19,6 +19,7 @@ pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) ->
d.message.clone(),
display_range,
)
+ .stable()
}
// Diagnostic: macro-def-error
@@ -33,6 +34,7 @@ pub(crate) fn macro_def_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroDefErr
d.message.clone(),
display_range,
)
+ .stable()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/malformed_derive.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/malformed_derive.rs
index 0e47fff..701b30b 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/malformed_derive.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/malformed_derive.rs
@@ -14,6 +14,7 @@ pub(crate) fn malformed_derive(
"malformed derive input, derive attributes are of the form `#[derive(Derive1, Derive2, ...)]`",
display_range,
)
+ .stable()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
index 63fd9b4..25c1e63 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
@@ -26,6 +26,7 @@ pub(crate) fn mismatched_tuple_struct_pat_arg_count(
message,
invalid_args_range(ctx, d.expr_or_pat, d.expected, d.found),
)
+ .stable()
}
// Diagnostic: mismatched-arg-count
@@ -42,6 +43,7 @@ pub(crate) fn mismatched_arg_count(
message,
invalid_args_range(ctx, d.call_expr, d.expected, d.found),
)
+ .stable()
}
fn invalid_args_range(
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
index a354d12..2b76efb 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
@@ -47,6 +47,7 @@ pub(crate) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingField
);
Diagnostic::new_with_syntax_node_ptr(ctx, DiagnosticCode::RustcHardError("E0063"), message, ptr)
+ .stable()
.with_fixes(fixes(ctx, d))
}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs
index 8cdbb63..76b3074 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs
@@ -13,7 +13,6 @@ pub(crate) fn missing_lifetime(
"missing lifetime specifier",
d.generics_or_segment.map(Into::into),
)
- .experimental()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
index d3d3c3a..1fc96b7 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
@@ -13,6 +13,7 @@ pub(crate) fn missing_match_arms(
format!("missing match arm: {}", d.uncovered_patterns),
d.scrutinee_expr.map(Into::into),
)
+ .stable()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
index 3c36b45..364bead 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
@@ -23,6 +23,7 @@ pub(crate) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsaf
format!("{operation} is unsafe and requires an unsafe function or block"),
d.node.map(|it| it.into()),
)
+ .stable()
.with_fixes(fixes(ctx, d))
}
@@ -893,4 +894,25 @@ fn main() {
"#,
);
}
+
+ #[test]
+ fn asm_label() {
+ check_diagnostics(
+ r#"
+//- minicore: asm
+fn foo() {
+ unsafe {
+ core::arch::asm!(
+ "jmp {}",
+ label {
+ let p = 0xDEADBEAF as *mut u8;
+ *p = 3;
+ // ^^ error: dereference of raw pointer is unsafe and requires an unsafe function or block
+ },
+ );
+ }
+}
+ "#,
+ );
+ }
}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
index 7802713..01cf5e8 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
@@ -11,7 +11,7 @@ pub(crate) fn moved_out_of_ref(ctx: &DiagnosticsContext<'_>, d: &hir::MovedOutOf
format!("cannot move `{}` out of reference", d.ty.display(ctx.sema.db, ctx.display_target)),
d.span,
)
- .experimental() // spans are broken, and I'm not sure how precise we can detect copy types
+ // spans are broken, and I'm not sure how precise we can detect copy types
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
index 5d25f2c..8831efa 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
@@ -55,6 +55,7 @@ pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Option
),
span,
)
+ .stable()
.with_fixes(fixes),
)
}
@@ -94,7 +95,7 @@ pub(crate) fn unused_mut(ctx: &DiagnosticsContext<'_>, d: &hir::UnusedMut) -> Op
"variable does not need to be mutable",
ast,
)
- .experimental() // Not supporting `#[allow(unused_mut)]` in proc macros leads to false positive.
+ // Not supporting `#[allow(unused_mut)]` in proc macros leads to false positive, hence not stable.
.with_fixes(fixes),
)
}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
index fa3347a..84fb467 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
@@ -22,6 +22,7 @@ pub(crate) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField)
"field is private",
node,
)
+ .stable()
} else {
Diagnostic::new_with_syntax_node_ptr(
ctx,
@@ -32,6 +33,7 @@ pub(crate) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField)
"no such field",
node,
)
+ .stable()
.with_fixes(fixes(ctx, d))
}
}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs
index ff1eeb0..35cefd2 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs
@@ -14,6 +14,7 @@ pub(crate) fn non_exhaustive_let(
format!("non-exhaustive pattern: {}", d.uncovered_patterns),
d.pat.map(Into::into),
)
+ .stable()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/parenthesized_generic_args_without_fn_trait.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/parenthesized_generic_args_without_fn_trait.rs
index ccf5172..68f2b19 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/parenthesized_generic_args_without_fn_trait.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/parenthesized_generic_args_without_fn_trait.rs
@@ -14,6 +14,7 @@ pub(crate) fn parenthesized_generic_args_without_fn_trait(
"parenthesized type parameters may only be used with a `Fn` trait",
d.args.map(Into::into),
)
+ .stable()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_assoc_item.rs
index fe32c59..6d33ae0 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_assoc_item.rs
@@ -28,6 +28,7 @@ pub(crate) fn private_assoc_item(
),
d.expr_or_pat.map(Into::into),
)
+ .stable()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs
index 237a9b8..5b4273a 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs
@@ -15,6 +15,7 @@ pub(crate) fn private_field(ctx: &DiagnosticsContext<'_>, d: &hir::PrivateField)
),
d.expr.map(|it| it.into()),
)
+ .stable()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
index 6b78645..dec7be8 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
@@ -31,6 +31,7 @@ pub(crate) fn remove_trailing_return(
"replace return <expr>; with <expr>",
display_range,
)
+ .stable()
.with_fixes(fixes(ctx, d)),
)
}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
index 8d717b9..7dc5b5b 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
@@ -36,7 +36,6 @@ pub(crate) fn remove_unnecessary_else(
"remove unnecessary else block",
display_range,
)
- .experimental()
.with_fixes(fixes(ctx, d)),
)
}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
index 6b335c5..37ce5f5 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
@@ -21,6 +21,7 @@ pub(crate) fn replace_filter_map_next_with_find_map(
"replace filter_map(..).next() with find_map(..)",
InFile::new(d.file, d.next_expr.into()),
)
+ .stable()
.with_fixes(fixes(ctx, d))
}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs
index 19ee1ca..dd142db 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs
@@ -33,6 +33,7 @@ pub(crate) fn trait_impl_incorrect_safety(
},
),
)
+ .stable()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs
index 2d7d78f..fa7ba90 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs
@@ -29,6 +29,7 @@ pub(crate) fn trait_impl_missing_assoc_item(
&|impl_| impl_.trait_().map(|t| t.syntax().text_range()),
),
)
+ .stable()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs
index 35dc9b0..96911d4 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs
@@ -16,8 +16,6 @@ pub(crate) fn trait_impl_orphan(
.to_owned(),
InFile::new(d.file_id, d.impl_.into()),
)
- // Not yet checked for false positives
- .experimental()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
index d5c4bcf..4327b12 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
@@ -61,6 +61,7 @@ pub(crate) fn trait_impl_redundant_assoc_item(
format!("{redundant_item_name} is not a member of trait `{trait_name}`"),
ide_db::FileRange { file_id: file_id.file_id(ctx.sema.db), range },
)
+ .stable()
.with_fixes(quickfix_for_redundant_assoc_item(
ctx,
d,
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index 500c5de..5253734 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -53,8 +53,8 @@ pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch)
display_range,
)
.with_fixes(fixes(ctx, d));
- if diag.fixes.is_none() {
- diag.experimental = true;
+ if diag.fixes.is_some() {
+ diag.experimental = false;
}
diag
}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
index a933f1b..1915a88 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
@@ -37,6 +37,7 @@ pub(crate) fn typed_hole(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Di
};
Diagnostic::new(DiagnosticCode::RustcHardError("typed-hole"), message, display_range)
+ .stable()
.with_fixes(fixes)
}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs
index d16bfb8..f81d343 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs
@@ -12,6 +12,7 @@ pub(crate) fn undeclared_label(
format!("use of undeclared label `{}`", name.display(ctx.sema.db, ctx.edition)),
d.node.map(|it| it.into()),
)
+ .stable()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs
index 06f176f..5627393 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs
@@ -13,4 +13,5 @@ pub(crate) fn unimplemented_builtin_macro(
"unimplemented built-in macro".to_owned(),
d.node,
)
+ .stable()
}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
index 47fa305..af9126c 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
@@ -2,7 +2,8 @@
use std::iter;
-use hir::{DefMap, InFile, ModuleSource, db::DefDatabase};
+use hir::crate_def_map;
+use hir::{DefMap, InFile, ModuleSource};
use ide_db::base_db::RootQueryDb;
use ide_db::text_edit::TextEdit;
use ide_db::{
@@ -101,7 +102,8 @@ fn fixes(
// check crate roots, i.e. main.rs, lib.rs, ...
let relevant_crates = db.relevant_crates(file_id);
'crates: for &krate in &*relevant_crates {
- let crate_def_map = ctx.sema.db.crate_def_map(krate);
+ // FIXME: This shouldnt need to access the crate def map directly
+ let crate_def_map = crate_def_map(ctx.sema.db, krate);
let root_module = &crate_def_map[DefMap::ROOT];
let Some(root_file_id) = root_module.origin.file_id() else { continue };
@@ -156,7 +158,7 @@ fn fixes(
stack.pop();
let relevant_crates = db.relevant_crates(parent_id);
'crates: for &krate in relevant_crates.iter() {
- let crate_def_map = ctx.sema.db.crate_def_map(krate);
+ let crate_def_map = crate_def_map(ctx.sema.db, krate);
let Some((_, module)) = crate_def_map.modules().find(|(_, module)| {
module.origin.file_id().map(|file_id| file_id.file_id(ctx.sema.db)) == Some(parent_id)
&& !module.origin.is_inline()
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs
index bdff241..0c9e0d6 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs
@@ -12,6 +12,7 @@ pub(crate) fn unreachable_label(
format!("use of unreachable label `{}`", name.display(ctx.sema.db, ctx.edition)),
d.node.map(|it| it.into()),
)
+ .stable()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_assoc_item.rs
index 614057a..4ae528b 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_assoc_item.rs
@@ -13,7 +13,6 @@ pub(crate) fn unresolved_assoc_item(
"no such associated item",
d.expr_or_pat.map(Into::into),
)
- .experimental()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_extern_crate.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_extern_crate.rs
index 4cd73d4..7c3eacf7 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_extern_crate.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_extern_crate.rs
@@ -13,6 +13,7 @@ pub(crate) fn unresolved_extern_crate(
"unresolved extern crate",
d.decl.map(|it| it.into()),
)
+ .stable()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
index a4f4813..0649c97 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
@@ -52,7 +52,6 @@ pub(crate) fn unresolved_field(
}),
)
.with_fixes(fixes(ctx, d))
- .experimental()
}
fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Option<Vec<Assist>> {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs
index 4f64dab..801023d 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs
@@ -13,7 +13,6 @@ pub(crate) fn unresolved_ident(
range.range = in_node_range + range.range.start();
}
Diagnostic::new(DiagnosticCode::RustcHardError("E0425"), "no such value in this scope", range)
- .experimental()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_import.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_import.rs
index 67c7e76..0da535d 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_import.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_import.rs
@@ -18,7 +18,6 @@ pub(crate) fn unresolved_import(
// - `cfg_if!`-generated code in libstd (we don't load the sysroot correctly)
// - `core::arch` (we don't handle `#[path = "../<path>"]` correctly)
// - proc macros and/or proc macro generated code
- .experimental()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs
index 0d1c977..a87b8c4 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs
@@ -16,7 +16,6 @@ pub(crate) fn unresolved_macro_call(
format!("unresolved macro `{}{bang}`", d.path.display(ctx.sema.db, ctx.edition)),
display_range,
)
- .experimental()
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
index 7f07009..00c2a8c 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
@@ -47,7 +47,6 @@ pub(crate) fn unresolved_method(
}),
)
.with_fixes(fixes(ctx, d))
- .experimental()
}
fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) -> Option<Vec<Assist>> {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs
index 599cabe..1a409d7 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs
@@ -28,6 +28,7 @@ pub(crate) fn unresolved_module(
},
d.decl.map(|it| it.into()),
)
+ .stable()
.with_fixes(fixes(ctx, d))
}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
index 77b1075..e6bbff0 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
@@ -50,8 +50,7 @@ pub(crate) fn unused_variables(
ast.file_id.is_macro(),
ctx.edition,
)
- }))
- .experimental(),
+ })),
)
}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
index 607721d..2af14ca 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -182,7 +182,7 @@ fn new(
DiagnosticCode::Ra(_, s) => s,
},
unused: false,
- experimental: false,
+ experimental: true,
fixes: None,
main_node: None,
}
@@ -198,8 +198,8 @@ fn new_with_syntax_node_ptr(
.with_main_node(node)
}
- fn experimental(mut self) -> Diagnostic {
- self.experimental = true;
+ fn stable(mut self) -> Diagnostic {
+ self.experimental = false;
self
}
@@ -424,14 +424,11 @@ pub fn semantic_diagnostics(
AnyDiagnostic::MacroExpansionParseError(d) => {
// FIXME: Point to the correct error span here, not just the macro-call name
res.extend(d.errors.iter().take(16).map(|err| {
- {
Diagnostic::new(
DiagnosticCode::SyntaxError,
format!("Syntax Error in Expansion: {err}"),
ctx.resolve_precise_location(&d.node.clone(), d.precise_location),
)
- }
- .experimental()
}));
continue;
},
@@ -485,12 +482,8 @@ pub fn semantic_diagnostics(
Some(it) => it,
None => continue,
},
- AnyDiagnostic::GenericArgsProhibited(d) => {
- handlers::generic_args_prohibited::generic_args_prohibited(&ctx, &d)
- }
- AnyDiagnostic::ParenthesizedGenericArgsWithoutFnTrait(d) => {
- handlers::parenthesized_generic_args_without_fn_trait::parenthesized_generic_args_without_fn_trait(&ctx, &d)
- }
+ AnyDiagnostic::GenericArgsProhibited(d) => handlers::generic_args_prohibited::generic_args_prohibited(&ctx, &d),
+ AnyDiagnostic::ParenthesizedGenericArgsWithoutFnTrait(d) => handlers::parenthesized_generic_args_without_fn_trait::parenthesized_generic_args_without_fn_trait(&ctx, &d),
AnyDiagnostic::BadRtn(d) => handlers::bad_rtn::bad_rtn(&ctx, &d),
AnyDiagnostic::IncorrectGenericsLen(d) => handlers::incorrect_generics_len::incorrect_generics_len(&ctx, &d),
AnyDiagnostic::IncorrectGenericsOrder(d) => handlers::incorrect_generics_order::incorrect_generics_order(&ctx, &d),
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
index f0247f3..2c98328 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
@@ -5,17 +5,21 @@
mod intra_doc_links;
+use std::ops::Range;
+
use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag};
use pulldown_cmark_to_cmark::{Options as CMarkOptions, cmark_resume_with_options};
use stdx::format_to;
use url::Url;
-use hir::{Adt, AsAssocItem, AssocItem, AssocItemContainer, HasAttrs, db::HirDatabase, sym};
+use hir::{
+ Adt, AsAssocItem, AssocItem, AssocItemContainer, AttrsWithOwner, HasAttrs, db::HirDatabase, sym,
+};
use ide_db::{
RootDatabase,
base_db::{CrateOrigin, LangCrateOrigin, ReleaseChannel, RootQueryDb},
defs::{Definition, NameClass, NameRefClass},
- documentation::{Documentation, HasDocs, docs_with_rangemap},
+ documentation::{DocsRangeMap, Documentation, HasDocs, docs_with_rangemap},
helpers::pick_best_token,
};
use syntax::{
@@ -46,11 +50,17 @@ pub struct DocumentationLinks {
Options::ENABLE_FOOTNOTES.union(Options::ENABLE_TABLES).union(Options::ENABLE_TASKLISTS);
/// Rewrite documentation links in markdown to point to an online host (e.g. docs.rs)
-pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: Definition) -> String {
+pub(crate) fn rewrite_links(
+ db: &RootDatabase,
+ markdown: &str,
+ definition: Definition,
+ range_map: Option<DocsRangeMap>,
+) -> String {
let mut cb = broken_link_clone_cb;
- let doc = Parser::new_with_broken_link_callback(markdown, MARKDOWN_OPTIONS, Some(&mut cb));
+ let doc = Parser::new_with_broken_link_callback(markdown, MARKDOWN_OPTIONS, Some(&mut cb))
+ .into_offset_iter();
- let doc = map_links(doc, |target, title| {
+ let doc = map_links(doc, |target, title, range| {
// This check is imperfect, there's some overlap between valid intra-doc links
// and valid URLs so we choose to be too eager to try to resolve what might be
// a URL.
@@ -60,7 +70,16 @@ pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: Defin
// Two possibilities:
// * path-based links: `../../module/struct.MyStruct.html`
// * module-based links (AKA intra-doc links): `super::super::module::MyStruct`
- if let Some((target, title)) = rewrite_intra_doc_link(db, definition, target, title) {
+ let text_range =
+ TextRange::new(range.start.try_into().unwrap(), range.end.try_into().unwrap());
+ let is_inner_doc = range_map
+ .as_ref()
+ .and_then(|range_map| range_map.map(text_range))
+ .map(|(_, attr_id)| attr_id.is_inner_attr())
+ .unwrap_or(false);
+ if let Some((target, title)) =
+ rewrite_intra_doc_link(db, definition, target, title, is_inner_doc)
+ {
(None, target, title)
} else if let Some(target) = rewrite_url_link(db, definition, target) {
(Some(LinkType::Inline), target, title.to_owned())
@@ -195,22 +214,23 @@ pub(crate) fn resolve_doc_path_for_def(
def: Definition,
link: &str,
ns: Option<hir::Namespace>,
+ is_inner_doc: bool,
) -> Option<Definition> {
match def {
- Definition::Module(it) => it.resolve_doc_path(db, link, ns),
- Definition::Crate(it) => it.resolve_doc_path(db, link, ns),
- Definition::Function(it) => it.resolve_doc_path(db, link, ns),
- Definition::Adt(it) => it.resolve_doc_path(db, link, ns),
- Definition::Variant(it) => it.resolve_doc_path(db, link, ns),
- Definition::Const(it) => it.resolve_doc_path(db, link, ns),
- Definition::Static(it) => it.resolve_doc_path(db, link, ns),
- Definition::Trait(it) => it.resolve_doc_path(db, link, ns),
- Definition::TraitAlias(it) => it.resolve_doc_path(db, link, ns),
- Definition::TypeAlias(it) => it.resolve_doc_path(db, link, ns),
- Definition::Macro(it) => it.resolve_doc_path(db, link, ns),
- Definition::Field(it) => it.resolve_doc_path(db, link, ns),
- Definition::SelfType(it) => it.resolve_doc_path(db, link, ns),
- Definition::ExternCrateDecl(it) => it.resolve_doc_path(db, link, ns),
+ Definition::Module(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+ Definition::Crate(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+ Definition::Function(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+ Definition::Adt(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+ Definition::Variant(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+ Definition::Const(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+ Definition::Static(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+ Definition::Trait(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+ Definition::TraitAlias(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+ Definition::TypeAlias(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+ Definition::Macro(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+ Definition::Field(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+ Definition::SelfType(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
+ Definition::ExternCrateDecl(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
Definition::BuiltinAttr(_)
| Definition::BuiltinType(_)
| Definition::BuiltinLifetime(_)
@@ -289,31 +309,58 @@ pub(crate) fn get_definition_with_descend_at<T>(
let relative_comment_offset = offset - original_start - prefix_len;
sema.descend_into_macros(doc_token).into_iter().find_map(|t| {
- let (node, descended_prefix_len) = match_ast! {
+ let (node, descended_prefix_len, is_inner) = match_ast!{
match t {
- ast::Comment(comment) => (t.parent()?, TextSize::try_from(comment.prefix().len()).ok()?),
- ast::String(string) => (t.parent_ancestors().skip_while(|n| n.kind() != ATTR).nth(1)?, string.open_quote_text_range()?.len()),
+ ast::Comment(comment) => {
+ (t.parent()?, TextSize::try_from(comment.prefix().len()).ok()?, comment.is_inner())
+ },
+ ast::String(string) => {
+ let attr = t.parent_ancestors().find_map(ast::Attr::cast)?;
+ let attr_is_inner = attr.excl_token().map(|excl| excl.kind() == BANG).unwrap_or(false);
+ (attr.syntax().parent()?, string.open_quote_text_range()?.len(), attr_is_inner)
+ },
_ => return None,
}
};
let token_start = t.text_range().start();
let abs_in_expansion_offset = token_start + relative_comment_offset + descended_prefix_len;
-
- let (attributes, def) = doc_attributes(sema, &node)?;
+ let (attributes, def) = Self::doc_attributes(sema, &node, is_inner)?;
let (docs, doc_mapping) = docs_with_rangemap(sema.db, &attributes)?;
- let (in_expansion_range, link, ns) =
+ let (in_expansion_range, link, ns, is_inner) =
extract_definitions_from_docs(&docs).into_iter().find_map(|(range, link, ns)| {
- let mapped = doc_mapping.map(range)?;
- (mapped.value.contains(abs_in_expansion_offset)).then_some((mapped.value, link, ns))
+ let (mapped, idx) = doc_mapping.map(range)?;
+ (mapped.value.contains(abs_in_expansion_offset)).then_some((mapped.value, link, ns, idx.is_inner_attr()))
})?;
// get the relative range to the doc/attribute in the expansion
let in_expansion_relative_range = in_expansion_range - descended_prefix_len - token_start;
// Apply relative range to the original input comment
let absolute_range = in_expansion_relative_range + original_start + prefix_len;
- let def = resolve_doc_path_for_def(sema.db, def, &link, ns)?;
+ let def = resolve_doc_path_for_def(sema.db, def, &link, ns, is_inner)?;
cb(def, node, absolute_range)
})
}
+
+ /// When we hover a inner doc item, this find a attached definition.
+ /// ```
+ /// // node == ITEM_LIST
+ /// // node.parent == EXPR_BLOCK
+ /// // node.parent().parent() == FN
+ /// fn f() {
+ /// //! [`S$0`]
+ /// }
+ /// ```
+ fn doc_attributes(
+ sema: &Semantics<'_, RootDatabase>,
+ node: &SyntaxNode,
+ is_inner_doc: bool,
+ ) -> Option<(AttrsWithOwner, Definition)> {
+ if is_inner_doc && node.kind() != SOURCE_FILE {
+ let parent = node.parent()?;
+ doc_attributes(sema, &parent).or(doc_attributes(sema, &parent.parent()?))
+ } else {
+ doc_attributes(sema, node)
+ }
+ }
}
fn broken_link_clone_cb(link: BrokenLink<'_>) -> Option<(CowStr<'_>, CowStr<'_>)> {
@@ -369,6 +416,7 @@ fn rewrite_intra_doc_link(
def: Definition,
target: &str,
title: &str,
+ is_inner_doc: bool,
) -> Option<(String, String)> {
let (link, ns) = parse_intra_doc_link(target);
@@ -377,7 +425,7 @@ fn rewrite_intra_doc_link(
None => (link, None),
};
- let resolved = resolve_doc_path_for_def(db, def, link, ns)?;
+ let resolved = resolve_doc_path_for_def(db, def, link, ns, is_inner_doc)?;
let mut url = get_doc_base_urls(db, resolved, None, None).0?;
let (_, file, frag) = filename_and_frag_for_def(db, resolved)?;
@@ -421,8 +469,8 @@ fn mod_path_of_def(db: &RootDatabase, def: Definition) -> Option<String> {
/// Rewrites a markdown document, applying 'callback' to each link.
fn map_links<'e>(
- events: impl Iterator<Item = Event<'e>>,
- callback: impl Fn(&str, &str) -> (Option<LinkType>, String, String),
+ events: impl Iterator<Item = (Event<'e>, Range<usize>)>,
+ callback: impl Fn(&str, &str, Range<usize>) -> (Option<LinkType>, String, String),
) -> impl Iterator<Item = Event<'e>> {
let mut in_link = false;
// holds the origin link target on start event and the rewritten one on end event
@@ -432,7 +480,7 @@ fn map_links<'e>(
// `Shortcut` type parsed from Start/End tags doesn't make sense for url links
let mut end_link_type: Option<LinkType> = None;
- events.map(move |evt| match evt {
+ events.map(move |(evt, range)| match evt {
Event::Start(Tag::Link(link_type, ref target, _)) => {
in_link = true;
end_link_target = Some(target.clone());
@@ -449,7 +497,7 @@ fn map_links<'e>(
}
Event::Text(s) if in_link => {
let (link_type, link_target_s, link_name) =
- callback(&end_link_target.take().unwrap(), &s);
+ callback(&end_link_target.take().unwrap(), &s, range);
end_link_target = Some(CowStr::Boxed(link_target_s.into()));
if !matches!(end_link_type, Some(LinkType::Autolink)) {
end_link_type = link_type;
@@ -458,7 +506,7 @@ fn map_links<'e>(
}
Event::Code(s) if in_link => {
let (link_type, link_target_s, link_name) =
- callback(&end_link_target.take().unwrap(), &s);
+ callback(&end_link_target.take().unwrap(), &s, range);
end_link_target = Some(CowStr::Boxed(link_target_s.into()));
if !matches!(end_link_type, Some(LinkType::Autolink)) {
end_link_type = link_type;
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
index 91785be..6af156f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
@@ -5,7 +5,7 @@
use ide_db::{
FilePosition, FileRange, RootDatabase,
defs::Definition,
- documentation::{Documentation, HasDocs},
+ documentation::{DocsRangeMap, Documentation, HasDocs},
};
use itertools::Itertools;
use syntax::{AstNode, SyntaxNode, ast, match_ast};
@@ -45,8 +45,8 @@ fn check_external_docs(
fn check_rewrite(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
let (analysis, position) = fixture::position(ra_fixture);
let sema = &Semantics::new(&analysis.db);
- let (cursor_def, docs) = def_under_cursor(sema, &position);
- let res = rewrite_links(sema.db, docs.as_str(), cursor_def);
+ let (cursor_def, docs, range) = def_under_cursor(sema, &position);
+ let res = rewrite_links(sema.db, docs.as_str(), cursor_def, Some(range));
expect.assert_eq(&res)
}
@@ -56,12 +56,14 @@ fn check_doc_links(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
let (analysis, position, mut expected) = fixture::annotations(ra_fixture);
expected.sort_by_key(key_fn);
let sema = &Semantics::new(&analysis.db);
- let (cursor_def, docs) = def_under_cursor(sema, &position);
+ let (cursor_def, docs, range) = def_under_cursor(sema, &position);
let defs = extract_definitions_from_docs(&docs);
let actual: Vec<_> = defs
.into_iter()
- .flat_map(|(_, link, ns)| {
- let def = resolve_doc_path_for_def(sema.db, cursor_def, &link, ns)
+ .flat_map(|(text_range, link, ns)| {
+ let attr = range.map(text_range);
+ let is_inner_attr = attr.map(|(_file, attr)| attr.is_inner_attr()).unwrap_or(false);
+ let def = resolve_doc_path_for_def(sema.db, cursor_def, &link, ns, is_inner_attr)
.unwrap_or_else(|| panic!("Failed to resolve {link}"));
def.try_to_nav(sema.db).unwrap().into_iter().zip(iter::repeat(link))
})
@@ -78,7 +80,7 @@ fn check_doc_links(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
fn def_under_cursor(
sema: &Semantics<'_, RootDatabase>,
position: &FilePosition,
-) -> (Definition, Documentation) {
+) -> (Definition, Documentation, DocsRangeMap) {
let (docs, def) = sema
.parse_guess_edition(position.file_id)
.syntax()
@@ -89,31 +91,31 @@ fn def_under_cursor(
.find_map(|it| node_to_def(sema, &it))
.expect("no def found")
.unwrap();
- let docs = docs.expect("no docs found for cursor def");
- (def, docs)
+ let (docs, range) = docs.expect("no docs found for cursor def");
+ (def, docs, range)
}
fn node_to_def(
sema: &Semantics<'_, RootDatabase>,
node: &SyntaxNode,
-) -> Option<Option<(Option<Documentation>, Definition)>> {
+) -> Option<Option<(Option<(Documentation, DocsRangeMap)>, Definition)>> {
Some(match_ast! {
match node {
- ast::SourceFile(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Module(def))),
- ast::Module(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Module(def))),
- ast::Fn(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Function(def))),
- ast::Struct(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Adt(hir::Adt::Struct(def)))),
- ast::Union(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Adt(hir::Adt::Union(def)))),
- ast::Enum(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Adt(hir::Adt::Enum(def)))),
- ast::Variant(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Variant(def))),
- ast::Trait(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Trait(def))),
- ast::Static(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Static(def))),
- ast::Const(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Const(def))),
- ast::TypeAlias(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::TypeAlias(def))),
- ast::Impl(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::SelfType(def))),
- ast::RecordField(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Field(def))),
- ast::TupleField(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Field(def))),
- ast::Macro(it) => sema.to_def(&it).map(|def| (def.docs(sema.db), Definition::Macro(def))),
+ ast::SourceFile(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Module(def))),
+ ast::Module(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Module(def))),
+ ast::Fn(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Function(def))),
+ ast::Struct(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Adt(hir::Adt::Struct(def)))),
+ ast::Union(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Adt(hir::Adt::Union(def)))),
+ ast::Enum(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Adt(hir::Adt::Enum(def)))),
+ ast::Variant(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Variant(def))),
+ ast::Trait(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Trait(def))),
+ ast::Static(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Static(def))),
+ ast::Const(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Const(def))),
+ ast::TypeAlias(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::TypeAlias(def))),
+ ast::Impl(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::SelfType(def))),
+ ast::RecordField(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Field(def))),
+ ast::TupleField(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Field(def))),
+ ast::Macro(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Macro(def))),
// ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))),
_ => return None,
}
@@ -576,6 +578,40 @@ fn doc_links_tuple_field_via_self() {
}
#[test]
+fn doc_links_module() {
+ check_doc_links(
+ r#"
+/// [`M`]
+/// [`M::f`]
+mod M$0 {
+ //^ M
+ #![doc = "inner_item[`S`]"]
+
+ pub fn f() {}
+ //^ M::f
+ pub struct S;
+ //^ S
+}
+"#,
+ );
+
+ check_doc_links(
+ r#"
+mod M$0 {
+ //^ super::M
+ //! [`super::M`]
+ //! [`super::M::f`]
+ //! [`super::M::S`]
+ pub fn f() {}
+ //^ super::M::f
+ pub struct S;
+ //^ super::M::S
+}
+"#,
+ );
+}
+
+#[test]
fn rewrite_html_root_url() {
check_rewrite(
r#"
@@ -691,6 +727,29 @@ fn main() {}
}
#[test]
+fn rewrite_module() {
+ check_rewrite(
+ r#"
+//- /main.rs crate:foo
+/// [Foo]
+pub mod $0Foo{
+};
+"#,
+ expect"#]],
+ );
+
+ check_rewrite(
+ r#"
+//- /main.rs crate:foo
+pub mod $0Foo{
+ //! [super::Foo]
+};
+"#,
+ expect"#]],
+ );
+}
+
+#[test]
fn rewrite_intra_doc_link_to_associated_item() {
check_rewrite(
r#"
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
index b894e85..c60ca35 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -1923,6 +1923,74 @@ pub fn foo() { }
}
#[test]
+ fn goto_def_for_intra_doc_link_outer_same_file() {
+ check(
+ r#"
+/// [`S$0`]
+mod m {
+ //! [`super::S`]
+}
+struct S;
+ //^
+ "#,
+ );
+
+ check(
+ r#"
+/// [`S$0`]
+mod m {}
+struct S;
+ //^
+ "#,
+ );
+
+ check(
+ r#"
+/// [`S$0`]
+fn f() {
+ //! [`S`]
+}
+struct S;
+ //^
+ "#,
+ );
+ }
+
+ #[test]
+ fn goto_def_for_intra_doc_link_inner_same_file() {
+ check(
+ r#"
+/// [`S`]
+mod m {
+ //! [`super::S$0`]
+}
+struct S;
+ //^
+ "#,
+ );
+
+ check(
+ r#"
+mod m {
+ //! [`super::S$0`]
+}
+struct S;
+ //^
+ "#,
+ );
+
+ check(
+ r#"
+fn f() {
+ //! [`S$0`]
+}
+struct S;
+ //^
+ "#,
+ );
+ }
+
+ #[test]
fn goto_def_for_intra_doc_link_inner() {
check(
r#"
diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
index 80624ee..fb8dbcf 100644
--- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
@@ -89,6 +89,9 @@ pub(crate) fn highlight_related(
T![break] | T![loop] | T![while] | T![continue] if config.break_points => {
highlight_break_points(sema, token).remove(&file_id)
}
+ T![unsafe] if token.parent().and_then(ast::BlockExpr::cast).is_some() => {
+ highlight_unsafe_points(sema, token).remove(&file_id)
+ }
T![|] if config.closure_captures => {
highlight_closure_captures(sema, token, file_id, span_file_id.file_id())
}
@@ -706,6 +709,44 @@ fn is_async_const_block_or_closure(expr: &ast::Expr) -> bool {
}
}
+pub(crate) fn highlight_unsafe_points(
+ sema: &Semantics<'_, RootDatabase>,
+ token: SyntaxToken,
+) -> FxHashMap<EditionedFileId, Vec<HighlightedRange>> {
+ fn hl(
+ sema: &Semantics<'_, RootDatabase>,
+ unsafe_token: &SyntaxToken,
+ block_expr: Option<ast::BlockExpr>,
+ ) -> Option<FxHashMap<EditionedFileId, Vec<HighlightedRange>>> {
+ let mut highlights: FxHashMap<EditionedFileId, Vec<_>> = FxHashMap::default();
+
+ let mut push_to_highlights = |file_id, range| {
+ if let Some(FileRange { file_id, range }) = original_frange(sema.db, file_id, range) {
+ let hrange = HighlightedRange { category: ReferenceCategory::empty(), range };
+ highlights.entry(file_id).or_default().push(hrange);
+ }
+ };
+
+ // highlight unsafe keyword itself
+ let unsafe_token_file_id = sema.hir_file_for(&unsafe_token.parent()?);
+ push_to_highlights(unsafe_token_file_id, Some(unsafe_token.text_range()));
+
+ // highlight unsafe operations
+ if let Some(block) = block_expr {
+ if let Some(body) = sema.body_for(InFile::new(unsafe_token_file_id, block.syntax())) {
+ let unsafe_ops = sema.get_unsafe_ops(body);
+ for unsafe_op in unsafe_ops {
+ push_to_highlights(unsafe_op.file_id, Some(unsafe_op.value.text_range()));
+ }
+ }
+ }
+
+ Some(highlights)
+ }
+
+ hl(sema, &token, token.parent().and_then(ast::BlockExpr::cast)).unwrap_or_default()
+}
+
#[cfg(test)]
mod tests {
use itertools::Itertools;
@@ -755,6 +796,32 @@ fn check_with_config(
}
#[test]
+ fn test_hl_unsafe_block() {
+ check(
+ r#"
+fn foo() {
+ unsafe fn this_is_unsafe_function() {}
+
+ unsa$0fe {
+ //^^^^^^
+ let raw_ptr = &42 as *const i32;
+ let val = *raw_ptr;
+ //^^^^^^^^
+
+ let mut_ptr = &mut 5 as *mut i32;
+ *mut_ptr = 10;
+ //^^^^^^^^
+
+ this_is_unsafe_function();
+ //^^^^^^^^^^^^^^^^^^^^^^^^^
+ }
+
+}
+"#,
+ );
+ }
+
+ #[test]
fn test_hl_tuple_fields() {
check(
r#"
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index 075afce..873e31b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -456,7 +456,7 @@ pub(crate) fn hover_for_definition(
let notable_traits = def_ty.map(|ty| notable_traits(db, &ty)).unwrap_or_default();
let subst_types = subst.map(|subst| subst.types(db));
- let markup = render::definition(
+ let (markup, range_map) = render::definition(
sema.db,
def,
famous_defs.as_ref(),
@@ -469,7 +469,7 @@ pub(crate) fn hover_for_definition(
display_target,
);
HoverResult {
- markup: render::process_markup(sema.db, def, &markup, config),
+ markup: render::process_markup(sema.db, def, &markup, range_map, config),
actions: [
show_fn_references_action(sema.db, def),
show_implementations_action(sema.db, def),
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
index 69b83f3..ad720c8 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -11,7 +11,7 @@
use ide_db::{
RootDatabase,
defs::Definition,
- documentation::HasDocs,
+ documentation::{DocsRangeMap, HasDocs},
famous_defs::FamousDefs,
generated::lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES},
syntax_helpers::prettify_macro_expansion,
@@ -21,7 +21,7 @@
Float,
ieee::{Half as f16, Quad as f128},
};
-use span::Edition;
+use span::{Edition, TextSize};
use stdx::format_to;
use syntax::{AstNode, AstToken, Direction, SyntaxToken, T, algo, ast, match_ast};
@@ -276,13 +276,10 @@ pub(super) fn keyword(
keyword_hints(sema, token, parent, edition, display_target);
let doc_owner = find_std_module(&famous_defs, &keyword_mod, edition)?;
- let docs = doc_owner.docs(sema.db)?;
- let markup = process_markup(
- sema.db,
- Definition::Module(doc_owner),
- &markup(Some(docs.into()), description, None, None, String::new()),
- config,
- );
+ let (docs, range_map) = doc_owner.docs_with_rangemap(sema.db)?;
+ let (markup, range_map) =
+ markup(Some(docs.into()), Some(range_map), description, None, None, String::new());
+ let markup = process_markup(sema.db, Definition::Module(doc_owner), &markup, range_map, config);
Some(HoverResult { markup, actions })
}
@@ -371,11 +368,15 @@ pub(super) fn process_markup(
db: &RootDatabase,
def: Definition,
markup: &Markup,
+ markup_range_map: Option<DocsRangeMap>,
config: &HoverConfig,
) -> Markup {
let markup = markup.as_str();
- let markup =
- if config.links_in_hover { rewrite_links(db, markup, def) } else { remove_links(markup) };
+ let markup = if config.links_in_hover {
+ rewrite_links(db, markup, def, markup_range_map)
+ } else {
+ remove_links(markup)
+ };
Markup::from(markup)
}
@@ -482,7 +483,7 @@ pub(super) fn definition(
config: &HoverConfig,
edition: Edition,
display_target: DisplayTarget,
-) -> Markup {
+) -> (Markup, Option<DocsRangeMap>) {
let mod_path = definition_path(db, &def, edition);
let label = match def {
Definition::Trait(trait_) => trait_
@@ -518,7 +519,12 @@ pub(super) fn definition(
}
_ => def.label(db, display_target),
};
- let docs = def.docs(db, famous_defs, display_target);
+ let (docs, range_map) =
+ if let Some((docs, doc_range)) = def.docs_with_rangemap(db, famous_defs, display_target) {
+ (Some(docs), doc_range)
+ } else {
+ (None, None)
+ };
let value = || match def {
Definition::Variant(it) => {
if !it.parent_enum(db).is_data_carrying(db) {
@@ -807,6 +813,7 @@ pub(super) fn definition(
markup(
docs.map(Into::into),
+ range_map,
desc,
extra.is_empty().not().then_some(extra),
mod_path,
@@ -1083,11 +1090,12 @@ fn definition_path(db: &RootDatabase, &def: &Definition, edition: Edition) -> Op
fn markup(
docs: Option<String>,
+ range_map: Option<DocsRangeMap>,
rust: String,
extra: Option<String>,
mod_path: Option<String>,
subst_types: String,
-) -> Markup {
+) -> (Markup, Option<DocsRangeMap>) {
let mut buf = String::new();
if let Some(mod_path) = mod_path {
@@ -1106,9 +1114,15 @@ fn markup(
}
if let Some(doc) = docs {
- format_to!(buf, "\n___\n\n{}", doc);
+ format_to!(buf, "\n___\n\n");
+ let offset = TextSize::new(buf.len() as u32);
+ let buf_range_map = range_map.map(|range_map| range_map.shift_docstring_line_range(offset));
+ format_to!(buf, "{}", doc);
+
+ (buf.into(), buf_range_map)
+ } else {
+ (buf.into(), None)
}
- buf.into()
}
fn find_std_module(
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
index 7b7eef9..06ca24c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -7375,6 +7375,128 @@ pub struct Foo(i32)
}
#[test]
+fn hover_intra_inner_attr() {
+ check(
+ r#"
+/// outer comment for [`Foo`]
+#[doc = "Doc outer comment for [`Foo`]"]
+pub fn Foo {
+ //! inner comment for [`Foo$0`]
+ #![doc = "Doc inner comment for [`Foo`]"]
+}
+"#,
+ expect![[r#"
+ *[`Foo`]*
+
+ ```rust
+ ra_test_fixture
+ ```
+
+ ```rust
+ pub fn Foo()
+ ```
+
+ ---
+
+ outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html)
+ Doc outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html)
+ inner comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html)
+ Doc inner comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html)
+ "#]],
+ );
+
+ check(
+ r#"
+/// outer comment for [`Foo`]
+#[doc = "Doc outer comment for [`Foo`]"]
+pub mod Foo {
+ //! inner comment for [`super::Foo$0`]
+ #![doc = "Doc inner comment for [`super::Foo`]"]
+}
+"#,
+ expect![[r#"
+ *[`super::Foo`]*
+
+ ```rust
+ ra_test_fixture
+ ```
+
+ ```rust
+ pub mod Foo
+ ```
+
+ ---
+
+ outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html)
+ Doc outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html)
+ inner comment for [`super::Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html)
+ Doc inner comment for [`super::Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html)
+ "#]],
+ );
+}
+
+#[test]
+fn hover_intra_outer_attr() {
+ check(
+ r#"
+/// outer comment for [`Foo$0`]
+#[doc = "Doc outer comment for [`Foo`]"]
+pub fn Foo() {
+ //! inner comment for [`Foo`]
+ #![doc = "Doc inner comment for [`Foo`]"]
+}
+"#,
+ expect![[r#"
+ *[`Foo`]*
+
+ ```rust
+ ra_test_fixture
+ ```
+
+ ```rust
+ pub fn Foo()
+ ```
+
+ ---
+
+ outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html)
+ Doc outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html)
+ inner comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html)
+ Doc inner comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/fn.Foo.html)
+ "#]],
+ );
+
+ check(
+ r#"
+/// outer comment for [`Foo$0`]
+#[doc = "Doc outer comment for [`Foo`]"]
+pub mod Foo {
+ //! inner comment for [`super::Foo`]
+ #![doc = "Doc inner comment for [`super::Foo`]"]
+}
+"#,
+ expect![[r#"
+ *[`Foo`]*
+
+ ```rust
+ ra_test_fixture
+ ```
+
+ ```rust
+ pub mod Foo
+ ```
+
+ ---
+
+ outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html)
+ Doc outer comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html)
+ inner comment for [`super::Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html)
+ Doc inner comment for [`super::Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/Foo/index.html)
+ "#]],
+ );
+}
+
+#[test]
fn hover_intra_generics() {
check(
r#"
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index aa525a8..d649dff 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -62,7 +62,7 @@
use cfg::CfgOptions;
use fetch_crates::CrateInfo;
-use hir::{ChangeWithProcMacros, EditionedFileId, sym};
+use hir::{ChangeWithProcMacros, EditionedFileId, crate_def_map, sym};
use ide_db::{
FxHashMap, FxIndexSet, LineIndexDatabase,
base_db::{
@@ -627,7 +627,7 @@ pub fn is_proc_macro_crate(&self, crate_id: Crate) -> Cancellable<bool> {
/// Returns true if this crate has `no_std` or `no_core` specified.
pub fn is_crate_no_std(&self, crate_id: Crate) -> Cancellable<bool> {
- self.with_db(|db| hir::db::DefDatabase::crate_def_map(db, crate_id).is_no_std())
+ self.with_db(|db| crate_def_map(db, crate_id).is_no_std())
}
/// Returns the root file of the given crate.
diff --git a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
index 6dc01c4..50219ce 100644
--- a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
@@ -1,4 +1,4 @@
-use hir::{Semantics, db::DefDatabase};
+use hir::{Semantics, crate_def_map};
use ide_db::{
FileId, FilePosition, RootDatabase,
base_db::{Crate, RootQueryDb},
@@ -58,7 +58,7 @@ pub(crate) fn crates_for(db: &RootDatabase, file_id: FileId) -> Vec<Crate> {
.iter()
.copied()
.filter(|&crate_id| {
- db.crate_def_map(crate_id).modules_for_file(db, file_id).next().is_some()
+ crate_def_map(db, crate_id).modules_for_file(db, file_id).next().is_some()
})
.sorted()
.collect()
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
index 0998e14..7f5c2c1 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
@@ -129,11 +129,18 @@ pub(super) fn doc_comment(
extract_definitions_from_docs(&docs)
.into_iter()
.filter_map(|(range, link, ns)| {
- doc_mapping.map(range).filter(|mapping| mapping.file_id == src_file_id).and_then(
- |InFile { value: mapped_range, .. }| {
- Some(mapped_range).zip(resolve_doc_path_for_def(sema.db, def, &link, ns))
- },
- )
+ doc_mapping
+ .map(range)
+ .filter(|(mapping, _)| mapping.file_id == src_file_id)
+ .and_then(|(InFile { value: mapped_range, .. }, attr_id)| {
+ Some(mapped_range).zip(resolve_doc_path_for_def(
+ sema.db,
+ def,
+ &link,
+ ns,
+ attr_id.is_inner_attr(),
+ ))
+ })
})
.for_each(|(range, def)| {
hl.add(HlRange {
diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
index 2686a75..30e2d54 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -512,10 +512,6 @@ fn expand(
Err(err) => Err(ProcMacroExpansionError::System(err.to_string())),
}
}
-
- fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
- other.as_any().downcast_ref::<Self>().is_some_and(|other| self == other)
- }
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/mbe/src/tests.rs b/src/tools/rust-analyzer/crates/mbe/src/tests.rs
index a5672e4..3369dff 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/tests.rs
@@ -356,3 +356,120 @@ fn expr_2021() {
;"#]],
);
}
+
+#[test]
+fn minus_belongs_to_literal() {
+ let decl = r#"
+(-1) => {-1};
+(- 2) => {- 2};
+(- 3.0) => {- 3.0};
+(@$lit:literal) => {$lit}
+"#;
+ let check = |args, expect| check(Edition::CURRENT, Edition::CURRENT, decl, args, expect);
+ check(
+ "-1",
+ expect![[r#"
+ SUBTREE $$ 1:0@0..2#ROOT2024 1:0@0..2#ROOT2024
+ PUNCH - [alone] 0:0@10..11#ROOT2024
+ LITERAL Integer 1 0:0@11..12#ROOT2024
+
+ -1"#]],
+ );
+ check(
+ "- 1",
+ expect![[r#"
+ SUBTREE $$ 1:0@0..3#ROOT2024 1:0@0..3#ROOT2024
+ PUNCH - [alone] 0:0@10..11#ROOT2024
+ LITERAL Integer 1 0:0@11..12#ROOT2024
+
+ -1"#]],
+ );
+ check(
+ "-2",
+ expect![[r#"
+ SUBTREE $$ 1:0@0..2#ROOT2024 1:0@0..2#ROOT2024
+ PUNCH - [alone] 0:0@25..26#ROOT2024
+ LITERAL Integer 2 0:0@27..28#ROOT2024
+
+ -2"#]],
+ );
+ check(
+ "- 2",
+ expect![[r#"
+ SUBTREE $$ 1:0@0..3#ROOT2024 1:0@0..3#ROOT2024
+ PUNCH - [alone] 0:0@25..26#ROOT2024
+ LITERAL Integer 2 0:0@27..28#ROOT2024
+
+ -2"#]],
+ );
+ check(
+ "-3.0",
+ expect![[r#"
+ SUBTREE $$ 1:0@0..4#ROOT2024 1:0@0..4#ROOT2024
+ PUNCH - [alone] 0:0@43..44#ROOT2024
+ LITERAL Float 3.0 0:0@45..48#ROOT2024
+
+ -3.0"#]],
+ );
+ check(
+ "- 3.0",
+ expect![[r#"
+ SUBTREE $$ 1:0@0..5#ROOT2024 1:0@0..5#ROOT2024
+ PUNCH - [alone] 0:0@43..44#ROOT2024
+ LITERAL Float 3.0 0:0@45..48#ROOT2024
+
+ -3.0"#]],
+ );
+ check(
+ "@1",
+ expect![[r#"
+ SUBTREE $$ 1:0@0..2#ROOT2024 1:0@0..2#ROOT2024
+ LITERAL Integer 1 1:0@1..2#ROOT2024
+
+ 1"#]],
+ );
+ check(
+ "@-1",
+ expect![[r#"
+ SUBTREE $$ 1:0@0..3#ROOT2024 1:0@0..3#ROOT2024
+ PUNCH - [alone] 1:0@1..2#ROOT2024
+ LITERAL Integer 1 1:0@2..3#ROOT2024
+
+ -1"#]],
+ );
+ check(
+ "@1.0",
+ expect![[r#"
+ SUBTREE $$ 1:0@0..4#ROOT2024 1:0@0..4#ROOT2024
+ LITERAL Float 1.0 1:0@1..4#ROOT2024
+
+ 1.0"#]],
+ );
+ check(
+ "@-1.0",
+ expect![[r#"
+ SUBTREE $$ 1:0@0..5#ROOT2024 1:0@0..5#ROOT2024
+ PUNCH - [alone] 1:0@1..2#ROOT2024
+ LITERAL Float 1.0 1:0@2..5#ROOT2024
+
+ -1.0"#]],
+ );
+ check(
+ "@--1.0",
+ expect![[r#"
+ ExpandError {
+ inner: (
+ 1:0@1..2#ROOT2024,
+ BindingError(
+ "expected literal",
+ ),
+ ),
+ }
+
+ SUBTREE $$ 1:0@0..6#ROOT2024 1:0@0..6#ROOT2024
+ PUNCH - [joint] 1:0@1..2#ROOT2024
+ PUNCH - [alone] 1:0@2..3#ROOT2024
+
+ --"#]],
+ );
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs
index 5faf6fc..8cc332d 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs
@@ -381,10 +381,14 @@ fn parse_asm_expr(p: &mut Parser<'_>, m: Marker) -> Option<CompletedMarker> {
op.complete(p, ASM_REG_OPERAND);
op_n.complete(p, ASM_OPERAND_NAMED);
} else if p.eat_contextual_kw(T![label]) {
+ // test asm_label
+ // fn foo() {
+ // builtin#asm("", label {});
+ // }
dir_spec.abandon(p);
block_expr(p);
- op.complete(p, ASM_OPERAND_NAMED);
- op_n.complete(p, ASM_LABEL);
+ op.complete(p, ASM_LABEL);
+ op_n.complete(p, ASM_OPERAND_NAMED);
} else if p.eat(T![const]) {
dir_spec.abandon(p);
expr(p);
diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
index 0a5c16d..0fa9a26 100644
--- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
@@ -179,7 +179,10 @@ fn extend_token(&mut self, kind: &rustc_lexer::TokenKind, mut token_text: &str)
COMMENT
}
- rustc_lexer::TokenKind::Frontmatter { has_invalid_preceding_whitespace, invalid_infostring } => {
+ rustc_lexer::TokenKind::Frontmatter {
+ has_invalid_preceding_whitespace,
+ invalid_infostring,
+ } => {
if *has_invalid_preceding_whitespace {
err = "invalid preceding whitespace for frontmatter opening"
} else if *invalid_infostring {
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
index 24db947..030d8e0 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
+++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
@@ -21,6 +21,8 @@ fn arb_self_types() {
#[test]
fn asm_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/asm_expr.rs"); }
#[test]
+ fn asm_label() { run_and_expect_no_errors("test_data/parser/inline/ok/asm_label.rs"); }
+ #[test]
fn assoc_const_eq() {
run_and_expect_no_errors("test_data/parser/inline/ok/assoc_const_eq.rs");
}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_label.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_label.rast
new file mode 100644
index 0000000..38999c9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_label.rast
@@ -0,0 +1,37 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ ASM_EXPR
+ BUILTIN_KW "builtin"
+ POUND "#"
+ ASM_KW "asm"
+ L_PAREN "("
+ LITERAL
+ STRING "\"\""
+ COMMA ","
+ WHITESPACE " "
+ ASM_OPERAND_NAMED
+ ASM_LABEL
+ LABEL_KW "label"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_label.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_label.rs
new file mode 100644
index 0000000..996c1c8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_label.rs
@@ -0,0 +1,3 @@
+fn foo() {
+ builtin#asm("", label {});
+}
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs
index dfdbb4c..6820e4b 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs
@@ -31,12 +31,17 @@ pub fn fn_like_mk_literals(_args: TokenStream) -> TokenStream {
TokenTree::from(Literal::byte_string(b"byte_string")),
TokenTree::from(Literal::character('c')),
TokenTree::from(Literal::string("string")),
+ TokenTree::from(Literal::c_string(c"cstring")),
// as of 2022-07-21, there's no method on `Literal` to build a raw
// string or a raw byte string
TokenTree::from(Literal::f64_suffixed(3.14)),
+ TokenTree::from(Literal::f64_suffixed(-3.14)),
TokenTree::from(Literal::f64_unsuffixed(3.14)),
+ TokenTree::from(Literal::f64_unsuffixed(-3.14)),
TokenTree::from(Literal::i64_suffixed(123)),
+ TokenTree::from(Literal::i64_suffixed(-123)),
TokenTree::from(Literal::i64_unsuffixed(123)),
+ TokenTree::from(Literal::i64_unsuffixed(-123)),
];
TokenStream::from_iter(trees)
}
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs
index 3d99942..11dbd92 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs
@@ -16,9 +16,8 @@
pub use token_stream::TokenStream;
pub mod rust_analyzer_span;
-// mod symbol;
pub mod token_id;
-// pub use symbol::*;
+
use tt::Spacing;
#[derive(Clone)]
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
index 47555a5..64b40e7 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
@@ -168,16 +168,38 @@ fn from_token_tree(
}
bridge::TokenTree::Literal(literal) => {
- let literal = tt::Literal {
- symbol: literal.symbol,
- suffix: literal.suffix,
- span: literal.span,
- kind: literal_kind_to_internal(literal.kind),
- };
+ let token_trees =
+ if let Some((_minus, symbol)) = literal.symbol.as_str().split_once('-') {
+ let punct = tt::Punct {
+ spacing: tt::Spacing::Alone,
+ span: literal.span,
+ char: '-' as char,
+ };
+ let leaf: tt::Leaf = tt::Leaf::from(punct);
+ let minus_tree = tt::TokenTree::from(leaf);
- let leaf: tt::Leaf = tt::Leaf::from(literal);
- let tree = tt::TokenTree::from(leaf);
- TokenStream { token_trees: vec![tree] }
+ let literal = tt::Literal {
+ symbol: Symbol::intern(symbol),
+ suffix: literal.suffix,
+ span: literal.span,
+ kind: literal_kind_to_internal(literal.kind),
+ };
+ let leaf: tt::Leaf = tt::Leaf::from(literal);
+ let tree = tt::TokenTree::from(leaf);
+ vec![minus_tree, tree]
+ } else {
+ let literal = tt::Literal {
+ symbol: literal.symbol,
+ suffix: literal.suffix,
+ span: literal.span,
+ kind: literal_kind_to_internal(literal.kind),
+ };
+
+ let leaf: tt::Leaf = tt::Leaf::from(literal);
+ let tree = tt::TokenTree::from(leaf);
+ vec![tree]
+ };
+ TokenStream { token_trees }
}
bridge::TokenTree::Punct(p) => {
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/symbol.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/symbol.rs
deleted file mode 100644
index 6863ce9..0000000
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/symbol.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-//! Symbol interner for proc-macro-srv
-
-use std::{cell::RefCell, collections::HashMap, thread::LocalKey};
-
-thread_local! {
- pub(crate) static SYMBOL_INTERNER: RefCell<SymbolInterner> = Default::default();
-}
-
-// ID for an interned symbol.
-#[derive(Hash, Eq, PartialEq, Copy, Clone)]
-pub struct Symbol(u32);
-
-pub(crate) type SymbolInternerRef = &'static LocalKey<RefCell<SymbolInterner>>;
-
-impl Symbol {
- pub(super) fn intern(interner: SymbolInternerRef, data: &str) -> Symbol {
- interner.with(|i| i.borrow_mut().intern(data))
- }
-
- pub(super) fn text(&self, interner: SymbolInternerRef) -> SmolStr {
- interner.with(|i| i.borrow().get(self).clone())
- }
-}
-
-#[derive(Default)]
-pub(crate) struct SymbolInterner {
- idents: HashMap<SmolStr, u32>,
- ident_data: Vec<SmolStr>,
-}
-
-impl SymbolInterner {
- fn intern(&mut self, data: &str) -> Symbol {
- if let Some(index) = self.idents.get(data) {
- return Symbol(*index);
- }
-
- let index = self.idents.len() as u32;
- let data = SmolStr::from(data);
- self.ident_data.push(data.clone());
- self.idents.insert(data, index);
- Symbol(index)
- }
-
- fn get(&self, sym: &Symbol) -> &SmolStr {
- &self.ident_data[sym.0 as usize]
- }
-}
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
index c002be4..24a67bf 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
@@ -153,16 +153,38 @@ fn from_token_tree(
}
bridge::TokenTree::Literal(literal) => {
- let literal = Literal {
- symbol: literal.symbol,
- suffix: literal.suffix,
- span: literal.span,
- kind: literal_kind_to_internal(literal.kind),
- };
+ let token_trees =
+ if let Some((_minus, symbol)) = literal.symbol.as_str().split_once('-') {
+ let punct = tt::Punct {
+ spacing: tt::Spacing::Alone,
+ span: literal.span,
+ char: '-' as char,
+ };
+ let leaf: tt::Leaf = tt::Leaf::from(punct);
+ let minus_tree = tt::TokenTree::from(leaf);
- let leaf = tt::Leaf::from(literal);
- let tree = TokenTree::from(leaf);
- TokenStream { token_trees: vec![tree] }
+ let literal = Literal {
+ symbol: Symbol::intern(symbol),
+ suffix: literal.suffix,
+ span: literal.span,
+ kind: literal_kind_to_internal(literal.kind),
+ };
+ let leaf: tt::Leaf = tt::Leaf::from(literal);
+ let tree = tt::TokenTree::from(leaf);
+ vec![minus_tree, tree]
+ } else {
+ let literal = Literal {
+ symbol: literal.symbol,
+ suffix: literal.suffix,
+ span: literal.span,
+ kind: literal_kind_to_internal(literal.kind),
+ };
+
+ let leaf: tt::Leaf = tt::Leaf::from(literal);
+ let tree = tt::TokenTree::from(leaf);
+ vec![tree]
+ };
+ TokenStream { token_trees }
}
bridge::TokenTree::Punct(p) => {
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_stream.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_stream.rs
index 4946a4f..0725579 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_stream.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_stream.rs
@@ -68,6 +68,11 @@ pub(crate) fn into_bridge(self) -> Vec<bridge::TokenTree<Self, S, intern::Symbol
span: ident.span,
}))
}
+ // Note, we do not have to assemble our `-` punct and literal split into a single
+ // negative bridge literal here. As the proc-macro docs state
+ // > Literals created from negative numbers might not survive round-trips through
+ // > TokenStream or strings and may be broken into two tokens (- and positive
+ // > literal).
tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => {
result.push(bridge::TokenTree::Literal(bridge::Literal {
span: lit.span,
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
index a81fea7..3868fee 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
@@ -11,8 +11,24 @@ fn test_derive_empty() {
assert_expand(
"DeriveEmpty",
r#"struct S;"#,
- expect!["SUBTREE $$ 1 1"],
- expect!["SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024"],
+ expect![[r#"
+ SUBTREE $$ 1 1
+ IDENT struct 1
+ IDENT S 1
+ PUNCH ; [alone] 1
+
+
+
+ SUBTREE $$ 1 1"#]],
+ expect![[r#"
+ SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+ IDENT struct 42:2@0..6#ROOT2024
+ IDENT S 42:2@7..8#ROOT2024
+ PUNCH ; [alone] 42:2@8..9#ROOT2024
+
+
+
+ SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024"#]],
);
}
@@ -23,6 +39,13 @@ fn test_derive_error() {
r#"struct S;"#,
expect![[r#"
SUBTREE $$ 1 1
+ IDENT struct 1
+ IDENT S 1
+ PUNCH ; [alone] 1
+
+
+
+ SUBTREE $$ 1 1
IDENT compile_error 1
PUNCH ! [alone] 1
SUBTREE () 1 1
@@ -30,6 +53,13 @@ fn test_derive_error() {
PUNCH ; [alone] 1"#]],
expect![[r#"
SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+ IDENT struct 42:2@0..6#ROOT2024
+ IDENT S 42:2@7..8#ROOT2024
+ PUNCH ; [alone] 42:2@8..9#ROOT2024
+
+
+
+ SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
IDENT compile_error 42:2@0..100#ROOT2024
PUNCH ! [alone] 42:2@0..100#ROOT2024
SUBTREE () 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
@@ -51,6 +81,17 @@ fn test_fn_like_macro_noop() {
PUNCH , [alone] 1
LITERAL Integer 1 1
PUNCH , [alone] 1
+ SUBTREE [] 1 1
+
+
+
+ SUBTREE $$ 1 1
+ IDENT ident 1
+ PUNCH , [alone] 1
+ LITERAL Integer 0 1
+ PUNCH , [alone] 1
+ LITERAL Integer 1 1
+ PUNCH , [alone] 1
SUBTREE [] 1 1"#]],
expect![[r#"
SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
@@ -60,6 +101,17 @@ fn test_fn_like_macro_noop() {
PUNCH , [alone] 42:2@8..9#ROOT2024
LITERAL Integer 1 42:2@10..11#ROOT2024
PUNCH , [alone] 42:2@11..12#ROOT2024
+ SUBTREE [] 42:2@13..14#ROOT2024 42:2@14..15#ROOT2024
+
+
+
+ SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+ IDENT ident 42:2@0..5#ROOT2024
+ PUNCH , [alone] 42:2@5..6#ROOT2024
+ LITERAL Integer 0 42:2@7..8#ROOT2024
+ PUNCH , [alone] 42:2@8..9#ROOT2024
+ LITERAL Integer 1 42:2@10..11#ROOT2024
+ PUNCH , [alone] 42:2@11..12#ROOT2024
SUBTREE [] 42:2@13..14#ROOT2024 42:2@14..15#ROOT2024"#]],
);
}
@@ -73,11 +125,25 @@ fn test_fn_like_macro_clone_ident_subtree() {
SUBTREE $$ 1 1
IDENT ident 1
PUNCH , [alone] 1
+ SUBTREE [] 1 1
+
+
+
+ SUBTREE $$ 1 1
+ IDENT ident 1
+ PUNCH , [alone] 1
SUBTREE [] 1 1"#]],
expect![[r#"
SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
IDENT ident 42:2@0..5#ROOT2024
PUNCH , [alone] 42:2@5..6#ROOT2024
+ SUBTREE [] 42:2@7..8#ROOT2024 42:2@8..9#ROOT2024
+
+
+
+ SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+ IDENT ident 42:2@0..5#ROOT2024
+ PUNCH , [alone] 42:2@5..6#ROOT2024
SUBTREE [] 42:2@7..8#ROOT2024 42:2@7..8#ROOT2024"#]],
);
}
@@ -89,9 +155,19 @@ fn test_fn_like_macro_clone_raw_ident() {
"r#async",
expect![[r#"
SUBTREE $$ 1 1
+ IDENT r#async 1
+
+
+
+ SUBTREE $$ 1 1
IDENT r#async 1"#]],
expect![[r#"
SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+ IDENT r#async 42:2@0..7#ROOT2024
+
+
+
+ SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
IDENT r#async 42:2@0..7#ROOT2024"#]],
);
}
@@ -103,9 +179,21 @@ fn test_fn_like_fn_like_span_join() {
"foo bar",
expect![[r#"
SUBTREE $$ 1 1
+ IDENT foo 1
+ IDENT bar 1
+
+
+
+ SUBTREE $$ 1 1
IDENT r#joined 1"#]],
expect![[r#"
SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+ IDENT foo 42:2@0..3#ROOT2024
+ IDENT bar 42:2@8..11#ROOT2024
+
+
+
+ SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
IDENT r#joined 42:2@0..11#ROOT2024"#]],
);
}
@@ -117,11 +205,25 @@ fn test_fn_like_fn_like_span_ops() {
"set_def_site resolved_at_def_site start_span",
expect![[r#"
SUBTREE $$ 1 1
+ IDENT set_def_site 1
+ IDENT resolved_at_def_site 1
+ IDENT start_span 1
+
+
+
+ SUBTREE $$ 1 1
IDENT set_def_site 0
IDENT resolved_at_def_site 1
IDENT start_span 1"#]],
expect![[r#"
SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+ IDENT set_def_site 42:2@0..12#ROOT2024
+ IDENT resolved_at_def_site 42:2@13..33#ROOT2024
+ IDENT start_span 42:2@34..44#ROOT2024
+
+
+
+ SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
IDENT set_def_site 41:1@0..150#ROOT2024
IDENT resolved_at_def_site 42:2@13..33#ROOT2024
IDENT start_span 42:2@34..34#ROOT2024"#]],
@@ -135,21 +237,47 @@ fn test_fn_like_mk_literals() {
r#""#,
expect![[r#"
SUBTREE $$ 1 1
+
+
+
+ SUBTREE $$ 1 1
LITERAL ByteStr byte_string 1
LITERAL Char c 1
LITERAL Str string 1
+ LITERAL CStr cstring 1
+ LITERAL Float 3.14f64 1
+ PUNCH - [alone] 1
LITERAL Float 3.14f64 1
LITERAL Float 3.14 1
+ PUNCH - [alone] 1
+ LITERAL Float 3.14 1
LITERAL Integer 123i64 1
+ PUNCH - [alone] 1
+ LITERAL Integer 123i64 1
+ LITERAL Integer 123 1
+ PUNCH - [alone] 1
LITERAL Integer 123 1"#]],
expect![[r#"
SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+
+
+
+ SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
LITERAL ByteStr byte_string 42:2@0..100#ROOT2024
LITERAL Char c 42:2@0..100#ROOT2024
LITERAL Str string 42:2@0..100#ROOT2024
+ LITERAL CStr cstring 42:2@0..100#ROOT2024
+ LITERAL Float 3.14f64 42:2@0..100#ROOT2024
+ PUNCH - [alone] 42:2@0..100#ROOT2024
LITERAL Float 3.14f64 42:2@0..100#ROOT2024
LITERAL Float 3.14 42:2@0..100#ROOT2024
+ PUNCH - [alone] 42:2@0..100#ROOT2024
+ LITERAL Float 3.14 42:2@0..100#ROOT2024
LITERAL Integer 123i64 42:2@0..100#ROOT2024
+ PUNCH - [alone] 42:2@0..100#ROOT2024
+ LITERAL Integer 123i64 42:2@0..100#ROOT2024
+ LITERAL Integer 123 42:2@0..100#ROOT2024
+ PUNCH - [alone] 42:2@0..100#ROOT2024
LITERAL Integer 123 42:2@0..100#ROOT2024"#]],
);
}
@@ -161,10 +289,18 @@ fn test_fn_like_mk_idents() {
r#""#,
expect![[r#"
SUBTREE $$ 1 1
+
+
+
+ SUBTREE $$ 1 1
IDENT standard 1
IDENT r#raw 1"#]],
expect![[r#"
SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+
+
+
+ SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
IDENT standard 42:2@0..100#ROOT2024
IDENT r#raw 42:2@0..100#ROOT2024"#]],
);
@@ -196,6 +332,30 @@ fn test_fn_like_macro_clone_literals() {
PUNCH , [alone] 1
LITERAL Byte b 1
PUNCH , [alone] 1
+ LITERAL CStr null 1
+
+
+
+ SUBTREE $$ 1 1
+ LITERAL Integer 1u16 1
+ PUNCH , [alone] 1
+ LITERAL Integer 2_u32 1
+ PUNCH , [alone] 1
+ PUNCH - [alone] 1
+ LITERAL Integer 4i64 1
+ PUNCH , [alone] 1
+ LITERAL Float 3.14f32 1
+ PUNCH , [alone] 1
+ LITERAL Str hello bridge 1
+ PUNCH , [alone] 1
+ LITERAL Str suffixedsuffix 1
+ PUNCH , [alone] 1
+ LITERAL StrRaw(2) raw 1
+ PUNCH , [alone] 1
+ LITERAL Char a 1
+ PUNCH , [alone] 1
+ LITERAL Byte b 1
+ PUNCH , [alone] 1
LITERAL CStr null 1"#]],
expect![[r#"
SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
@@ -218,11 +378,99 @@ fn test_fn_like_macro_clone_literals() {
PUNCH , [alone] 42:2@78..79#ROOT2024
LITERAL Byte b 42:2@80..84#ROOT2024
PUNCH , [alone] 42:2@84..85#ROOT2024
+ LITERAL CStr null 42:2@86..93#ROOT2024
+
+
+
+ SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+ LITERAL Integer 1u16 42:2@0..4#ROOT2024
+ PUNCH , [alone] 42:2@4..5#ROOT2024
+ LITERAL Integer 2_u32 42:2@6..11#ROOT2024
+ PUNCH , [alone] 42:2@11..12#ROOT2024
+ PUNCH - [alone] 42:2@13..14#ROOT2024
+ LITERAL Integer 4i64 42:2@14..18#ROOT2024
+ PUNCH , [alone] 42:2@18..19#ROOT2024
+ LITERAL Float 3.14f32 42:2@20..27#ROOT2024
+ PUNCH , [alone] 42:2@27..28#ROOT2024
+ LITERAL Str hello bridge 42:2@29..43#ROOT2024
+ PUNCH , [alone] 42:2@43..44#ROOT2024
+ LITERAL Str suffixedsuffix 42:2@45..61#ROOT2024
+ PUNCH , [alone] 42:2@61..62#ROOT2024
+ LITERAL StrRaw(2) raw 42:2@63..73#ROOT2024
+ PUNCH , [alone] 42:2@73..74#ROOT2024
+ LITERAL Char a 42:2@75..78#ROOT2024
+ PUNCH , [alone] 42:2@78..79#ROOT2024
+ LITERAL Byte b 42:2@80..84#ROOT2024
+ PUNCH , [alone] 42:2@84..85#ROOT2024
LITERAL CStr null 42:2@86..93#ROOT2024"#]],
);
}
#[test]
+fn test_fn_like_macro_negative_literals() {
+ assert_expand(
+ "fn_like_clone_tokens",
+ r###"-1u16, - 2_u32, -3.14f32, - 2.7"###,
+ expect![[r#"
+ SUBTREE $$ 1 1
+ PUNCH - [alone] 1
+ LITERAL Integer 1u16 1
+ PUNCH , [alone] 1
+ PUNCH - [alone] 1
+ LITERAL Integer 2_u32 1
+ PUNCH , [alone] 1
+ PUNCH - [alone] 1
+ LITERAL Float 3.14f32 1
+ PUNCH , [alone] 1
+ PUNCH - [alone] 1
+ LITERAL Float 2.7 1
+
+
+
+ SUBTREE $$ 1 1
+ PUNCH - [alone] 1
+ LITERAL Integer 1u16 1
+ PUNCH , [alone] 1
+ PUNCH - [alone] 1
+ LITERAL Integer 2_u32 1
+ PUNCH , [alone] 1
+ PUNCH - [alone] 1
+ LITERAL Float 3.14f32 1
+ PUNCH , [alone] 1
+ PUNCH - [alone] 1
+ LITERAL Float 2.7 1"#]],
+ expect![[r#"
+ SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+ PUNCH - [alone] 42:2@0..1#ROOT2024
+ LITERAL Integer 1u16 42:2@1..5#ROOT2024
+ PUNCH , [alone] 42:2@5..6#ROOT2024
+ PUNCH - [alone] 42:2@7..8#ROOT2024
+ LITERAL Integer 2_u32 42:2@9..14#ROOT2024
+ PUNCH , [alone] 42:2@14..15#ROOT2024
+ PUNCH - [alone] 42:2@16..17#ROOT2024
+ LITERAL Float 3.14f32 42:2@17..24#ROOT2024
+ PUNCH , [alone] 42:2@24..25#ROOT2024
+ PUNCH - [alone] 42:2@26..27#ROOT2024
+ LITERAL Float 2.7 42:2@28..31#ROOT2024
+
+
+
+ SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+ PUNCH - [alone] 42:2@0..1#ROOT2024
+ LITERAL Integer 1u16 42:2@1..5#ROOT2024
+ PUNCH , [alone] 42:2@5..6#ROOT2024
+ PUNCH - [alone] 42:2@7..8#ROOT2024
+ LITERAL Integer 2_u32 42:2@9..14#ROOT2024
+ PUNCH , [alone] 42:2@14..15#ROOT2024
+ PUNCH - [alone] 42:2@16..17#ROOT2024
+ LITERAL Float 3.14f32 42:2@17..24#ROOT2024
+ PUNCH , [alone] 42:2@24..25#ROOT2024
+ PUNCH - [alone] 42:2@26..27#ROOT2024
+ LITERAL Float 2.7 42:2@28..31#ROOT2024"#]],
+ );
+}
+
+#[test]
fn test_attr_macro() {
// Corresponds to
// #[proc_macro_test::attr_error(some arguments)]
@@ -233,6 +481,15 @@ fn test_attr_macro() {
r#"some arguments"#,
expect![[r#"
SUBTREE $$ 1 1
+ IDENT mod 1
+ IDENT m 1
+ SUBTREE {} 1 1
+
+ SUBTREE $$ 1 1
+ IDENT some 1
+ IDENT arguments 1
+
+ SUBTREE $$ 1 1
IDENT compile_error 1
PUNCH ! [alone] 1
SUBTREE () 1 1
@@ -240,6 +497,15 @@ fn test_attr_macro() {
PUNCH ; [alone] 1"#]],
expect![[r#"
SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+ IDENT mod 42:2@0..3#ROOT2024
+ IDENT m 42:2@4..5#ROOT2024
+ SUBTREE {} 42:2@6..7#ROOT2024 42:2@7..8#ROOT2024
+
+ SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+ IDENT some 42:2@0..4#ROOT2024
+ IDENT arguments 42:2@5..14#ROOT2024
+
+ SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
IDENT compile_error 42:2@0..100#ROOT2024
PUNCH ! [alone] 42:2@0..100#ROOT2024
SUBTREE () 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs
index a476a70..a0a45b2 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs
@@ -32,9 +32,9 @@ pub fn assert_expand(
macro_name: &str,
#[rust_analyzer::rust_fixture] ra_fixture: &str,
expect: Expect,
- expect_s: Expect,
+ expect_spanned: Expect,
) {
- assert_expand_impl(macro_name, ra_fixture, None, expect, expect_s);
+ assert_expand_impl(macro_name, ra_fixture, None, expect, expect_spanned);
}
pub fn assert_expand_attr(
@@ -42,9 +42,9 @@ pub fn assert_expand_attr(
#[rust_analyzer::rust_fixture] ra_fixture: &str,
attr_args: &str,
expect: Expect,
- expect_s: Expect,
+ expect_spanned: Expect,
) {
- assert_expand_impl(macro_name, ra_fixture, Some(attr_args), expect, expect_s);
+ assert_expand_impl(macro_name, ra_fixture, Some(attr_args), expect, expect_spanned);
}
fn assert_expand_impl(
@@ -52,7 +52,7 @@ fn assert_expand_impl(
input: &str,
attr: Option<&str>,
expect: Expect,
- expect_s: Expect,
+ expect_spanned: Expect,
) {
let path = proc_macro_test_dylib_path();
let expander = dylib::Expander::new(&path).unwrap();
@@ -60,20 +60,17 @@ fn assert_expand_impl(
let def_site = TokenId(0);
let call_site = TokenId(1);
let mixed_site = TokenId(2);
- let input_ts = parse_string(call_site, input);
+ let input_ts = parse_string(call_site, input).into_subtree(call_site);
let attr_ts = attr.map(|attr| parse_string(call_site, attr).into_subtree(call_site));
+ let input_ts_string = format!("{input_ts:?}");
+ let attr_ts_string = attr_ts.as_ref().map(|it| format!("{it:?}"));
- let res = expander
- .expand(
- macro_name,
- input_ts.into_subtree(call_site),
- attr_ts,
- def_site,
- call_site,
- mixed_site,
- )
- .unwrap();
- expect.assert_eq(&format!("{res:?}"));
+ let res =
+ expander.expand(macro_name, input_ts, attr_ts, def_site, call_site, mixed_site).unwrap();
+ expect.assert_eq(&format!(
+ "{input_ts_string}\n\n{}\n\n{res:?}",
+ attr_ts_string.unwrap_or_default()
+ ));
let def_site = Span {
range: TextRange::new(0.into(), 150.into()),
@@ -93,15 +90,17 @@ fn assert_expand_impl(
};
let mixed_site = call_site;
- let fixture = parse_string_spanned(call_site.anchor, call_site.ctx, input);
+ let fixture =
+ parse_string_spanned(call_site.anchor, call_site.ctx, input).into_subtree(call_site);
let attr = attr.map(|attr| {
parse_string_spanned(call_site.anchor, call_site.ctx, attr).into_subtree(call_site)
});
+ let fixture_string = format!("{fixture:?}");
+ let attr_string = attr.as_ref().map(|it| format!("{it:?}"));
- let res = expander
- .expand(macro_name, fixture.into_subtree(call_site), attr, def_site, call_site, mixed_site)
- .unwrap();
- expect_s.assert_eq(&format!("{res:#?}"));
+ let res = expander.expand(macro_name, fixture, attr, def_site, call_site, mixed_site).unwrap();
+ expect_spanned
+ .assert_eq(&format!("{fixture_string}\n\n{}\n\n{res:#?}", attr_string.unwrap_or_default()));
}
pub(crate) fn list() -> Vec<String> {
diff --git a/src/tools/rust-analyzer/crates/project-model/src/env.rs b/src/tools/rust-analyzer/crates/project-model/src/env.rs
index e7293b0..450def5 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/env.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/env.rs
@@ -18,6 +18,7 @@ pub(crate) fn inject_cargo_package_env(env: &mut Env, package: &PackageData) {
let manifest_dir = package.manifest.parent();
env.set("CARGO_MANIFEST_DIR", manifest_dir.as_str());
+ env.set("CARGO_MANIFEST_PATH", package.manifest.as_str());
env.set("CARGO_PKG_VERSION", package.version.to_string());
env.set("CARGO_PKG_VERSION_MAJOR", package.version.major.to_string());
diff --git a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
index c7c1b04..d4055d9 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
@@ -137,7 +137,12 @@ pub fn tool(
}
let mut cmd = toolchain::command(tool.prefer_proxy(), current_dir, envs);
- cmd.env("RUSTUP_TOOLCHAIN", AsRef::<std::path::Path>::as_ref(root));
+ if !envs.contains_key("RUSTUP_TOOLCHAIN")
+ && std::env::var_os("RUSTUP_TOOLCHAIN").is_none()
+ {
+ cmd.env("RUSTUP_TOOLCHAIN", AsRef::<std::path::Path>::as_ref(root));
+ }
+
cmd
}
_ => toolchain::command(tool.path(), current_dir, envs),
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
index 4ef9d81..3722e2c 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
@@ -52,6 +52,7 @@
"CARGO": "$CARGO$",
"CARGO_CRATE_NAME": "hello_world",
"CARGO_MANIFEST_DIR": "$ROOT$hello-world",
+ "CARGO_MANIFEST_PATH": "$ROOT$hello-world/Cargo.toml",
"CARGO_PKG_AUTHORS": "",
"CARGO_PKG_DESCRIPTION": "",
"CARGO_PKG_HOMEPAGE": "",
@@ -136,6 +137,7 @@
"CARGO": "$CARGO$",
"CARGO_CRATE_NAME": "hello_world",
"CARGO_MANIFEST_DIR": "$ROOT$hello-world",
+ "CARGO_MANIFEST_PATH": "$ROOT$hello-world/Cargo.toml",
"CARGO_PKG_AUTHORS": "",
"CARGO_PKG_DESCRIPTION": "",
"CARGO_PKG_HOMEPAGE": "",
@@ -220,6 +222,7 @@
"CARGO": "$CARGO$",
"CARGO_CRATE_NAME": "an_example",
"CARGO_MANIFEST_DIR": "$ROOT$hello-world",
+ "CARGO_MANIFEST_PATH": "$ROOT$hello-world/Cargo.toml",
"CARGO_PKG_AUTHORS": "",
"CARGO_PKG_DESCRIPTION": "",
"CARGO_PKG_HOMEPAGE": "",
@@ -304,6 +307,7 @@
"CARGO": "$CARGO$",
"CARGO_CRATE_NAME": "it",
"CARGO_MANIFEST_DIR": "$ROOT$hello-world",
+ "CARGO_MANIFEST_PATH": "$ROOT$hello-world/Cargo.toml",
"CARGO_PKG_AUTHORS": "",
"CARGO_PKG_DESCRIPTION": "",
"CARGO_PKG_HOMEPAGE": "",
@@ -384,6 +388,7 @@
"CARGO": "$CARGO$",
"CARGO_CRATE_NAME": "libc",
"CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98",
+ "CARGO_MANIFEST_PATH": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98/Cargo.toml",
"CARGO_PKG_AUTHORS": "The Rust Project Developers",
"CARGO_PKG_DESCRIPTION": "Raw FFI bindings to platform libraries like libc.\n",
"CARGO_PKG_HOMEPAGE": "https://github.com/rust-lang/libc",
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
index 4ef9d81..3722e2c 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
@@ -52,6 +52,7 @@
"CARGO": "$CARGO$",
"CARGO_CRATE_NAME": "hello_world",
"CARGO_MANIFEST_DIR": "$ROOT$hello-world",
+ "CARGO_MANIFEST_PATH": "$ROOT$hello-world/Cargo.toml",
"CARGO_PKG_AUTHORS": "",
"CARGO_PKG_DESCRIPTION": "",
"CARGO_PKG_HOMEPAGE": "",
@@ -136,6 +137,7 @@
"CARGO": "$CARGO$",
"CARGO_CRATE_NAME": "hello_world",
"CARGO_MANIFEST_DIR": "$ROOT$hello-world",
+ "CARGO_MANIFEST_PATH": "$ROOT$hello-world/Cargo.toml",
"CARGO_PKG_AUTHORS": "",
"CARGO_PKG_DESCRIPTION": "",
"CARGO_PKG_HOMEPAGE": "",
@@ -220,6 +222,7 @@
"CARGO": "$CARGO$",
"CARGO_CRATE_NAME": "an_example",
"CARGO_MANIFEST_DIR": "$ROOT$hello-world",
+ "CARGO_MANIFEST_PATH": "$ROOT$hello-world/Cargo.toml",
"CARGO_PKG_AUTHORS": "",
"CARGO_PKG_DESCRIPTION": "",
"CARGO_PKG_HOMEPAGE": "",
@@ -304,6 +307,7 @@
"CARGO": "$CARGO$",
"CARGO_CRATE_NAME": "it",
"CARGO_MANIFEST_DIR": "$ROOT$hello-world",
+ "CARGO_MANIFEST_PATH": "$ROOT$hello-world/Cargo.toml",
"CARGO_PKG_AUTHORS": "",
"CARGO_PKG_DESCRIPTION": "",
"CARGO_PKG_HOMEPAGE": "",
@@ -384,6 +388,7 @@
"CARGO": "$CARGO$",
"CARGO_CRATE_NAME": "libc",
"CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98",
+ "CARGO_MANIFEST_PATH": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98/Cargo.toml",
"CARGO_PKG_AUTHORS": "The Rust Project Developers",
"CARGO_PKG_DESCRIPTION": "Raw FFI bindings to platform libraries like libc.\n",
"CARGO_PKG_HOMEPAGE": "https://github.com/rust-lang/libc",
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
index 52089d1..7b156ea 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
@@ -51,6 +51,7 @@
"CARGO": "$CARGO$",
"CARGO_CRATE_NAME": "hello_world",
"CARGO_MANIFEST_DIR": "$ROOT$hello-world",
+ "CARGO_MANIFEST_PATH": "$ROOT$hello-world/Cargo.toml",
"CARGO_PKG_AUTHORS": "",
"CARGO_PKG_DESCRIPTION": "",
"CARGO_PKG_HOMEPAGE": "",
@@ -134,6 +135,7 @@
"CARGO": "$CARGO$",
"CARGO_CRATE_NAME": "hello_world",
"CARGO_MANIFEST_DIR": "$ROOT$hello-world",
+ "CARGO_MANIFEST_PATH": "$ROOT$hello-world/Cargo.toml",
"CARGO_PKG_AUTHORS": "",
"CARGO_PKG_DESCRIPTION": "",
"CARGO_PKG_HOMEPAGE": "",
@@ -217,6 +219,7 @@
"CARGO": "$CARGO$",
"CARGO_CRATE_NAME": "an_example",
"CARGO_MANIFEST_DIR": "$ROOT$hello-world",
+ "CARGO_MANIFEST_PATH": "$ROOT$hello-world/Cargo.toml",
"CARGO_PKG_AUTHORS": "",
"CARGO_PKG_DESCRIPTION": "",
"CARGO_PKG_HOMEPAGE": "",
@@ -300,6 +303,7 @@
"CARGO": "$CARGO$",
"CARGO_CRATE_NAME": "it",
"CARGO_MANIFEST_DIR": "$ROOT$hello-world",
+ "CARGO_MANIFEST_PATH": "$ROOT$hello-world/Cargo.toml",
"CARGO_PKG_AUTHORS": "",
"CARGO_PKG_DESCRIPTION": "",
"CARGO_PKG_HOMEPAGE": "",
@@ -380,6 +384,7 @@
"CARGO": "$CARGO$",
"CARGO_CRATE_NAME": "libc",
"CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98",
+ "CARGO_MANIFEST_PATH": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98/Cargo.toml",
"CARGO_PKG_AUTHORS": "The Rust Project Developers",
"CARGO_PKG_DESCRIPTION": "Raw FFI bindings to platform libraries like libc.\n",
"CARGO_PKG_HOMEPAGE": "https://github.com/rust-lang/libc",
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
index a1e4adf..671e838 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -4,6 +4,7 @@
use std::{
env, fmt,
ops::AddAssign,
+ panic::{AssertUnwindSafe, catch_unwind},
time::{SystemTime, UNIX_EPOCH},
};
@@ -721,6 +722,7 @@ fn run_inference(
let mut num_pats_unknown = 0;
let mut num_pats_partially_unknown = 0;
let mut num_pat_type_mismatches = 0;
+ let mut panics = 0;
for &body_id in bodies {
let name = body_id.name(db).unwrap_or_else(Name::missing);
let module = body_id.module(db);
@@ -774,7 +776,20 @@ fn run_inference(
}
bar.set_message(msg);
let body = db.body(body_id.into());
- let inference_result = db.infer(body_id.into());
+ let inference_result = catch_unwind(AssertUnwindSafe(|| db.infer(body_id.into())));
+ let inference_result = match inference_result {
+ Ok(inference_result) => inference_result,
+ Err(p) => {
+ if let Some(s) = p.downcast_ref::<&str>() {
+ eprintln!("infer panicked for {}: {}", full_name(), s);
+ } else if let Some(s) = p.downcast_ref::<String>() {
+ eprintln!("infer panicked for {}: {}", full_name(), s);
+ }
+ panics += 1;
+ bar.inc(1);
+ continue;
+ }
+ };
// This query is LRU'd, so actually calling it will skew the timing results.
let sm = || db.body_with_source_map(body_id.into()).1;
@@ -1008,6 +1023,7 @@ fn run_inference(
percentage(num_pats_partially_unknown, num_pats),
num_pat_type_mismatches
);
+ eprintln!(" panics: {}", panics);
eprintln!("{:<20} {}", "Inference:", inference_time);
report_metric("unknown type", num_exprs_unknown, "#");
report_metric("type mismatches", num_expr_type_mismatches, "#");
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs
index 57f95d1..16f3512 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs
@@ -150,8 +150,8 @@
optional --disable-proc-macros
/// Run the proc-macro-srv binary at the specified path.
optional --proc-macro-srv path: PathBuf
- /// Run cache priming in parallel.
- optional --parallel
+ /// The number of threads to use. Defaults to the number of physical cores.
+ optional --num-threads num_threads: usize
}
cmd ssr {
@@ -299,7 +299,7 @@ pub struct PrimeCaches {
pub disable_build_scripts: bool,
pub disable_proc_macros: bool,
pub proc_macro_srv: Option<PathBuf>,
- pub parallel: bool,
+ pub num_threads: Option<usize>,
}
#[derive(Debug)]
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/prime_caches.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/prime_caches.rs
index 46fb701..467d8a5 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/prime_caches.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/prime_caches.rs
@@ -52,7 +52,7 @@ pub fn run(self) -> anyhow::Result<()> {
elapsed.memory.allocated.megabytes() as u64
);
- let threads = if self.parallel { num_cpus::get() } else { 1 };
+ let threads = self.num_threads.unwrap_or_else(num_cpus::get_physical);
ide_db::prime_caches::parallel_prime_caches(&db, threads, &|_| ());
let elapsed = stop_watch.elapsed();
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
index fc31243..0e41824 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
@@ -470,7 +470,11 @@ fn check_command(
let mut cmd =
toolchain::command(Tool::Cargo.path(), &*self.root, &options.extra_env);
if let Some(sysroot_root) = &self.sysroot_root {
- cmd.env("RUSTUP_TOOLCHAIN", AsRef::<std::path::Path>::as_ref(sysroot_root));
+ if !options.extra_env.contains_key("RUSTUP_TOOLCHAIN")
+ && std::env::var_os("RUSTUP_TOOLCHAIN").is_none()
+ {
+ cmd.env("RUSTUP_TOOLCHAIN", AsRef::<std::path::Path>::as_ref(sysroot_root));
+ }
}
cmd.arg(command);
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
index 3b3b9c8..a870232 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
@@ -3,7 +3,11 @@
//!
//! Each tick provides an immutable snapshot of the state as `WorldSnapshot`.
-use std::{ops::Not as _, time::Instant};
+use std::{
+ ops::Not as _,
+ panic::AssertUnwindSafe,
+ time::{Duration, Instant},
+};
use crossbeam_channel::{Receiver, Sender, unbounded};
use hir::ChangeWithProcMacros;
@@ -19,6 +23,7 @@
use proc_macro_api::ProcMacroClient;
use project_model::{ManifestPath, ProjectWorkspace, ProjectWorkspaceKind, WorkspaceBuildScripts};
use rustc_hash::{FxHashMap, FxHashSet};
+use stdx::thread;
use tracing::{Level, span, trace};
use triomphe::Arc;
use vfs::{AbsPathBuf, AnchoredPathBuf, ChangeKind, Vfs, VfsPath};
@@ -40,6 +45,7 @@
test_runner::{CargoTestHandle, CargoTestMessage},
};
+#[derive(Debug)]
pub(crate) struct FetchWorkspaceRequest {
pub(crate) path: Option<AbsPathBuf>,
pub(crate) force_crate_graph_reload: bool,
@@ -78,6 +84,7 @@ pub(crate) struct GlobalState {
pub(crate) task_pool: Handle<TaskPool<Task>, Receiver<Task>>,
pub(crate) fmt_pool: Handle<TaskPool<Task>, Receiver<Task>>,
+ pub(crate) cancellation_pool: thread::Pool,
pub(crate) config: Arc<Config>,
pub(crate) config_errors: Option<ConfigErrors>,
@@ -114,6 +121,11 @@ pub(crate) struct GlobalState {
pub(crate) discover_sender: Sender<discover::DiscoverProjectMessage>,
pub(crate) discover_receiver: Receiver<discover::DiscoverProjectMessage>,
+ // Debouncing channel for fetching the workspace
+ // we want to delay it until the VFS looks stable-ish (and thus is not currently in the middle
+ // of a VCS operation like `git switch`)
+ pub(crate) fetch_ws_receiver: Option<(Receiver<Instant>, FetchWorkspaceRequest)>,
+
// VFS
pub(crate) loader: Handle<Box<dyn vfs::loader::Handle>, Receiver<vfs::loader::Message>>,
pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
@@ -210,6 +222,7 @@ pub(crate) fn new(sender: Sender<lsp_server::Message>, config: Config) -> Global
let handle = TaskPool::new_with_threads(sender, 1);
Handle { handle, receiver }
};
+ let cancellation_pool = thread::Pool::new(1);
let task_queue = {
let (sender, receiver) = unbounded();
@@ -230,6 +243,7 @@ pub(crate) fn new(sender: Sender<lsp_server::Message>, config: Config) -> Global
req_queue: ReqQueue::default(),
task_pool,
fmt_pool,
+ cancellation_pool,
loader,
config: Arc::new(config.clone()),
analysis_host,
@@ -264,6 +278,8 @@ pub(crate) fn new(sender: Sender<lsp_server::Message>, config: Config) -> Global
discover_sender,
discover_receiver,
+ fetch_ws_receiver: None,
+
vfs: Arc::new(RwLock::new((vfs::Vfs::default(), Default::default()))),
vfs_config_version: 0,
vfs_progress_config_version: 0,
@@ -290,7 +306,6 @@ pub(crate) fn new(sender: Sender<lsp_server::Message>, config: Config) -> Global
pub(crate) fn process_changes(&mut self) -> bool {
let _p = span!(Level::INFO, "GlobalState::process_changes").entered();
-
// We cannot directly resolve a change in a ratoml file to a format
// that can be used by the config module because config talks
// in `SourceRootId`s instead of `FileId`s and `FileId` -> `SourceRootId`
@@ -298,66 +313,75 @@ pub(crate) fn process_changes(&mut self) -> bool {
let mut modified_ratoml_files: FxHashMap<FileId, (ChangeKind, vfs::VfsPath)> =
FxHashMap::default();
- let (change, modified_rust_files, workspace_structure_change) = {
- let mut change = ChangeWithProcMacros::default();
- let mut guard = self.vfs.write();
- let changed_files = guard.0.take_changes();
- if changed_files.is_empty() {
- return false;
- }
+ let mut change = ChangeWithProcMacros::default();
+ let mut guard = self.vfs.write();
+ let changed_files = guard.0.take_changes();
+ if changed_files.is_empty() {
+ return false;
+ }
- // downgrade to read lock to allow more readers while we are normalizing text
- let guard = RwLockWriteGuard::downgrade_to_upgradable(guard);
- let vfs: &Vfs = &guard.0;
+ let (change, modified_rust_files, workspace_structure_change) =
+ self.cancellation_pool.scoped(|s| {
+ // start cancellation in parallel, this will kick off lru eviction
+ // allowing us to do meaningful work while waiting
+ let analysis_host = AssertUnwindSafe(&mut self.analysis_host);
+ s.spawn(thread::ThreadIntent::LatencySensitive, || {
+ { analysis_host }.0.request_cancellation()
+ });
- let mut workspace_structure_change = None;
- // A file was added or deleted
- let mut has_structure_changes = false;
- let mut bytes = vec![];
- let mut modified_rust_files = vec![];
- for file in changed_files.into_values() {
- let vfs_path = vfs.file_path(file.file_id);
- if let Some(("rust-analyzer", Some("toml"))) = vfs_path.name_and_extension() {
- // Remember ids to use them after `apply_changes`
- modified_ratoml_files.insert(file.file_id, (file.kind(), vfs_path.clone()));
- }
+ // downgrade to read lock to allow more readers while we are normalizing text
+ let guard = RwLockWriteGuard::downgrade_to_upgradable(guard);
+ let vfs: &Vfs = &guard.0;
- if let Some(path) = vfs_path.as_path() {
- has_structure_changes |= file.is_created_or_deleted();
-
- if file.is_modified() && path.extension() == Some("rs") {
- modified_rust_files.push(file.file_id);
+ let mut workspace_structure_change = None;
+ // A file was added or deleted
+ let mut has_structure_changes = false;
+ let mut bytes = vec![];
+ let mut modified_rust_files = vec![];
+ for file in changed_files.into_values() {
+ let vfs_path = vfs.file_path(file.file_id);
+ if let Some(("rust-analyzer", Some("toml"))) = vfs_path.name_and_extension() {
+ // Remember ids to use them after `apply_changes`
+ modified_ratoml_files.insert(file.file_id, (file.kind(), vfs_path.clone()));
}
- let additional_files = self
- .config
- .discover_workspace_config()
- .map(|cfg| {
- cfg.files_to_watch.iter().map(String::as_str).collect::<Vec<&str>>()
- })
- .unwrap_or_default();
+ if let Some(path) = vfs_path.as_path() {
+ has_structure_changes |= file.is_created_or_deleted();
- let path = path.to_path_buf();
- if file.is_created_or_deleted() {
- workspace_structure_change.get_or_insert((path, false)).1 |=
- self.crate_graph_file_dependencies.contains(vfs_path);
- } else if reload::should_refresh_for_change(
- &path,
- file.kind(),
- &additional_files,
- ) {
- trace!(?path, kind = ?file.kind(), "refreshing for a change");
- workspace_structure_change.get_or_insert((path.clone(), false));
+ if file.is_modified() && path.extension() == Some("rs") {
+ modified_rust_files.push(file.file_id);
+ }
+
+ let additional_files = self
+ .config
+ .discover_workspace_config()
+ .map(|cfg| {
+ cfg.files_to_watch.iter().map(String::as_str).collect::<Vec<&str>>()
+ })
+ .unwrap_or_default();
+
+ let path = path.to_path_buf();
+ if file.is_created_or_deleted() {
+ workspace_structure_change.get_or_insert((path, false)).1 |=
+ self.crate_graph_file_dependencies.contains(vfs_path);
+ } else if reload::should_refresh_for_change(
+ &path,
+ file.kind(),
+ &additional_files,
+ ) {
+ trace!(?path, kind = ?file.kind(), "refreshing for a change");
+ workspace_structure_change.get_or_insert((path.clone(), false));
+ }
}
- }
- // Clear native diagnostics when their file gets deleted
- if !file.exists() {
- self.diagnostics.clear_native_for(file.file_id);
- }
+ // Clear native diagnostics when their file gets deleted
+ if !file.exists() {
+ self.diagnostics.clear_native_for(file.file_id);
+ }
- let text =
- if let vfs::Change::Create(v, _) | vfs::Change::Modify(v, _) = file.change {
+ let text = if let vfs::Change::Create(v, _) | vfs::Change::Modify(v, _) =
+ file.change
+ {
String::from_utf8(v).ok().map(|text| {
// FIXME: Consider doing normalization in the `vfs` instead? That allows
// getting rid of some locking
@@ -367,29 +391,28 @@ pub(crate) fn process_changes(&mut self) -> bool {
} else {
None
};
- // delay `line_endings_map` changes until we are done normalizing the text
- // this allows delaying the re-acquisition of the write lock
- bytes.push((file.file_id, text));
- }
- let (vfs, line_endings_map) = &mut *RwLockUpgradableReadGuard::upgrade(guard);
- bytes.into_iter().for_each(|(file_id, text)| {
- let text = match text {
- None => None,
- Some((text, line_endings)) => {
- line_endings_map.insert(file_id, line_endings);
- Some(text)
- }
- };
- change.change_file(file_id, text);
+ // delay `line_endings_map` changes until we are done normalizing the text
+ // this allows delaying the re-acquisition of the write lock
+ bytes.push((file.file_id, text));
+ }
+ let (vfs, line_endings_map) = &mut *RwLockUpgradableReadGuard::upgrade(guard);
+ bytes.into_iter().for_each(|(file_id, text)| {
+ let text = match text {
+ None => None,
+ Some((text, line_endings)) => {
+ line_endings_map.insert(file_id, line_endings);
+ Some(text)
+ }
+ };
+ change.change_file(file_id, text);
+ });
+ if has_structure_changes {
+ let roots = self.source_root_config.partition(vfs);
+ change.set_roots(roots);
+ }
+ (change, modified_rust_files, workspace_structure_change)
});
- if has_structure_changes {
- let roots = self.source_root_config.partition(vfs);
- change.set_roots(roots);
- }
- (change, modified_rust_files, workspace_structure_change)
- };
- let _p = span!(Level::INFO, "GlobalState::process_changes/apply_change").entered();
self.analysis_host.apply_change(change);
if !modified_ratoml_files.is_empty()
|| !self.config.same_source_root_parent_map(&self.local_roots_parent_map)
@@ -508,11 +531,7 @@ pub(crate) fn process_changes(&mut self) -> bool {
if let Some((path, force_crate_graph_reload)) = workspace_structure_change {
let _p = span!(Level::INFO, "GlobalState::process_changes/ws_structure_change")
.entered();
-
- self.fetch_workspaces_queue.request_op(
- format!("workspace vfs file change: {path}"),
- FetchWorkspaceRequest { path: Some(path), force_crate_graph_reload },
- );
+ self.enqueue_workspace_fetch(path, force_crate_graph_reload);
}
}
@@ -660,6 +679,30 @@ pub(crate) fn check_workspaces_msrv(&self) -> impl Iterator<Item = String> + '_
None
})
}
+
+ fn enqueue_workspace_fetch(&mut self, path: AbsPathBuf, force_crate_graph_reload: bool) {
+ let already_requested = self.fetch_workspaces_queue.op_requested()
+ && !self.fetch_workspaces_queue.op_in_progress();
+ if self.fetch_ws_receiver.is_none() && already_requested {
+ // Don't queue up a new fetch request if we already have done so
+ // Otherwise we will re-fetch in quick succession which is unnecessary
+ // Note though, that if one is already in progress, we *want* to re-queue
+ // as the in-progress fetch might not have the latest changes in it anymore
+ // FIXME: We should cancel the in-progress fetch here
+ return;
+ }
+
+ self.fetch_ws_receiver = Some((
+ crossbeam_channel::after(Duration::from_millis(100)),
+ FetchWorkspaceRequest { path: Some(path), force_crate_graph_reload },
+ ));
+ }
+
+ pub(crate) fn debounce_workspace_fetch(&mut self) {
+ if let Some((fetch_receiver, _)) = &mut self.fetch_ws_receiver {
+ *fetch_receiver = crossbeam_channel::after(Duration::from_millis(100));
+ }
+ }
}
impl Drop for GlobalState {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
index bd213ff..0c0438c 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
@@ -8,7 +8,7 @@
time::{Duration, Instant},
};
-use crossbeam_channel::{Receiver, select};
+use crossbeam_channel::{Receiver, never, select};
use ide_db::base_db::{SourceDatabase, VfsPath, salsa::Database as _};
use lsp_server::{Connection, Notification, Request};
use lsp_types::{TextDocumentIdentifier, notification::Notification as _};
@@ -71,6 +71,7 @@ enum Event {
Flycheck(FlycheckMessage),
TestResult(CargoTestMessage),
DiscoverProject(DiscoverProjectMessage),
+ FetchWorkspaces(FetchWorkspaceRequest),
}
impl fmt::Display for Event {
@@ -83,6 +84,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Event::QueuedTask(_) => write!(f, "Event::QueuedTask"),
Event::TestResult(_) => write!(f, "Event::TestResult"),
Event::DiscoverProject(_) => write!(f, "Event::DiscoverProject"),
+ Event::FetchWorkspaces(_) => write!(f, "Event::SwitchWorkspaces"),
}
}
}
@@ -150,6 +152,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
_ => (),
}
+
match self {
Event::Lsp(it) => fmt::Debug::fmt(it, f),
Event::Task(it) => fmt::Debug::fmt(it, f),
@@ -158,6 +161,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Event::Flycheck(it) => fmt::Debug::fmt(it, f),
Event::TestResult(it) => fmt::Debug::fmt(it, f),
Event::DiscoverProject(it) => fmt::Debug::fmt(it, f),
+ Event::FetchWorkspaces(it) => fmt::Debug::fmt(it, f),
}
}
}
@@ -251,7 +255,7 @@ fn register_did_save_capability(&mut self, additional_patterns: impl Iterator<It
}
fn next_event(
- &self,
+ &mut self,
inbox: &Receiver<lsp_server::Message>,
) -> Result<Option<Event>, crossbeam_channel::RecvError> {
// Make sure we reply to formatting requests ASAP so the editor doesn't block
@@ -283,6 +287,10 @@ fn next_event(
recv(self.discover_receiver) -> task =>
task.map(Event::DiscoverProject),
+
+ recv(self.fetch_ws_receiver.as_ref().map_or(&never(), |(chan, _)| chan)) -> _instant => {
+ Ok(Event::FetchWorkspaces(self.fetch_ws_receiver.take().unwrap().1))
+ },
}
.map(Some)
}
@@ -412,6 +420,9 @@ fn handle_event(&mut self, event: Event) {
self.handle_discover_msg(message);
}
}
+ Event::FetchWorkspaces(req) => {
+ self.fetch_workspaces_queue.request_op("project structure change".to_owned(), req)
+ }
}
let event_handling_duration = loop_start.elapsed();
let (state_changed, memdocs_added_or_removed) = if self.vfs_done {
@@ -830,6 +841,7 @@ fn handle_vfs_msg(&mut self, message: vfs::loader::Message) {
match message {
vfs::loader::Message::Changed { files } | vfs::loader::Message::Loaded { files } => {
let _p = tracing::info_span!("GlobalState::handle_vfs_msg{changed/load}").entered();
+ self.debounce_workspace_fetch();
let vfs = &mut self.vfs.write().0;
for (path, contents) in files {
let path = VfsPath::from(path);
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/op_queue.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/op_queue.rs
index 709d99b..7af5b48 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/op_queue.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/op_queue.rs
@@ -36,7 +36,7 @@ fn default() -> Self {
}
}
-impl<Args, Output> OpQueue<Args, Output> {
+impl<Args: std::fmt::Debug, Output> OpQueue<Args, Output> {
/// Request an operation to start.
pub(crate) fn request_op(&mut self, reason: Cause, args: Args) {
self.op_requested = Some((reason, args));
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
index 55ed192..ae9e3e9 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -69,6 +69,7 @@ impl GlobalState {
/// are ready to do semantic work.
pub(crate) fn is_quiescent(&self) -> bool {
self.vfs_done
+ && self.fetch_ws_receiver.is_none()
&& !self.fetch_workspaces_queue.op_in_progress()
&& !self.fetch_build_data_queue.op_in_progress()
&& !self.fetch_proc_macros_queue.op_in_progress()
@@ -659,6 +660,10 @@ pub(crate) fn switch_workspaces(&mut self, cause: Cause) {
.chain(
ws.sysroot
.root()
+ .filter(|_| {
+ !self.config.extra_env(None).contains_key("RUSTUP_TOOLCHAIN")
+ && std::env::var_os("RUSTUP_TOOLCHAIN").is_none()
+ })
.map(|it| ("RUSTUP_TOOLCHAIN".to_owned(), Some(it.to_string()))),
)
.collect(),
diff --git a/src/tools/rust-analyzer/crates/stdx/Cargo.toml b/src/tools/rust-analyzer/crates/stdx/Cargo.toml
index 7bda106..b37aded 100644
--- a/src/tools/rust-analyzer/crates/stdx/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/stdx/Cargo.toml
@@ -17,6 +17,7 @@
crossbeam-channel.workspace = true
itertools.workspace = true
tracing.workspace = true
+crossbeam-utils = "0.8.21"
# Think twice before adding anything here
[target.'cfg(unix)'.dependencies]
diff --git a/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs b/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs
index a8de4db..8d76c5f 100644
--- a/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs
+++ b/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs
@@ -8,6 +8,7 @@
//! the threading utilities in [`crate::thread`].
use std::{
+ marker::PhantomData,
panic::{self, UnwindSafe},
sync::{
Arc,
@@ -16,8 +17,9 @@
};
use crossbeam_channel::{Receiver, Sender};
+use crossbeam_utils::sync::WaitGroup;
-use super::{Builder, JoinHandle, ThreadIntent};
+use crate::thread::{Builder, JoinHandle, ThreadIntent};
pub struct Pool {
// `_handles` is never read: the field is present
@@ -79,9 +81,6 @@ pub fn new(threads: usize) -> Self {
Self { _handles: handles.into_boxed_slice(), extant_tasks, job_sender }
}
- /// # Panics
- ///
- /// Panics if job panics
pub fn spawn<F>(&self, intent: ThreadIntent, f: F)
where
F: FnOnce() + Send + UnwindSafe + 'static,
@@ -97,6 +96,17 @@ pub fn spawn<F>(&self, intent: ThreadIntent, f: F)
self.job_sender.send(job).unwrap();
}
+ pub fn scoped<'pool, 'scope, F, R>(&'pool self, f: F) -> R
+ where
+ F: FnOnce(&Scope<'pool, 'scope>) -> R,
+ {
+ let wg = WaitGroup::new();
+ let scope = Scope { pool: self, wg, _marker: PhantomData };
+ let r = f(&scope);
+ scope.wg.wait();
+ r
+ }
+
#[must_use]
pub fn len(&self) -> usize {
self.extant_tasks.load(Ordering::SeqCst)
@@ -107,3 +117,36 @@ pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
+
+pub struct Scope<'pool, 'scope> {
+ pool: &'pool Pool,
+ wg: WaitGroup,
+ _marker: PhantomData<fn(&'scope ()) -> &'scope ()>,
+}
+
+impl<'scope> Scope<'_, 'scope> {
+ pub fn spawn<F>(&self, intent: ThreadIntent, f: F)
+ where
+ F: 'scope + FnOnce() + Send + UnwindSafe,
+ {
+ let wg = self.wg.clone();
+ let f = Box::new(move || {
+ if cfg!(debug_assertions) {
+ intent.assert_is_used_on_current_thread();
+ }
+ f();
+ drop(wg);
+ });
+
+ let job = Job {
+ requested_intent: intent,
+ f: unsafe {
+ std::mem::transmute::<
+ Box<dyn 'scope + FnOnce() + Send + UnwindSafe>,
+ Box<dyn 'static + FnOnce() + Send + UnwindSafe>,
+ >(f)
+ },
+ };
+ self.pool.job_sender.send(job).unwrap();
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
index da0bfd4..e60243f 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
@@ -109,6 +109,67 @@ fn get_or_create_where_clause(&self) -> ast::WhereClause {
}
}
+impl GenericParamsOwnerEdit for ast::TraitAlias {
+ fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
+ match self.generic_param_list() {
+ Some(it) => it,
+ None => {
+ let position = if let Some(name) = self.name() {
+ Position::after(name.syntax)
+ } else if let Some(trait_token) = self.trait_token() {
+ Position::after(trait_token)
+ } else {
+ Position::last_child_of(self.syntax())
+ };
+ create_generic_param_list(position)
+ }
+ }
+ }
+
+ fn get_or_create_where_clause(&self) -> ast::WhereClause {
+ if self.where_clause().is_none() {
+ let position = match self.semicolon_token() {
+ Some(tok) => Position::before(tok),
+ None => Position::last_child_of(self.syntax()),
+ };
+ create_where_clause(position);
+ }
+ self.where_clause().unwrap()
+ }
+}
+
+impl GenericParamsOwnerEdit for ast::TypeAlias {
+ fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
+ match self.generic_param_list() {
+ Some(it) => it,
+ None => {
+ let position = if let Some(name) = self.name() {
+ Position::after(name.syntax)
+ } else if let Some(trait_token) = self.type_token() {
+ Position::after(trait_token)
+ } else {
+ Position::last_child_of(self.syntax())
+ };
+ create_generic_param_list(position)
+ }
+ }
+ }
+
+ fn get_or_create_where_clause(&self) -> ast::WhereClause {
+ if self.where_clause().is_none() {
+ let position = match self.eq_token() {
+ Some(tok) => Position::before(tok),
+ None => match self.semicolon_token() {
+ Some(tok) => Position::before(tok),
+ None => Position::last_child_of(self.syntax()),
+ },
+ };
+ create_where_clause(position);
+ }
+ self.where_clause().unwrap()
+ }
+}
+
impl GenericParamsOwnerEdit for ast::Struct {
fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
match self.generic_param_list() {
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
index 596f73e..fab4cb2 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
@@ -13,6 +13,7 @@
mod quote;
+use either::Either;
use itertools::Itertools;
use parser::{Edition, T};
use rowan::NodeOrToken;
@@ -881,7 +882,7 @@ fn from_text(text: &str) -> ast::MatchArmList {
}
pub fn where_pred(
- path: ast::Type,
+ path: Either<ast::Lifetime, ast::Type>,
bounds: impl IntoIterator<Item = ast::TypeBound>,
) -> ast::WherePred {
let bounds = bounds.into_iter().join(" + ");
diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
index f6ca5ab..96e1301 100644
--- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
@@ -662,10 +662,6 @@ fn expand(
) -> Result<TopSubtree, ProcMacroExpansionError> {
Ok(subtree.clone())
}
-
- fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
- other.as_any().type_id() == std::any::TypeId::of::<Self>()
- }
}
// Expands to a macro_rules! macro, for issue #18089.
@@ -697,10 +693,6 @@ macro_rules! my_macro___ {
#subtree
})
}
-
- fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
- other.as_any().type_id() == std::any::TypeId::of::<Self>()
- }
}
// Pastes the attribute input as its output
@@ -721,10 +713,6 @@ fn expand(
.cloned()
.ok_or_else(|| ProcMacroExpansionError::Panic("Expected attribute input".into()))
}
-
- fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
- other.as_any().type_id() == std::any::TypeId::of::<Self>()
- }
}
#[derive(Debug)]
@@ -756,10 +744,6 @@ fn expand(
top_subtree_delimiter_mut.close = def_site;
Ok(result)
}
-
- fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
- other.as_any().type_id() == std::any::TypeId::of::<Self>()
- }
}
#[derive(Debug)]
@@ -791,10 +775,6 @@ fn traverse(builder: &mut TopSubtreeBuilder, iter: TtIter<'_>) {
traverse(&mut builder, input.iter());
Ok(builder.build())
}
-
- fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
- other.as_any().type_id() == std::any::TypeId::of::<Self>()
- }
}
// Replaces every literal with an empty string literal and every identifier with its first letter,
@@ -835,10 +815,6 @@ fn modify_leaf(leaf: &mut Leaf) {
}
}
}
-
- fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
- other.as_any().type_id() == std::any::TypeId::of::<Self>()
- }
}
// Reads ident type within string quotes, for issue #17479.
@@ -864,10 +840,6 @@ fn expand(
#symbol()
})
}
-
- fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
- other.as_any().type_id() == std::any::TypeId::of::<Self>()
- }
}
// Reads ident type within string quotes, for issue #17479.
@@ -919,10 +891,6 @@ fn foo() {
}
})
}
-
- fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
- other.as_any().type_id() == std::any::TypeId::of::<Self>()
- }
}
// Reads ident type within string quotes, for issue #17479.
@@ -950,8 +918,4 @@ fn expand(
}
Ok(subtree.clone())
}
-
- fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
- other.as_any().type_id() == std::any::TypeId::of::<Self>()
- }
}
diff --git a/src/tools/rust-analyzer/crates/tt/src/lib.rs b/src/tools/rust-analyzer/crates/tt/src/lib.rs
index 1dbc07c..14574a6 100644
--- a/src/tools/rust-analyzer/crates/tt/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/tt/src/lib.rs
@@ -817,6 +817,58 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
}
+impl<S> Literal<S> {
+ pub fn display_no_minus(&self) -> impl fmt::Display {
+ struct NoMinus<'a, S>(&'a Literal<S>);
+ impl<S> fmt::Display for NoMinus<'_, S> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let symbol =
+ self.0.symbol.as_str().strip_prefix('-').unwrap_or(self.0.symbol.as_str());
+ match self.0.kind {
+ LitKind::Byte => write!(f, "b'{symbol}'"),
+ LitKind::Char => write!(f, "'{symbol}'"),
+ LitKind::Integer | LitKind::Float | LitKind::Err(_) => write!(f, "{symbol}"),
+ LitKind::Str => write!(f, "\"{symbol}\""),
+ LitKind::ByteStr => write!(f, "b\"{symbol}\""),
+ LitKind::CStr => write!(f, "c\"{symbol}\""),
+ LitKind::StrRaw(num_of_hashes) => {
+ let num_of_hashes = num_of_hashes as usize;
+ write!(
+ f,
+ r#"r{0:#<num_of_hashes$}"{text}"{0:#<num_of_hashes$}"#,
+ "",
+ text = symbol
+ )
+ }
+ LitKind::ByteStrRaw(num_of_hashes) => {
+ let num_of_hashes = num_of_hashes as usize;
+ write!(
+ f,
+ r#"br{0:#<num_of_hashes$}"{text}"{0:#<num_of_hashes$}"#,
+ "",
+ text = symbol
+ )
+ }
+ LitKind::CStrRaw(num_of_hashes) => {
+ let num_of_hashes = num_of_hashes as usize;
+ write!(
+ f,
+ r#"cr{0:#<num_of_hashes$}"{text}"{0:#<num_of_hashes$}"#,
+ "",
+ text = symbol
+ )
+ }
+ }?;
+ if let Some(suffix) = &self.0.suffix {
+ write!(f, "{suffix}")?;
+ }
+ Ok(())
+ }
+ }
+ NoMinus(self)
+ }
+}
+
impl<S> fmt::Display for Literal<S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.kind {
diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json
index 11a37c2..18fb097 100644
--- a/src/tools/rust-analyzer/editors/code/package-lock.json
+++ b/src/tools/rust-analyzer/editors/code/package-lock.json
@@ -5730,9 +5730,9 @@
"license": "MIT"
},
"node_modules/undici": {
- "version": "6.21.1",
- "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.1.tgz",
- "integrity": "sha512-q/1rj5D0/zayJB2FraXdaWxbhWiNKDvu8naDT2dl1yTlvJp4BLtOcp2a5BvgGNQpYYJzau7tf1WgKv3b+7mqpQ==",
+ "version": "6.21.3",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.3.tgz",
+ "integrity": "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==",
"dev": true,
"license": "MIT",
"engines": {
diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version
index 90e4d65..5b47d1b 100644
--- a/src/tools/rust-analyzer/rust-version
+++ b/src/tools/rust-analyzer/rust-version
@@ -1 +1 @@
-6e23095adf9209614a45f7f75fea36dad7b92afb
+a8e4c68dcb4dc1e48a0db294c5323cab0227fcb9
diff --git a/src/tools/rust-analyzer/xtask/Cargo.toml b/src/tools/rust-analyzer/xtask/Cargo.toml
index 6195de5..bb7d83c 100644
--- a/src/tools/rust-analyzer/xtask/Cargo.toml
+++ b/src/tools/rust-analyzer/xtask/Cargo.toml
@@ -14,7 +14,7 @@
xshell.workspace = true
xflags = "0.3.2"
time = { version = "0.3", default-features = false }
-zip = { version = "2.4", default-features = false, features = ["deflate-flate2", "flate2", "time"] }
+zip = { version = "3.0", default-features = false, features = ["deflate-flate2", "time"] }
stdx.workspace = true
proc-macro2 = "1.0.94"
quote = "1.0.40"
diff --git a/tests/crashes/140823.rs b/tests/crashes/140823.rs
deleted file mode 100644
index ca2d683..0000000
--- a/tests/crashes/140823.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ known-bug: #140823
-
-struct Container<T> {
- data: T,
-}
-
-fn ice(callback: Box<dyn Fn(Container<&u8>)>) {
- let fails: Box<dyn Fn(&Container<&u8>)> = callback;
-}
diff --git a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-abort.diff
index 7f32524..d73cc3d 100644
--- a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-abort.diff
@@ -45,7 +45,7 @@
_9 = copy _10;
_8 = move _9 as *mut i32 (PtrToPtr);
StorageDead(_9);
-- _3 = copy_nonoverlapping::<i32>(move _4, move _8, const 0_usize) -> [return: bb1, unwind unreachable];
+- _3 = std::intrinsics::copy_nonoverlapping::<i32>(move _4, move _8, const 0_usize) -> [return: bb1, unwind unreachable];
+ copy_nonoverlapping(dst = move _8, src = move _4, count = const 0_usize);
+ goto -> bb1;
}
diff --git a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-unwind.diff
index 7f32524..d73cc3d 100644
--- a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.panic-unwind.diff
@@ -45,7 +45,7 @@
_9 = copy _10;
_8 = move _9 as *mut i32 (PtrToPtr);
StorageDead(_9);
-- _3 = copy_nonoverlapping::<i32>(move _4, move _8, const 0_usize) -> [return: bb1, unwind unreachable];
+- _3 = std::intrinsics::copy_nonoverlapping::<i32>(move _4, move _8, const 0_usize) -> [return: bb1, unwind unreachable];
+ copy_nonoverlapping(dst = move _8, src = move _4, count = const 0_usize);
+ goto -> bb1;
}
diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs
index 5afddc5..4e000b0 100644
--- a/tests/mir-opt/lower_intrinsics.rs
+++ b/tests/mir-opt/lower_intrinsics.rs
@@ -1,9 +1,11 @@
//@ test-mir-pass: LowerIntrinsics
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
-#![feature(core_intrinsics, intrinsics, rustc_attrs)]
+#![feature(core_intrinsics)]
#![crate_type = "lib"]
+use std::intrinsics::copy_nonoverlapping;
+
// EMIT_MIR lower_intrinsics.wrapping.LowerIntrinsics.diff
pub fn wrapping(a: i32, b: i32) {
// CHECK-LABEL: fn wrapping(
@@ -153,11 +155,6 @@ pub fn discriminant<T>(t: T) {
core::intrinsics::discriminant_value(&E::B);
}
-// Cannot use `std::intrinsics::copy_nonoverlapping` as that is a wrapper function
-#[rustc_nounwind]
-#[rustc_intrinsic]
-unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
-
// EMIT_MIR lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff
pub fn f_copy_nonoverlapping() {
// CHECK-LABEL: fn f_copy_nonoverlapping(
diff --git a/tests/ui/async-await/async-drop/dependency-dropped.rs b/tests/ui/async-await/async-drop/dependency-dropped.rs
index c8670be..d7f415e 100644
--- a/tests/ui/async-await/async-drop/dependency-dropped.rs
+++ b/tests/ui/async-await/async-drop/dependency-dropped.rs
@@ -5,7 +5,7 @@
//@ edition:2021
#![cfg_attr(with_feature, feature(async_drop))]
-//[without_feature]~^ WARN found async drop types in dependecy `async_drop_dep`, but async_drop feature is disabled for `dependency_dropped`
+//[without_feature]~^ WARN found async drop types in dependency `async_drop_dep`, but async_drop feature is disabled for `dependency_dropped`
#![allow(incomplete_features)]
diff --git a/tests/ui/async-await/async-drop/dependency-dropped.without_feature.stderr b/tests/ui/async-await/async-drop/dependency-dropped.without_feature.stderr
index 56e4956..96a4572 100644
--- a/tests/ui/async-await/async-drop/dependency-dropped.without_feature.stderr
+++ b/tests/ui/async-await/async-drop/dependency-dropped.without_feature.stderr
@@ -1,4 +1,4 @@
-warning: found async drop types in dependecy `async_drop_dep`, but async_drop feature is disabled for `dependency_dropped`
+warning: found async drop types in dependency `async_drop_dep`, but async_drop feature is disabled for `dependency_dropped`
--> $DIR/dependency-dropped.rs:7:1
|
LL | #![cfg_attr(with_feature, feature(async_drop))]
diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.rs b/tests/ui/consts/const-eval/raw-pointer-ub.rs
index 13a95f9..1383de6 100644
--- a/tests/ui/consts/const-eval/raw-pointer-ub.rs
+++ b/tests/ui/consts/const-eval/raw-pointer-ub.rs
@@ -19,7 +19,7 @@
y.copy_to_nonoverlapping(&mut z, 1);
//~^ ERROR evaluation of constant value failed
//~| NOTE inside `std::ptr::const_ptr
- //~| NOTE inside `copy_nonoverlapping::<u32>`
+ //~| NOTE inside `std::ptr::copy_nonoverlapping::<u32>`
//~| NOTE accessing memory with alignment 1, but alignment 4 is required
// The actual error points into the implementation of `copy_to_nonoverlapping`.
};
diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.stderr b/tests/ui/consts/const-eval/raw-pointer-ub.stderr
index ed5793c..0f3dc33 100644
--- a/tests/ui/consts/const-eval/raw-pointer-ub.stderr
+++ b/tests/ui/consts/const-eval/raw-pointer-ub.stderr
@@ -18,8 +18,8 @@
|
note: inside `std::ptr::const_ptr::<impl *const u32>::copy_to_nonoverlapping`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `copy_nonoverlapping::<u32>`
- --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL
+note: inside `std::ptr::copy_nonoverlapping::<u32>`
+ --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
error[E0080]: evaluation of constant value failed
--> $DIR/raw-pointer-ub.rs:34:16
diff --git a/tests/ui/consts/copy-intrinsic.rs b/tests/ui/consts/copy-intrinsic.rs
index da483d6..d0242f2 100644
--- a/tests/ui/consts/copy-intrinsic.rs
+++ b/tests/ui/consts/copy-intrinsic.rs
@@ -1,22 +1,8 @@
-#![stable(feature = "dummy", since = "1.0.0")]
-
// ignore-tidy-linelength
-#![feature(intrinsics, staged_api, rustc_attrs)]
+#![feature(core_intrinsics)]
+
use std::mem;
-
-#[stable(feature = "dummy", since = "1.0.0")]
-#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
-#[rustc_intrinsic]
-const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
- unimplemented!()
-}
-
-#[stable(feature = "dummy", since = "1.0.0")]
-#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
-#[rustc_intrinsic]
-const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
- unimplemented!()
-}
+use std::intrinsics::{copy, copy_nonoverlapping};
const COPY_ZERO: () = unsafe {
// Since we are not copying anything, this should be allowed.
diff --git a/tests/ui/consts/copy-intrinsic.stderr b/tests/ui/consts/copy-intrinsic.stderr
index 13321b5..8d58642 100644
--- a/tests/ui/consts/copy-intrinsic.stderr
+++ b/tests/ui/consts/copy-intrinsic.stderr
@@ -1,23 +1,23 @@
error[E0080]: evaluation of constant value failed
- --> $DIR/copy-intrinsic.rs:34:5
+ --> $DIR/copy-intrinsic.rs:20:5
|
LL | copy_nonoverlapping(0x100 as *const i32, dangle, 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got 0x100[noalloc] which is a dangling pointer (it has no provenance)
error[E0080]: evaluation of constant value failed
- --> $DIR/copy-intrinsic.rs:43:5
+ --> $DIR/copy-intrinsic.rs:29:5
|
LL | copy_nonoverlapping(dangle, 0x100 as *mut i32, 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got ALLOC0+0x28 which is at or beyond the end of the allocation of size 4 bytes
error[E0080]: evaluation of constant value failed
- --> $DIR/copy-intrinsic.rs:50:5
+ --> $DIR/copy-intrinsic.rs:36:5
|
LL | copy(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy`
error[E0080]: evaluation of constant value failed
- --> $DIR/copy-intrinsic.rs:56:5
+ --> $DIR/copy-intrinsic.rs:42:5
|
LL | copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy_nonoverlapping`
diff --git a/tests/ui/consts/missing_span_in_backtrace.stderr b/tests/ui/consts/missing_span_in_backtrace.stderr
index 88b3e37..7c07710 100644
--- a/tests/ui/consts/missing_span_in_backtrace.stderr
+++ b/tests/ui/consts/missing_span_in_backtrace.stderr
@@ -14,8 +14,8 @@
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
note: inside `std::ptr::swap_nonoverlapping_const::<MaybeUninit<u8>>`
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-note: inside `copy_nonoverlapping::<MaybeUninit<u8>>`
- --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL
+note: inside `std::ptr::copy_nonoverlapping::<MaybeUninit<u8>>`
+ --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
= help: this code performed an operation that depends on the underlying bytes representing a pointer
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
= note: this error originates in the macro `$crate::intrinsics::const_eval_select` which comes from the expansion of the macro `const_eval_select` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/fn/coerce-suggestion-infer-region.rs b/tests/ui/fn/coerce-suggestion-infer-region.rs
new file mode 100644
index 0000000..7edb828
--- /dev/null
+++ b/tests/ui/fn/coerce-suggestion-infer-region.rs
@@ -0,0 +1,26 @@
+//! Functions with a mismatch between the expected and found type where the difference is a
+//! reference may trigger analysis for additional help. In this test the expected type will be
+//! &'a Container<&'a u8> and the found type will be Container<&'?0 u8>.
+//!
+//! This test exercises a scenario where the found type being analyzed contains an inference region
+//! variable ('?0). This cannot be used in comparisons because the variable no longer exists by the
+//! time the later analysis is performed.
+//!
+//! This is a regression test of #140823
+
+trait MyFn<P> {}
+
+struct Container<T> {
+ data: T,
+}
+
+struct Desugared {
+ callback: Box<dyn for<'a> MyFn<&'a Container<&'a u8>>>,
+}
+
+fn test(callback: Box<dyn for<'a> MyFn<Container<&'a u8>>>) -> Desugared {
+ Desugared { callback }
+ //~^ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/tests/ui/fn/coerce-suggestion-infer-region.stderr b/tests/ui/fn/coerce-suggestion-infer-region.stderr
new file mode 100644
index 0000000..9dd0fcf
--- /dev/null
+++ b/tests/ui/fn/coerce-suggestion-infer-region.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+ --> $DIR/coerce-suggestion-infer-region.rs:22:17
+ |
+LL | Desugared { callback }
+ | ^^^^^^^^ expected `Box<dyn MyFn<&Container<&u8>>>`, found `Box<dyn MyFn<Container<&u8>>>`
+ |
+ = note: expected struct `Box<(dyn for<'a> MyFn<&'a Container<&'a u8>> + 'static)>`
+ found struct `Box<(dyn for<'a> MyFn<Container<&'a u8>> + 'static)>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/impl-trait/issues/issue-100075-2.stderr b/tests/ui/impl-trait/issues/issue-100075-2.stderr
index b3b6967..554c3ea 100644
--- a/tests/ui/impl-trait/issues/issue-100075-2.stderr
+++ b/tests/ui/impl-trait/issues/issue-100075-2.stderr
@@ -1,3 +1,9 @@
+error[E0720]: cannot resolve opaque type
+ --> $DIR/issue-100075-2.rs:1:23
+ |
+LL | fn opaque<T>(t: T) -> impl Sized {
+ | ^^^^^^^^^^
+
warning: function cannot return without recursing
--> $DIR/issue-100075-2.rs:1:1
|
@@ -10,15 +16,6 @@
= help: a `loop` may express intention better if this is on purpose
= note: `#[warn(unconditional_recursion)]` on by default
-error[E0720]: cannot resolve opaque type
- --> $DIR/issue-100075-2.rs:1:23
- |
-LL | fn opaque<T>(t: T) -> impl Sized {
- | ^^^^^^^^^^ recursive opaque type
-...
-LL | opaque(Some(t))
- | --------------- returning here with type `impl Sized`
-
error: aborting due to 1 previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0720`.
diff --git a/tests/ui/impl-trait/issues/issue-100075.stderr b/tests/ui/impl-trait/issues/issue-100075.stderr
index 7596348..bca2874 100644
--- a/tests/ui/impl-trait/issues/issue-100075.stderr
+++ b/tests/ui/impl-trait/issues/issue-100075.stderr
@@ -2,10 +2,7 @@
--> $DIR/issue-100075.rs:13:37
|
LL | fn _g<T>(t: &'static T) -> &'static impl Marker {
- | ^^^^^^^^^^^ recursive opaque type
-...
-LL | return _g(t);
- | ----- returning here with type `&impl Marker`
+ | ^^^^^^^^^^^
error: aborting due to 1 previous error
diff --git a/tests/ui/impl-trait/issues/issue-103599.rs b/tests/ui/impl-trait/issues/issue-103599.rs
index 62741a7..e674ce3 100644
--- a/tests/ui/impl-trait/issues/issue-103599.rs
+++ b/tests/ui/impl-trait/issues/issue-103599.rs
@@ -1,9 +1,8 @@
-//@ check-pass
-
trait T {}
fn wrap(x: impl T) -> impl T {
- //~^ WARN function cannot return without recursing
+ //~^ ERROR cannot resolve opaque type
+ //~| WARN function cannot return without recursing
wrap(wrap(x))
}
diff --git a/tests/ui/impl-trait/issues/issue-103599.stderr b/tests/ui/impl-trait/issues/issue-103599.stderr
index 82038c1..9878b12 100644
--- a/tests/ui/impl-trait/issues/issue-103599.stderr
+++ b/tests/ui/impl-trait/issues/issue-103599.stderr
@@ -1,14 +1,21 @@
+error[E0720]: cannot resolve opaque type
+ --> $DIR/issue-103599.rs:3:23
+ |
+LL | fn wrap(x: impl T) -> impl T {
+ | ^^^^^^
+
warning: function cannot return without recursing
- --> $DIR/issue-103599.rs:5:1
+ --> $DIR/issue-103599.rs:3:1
|
LL | fn wrap(x: impl T) -> impl T {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
-LL |
+...
LL | wrap(wrap(x))
| ------- recursive call site
|
= help: a `loop` may express intention better if this is on purpose
= note: `#[warn(unconditional_recursion)]` on by default
-warning: 1 warning emitted
+error: aborting due to 1 previous error; 1 warning emitted
+For more information about this error, try `rustc --explain E0720`.
diff --git a/tests/ui/impl-trait/issues/issue-87450.rs b/tests/ui/impl-trait/issues/issue-87450.rs
index 983ef7c..5a7759a 100644
--- a/tests/ui/impl-trait/issues/issue-87450.rs
+++ b/tests/ui/impl-trait/issues/issue-87450.rs
@@ -3,8 +3,8 @@
}
fn foo() -> impl Fn() {
- //~^ WARNING 5:1: 5:22: function cannot return without recursing [unconditional_recursion]
- //~| ERROR 5:13: 5:22: cannot resolve opaque type [E0720]
+ //~^ WARN function cannot return without recursing
+ //~| ERROR cannot resolve opaque type
wrap(wrap(wrap(wrap(wrap(wrap(wrap(foo())))))))
}
diff --git a/tests/ui/impl-trait/issues/issue-87450.stderr b/tests/ui/impl-trait/issues/issue-87450.stderr
index 9567e09..f0f8b58 100644
--- a/tests/ui/impl-trait/issues/issue-87450.stderr
+++ b/tests/ui/impl-trait/issues/issue-87450.stderr
@@ -1,3 +1,9 @@
+error[E0720]: cannot resolve opaque type
+ --> $DIR/issue-87450.rs:5:13
+ |
+LL | fn foo() -> impl Fn() {
+ | ^^^^^^^^^
+
warning: function cannot return without recursing
--> $DIR/issue-87450.rs:5:1
|
@@ -10,18 +16,6 @@
= help: a `loop` may express intention better if this is on purpose
= note: `#[warn(unconditional_recursion)]` on by default
-error[E0720]: cannot resolve opaque type
- --> $DIR/issue-87450.rs:5:13
- |
-LL | fn foo() -> impl Fn() {
- | ^^^^^^^^^ recursive opaque type
-...
-LL | wrap(wrap(wrap(wrap(wrap(wrap(wrap(foo())))))))
- | ----------------------------------------------- returning here with type `impl Fn()`
-...
-LL | fn wrap(f: impl Fn()) -> impl Fn() {
- | --------- returning this opaque type `impl Fn()`
-
error: aborting due to 1 previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0720`.
diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr
index 2d2731e..af84375 100644
--- a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr
+++ b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr
@@ -2,112 +2,67 @@
--> $DIR/recursive-impl-trait-type-indirect.rs:6:22
|
LL | fn option(i: i32) -> impl Sized {
- | ^^^^^^^^^^ recursive opaque type
-LL |
-LL | if i < 0 { None } else { Some((option(i - 1), i)) }
- | ---- ------------------------ returning here with type `Option<(impl Sized, i32)>`
- | |
- | returning here with type `Option<(impl Sized, i32)>`
+ | ^^^^^^^^^^
error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:11:15
|
LL | fn tuple() -> impl Sized {
- | ^^^^^^^^^^ recursive opaque type
-LL |
-LL | (tuple(),)
- | ---------- returning here with type `(impl Sized,)`
+ | ^^^^^^^^^^
error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:16:15
|
LL | fn array() -> impl Sized {
- | ^^^^^^^^^^ recursive opaque type
-LL |
-LL | [array()]
- | --------- returning here with type `[impl Sized; 1]`
+ | ^^^^^^^^^^
error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:21:13
|
LL | fn ptr() -> impl Sized {
- | ^^^^^^^^^^ recursive opaque type
-LL |
-LL | &ptr() as *const _
- | ------------------ returning here with type `*const impl Sized`
+ | ^^^^^^^^^^
error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:26:16
|
LL | fn fn_ptr() -> impl Sized {
- | ^^^^^^^^^^ recursive opaque type
-LL |
-LL | fn_ptr as fn() -> _
- | ------------------- returning here with type `fn() -> impl Sized`
+ | ^^^^^^^^^^
error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:31:25
|
-LL | fn closure_capture() -> impl Sized {
- | ^^^^^^^^^^ recursive opaque type
-...
-LL | / move || {
-LL | | x;
- | | - closure captures itself here
-LL | | }
- | |_____- returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:34:5: 34:12}`
+LL | fn closure_capture() -> impl Sized {
+ | ^^^^^^^^^^
error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:39:29
|
-LL | fn closure_ref_capture() -> impl Sized {
- | ^^^^^^^^^^ recursive opaque type
-...
-LL | / move || {
-LL | | &x;
- | | - closure captures itself here
-LL | | }
- | |_____- returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:42:5: 42:12}`
+LL | fn closure_ref_capture() -> impl Sized {
+ | ^^^^^^^^^^
error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:47:21
|
LL | fn closure_sig() -> impl Sized {
- | ^^^^^^^^^^ recursive opaque type
-LL |
-LL | || closure_sig()
- | ---------------- returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:49:5: 49:7}`
+ | ^^^^^^^^^^
error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:52:23
|
LL | fn coroutine_sig() -> impl Sized {
- | ^^^^^^^^^^ recursive opaque type
-LL |
-LL | || coroutine_sig()
- | ------------------ returning here with type `{closure@$DIR/recursive-impl-trait-type-indirect.rs:54:5: 54:7}`
+ | ^^^^^^^^^^
error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:57:27
|
-LL | fn coroutine_capture() -> impl Sized {
- | ^^^^^^^^^^ recursive opaque type
-...
-LL | / move || {
-LL | | yield;
-LL | | x;
- | | - coroutine captures itself here
-LL | | }
- | |_____- returning here with type `{coroutine@$DIR/recursive-impl-trait-type-indirect.rs:62:5: 62:12}`
+LL | fn coroutine_capture() -> impl Sized {
+ | ^^^^^^^^^^
error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:68:35
|
LL | fn substs_change<T: 'static>() -> impl Sized {
- | ^^^^^^^^^^ recursive opaque type
-LL |
-LL | (substs_change::<&T>(),)
- | ------------------------ returning here with type `(impl Sized,)`
+ | ^^^^^^^^^^
error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:78:26
diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr b/tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr
index 42dbc7c..080c328 100644
--- a/tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr
+++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.current.stderr
@@ -1,56 +1,21 @@
-warning: function cannot return without recursing
- --> $DIR/recursive-in-exhaustiveness.rs:17:1
+error[E0720]: cannot resolve opaque type
+ --> $DIR/recursive-in-exhaustiveness.rs:17:22
|
LL | fn build<T>(x: T) -> impl Sized {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
-LL |
-LL | let (x,) = (build(x),);
- | -------- recursive call site
- |
- = help: a `loop` may express intention better if this is on purpose
- = note: `#[warn(unconditional_recursion)]` on by default
-
-warning: function cannot return without recursing
- --> $DIR/recursive-in-exhaustiveness.rs:27:1
- |
-LL | fn build2<T>(x: T) -> impl Sized {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
-...
-LL | let (x,) = (build2(x),);
- | --------- recursive call site
- |
- = help: a `loop` may express intention better if this is on purpose
+ | ^^^^^^^^^^
error[E0720]: cannot resolve opaque type
--> $DIR/recursive-in-exhaustiveness.rs:27:23
|
LL | fn build2<T>(x: T) -> impl Sized {
- | ^^^^^^^^^^ recursive opaque type
-...
-LL | (build2(x),)
- | ------------ returning here with type `(impl Sized,)`
+ | ^^^^^^^^^^
-warning: function cannot return without recursing
- --> $DIR/recursive-in-exhaustiveness.rs:40:1
+error[E0720]: cannot resolve opaque type
+ --> $DIR/recursive-in-exhaustiveness.rs:39:23
|
LL | fn build3<T>(x: T) -> impl Sized {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
-LL |
-LL | let (x,) = (build3((x,)),);
- | ------------ recursive call site
- |
- = help: a `loop` may express intention better if this is on purpose
+ | ^^^^^^^^^^
-error[E0792]: expected generic type parameter, found `(T,)`
- --> $DIR/recursive-in-exhaustiveness.rs:49:5
- |
-LL | fn build3<T>(x: T) -> impl Sized {
- | - this generic parameter must be used with a generic type parameter
-...
-LL | build3(x)
- | ^^^^^^^^^
+error: aborting due to 3 previous errors
-error: aborting due to 2 previous errors; 3 warnings emitted
-
-Some errors have detailed explanations: E0720, E0792.
-For more information about an error, try `rustc --explain E0720`.
+For more information about this error, try `rustc --explain E0720`.
diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr b/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr
index 4c3d5aa..a3609b9 100644
--- a/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr
+++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr
@@ -5,19 +5,19 @@
| ^^^^^^^^ cannot satisfy `impl Sized == _`
error[E0271]: type mismatch resolving `build2<(_,)>::{opaque#0} normalizes-to _`
- --> $DIR/recursive-in-exhaustiveness.rs:31:6
+ --> $DIR/recursive-in-exhaustiveness.rs:30:6
|
LL | (build2(x),)
| ^^^^^^^^^ types differ
error[E0271]: type mismatch resolving `build2<(_,)>::{opaque#0} normalizes-to _`
- --> $DIR/recursive-in-exhaustiveness.rs:31:5
+ --> $DIR/recursive-in-exhaustiveness.rs:30:5
|
LL | (build2(x),)
| ^^^^^^^^^^^^ types differ
error[E0277]: the size for values of type `(impl Sized,)` cannot be known at compilation time
- --> $DIR/recursive-in-exhaustiveness.rs:31:5
+ --> $DIR/recursive-in-exhaustiveness.rs:30:5
|
LL | (build2(x),)
| ^^^^^^^^^^^^ doesn't have a size known at compile-time
@@ -26,13 +26,13 @@
= note: tuples must have a statically known size to be initialized
error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _`
- --> $DIR/recursive-in-exhaustiveness.rs:42:17
+ --> $DIR/recursive-in-exhaustiveness.rs:41:17
|
LL | let (x,) = (build3((x,)),);
| ^^^^^^^^^^^^ types differ
error[E0277]: the size for values of type `(impl Sized,)` cannot be known at compilation time
- --> $DIR/recursive-in-exhaustiveness.rs:42:16
+ --> $DIR/recursive-in-exhaustiveness.rs:41:16
|
LL | let (x,) = (build3((x,)),);
| ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
@@ -41,7 +41,7 @@
= note: tuples must have a statically known size to be initialized
error[E0308]: mismatched types
- --> $DIR/recursive-in-exhaustiveness.rs:42:16
+ --> $DIR/recursive-in-exhaustiveness.rs:41:16
|
LL | fn build3<T>(x: T) -> impl Sized {
| ---------- the found opaque type
@@ -53,7 +53,7 @@
found tuple `(impl Sized,)`
error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _`
- --> $DIR/recursive-in-exhaustiveness.rs:42:17
+ --> $DIR/recursive-in-exhaustiveness.rs:41:17
|
LL | let (x,) = (build3((x,)),);
| ^^^^^^^^^^^^ types differ
@@ -61,13 +61,13 @@
= note: the return type of a function must have a statically known size
error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _`
- --> $DIR/recursive-in-exhaustiveness.rs:42:16
+ --> $DIR/recursive-in-exhaustiveness.rs:41:16
|
LL | let (x,) = (build3((x,)),);
| ^^^^^^^^^^^^^^^ types differ
error[E0271]: type mismatch resolving `build3<(T,)>::{opaque#0} normalizes-to _`
- --> $DIR/recursive-in-exhaustiveness.rs:42:17
+ --> $DIR/recursive-in-exhaustiveness.rs:41:17
|
LL | let (x,) = (build3((x,)),);
| ^^^^^^^^^^^^ types differ
diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.rs b/tests/ui/impl-trait/recursive-in-exhaustiveness.rs
index 5894453..fa8fa0e 100644
--- a/tests/ui/impl-trait/recursive-in-exhaustiveness.rs
+++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.rs
@@ -15,7 +15,7 @@
// We unfortunately accept this today, and due to how opaque type relating is implemented
// in the NLL type relation, this defines `Opaque<T> = T`.
fn build<T>(x: T) -> impl Sized {
- //[current]~^ WARN function cannot return without recursing
+ //[current]~^ ERROR cannot resolve opaque type
let (x,) = (build(x),);
//[next]~^ ERROR type annotations needed
build(x)
@@ -26,7 +26,6 @@ fn build<T>(x: T) -> impl Sized {
// Not allowed today. Detected as recursive.
fn build2<T>(x: T) -> impl Sized {
//[current]~^ ERROR cannot resolve opaque type
- //[current]~| WARN function cannot return without recursing
let (x,) = (build2(x),);
(build2(x),)
//[next]~^ ERROR type mismatch resolving
@@ -38,7 +37,7 @@ fn build2<T>(x: T) -> impl Sized {
//
// Not allowed today. Detected as not defining.
fn build3<T>(x: T) -> impl Sized {
- //[current]~^ WARN function cannot return without recursing
+ //[current]~^ ERROR cannot resolve opaque type
let (x,) = (build3((x,)),);
//[next]~^ ERROR type mismatch resolving
//[next]~| ERROR type mismatch resolving
@@ -47,7 +46,6 @@ fn build3<T>(x: T) -> impl Sized {
//[next]~| ERROR the size for values of type
//[next]~| ERROR mismatched types
build3(x)
- //[current]~^ ERROR expected generic type parameter, found `(T,)`
}
fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/infinite-cycle-involving-weak.rs b/tests/ui/type-alias-impl-trait/infinite-cycle-involving-weak.rs
index ef6871b..0aaee5d 100644
--- a/tests/ui/type-alias-impl-trait/infinite-cycle-involving-weak.rs
+++ b/tests/ui/type-alias-impl-trait/infinite-cycle-involving-weak.rs
@@ -1,10 +1,10 @@
#![feature(type_alias_impl_trait)]
type T = impl Copy;
-//~^ ERROR cannot resolve opaque type
#[define_opaque(T)]
fn foo() -> T {
+ //~^ ERROR cannot resolve opaque type
None::<&'static T>
}
diff --git a/tests/ui/type-alias-impl-trait/infinite-cycle-involving-weak.stderr b/tests/ui/type-alias-impl-trait/infinite-cycle-involving-weak.stderr
index d820df4..426a6c2 100644
--- a/tests/ui/type-alias-impl-trait/infinite-cycle-involving-weak.stderr
+++ b/tests/ui/type-alias-impl-trait/infinite-cycle-involving-weak.stderr
@@ -1,8 +1,8 @@
error[E0720]: cannot resolve opaque type
- --> $DIR/infinite-cycle-involving-weak.rs:3:10
+ --> $DIR/infinite-cycle-involving-weak.rs:6:13
|
-LL | type T = impl Copy;
- | ^^^^^^^^^ cannot resolve opaque type
+LL | fn foo() -> T {
+ | ^
error: aborting due to 1 previous error
diff --git a/tests/crashes/139817.rs b/tests/ui/type-alias-impl-trait/match-upvar-discriminant-of-opaque.rs
similarity index 62%
rename from tests/crashes/139817.rs
rename to tests/ui/type-alias-impl-trait/match-upvar-discriminant-of-opaque.rs
index d439ed4..f4e2cb0 100644
--- a/tests/crashes/139817.rs
+++ b/tests/ui/type-alias-impl-trait/match-upvar-discriminant-of-opaque.rs
@@ -1,8 +1,12 @@
-//@ known-bug: #139817
+#![feature(type_alias_impl_trait)]
+
fn enum_upvar() {
type T = impl Copy;
let foo: T = Some((42, std::marker::PhantomData::<T>));
let x = move || match foo {
None => (),
+ //~^ ERROR cannot resolve opaque type
};
}
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/match-upvar-discriminant-of-opaque.stderr b/tests/ui/type-alias-impl-trait/match-upvar-discriminant-of-opaque.stderr
new file mode 100644
index 0000000..2bfce2d
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/match-upvar-discriminant-of-opaque.stderr
@@ -0,0 +1,9 @@
+error[E0720]: cannot resolve opaque type
+ --> $DIR/match-upvar-discriminant-of-opaque.rs:7:9
+ |
+LL | None => (),
+ | ^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0720`.
diff --git a/tests/ui/type-alias-impl-trait/recursive-fn-tait.rs b/tests/ui/type-alias-impl-trait/recursive-fn-tait.rs
index 94597ad..fe354cc 100644
--- a/tests/ui/type-alias-impl-trait/recursive-fn-tait.rs
+++ b/tests/ui/type-alias-impl-trait/recursive-fn-tait.rs
@@ -13,7 +13,7 @@ pub fn add(
n: Diff,
m: Diff,
) -> Diff {
- //~^ ERROR concrete type differs
+ //~^ ERROR cannot resolve opaque type
move |x: usize| m(n(x))
}
diff --git a/tests/ui/type-alias-impl-trait/recursive-fn-tait.stderr b/tests/ui/type-alias-impl-trait/recursive-fn-tait.stderr
index 59ff991..847f1cc 100644
--- a/tests/ui/type-alias-impl-trait/recursive-fn-tait.stderr
+++ b/tests/ui/type-alias-impl-trait/recursive-fn-tait.stderr
@@ -1,14 +1,9 @@
-error: concrete type differs from previous defining opaque type use
+error[E0720]: cannot resolve opaque type
--> $DIR/recursive-fn-tait.rs:15:6
|
LL | ) -> Diff {
- | ^^^^ expected `{closure@$DIR/recursive-fn-tait.rs:8:5: 8:16}`, got `{closure@$DIR/recursive-fn-tait.rs:17:5: 17:20}`
- |
-note: previous use here
- --> $DIR/recursive-fn-tait.rs:7:18
- |
-LL | pub fn lift() -> Diff {
- | ^^^^
+ | ^^^^
error: aborting due to 1 previous error
+For more information about this error, try `rustc --explain E0720`.
diff --git a/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn-2.rs b/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn-2.rs
index 858f2a2..7803b3b 100644
--- a/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn-2.rs
+++ b/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn-2.rs
@@ -13,7 +13,7 @@ fn transform<S>() -> impl std::fmt::Display {
}
#[define_opaque(Op)]
fn bad() -> Op {
- //~^ ERROR concrete type differs from previous defining opaque type use
+ //~^ ERROR cannot resolve opaque type
transform::<Op>()
}
diff --git a/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn-2.stderr b/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn-2.stderr
index e527b5b..837df7f 100644
--- a/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn-2.stderr
+++ b/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn-2.stderr
@@ -1,14 +1,9 @@
-error: concrete type differs from previous defining opaque type use
+error[E0720]: cannot resolve opaque type
--> $DIR/recursive-tait-conflicting-defn-2.rs:15:13
|
LL | fn bad() -> Op {
- | ^^ expected `&&str`, got `impl std::fmt::Display`
- |
-note: previous use here
- --> $DIR/recursive-tait-conflicting-defn-2.rs:7:13
- |
-LL | fn foo() -> Op {
| ^^
error: aborting due to 1 previous error
+For more information about this error, try `rustc --explain E0720`.
diff --git a/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.rs b/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.rs
index 90581a9..d66ceda 100644
--- a/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.rs
+++ b/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.rs
@@ -23,7 +23,7 @@ pub fn test() -> TestImpl {
#[define_opaque(TestImpl)]
fn make_option2() -> Option<TestImpl> {
- //~^ ERROR concrete type differs from previous defining opaque type use
+ //~^ ERROR cannot resolve opaque type
let inner = make_option().unwrap();
Some(B { inner })
}
diff --git a/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.stderr b/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.stderr
index 256f13b..c7a3381 100644
--- a/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.stderr
+++ b/tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.stderr
@@ -1,14 +1,9 @@
-error: concrete type differs from previous defining opaque type use
+error[E0720]: cannot resolve opaque type
--> $DIR/recursive-tait-conflicting-defn.rs:25:22
|
LL | fn make_option2() -> Option<TestImpl> {
- | ^^^^^^^^^^^^^^^^ expected `A`, got `B<TestImpl>`
- |
-note: previous use here
- --> $DIR/recursive-tait-conflicting-defn.rs:20:18
- |
-LL | pub fn test() -> TestImpl {
- | ^^^^^^^^
+ | ^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error
+For more information about this error, try `rustc --explain E0720`.
diff --git a/triagebot.toml b/triagebot.toml
index e62e49b..fd7a861 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -887,6 +887,7 @@
cc = [
"@GuillaumeGomez",
"@jsha",
+ "@lolbinarycat",
]
[mentions."tests/rustdoc-gui/"]