diff options
247 files changed, 4142 insertions, 2091 deletions
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index f48a571b86a..e98d6c50ee7 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -70,44 +70,32 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { } } - 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 19095f2e01e..422e79ca82f 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 a1386b4e1be..d13e17a481a 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 ba579e25f03..847905e8343 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 d1bc54ed73e..8182851a015 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -84,7 +84,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &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 9be041f75d7..b2497cb0de1 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 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { 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 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EagerlyNormalizeConsts<'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 cac8f34b0fa..bccffe39243 100644 --- a/compiler/rustc_metadata/messages.ftl +++ b/compiler/rustc_metadata/messages.ftl @@ -2,7 +2,7 @@ metadata_as_needed_compatibility = 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 a89d01dcbbe..d9f1888bfd9 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::mir::{self, Const}; 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 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { /// 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 eae3213ead0..1b5d04e6025 100644 --- a/compiler/rustc_type_ir/src/region_kind.rs +++ b/compiler/rustc_type_ir/src/region_kind.rs @@ -193,7 +193,7 @@ impl<I: Interner> fmt::Debug for RegionKind<I> { 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 24c5d4c92f7..8766fd904b0 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 @@ impl str { #[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 effdc3c63ee..23bafa778bc 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 unsafe fn typed_swap_nonoverlapping<T>(x: *mut T, y: *mut T) { /// `#[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); - - 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) } -} +#[rustc_nounwind] +#[rustc_intrinsic] +pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize); -/// 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); - - // 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) - } -} +#[rustc_nounwind] +#[rustc_intrinsic] +pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize); -/// 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 27387754633..0a5f3ee35b1 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -21,6 +21,8 @@ mod transmutability; #[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 257424b355f..aad073cc8cd 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1419,7 +1419,7 @@ impl<Ptr: DerefMut> Pin<Ptr> { #[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 bd6c4daa509..35a909f6904 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -405,16 +405,6 @@ mod alignment; #[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 @@ pub use unique::Unique; 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 72bdf03ee61..ead48775127 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -1040,7 +1040,7 @@ impl OsStr { /// 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 1a4a7aa7448..7959c633858 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -3163,7 +3163,7 @@ impl Path { /// 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 67daf81ee54..d5ea96b43f5 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1984,17 +1984,20 @@ impl Step for Assemble { 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 aa2c7509c2a..253fa224152 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -2274,9 +2274,9 @@ impl Step for LlvmTools { 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 @@ impl Step for LlvmTools { 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 c31c40e846b..585adf9be16 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -244,7 +244,7 @@ install!((self, builder, _config), ); } }; - 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 5522095e304..a9528e92915 100755 --- a/src/ci/scripts/install-clang.sh +++ b/src/ci/scripts/install-clang.sh @@ -10,8 +10,8 @@ IFS=$'\n\t' 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 5e4266f61da..0d889a5d5b9 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 31119496e75..a7b76233d19 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 513df1650c3..eeb2af5e6bc 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 @@ format is specific to `rustc`, and may change over time. This file contains: [`-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 @@ A `dylib` is a platform-specific shared library. It includes the `rustc` ### 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 @@ object files. ## 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 @@ much more. 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 @@ will also look at the [sysroot] to find dependencies. 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 408ae207004..4c77007ea44 100644 --- a/src/doc/rustc-dev-guide/src/cli.md +++ b/src/doc/rustc-dev-guide/src/cli.md @@ -28,6 +28,6 @@ adding a new command-line argument. 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 8bf14bef2a0..0e5b32a06f8 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 @@ filtering the search to areas you're interested in. For example: 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 40500e6bc7a..a3684397b29 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 @@ It acts as the glue for running the various phases of the compiler in the correc 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 @@ specifically [`rustc_driver_impl::run_compiler`][rdi_rc] [`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 58ca1f8b26f..fa709194f37 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 ba622466ba7..7728f6725b1 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 "C" fn function2() {} // compiles 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 44b3be23914..3b5f9b5a458 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 f22935df96c..1f7201b8ca8 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -28,11 +28,10 @@ use crate::formats::cache::Cache; 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 @@ impl<'tcx> Context<'tcx> { 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 3492df99955..06cb9269cc8 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 @@ const MAX_FULL_EXAMPLES: usize = 5; 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 render_call_locations<W: fmt::Write>(mut w: W, cx: &Context<'_>, item: &clean <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 render_call_locations<W: fmt::Write>(mut w: W, cx: &Context<'_>, item: &clean 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 render_call_locations<W: fmt::Write>(mut w: W, cx: &Context<'_>, item: &clean 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 cd0c9775f5c..a9029972d96 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) mod filters { } } -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 095795c711d..1fa6b5a60f3 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -11,9 +11,8 @@ use rustc_session::Session; 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 @@ impl SourceCollector<'_, '_> { &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 5b47d1bbaed..46989695302 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/intrinsics/copy_overlapping.rs b/src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs index e6282613df7..ff16ac61d8b 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 fef5a0a82a0..9b60a48703b 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 ded9d0b669e..311789cdc4b 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 2d0edd4e6cb..65dbdb3bbb6 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/rust-analyzer/.github/ISSUE_TEMPLATE/config.yml b/src/tools/rust-analyzer/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000000..466672e3d48 --- /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 23c43443c84..2b44bdc748f 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 @@ Troubleshooting guide: https://rust-analyzer.github.io/book/troubleshooting.html 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 a90ade882bd..00000000000 --- 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 a4146d60218..dc2f432bbc7 100644 --- a/src/tools/rust-analyzer/.github/workflows/metrics.yaml +++ b/src/tools/rust-analyzer/.github/workflows/metrics.yaml @@ -18,9 +18,9 @@ jobs: 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 @@ jobs: 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 8d6c8284e44..bd8146defae 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -61,9 +61,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[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 @@ version = "0.0.0" 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 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[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 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[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 @@ dependencies = [ [[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 @@ checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[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 @@ dependencies = [ [[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 @@ dependencies = [ [[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 @@ dependencies = [ [[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 @@ dependencies = [ [[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 @@ dependencies = [ [[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 @@ dependencies = [ [[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 @@ dependencies = [ [[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 @@ dependencies = [ [[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 @@ version = "0.0.0" dependencies = [ "backtrace", "crossbeam-channel", + "crossbeam-utils", "itertools 0.14.0", "jod-thread", "libc", @@ -2750,12 +2752,24 @@ dependencies = [ [[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 @@ dependencies = [ [[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 @@ dependencies = [ [[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 @@ dependencies = [ [[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 @@ dependencies = [ [[package]] name = "windows-link" -version = "0.1.0" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-numerics" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.0", + "windows-link", +] [[package]] name = "windows-result" @@ -2845,9 +2879,9 @@ dependencies = [ [[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 @@ dependencies = [ [[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 @@ dependencies = [ [[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 c4c2fdf34ba..07731bae3f3 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -85,11 +85,11 @@ vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } 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-to-cmark = "10.0.4" 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 e2e3253773f..3b423a86f97 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 @@ rustc-hash.workspace = true 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 9660e6e87cc..d42d7e5707d 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::DashMap; 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 @@ use crate::{CrateWorkspaceData, EditionedFileId, RootQueryDb}; 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 @@ impl CrateGraphBuilder { } 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 @@ impl CrateGraphBuilder { ); } - 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 @@ impl CrateGraphBuilder { 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 @@ impl CrateGraphBuilder { 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 2cbdbe16f9b..4a9a3b12cfa 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 @@ use crate::{ 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 e3775c4931a..f617c3225ae 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 rustc_hash::FxHashMap; use smallvec::SmallVec; use span::{Edition, SyntaxContext}; use syntax::{AstPtr, SyntaxNodePtr, ast}; -use triomphe::Arc; use tt::TextRange; use crate::{ @@ -30,7 +29,7 @@ use crate::{ 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 @@ impl ExpressionStore { 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 @@ impl ExpressionStore { 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 50505d54ba2..29871f5e04d 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 @@ use crate::{ 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 @@ impl ExprCollector<'_> { 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 @@ impl ExprCollector<'_> { let resolver = |path: &_| { self.def_map .resolve_path( - &self.local_def_map, + self.local_def_map, self.db, module, path, @@ -2163,12 +2163,12 @@ impl ExprCollector<'_> { }; 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 @@ impl ExprCollector<'_> { // 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 629d1f2ada7..be006c98a58 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 337cb103bde..8fd81c7b3df 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 syntax::ast::{self, make}; use test_fixture::WithFixture; use crate::{ - db::DefDatabase, expr_store::{ ExpressionStore, lower::{ @@ -14,13 +13,15 @@ use crate::{ 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 431ea9eb1d4..a46711c67e8 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 d6645dc1d1d..29e249b07a7 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 da3b65d4203..5f7b510bba4 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 80561d64708..efb558a7758 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 9d62d9ce652..bb75621c7e0 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 @@ mod tests { 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 f27a4062a63..271484da7b9 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 @@ pub(crate) fn parse( 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 db571f045d7..a6138fb6821 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 @@ use crate::{ 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 @@ impl ImportMap { 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 51a833b5f15..59344641f47 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 triomphe::Arc; 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 28011bda7c5..b41ff026bca 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 @@ use crate::{ 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 e21d1415aa2..3027aff3163 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 800c96ebdae..dc4334ee081 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 test_fixture::WithFixture; 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 @@ use crate::{ 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 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream 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 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream 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 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream 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 @@ impl ProcMacroExpander for IdentityWhenValidProcMacroExpander { 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 fc66d8e28d8..d4b30a1d3e6 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 @@ impl DefMap { 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 @@ impl DefMap { 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 @@ impl DefMap { 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 @@ impl DefMap { 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 448b908936a..d45709b8b90 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 @@ impl TraitItems { }) } + 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 @@ impl ImplItems { 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 @@ impl<'a> AssocItemCollector<'a> { 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 @@ impl<'a> AssocItemCollector<'a> { 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 8df0f092cd0..350c97c3982 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 syntax::ast; 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 @@ use crate::{ 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 @@ impl DefCollector<'_> { ); 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 @@ impl DefCollector<'_> { } 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 @@ impl DefCollector<'_> { 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 @@ impl DefCollector<'_> { 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 @@ impl DefCollector<'_> { 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 @@ impl DefCollector<'_> { 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 @@ impl DefCollector<'_> { 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 @@ impl DefCollector<'_> { }; 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 @@ impl DefCollector<'_> { ); // 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 @@ impl DefCollector<'_> { 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 @@ impl ModCollector<'_, '_> { 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 @@ impl ModCollector<'_, '_> { 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 a49155d878c..74ce33a6419 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 @@ use hir_expand::{ 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 @@ impl DefMap { return result; } - let mut arc; let mut current_map = self; let mut merge = |new: ResolvePathResult| { @@ -195,8 +198,7 @@ impl DefMap { 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 @@ impl DefMap { // 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 @@ impl DefMap { 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 @@ impl DefMap { // 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 @@ impl DefMap { 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 @@ impl DefMap { }, }; - 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 @@ impl DefMap { } }; - 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 @@ impl DefMap { 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 @@ impl DefMap { 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 @@ impl DefMap { let resolution = defp_map.resolve_path_fp_with_macro( LocalDefMap::EMPTY, db, - ResolveMode::Other, + mode, module.local_id, &path, shadow, @@ -553,6 +572,44 @@ impl DefMap { ), }; } + 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 @@ impl DefMap { } else { // Extend lifetime keep = prelude.def_map(db); - &keep + keep }; def_map[prelude.local_id].scope.get(name) } else { @@ -725,25 +782,23 @@ impl DefMap { } /// 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 3fd095a9a98..4a7974c4fa1 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 @@ mod primitives; 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 179a9c8fec2..948e8bed66d 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 span::Edition; 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 const BAZ: u32 = 0; ); 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 const BAZ: u32 = 0; 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 @@ m!(Z); 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 @@ m!(Z); { 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 @@ pub type Ty = (); { 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 5f8a01523d8..3cba88ec2f1 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 @@ pub struct bar; #[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 @@ pub macro Copy {} #[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 @@ pub macro derive($item:item) {} #[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! mk_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 071b55c83d8..9c97e42f4fd 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 @@ mod foo; #[path = "./foo.rs"] mod foo; "#, + |_| (), ); compute_crate_def_map( @@ -852,6 +853,7 @@ mod bar; #[path = "./foo.rs"] mod foo; "#, + |_| (), ); } @@ -894,3 +896,149 @@ struct AlsoShouldNotAppear; "#]], ) } + +#[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 8a8d17018c1..16988ddf04b 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 @@ use crate::{ 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 @@ impl fmt::Debug for ExprScope { } #[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 @@ impl Resolver { 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 @@ impl Resolver { #[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 @@ impl Resolver { 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 @@ impl Resolver { 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 @@ impl Scope { } } -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 @@ impl Resolver { 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 @@ impl ModuleItemMap { ) -> 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 @@ impl ScopeNames { 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 @@ impl HasResolver for ModuleId { } 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 @@ impl HasResolver for CrateRootModuleId { } 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 @@ impl HasResolver for DefWithBodyId { } 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 @@ impl HasResolver for ItemContainerId { } 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 @@ impl HasResolver for GenericDefId { } 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 @@ impl HasResolver for VariantId { } 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 @@ impl HasResolver for MacroId { } 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 47097548295..6c995ab6c23 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 triomphe::Arc; 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 @@ impl TestDB { 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 @@ impl TestDB { 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 @@ impl TestDB { 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 @@ impl TestDB { 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 b42c8d383d4..3c67ee9fe5b 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 @@ impl Visibility { 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 @@ impl Visibility { 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 bb17eb06276..94c97713f06 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 @@ impl RawAttrs { (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 ast_index(&self) -> usize { - self.id as usize & Self::AST_INDEX_MASK + 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 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 ast_index(&self) -> usize { + (self.id & !Self::INNER_ATTR_SET_BIT) as usize } - 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 @@ impl 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 68283b916d7..d135584a080 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 621e174cac9..539c7277284 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 8a1a33d7e3b..1cd975b980d 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 @@ pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe + AsAny { 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 d1a1e135fff..f903b06d65e 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 @@ impl From<MirEvalError> for ConstEvalError { 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 57106412765..e4a23cbbacf 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 068fc22f2ca..785277d70c6 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 73b99db7268..20cf3c78115 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 either::Either; 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 @@ impl<'a> UnsafeVisitor<'a> { } } + 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 @@ impl<'a> UnsafeVisitor<'a> { 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 @@ impl<'a> UnsafeVisitor<'a> { } } 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 106b996b13e..ed8d8dc2624 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_ir::{ }; 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 @@ where }) } 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 f0ec31db8bb..e698fb201cb 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 @@ impl Index<BindingId> for InferenceResult { /// 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 e3c4f5562d5..003364d4336 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 8084b394d04..87b7f3406ff 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 @@ impl InferenceContext<'_> { } 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 @@ impl InferenceContext<'_> { // 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 @@ impl InferenceContext<'_> { 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 9def39d5f97..ea8e7cc2be9 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_def::{ 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 @@ impl 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 @@ where /// 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 8e549ca0cbd..3b295d41e6e 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 chalk_ir::{UniverseIndex, WithKind, cast::Cast}; 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 @@ impl TraitImpls { 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 @@ impl TraitImpls { 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 @@ impl TraitImpls { 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 @@ impl InherentImpls { 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 @@ impl InherentImpls { 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 @@ impl InherentImpls { 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 26ef95d264b..7cf948b178e 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 std::cmp::{self, Ordering}; use chalk_ir::TyKind; use hir_def::{ + CrateRootModuleId, builtin_type::{BuiltinInt, BuiltinUint}, resolver::HasResolver, }; @@ -153,7 +154,7 @@ impl Evaluator<'_> { ) -> 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 7b48b15d9ea..7fcc89e5183 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 bcd8aa6c4e9..8f0d17c9dc4 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 @@ use base_db::{ 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 @@ impl TestDB { ) -> 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 cc37f65c26c..2b75bd6f160 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 @@ pub(crate) fn visit_module( 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 salsa_bug() { 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 salsa_bug() { 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 73f1ae56457..88d21be81ea 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 0542be0ba89..48474d2d26d 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 446f0b21a2a..ea7a113cae3 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 eeebe38f182..cf51671afb2 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 14137605c9f..2b527a4ae12 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 6e1cd9a310f..d6b43aeed4d 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 @@ struct FixedPoint<T, U, V>(&'static FixedPoint<(), T, U>, V); 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 b1c478d1bf4..b1cf30b98f5 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 @@ impl HasAttrs for crate::Crate { /// 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 3f1d5bb01f2..3a91050d15f 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 @@ pub use crate::{ diagnostics::*, has_source::HasSource, semantics::{ - PathResolution, Semantics, SemanticsImpl, SemanticsScope, TypeInfo, VisibleTraits, + PathResolution, PathResolutionPerNs, Semantics, SemanticsImpl, SemanticsScope, TypeInfo, + VisibleTraits, }, }; @@ -119,7 +120,7 @@ pub use { 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 @@ impl Crate { } 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 @@ impl Module { /// 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 @@ impl Function { { 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 @@ impl BuiltinAttr { 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 @@ impl BuiltinAttr { 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 @@ impl Impl { 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 4d092c1f0bb..caa6700de9f 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 @@ use hir_def::{ 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 @@ impl PathResolution { } } +#[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 @@ impl<'db> SemanticsImpl<'db> { 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 @@ impl<'db> SemanticsImpl<'db> { 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 @@ impl<'db> SemanticsImpl<'db> { } /// 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 @@ impl<'db> SemanticsImpl<'db> { &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 @@ impl<'db> SemanticsImpl<'db> { 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 @@ impl SemanticsScope<'_> { }) } - pub(crate) fn resolver(&self) -> &Resolver { + pub(crate) fn resolver(&self) -> &Resolver<'db> { &self.resolver } @@ -2133,7 +2157,7 @@ impl ops::Deref for VisibleTraits { 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 587c51d8cc9..172af456d92 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 @@ use hir_def::{ 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 @@ impl SourceToDefCtx<'_, '_> { 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 c1a75ce7e57..ea21546f9d7 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 std::iter::{self, once}; 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 @@ use hir_def::{ }, 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 @@ use triomphe::Arc; /// `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 @@ impl SourceAnalyzer { } 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 @@ impl SourceAnalyzer { } 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 @@ impl SourceAnalyzer { } 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { } 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { &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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { } } - 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { fn missing_fields( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, substs: &Substitution, variant: VariantId, missing_fields: Vec<LocalFieldId>, @@ -1270,7 +1294,7 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { fn resolve_impl_method_or_trait_def( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, func: FunctionId, substs: Substitution, ) -> FunctionId { @@ -1393,7 +1417,7 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 @@ impl SourceAnalyzer { 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 7e8735bd7a2..a9df6f6fc36 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 @@ mod tests { 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 1baf814ca68..16debc4d728 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); - } - } 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); + Some(u) + } else { + None } - } 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 00000000000..7b5adc1858b --- /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 627ed37b04e..2395091b6f2 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 @@ mod handlers { 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 01ab0be34b2..76134acb36e 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 cd18b3dcfdc..92cbf411c1e 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 @@ use crate::{ 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 54be7d2fbc3..3cdf2112835 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 391e2379dcd..284876ffc88 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 d5137949d42..e5467767d42 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 bf4f541ff54..d5db1c481b6 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 hir::{ 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 @@ impl Definition { 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 @@ impl Definition { 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 @@ impl Definition { 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 @@ impl Definition { 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 ef2c83992c0..30c355f8b3f 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 @@ impl From<Documentation> for String { 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 @@ impl DocsRangeMap { 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 @@ impl DocsRangeMap { + 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 @@ macro_rules! impl_has_docs { 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 @@ macro_rules! impl_has_docs_enum { 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 @@ impl HasDocs for hir::AssocItem { } } + 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 @@ impl HasDocs for hir::ExternCrateDecl { } .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 cbe31405ab7..5356614dce5 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 (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) + }; - let (work_sender, progress_receiver) = { + let (def_map_work_sender, import_map_work_sender, symbols_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()), - }); + 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, + })?; - match cancelled { - Ok(()) => progress_sender - .send(ParallelPrimeCacheWorkerProgress::EndCrate { crate_id })?, - Err(cancelled) => progress_sender - .send(ParallelPrimeCacheWorkerProgress::Cancelled(cancelled))?, - } - } + let cancelled = Cancelled::catch(|| _ = hir::crate_def_map(&db, crate_id)); - Ok::<_, crossbeam_channel::SendError<_>>(()) - }; + 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 @@ pub fn parallel_prime_caches( .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 c8a03863103..00000000000 --- 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 b8119e1aab3..fa2a46a0f7c 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 92ca7a74184..2a7b0098edf 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 9ed85f9f208..ae42a88c313 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 c25b0a7bf7d..cbcaab6c747 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 438dd2fdcb6..b284d9b3510 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 a6da0fd9c5e..7d2ac373dc0 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 b617c094983..9ae6f013c70 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 47e1c84fecd..8611ef653b0 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 0b9a2ec9db3..a0c364b0010 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 289a0765732..38f10c778d6 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 17c7f75880c..06f35759420 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 84496df2d7c..b71586d6be0 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 d72b21099ce..7a6e98fe1b5 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 ab0f5139f10..8b708f229d0 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 a2648a1995d..546512a6cf9 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 0e47fff6f93..701b30b9b59 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 63fd9b4e3f0..25c1e633ba3 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 a354d123f5a..2b76efb1965 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 8cdbb6384ff..76b30745a04 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 d3d3c3aa38d..1fc96b78eda 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 3c36b455ca9..364bead34ef 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 780271361d7..01cf5e8fa52 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 5d25f2c6a90..8831efa3117 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 fa3347aa12e..84fb467a5ce 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 ff1eeb0516a..35cefd23975 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 ccf51723418..68f2b196570 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 fe32c590492..6d33ae0cf9b 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 237a9b87871..5b4273a5a62 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 6b786450026..dec7be8b742 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 8d717b9093b..7dc5b5b45e5 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 6b335c52de7..37ce5f583f9 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 19ee1caa3e6..dd142db8590 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 2d7d78f5d7b..fa7ba90a756 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 35dc9b0fac8..96911d4781b 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 d5c4bcf768a..4327b12dce7 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 500c5de791d..5253734867e 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 a933f1b4261..1915a88dd00 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 d16bfb80024..f81d34377da 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 06f176f86f4..5627393f318 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 47fa3059362..af9126c8933 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 bdff2417ca1..0c9e0d6ce44 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 614057ab52b..4ae528bf9f2 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 4cd73d46d5f..7c3eacf7e3a 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 a4f4813cf5b..0649c97f820 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 4f64dabeb52..801023dabd9 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 67c7e76a3bc..0da535d11b4 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 0d1c9775062..a87b8c42ac1 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 7f07009dc56..00c2a8c4c46 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 599cabe3e4f..1a409d7e76a 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 77b1075ea53..e6bbff05f7e 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 607721d611d..2af14ca949b 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 @@ impl Diagnostic { DiagnosticCode::Ra(_, s) => s, }, unused: false, - experimental: false, + experimental: true, fixes: None, main_node: None, } @@ -198,8 +198,8 @@ impl Diagnostic { .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 f0247f32d7e..2c983287d89 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 tests; 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 @@ const MARKDOWN_OPTIONS: Options = 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 @@ impl DocCommentToken { 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 91785be8d8b..6af156fa668 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 hir::Semantics; 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 @@ struct S$0(i32); } #[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 rewrite_intra_doc_link_with_anchor() { } #[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 b894e857522..c60ca3562f6 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 80624eeae80..fb8dbcfc735 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 @@ impl<'a> WalkExpandedExprCtx<'a> { } } +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 @@ mod tests { } #[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 075afcec019..873e31b4a33 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 69b83f3b12d..ad720c8a627 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 hir::{ 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 @@ use rustc_apfloat::{ 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 7b7eef9d579..06ca24c3ec3 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 aa525a86123..d649dffbd90 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 std::panic::{AssertUnwindSafe, UnwindSafe}; 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 @@ impl Analysis { /// 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 6dc01c45063..50219cee57d 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 0998e14c87b..7f5c2c1ec84 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 2686a75c7c8..30e2d5416cf 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 @@ impl ProcMacroExpander for Expander { 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 a5672e4e050..3369dfff281 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 5faf6fc2759..8cc332d4633 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 0a5c16dc4c4..0fa9a264545 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 @@ impl<'a> Converter<'a> { 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 24db9478ee5..030d8e0f04d 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 @@ mod ok { #[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 00000000000..38999c9cd34 --- /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 00000000000..996c1c8477b --- /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 dfdbb4c95fc..6820e4b3353 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 3d999421794..11dbd920091 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 @@ mod token_stream; 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 47555a5db2f..64b40e7b943 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 @@ impl server::TokenStream for RaSpanServer { } 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 leaf: tt::Leaf = tt::Leaf::from(literal); - let tree = tt::TokenTree::from(leaf); - TokenStream { token_trees: vec![tree] } + 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 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 6863ce95997..00000000000 --- 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 c002be4be6f..24a67bf45c8 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 @@ impl server::TokenStream for TokenIdServer { } bridge::TokenTree::Literal(literal) => { - let literal = Literal { - symbol: literal.symbol, - suffix: literal.suffix, - span: literal.span, - kind: literal_kind_to_internal(literal.kind), - }; - - let leaf = tt::Leaf::from(literal); - let tree = TokenTree::from(leaf); - TokenStream { token_trees: vec![tree] } + 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 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 4946a4f2a62..072557913c2 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 @@ impl<S: Copy> TokenStream<S> { 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 a81fea7bec6..3868fee40fb 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 a476a70a740..a0a45b269e4 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 e7293b0b2ef..450def5461d 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 c7c1b043186..d4055d9a0af 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 @@ impl Sysroot { } 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 4ef9d816119..3722e2c7216 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 4ef9d816119..3722e2c7216 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 52089d1dbc2..7b156ea63a5 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 a1e4adf0844..671e838421f 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 @@ impl flags::AnalysisStats { 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 @@ impl flags::AnalysisStats { } 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 @@ impl flags::AnalysisStats { 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 57f95d114d9..16f351272b6 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 @@ xflags::xflags! { 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 46fb701ab42..467d8a53884 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 @@ impl flags::PrimeCaches { 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 fc312439d58..0e418240db0 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 @@ impl FlycheckActor { 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 3b3b9c87975..a870232d4a0 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 parking_lot::{ 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 @@ use crate::{ 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 @@ impl GlobalState { 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 @@ impl GlobalState { req_queue: ReqQueue::default(), task_pool, fmt_pool, + cancellation_pool, loader, config: Arc::new(config.clone()), analysis_host, @@ -264,6 +278,8 @@ impl GlobalState { 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 @@ impl GlobalState { 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 @@ impl GlobalState { 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 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 (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() + }); + + // 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 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())); + } - if let Some(path) = vfs_path.as_path() { - has_structure_changes |= file.is_created_or_deleted(); + 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); - } + 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)); + 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 @@ impl GlobalState { } 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 @@ impl GlobalState { 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 @@ impl GlobalState { 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 bd213ffa57a..0c0438c4b8f 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 @@ use std::{ 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 @@ impl fmt::Display for Event { 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 @@ impl fmt::Debug for Event { } _ => (), } + match self { Event::Lsp(it) => fmt::Debug::fmt(it, f), Event::Task(it) => fmt::Debug::fmt(it, f), @@ -158,6 +161,7 @@ impl fmt::Debug for Event { 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 @@ impl GlobalState { } 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 @@ impl GlobalState { 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 @@ impl GlobalState { 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 @@ impl GlobalState { 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 709d99bda75..7af5b48bb7a 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 @@ impl<Args, Output> Default for OpQueue<Args, Output> { } } -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 55ed1923653..ae9e3e99874 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 @@ impl GlobalState { .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 7bda106764b..b37aded6f68 100644 --- a/src/tools/rust-analyzer/crates/stdx/Cargo.toml +++ b/src/tools/rust-analyzer/crates/stdx/Cargo.toml @@ -17,6 +17,7 @@ jod-thread = "1.0.0" 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 a8de4db624f..8d76c5fd1fb 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 std::{ }; 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 @@ impl Pool { 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 @@ impl Pool { 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 @@ impl Pool { 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 da0bfd4f37f..e60243f2c91 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 @@ impl GenericParamsOwnerEdit for ast::Trait { } } +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 596f73e0b10..fab4cb287c3 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 @@ pub fn match_arm_list(arms: impl IntoIterator<Item = ast::MatchArm>) -> ast::Mat } 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 f6ca5ab6c8c..96e1301f227 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 @@ impl ProcMacroExpander for IdentityProcMacroExpander { ) -> 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 @@ impl ProcMacroExpander for Issue18089ProcMacroExpander { #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 @@ impl ProcMacroExpander for AttributeInputReplaceProcMacroExpander { .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 @@ impl ProcMacroExpander for Issue18840ProcMacroExpander { 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 @@ impl ProcMacroExpander for MirrorProcMacroExpander { 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 @@ impl ProcMacroExpander for ShortenProcMacroExpander { } } } - - 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 @@ impl ProcMacroExpander for Issue17479ProcMacroExpander { #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 @@ impl ProcMacroExpander for Issue18898ProcMacroExpander { } }) } - - 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 @@ impl ProcMacroExpander for DisallowCfgProcMacroExpander { } 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 1dbc07c0929..14574a6456b 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 @@ impl<S> fmt::Display for Ident<S> { } } +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 11a37c218f7..18fb097aad7 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 90e4d65bf96..5b47d1bbaed 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 6195de5d202..bb7d83c4b7d 100644 --- a/src/tools/rust-analyzer/xtask/Cargo.toml +++ b/src/tools/rust-analyzer/xtask/Cargo.toml @@ -14,7 +14,7 @@ write-json = "0.1.4" 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 ca2d683beed..00000000000 --- 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 7f325245bce..d73cc3d214e 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 7f325245bce..d73cc3d214e 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 5afddc5ff73..4e000b05a4b 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 c8670be4e8b..d7f415e19aa 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 56e49568e10..96a4572055c 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 13a95f9b78f..1383de63109 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 @@ const MISALIGNED_COPY: () = unsafe { 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 ed5793c84c5..0f3dc33f3a3 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 @@ LL | y.copy_to_nonoverlapping(&mut z, 1); | 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 da483d671f9..d0242f28544 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)] -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!() -} +#![feature(core_intrinsics)] -#[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::mem; +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 13321b5703a..8d586428e56 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 88b3e37bb84..7c07710332b 100644 --- a/tests/ui/consts/missing_span_in_backtrace.stderr +++ b/tests/ui/consts/missing_span_in_backtrace.stderr @@ -14,8 +14,8 @@ note: inside `swap_nonoverlapping::compiletime::<MaybeUninit<u8>>` --> $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 00000000000..7edb828c973 --- /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 00000000000..9dd0fcf76ce --- /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 b3b69677507..554c3ea3433 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 @@ LL | opaque(Some(t)) = 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 75963489236..bca2874b2b4 100644 --- a/tests/ui/impl-trait/issues/issue-100075.stderr +++ b/tests/ui/impl-trait/issues/issue-100075.stderr @@ -2,10 +2,7 @@ error[E0720]: cannot resolve opaque type --> $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 62741a7454c..e674ce3cbdf 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 82038c1dceb..9878b12044f 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 983ef7cfbe0..5a7759af111 100644 --- a/tests/ui/impl-trait/issues/issue-87450.rs +++ b/tests/ui/impl-trait/issues/issue-87450.rs @@ -3,8 +3,8 @@ fn bar() -> impl Fn() { } 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 9567e09651d..f0f8b5859c0 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 @@ LL | wrap(wrap(wrap(wrap(wrap(wrap(wrap(foo()))))))) = 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 2d2731e4368..af84375c747 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 @@ error[E0720]: cannot resolve opaque type --> $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 42dbc7c9160..080c3284641 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 - | -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 +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-in-exhaustiveness.rs:39:23 | 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 2 previous errors; 3 warnings emitted +error: aborting due to 3 previous errors -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 4c3d5aa8fb8..a3609b93cb3 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 @@ LL | let (x,) = (build(x),); | ^^^^^^^^ 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 @@ LL | (build2(x),) = 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 @@ LL | let (x,) = (build3((x,)),); = 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 @@ LL | let (x,) = (build3((x,)),); 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 @@ LL | let (x,) = (build3((x,)),); = 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 58944533686..fa8fa0e8174 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 ef6871bec7c..0aaee5d1764 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 d820df472f9..426a6c29fff 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 index d439ed4cacb..f4e2cb0c037 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 00000000000..2bfce2d63a8 --- /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 94597adfed0..fe354cc6545 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 59ff9917612..847f1cc6c2e 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 858f2a2feb6..7803b3b78db 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 e527b5bc7f8..837df7f5d43 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 90581a98a34..d66ceda5234 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 256f13b6221..c7a3381d615 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 e62e49b90fb..fd7a861bc92 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -887,6 +887,7 @@ message = "Some changes occurred in HTML/CSS/JS." cc = [ "@GuillaumeGomez", "@jsha", + "@lolbinarycat", ] [mentions."tests/rustdoc-gui/"] |
