diff --git a/compiler/rustc_borrowck/src/polonius/dump.rs b/compiler/rustc_borrowck/src/polonius/dump.rs
index 40e801d03885c..f71e6f3e6f3a6 100644
--- a/compiler/rustc_borrowck/src/polonius/dump.rs
+++ b/compiler/rustc_borrowck/src/polonius/dump.rs
@@ -1,14 +1,18 @@
use std::io;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_index::IndexVec;
use rustc_middle::mir::pretty::{
PassWhere, PrettyPrintMirOptions, create_dump_file, dump_enabled, dump_mir_to_writer,
};
use rustc_middle::mir::{Body, ClosureRegionRequirements};
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{RegionVid, TyCtxt};
use rustc_session::config::MirIncludeSpans;
use crate::borrow_set::BorrowSet;
+use crate::constraints::OutlivesConstraint;
use crate::polonius::{LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet};
+use crate::type_check::Locations;
use crate::{BorrowckInferCtxt, RegionInferenceContext};
/// `-Zdump-mir=polonius` dumps MIR annotated with NLL and polonius specific information.
@@ -50,6 +54,8 @@ pub(crate) fn dump_polonius_mir<'tcx>(
/// - the NLL MIR
/// - the list of polonius localized constraints
/// - a mermaid graph of the CFG
+/// - a mermaid graph of the NLL regions and the constraints between them
+/// - a mermaid graph of the NLL SCCs and the constraints between them
fn emit_polonius_dump<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
@@ -68,7 +74,7 @@ fn emit_polonius_dump<'tcx>(
// Section 1: the NLL + Polonius MIR.
writeln!(out, "
")?;
writeln!(out, "Raw MIR dump")?;
- writeln!(out, "
")?;
+ writeln!(out, "")?;
emit_html_mir(
tcx,
body,
@@ -78,15 +84,31 @@ fn emit_polonius_dump<'tcx>(
closure_region_requirements,
out,
)?;
- writeln!(out, "
")?;
+ writeln!(out, "")?;
writeln!(out, "
")?;
// Section 2: mermaid visualization of the CFG.
writeln!(out, "")?;
writeln!(out, "Control-flow graph")?;
- writeln!(out, "
")?;
+ writeln!(out, "")?;
emit_mermaid_cfg(body, out)?;
- writeln!(out, "
")?;
+ writeln!(out, "")?;
+ writeln!(out, "
")?;
+
+ // Section 3: mermaid visualization of the NLL region graph.
+ writeln!(out, "")?;
+ writeln!(out, "NLL regions")?;
+ writeln!(out, "
")?;
+ emit_mermaid_nll_regions(regioncx, out)?;
+ writeln!(out, "
")?;
+ writeln!(out, "
")?;
+
+ // Section 4: mermaid visualization of the NLL SCC graph.
+ writeln!(out, "")?;
+ writeln!(out, "NLL SCCs")?;
+ writeln!(out, "
")?;
+ emit_mermaid_nll_sccs(regioncx, out)?;
+ writeln!(out, "
")?;
writeln!(out, "
")?;
// Finalize the dump with the HTML epilogue.
@@ -261,3 +283,112 @@ fn emit_mermaid_cfg(body: &Body<'_>, out: &mut dyn io::Write) -> io::Result<()>
Ok(())
}
+
+/// Emits a region's label: index, universe, external name.
+fn render_region(
+ region: RegionVid,
+ regioncx: &RegionInferenceContext<'_>,
+ out: &mut dyn io::Write,
+) -> io::Result<()> {
+ let def = regioncx.region_definition(region);
+ let universe = def.universe;
+
+ write!(out, "'{}", region.as_usize())?;
+ if !universe.is_root() {
+ write!(out, "/{universe:?}")?;
+ }
+ if let Some(name) = def.external_name.and_then(|e| e.get_name()) {
+ write!(out, " ({name})")?;
+ }
+ Ok(())
+}
+
+/// Emits a mermaid flowchart of the NLL regions and the outlives constraints between them, similar
+/// to the graphviz version.
+fn emit_mermaid_nll_regions<'tcx>(
+ regioncx: &RegionInferenceContext<'tcx>,
+ out: &mut dyn io::Write,
+) -> io::Result<()> {
+ // The mermaid chart type: a top-down flowchart.
+ writeln!(out, "flowchart TD")?;
+
+ // Emit the region nodes.
+ for region in regioncx.var_infos.indices() {
+ write!(out, "{}[\"", region.as_usize())?;
+ render_region(region, regioncx, out)?;
+ writeln!(out, "\"]")?;
+ }
+
+ // Get a set of edges to check for the reverse edge being present.
+ let edges: FxHashSet<_> = regioncx.outlives_constraints().map(|c| (c.sup, c.sub)).collect();
+
+ // Order (and deduplicate) edges for traversal, to display them in a generally increasing order.
+ let constraint_key = |c: &OutlivesConstraint<'_>| {
+ let min = c.sup.min(c.sub);
+ let max = c.sup.max(c.sub);
+ (min, max)
+ };
+ let mut ordered_edges: Vec<_> = regioncx.outlives_constraints().collect();
+ ordered_edges.sort_by_key(|c| constraint_key(c));
+ ordered_edges.dedup_by_key(|c| constraint_key(c));
+
+ for outlives in ordered_edges {
+ // Source node.
+ write!(out, "{} ", outlives.sup.as_usize())?;
+
+ // The kind of arrow: bidirectional if the opposite edge exists in the set.
+ if edges.contains(&(outlives.sub, outlives.sup)) {
+ write!(out, "<")?;
+ }
+ write!(out, "-- ")?;
+
+ // Edge label from its `Locations`.
+ match outlives.locations {
+ Locations::All(_) => write!(out, "All")?,
+ Locations::Single(location) => write!(out, "{:?}", location)?,
+ }
+
+ // Target node.
+ writeln!(out, " --> {}", outlives.sub.as_usize())?;
+ }
+ Ok(())
+}
+
+/// Emits a mermaid flowchart of the NLL SCCs and the outlives constraints between them, similar
+/// to the graphviz version.
+fn emit_mermaid_nll_sccs<'tcx>(
+ regioncx: &RegionInferenceContext<'tcx>,
+ out: &mut dyn io::Write,
+) -> io::Result<()> {
+ // The mermaid chart type: a top-down flowchart.
+ writeln!(out, "flowchart TD")?;
+
+ // Gather and emit the SCC nodes.
+ let mut nodes_per_scc: IndexVec<_, _> =
+ regioncx.constraint_sccs().all_sccs().map(|_| Vec::new()).collect();
+ for region in regioncx.var_infos.indices() {
+ let scc = regioncx.constraint_sccs().scc(region);
+ nodes_per_scc[scc].push(region);
+ }
+ for (scc, regions) in nodes_per_scc.iter_enumerated() {
+ // The node label: the regions contained in the SCC.
+ write!(out, "{scc}[\"SCC({scc}) = {{", scc = scc.as_usize())?;
+ for (idx, ®ion) in regions.iter().enumerate() {
+ render_region(region, regioncx, out)?;
+ if idx < regions.len() - 1 {
+ write!(out, ",")?;
+ }
+ }
+ writeln!(out, "}}\"]")?;
+ }
+
+ // Emit the edges between SCCs.
+ let edges = regioncx.constraint_sccs().all_sccs().flat_map(|source| {
+ regioncx.constraint_sccs().successors(source).iter().map(move |&target| (source, target))
+ });
+ for (source, target) in edges {
+ writeln!(out, "{} --> {}", source.as_usize(), target.as_usize())?;
+ }
+
+ Ok(())
+}
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 2c99597922e8f..fdcd9caf4ac87 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -126,7 +126,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
&mut self,
name: &str,
params: Vec,
- returns: Vec,
+ mut returns: Vec,
args: &[Value],
) -> Cow<'_, [Value]> {
// Pass i128 arguments by-ref on Windows.
@@ -150,15 +150,19 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
(params, args.into())
};
- // Return i128 using a return area pointer on Windows and s390x.
- let adjust_ret_param =
- if self.tcx.sess.target.is_like_windows || self.tcx.sess.target.arch == "s390x" {
- returns.len() == 1 && returns[0].value_type == types::I128
- } else {
- false
- };
+ let ret_single_i128 = returns.len() == 1 && returns[0].value_type == types::I128;
+ if ret_single_i128 && self.tcx.sess.target.is_like_windows {
+ // Return i128 using the vector ABI on Windows
+ returns[0].value_type = types::I64X2;
+
+ let ret = self.lib_call_unadjusted(name, params, returns, &args)[0];
- if adjust_ret_param {
+ // FIXME(bytecodealliance/wasmtime#6104) use bitcast instead of store to get from i64x2 to i128
+ let ret_ptr = self.create_stack_slot(16, 16);
+ ret_ptr.store(self, ret, MemFlags::trusted());
+ Cow::Owned(vec![ret_ptr.load(self, types::I128, MemFlags::trusted())])
+ } else if ret_single_i128 && self.tcx.sess.target.arch == "s390x" {
+ // Return i128 using a return area pointer on s390x.
let mut params = params;
let mut args = args.to_vec();
diff --git a/compiler/rustc_codegen_cranelift/src/cast.rs b/compiler/rustc_codegen_cranelift/src/cast.rs
index 0b5cb1547fc69..4463631c524be 100644
--- a/compiler/rustc_codegen_cranelift/src/cast.rs
+++ b/compiler/rustc_codegen_cranelift/src/cast.rs
@@ -96,25 +96,9 @@ pub(crate) fn clif_int_or_float_cast(
},
);
- if fx.tcx.sess.target.is_like_windows {
- let ret = fx.lib_call(
- &name,
- vec![AbiParam::new(from_ty)],
- vec![AbiParam::new(types::I64X2)],
- &[from],
- )[0];
- // FIXME(bytecodealliance/wasmtime#6104) use bitcast instead of store to get from i64x2 to i128
- let ret_ptr = fx.create_stack_slot(16, 16);
- ret_ptr.store(fx, ret, MemFlags::trusted());
- ret_ptr.load(fx, types::I128, MemFlags::trusted())
- } else {
- fx.lib_call(
- &name,
- vec![AbiParam::new(from_ty)],
- vec![AbiParam::new(types::I128)],
- &[from],
- )[0]
- }
+ fx.lib_call(&name, vec![AbiParam::new(from_ty)], vec![AbiParam::new(types::I128)], &[
+ from,
+ ])[0]
} else if to_ty == types::I8 || to_ty == types::I16 {
// FIXME implement fcvt_to_*int_sat.i8/i16
let val = if to_signed {
diff --git a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
index dcfd7ddabbc42..df5a79086fa3e 100644
--- a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
+++ b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
@@ -33,28 +33,14 @@ pub(crate) fn maybe_codegen<'tcx>(
(BinOp::Rem, true) => "__modti3",
_ => unreachable!(),
};
- if fx.tcx.sess.target.is_like_windows {
- let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)];
- let ret = fx.lib_call(
- name,
- vec![AbiParam::new(types::I128), AbiParam::new(types::I128)],
- vec![AbiParam::new(types::I64X2)],
- &args,
- )[0];
- // FIXME(bytecodealliance/wasmtime#6104) use bitcast instead of store to get from i64x2 to i128
- let ret_place = CPlace::new_stack_slot(fx, lhs.layout());
- ret_place.to_ptr().store(fx, ret, MemFlags::trusted());
- Some(ret_place.to_cvalue(fx))
- } else {
- let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)];
- let ret_val = fx.lib_call(
- name,
- vec![AbiParam::new(types::I128), AbiParam::new(types::I128)],
- vec![AbiParam::new(types::I128)],
- &args,
- )[0];
- Some(CValue::by_val(ret_val, lhs.layout()))
- }
+ let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)];
+ let ret_val = fx.lib_call(
+ name,
+ vec![AbiParam::new(types::I128), AbiParam::new(types::I128)],
+ vec![AbiParam::new(types::I128)],
+ &args,
+ )[0];
+ Some(CValue::by_val(ret_val, lhs.layout()))
}
BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne | BinOp::Cmp => None,
BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => None,
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 74d02ac22276c..9495030f124b5 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -797,7 +797,6 @@ fn test_unstable_options_tracking_hash() {
tracked!(function_sections, Some(false));
tracked!(human_readable_cgu_names, true);
tracked!(incremental_ignore_spans, true);
- tracked!(inline_in_all_cgus, Some(true));
tracked!(inline_mir, Some(true));
tracked!(inline_mir_hint_threshold, Some(123));
tracked!(inline_mir_threshold, Some(123));
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 3eccf56d8c4dd..6fa3fa2432de5 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -91,13 +91,8 @@ impl<'tcx> MonoItem<'tcx> {
}
pub fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode {
- let generate_cgu_internal_copies = tcx
- .sess
- .opts
- .unstable_opts
- .inline_in_all_cgus
- .unwrap_or_else(|| tcx.sess.opts.optimize != OptLevel::No)
- && !tcx.sess.link_dead_code();
+ let generate_cgu_internal_copies =
+ (tcx.sess.opts.optimize != OptLevel::No) && !tcx.sess.link_dead_code();
match *self {
MonoItem::Fn(ref instance) => {
@@ -121,8 +116,8 @@ impl<'tcx> MonoItem<'tcx> {
}
// At this point we don't have explicit linkage and we're an
- // inlined function. If we're inlining into all CGUs then we'll
- // be creating a local copy per CGU.
+ // inlined function. If this crate's build settings permit,
+ // we'll be creating a local copy per CGU.
if generate_cgu_internal_copies {
return InstantiationMode::LocalCopy;
}
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 50287b706ce83..2373ab67d42ed 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -2830,9 +2830,10 @@ pub(crate) struct DynAfterMut {
pub(crate) struct FnPointerCannotBeConst {
#[primary_span]
pub span: Span,
- #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
#[label]
pub qualifier: Span,
+ #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
+ pub suggestion: Span,
}
#[derive(Diagnostic)]
@@ -2840,9 +2841,10 @@ pub(crate) struct FnPointerCannotBeConst {
pub(crate) struct FnPointerCannotBeAsync {
#[primary_span]
pub span: Span,
- #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
#[label]
pub qualifier: Span,
+ #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
+ pub suggestion: Span,
}
#[derive(Diagnostic)]
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 6497d19a173ca..dc5919b3630ce 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -609,16 +609,58 @@ impl<'a> Parser<'a> {
let span_start = self.token.span;
let ast::FnHeader { ext, safety, constness, coroutine_kind } =
self.parse_fn_front_matter(&inherited_vis, Case::Sensitive)?;
+ let fn_start_lo = self.prev_token.span.lo();
if self.may_recover() && self.token == TokenKind::Lt {
self.recover_fn_ptr_with_generics(lo, &mut params, param_insertion_point)?;
}
let decl = self.parse_fn_decl(|_| false, AllowPlus::No, recover_return_sign)?;
let whole_span = lo.to(self.prev_token.span);
- if let ast::Const::Yes(span) = constness {
- self.dcx().emit_err(FnPointerCannotBeConst { span: whole_span, qualifier: span });
+
+ // Order/parsing of "front matter" follows:
+ // ` fn()`
+ // ^ ^ ^ ^ ^
+ // | | | | fn_start_lo
+ // | | | ext_sp.lo
+ // | | safety_sp.lo
+ // | coroutine_sp.lo
+ // const_sp.lo
+ if let ast::Const::Yes(const_span) = constness {
+ let next_token_lo = if let Some(
+ ast::CoroutineKind::Async { span, .. }
+ | ast::CoroutineKind::Gen { span, .. }
+ | ast::CoroutineKind::AsyncGen { span, .. },
+ ) = coroutine_kind
+ {
+ span.lo()
+ } else if let ast::Safety::Unsafe(span) | ast::Safety::Safe(span) = safety {
+ span.lo()
+ } else if let ast::Extern::Implicit(span) | ast::Extern::Explicit(_, span) = ext {
+ span.lo()
+ } else {
+ fn_start_lo
+ };
+ let sugg_span = const_span.with_hi(next_token_lo);
+ self.dcx().emit_err(FnPointerCannotBeConst {
+ span: whole_span,
+ qualifier: const_span,
+ suggestion: sugg_span,
+ });
}
- if let Some(ast::CoroutineKind::Async { span, .. }) = coroutine_kind {
- self.dcx().emit_err(FnPointerCannotBeAsync { span: whole_span, qualifier: span });
+ if let Some(ast::CoroutineKind::Async { span: async_span, .. }) = coroutine_kind {
+ let next_token_lo = if let ast::Safety::Unsafe(span) | ast::Safety::Safe(span) = safety
+ {
+ span.lo()
+ } else if let ast::Extern::Implicit(span) | ast::Extern::Explicit(_, span) = ext {
+ span.lo()
+ } else {
+ fn_start_lo
+ };
+ let sugg_span = async_span.with_hi(next_token_lo);
+ self.dcx().emit_err(FnPointerCannotBeAsync {
+ span: whole_span,
+ qualifier: async_span,
+ suggestion: sugg_span,
+ });
}
// FIXME(gen_blocks): emit a similar error for `gen fn()`
let decl_span = span_start.to(self.prev_token.span);
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 63aaa3abc8e56..4ce6382512978 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1870,8 +1870,6 @@ options! {
"verify extended properties for incr. comp. (default: no):
- hashes of green query instances
- hash collisions of query keys"),
- inline_in_all_cgus: Option = (None, parse_opt_bool, [TRACKED],
- "control whether `#[inline]` functions are in all CGUs"),
inline_llvm: bool = (true, parse_bool, [TRACKED],
"enable LLVM inlining (default: yes)"),
inline_mir: Option = (None, parse_opt_bool, [TRACKED],
diff --git a/compiler/rustc_target/src/callconv/x86_win64.rs b/compiler/rustc_target/src/callconv/x86_win64.rs
index 0944bda26875d..816564d2fed8b 100644
--- a/compiler/rustc_target/src/callconv/x86_win64.rs
+++ b/compiler/rustc_target/src/callconv/x86_win64.rs
@@ -1,4 +1,4 @@
-use rustc_abi::{BackendRepr, Float, Primitive};
+use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind, Size};
use crate::abi::call::{ArgAbi, FnAbi, Reg};
use crate::spec::HasTargetSpec;
@@ -6,7 +6,7 @@ use crate::spec::HasTargetSpec;
// Win64 ABI: https://docs.microsoft.com/en-us/cpp/build/parameter-passing
pub(crate) fn compute_abi_info(_cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'_, Ty>) {
- let fixup = |a: &mut ArgAbi<'_, Ty>| {
+ let fixup = |a: &mut ArgAbi<'_, Ty>, is_ret: bool| {
match a.layout.backend_repr {
BackendRepr::Uninhabited | BackendRepr::Memory { sized: false } => {}
BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => {
@@ -23,11 +23,16 @@ pub(crate) fn compute_abi_info(_cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<
// (probably what clang calls "illegal vectors").
}
BackendRepr::Scalar(scalar) => {
- // Match what LLVM does for `f128` so that `compiler-builtins` builtins match up
- // with what LLVM expects.
- if a.layout.size.bytes() > 8
+ if is_ret && matches!(scalar.primitive(), Primitive::Int(Integer::I128, _)) {
+ // `i128` is returned in xmm0 by Clang and GCC
+ // FIXME(#134288): This may change for the `-msvc` targets in the future.
+ let reg = Reg { kind: RegKind::Vector, size: Size::from_bits(128) };
+ a.cast_to(reg);
+ } else if a.layout.size.bytes() > 8
&& !matches!(scalar.primitive(), Primitive::Float(Float::F128))
{
+ // Match what LLVM does for `f128` so that `compiler-builtins` builtins match up
+ // with what LLVM expects.
a.make_indirect();
} else {
a.extend_integer_width_to(32);
@@ -37,8 +42,9 @@ pub(crate) fn compute_abi_info(_cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<
};
if !fn_abi.ret.is_ignore() {
- fixup(&mut fn_abi.ret);
+ fixup(&mut fn_abi.ret, true);
}
+
for arg in fn_abi.args.iter_mut() {
if arg.is_ignore() && arg.layout.is_zst() {
// Windows ABIs do not talk about ZST since such types do not exist in MSVC.
@@ -49,7 +55,7 @@ pub(crate) fn compute_abi_info(_cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<
arg.make_indirect_from_ignore();
continue;
}
- fixup(arg);
+ fixup(arg, false);
}
// FIXME: We should likely also do something about ZST return types, similar to above.
// However, that's non-trivial due to `()`.
diff --git a/library/core/src/iter/sources/from_fn.rs b/library/core/src/iter/sources/from_fn.rs
index 5f3d404d7dca2..75cc0ffe3c77c 100644
--- a/library/core/src/iter/sources/from_fn.rs
+++ b/library/core/src/iter/sources/from_fn.rs
@@ -1,7 +1,7 @@
use crate::fmt;
-/// Creates a new iterator where each iteration calls the provided closure
-/// `F: FnMut() -> Option`.
+/// Creates an iterator with the provided closure
+/// `F: FnMut() -> Option` as its `[next](Iterator::next)` method.
///
/// The iterator will yield the `T`s returned from the closure.
///
diff --git a/library/std/src/f128.rs b/library/std/src/f128.rs
index 4f37e18a8cd76..54a992c9cf4b5 100644
--- a/library/std/src/f128.rs
+++ b/library/std/src/f128.rs
@@ -324,6 +324,18 @@ impl f128 {
///
/// The precision of this function is non-deterministic. This means it varies by platform,
/// Rust version, and can even differ within the same execution from one invocation to the next.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(f128)]
+ ///
+ /// let x = 2.0_f128;
+ /// let abs_difference = (x.powi(2) - (x * x)).abs();
+ /// assert!(abs_difference <= f128::EPSILON);
+ ///
+ /// assert_eq!(f128::powi(f128::NAN, 0), 1.0);
+ /// ```
#[inline]
#[rustc_allow_incoherent_impl]
#[unstable(feature = "f128", issue = "116909")]
@@ -347,8 +359,10 @@ impl f128 {
///
/// let x = 2.0_f128;
/// let abs_difference = (x.powf(2.0) - (x * x)).abs();
- ///
/// assert!(abs_difference <= f128::EPSILON);
+ ///
+ /// assert_eq!(f128::powf(1.0, f128::NAN), 1.0);
+ /// assert_eq!(f128::powf(f128::NAN, 0.0), 1.0);
/// # }
/// ```
#[inline]
diff --git a/library/std/src/f16.rs b/library/std/src/f16.rs
index 42cd6e3fe2a5f..e354f2dd98217 100644
--- a/library/std/src/f16.rs
+++ b/library/std/src/f16.rs
@@ -324,6 +324,18 @@ impl f16 {
///
/// The precision of this function is non-deterministic. This means it varies by platform,
/// Rust version, and can even differ within the same execution from one invocation to the next.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(f16)]
+ ///
+ /// let x = 2.0_f16;
+ /// let abs_difference = (x.powi(2) - (x * x)).abs();
+ /// assert!(abs_difference <= f16::EPSILON);
+ ///
+ /// assert_eq!(f16::powi(f16::NAN, 0), 1.0);
+ /// ```
#[inline]
#[rustc_allow_incoherent_impl]
#[unstable(feature = "f16", issue = "116909")]
@@ -347,8 +359,10 @@ impl f16 {
///
/// let x = 2.0_f16;
/// let abs_difference = (x.powf(2.0) - (x * x)).abs();
- ///
/// assert!(abs_difference <= f16::EPSILON);
+ ///
+ /// assert_eq!(f16::powf(1.0, f16::NAN), 1.0);
+ /// assert_eq!(f16::powf(f16::NAN, 0.0), 1.0);
/// # }
/// ```
#[inline]
diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs
index 438d77b1626be..f9b6723788ae3 100644
--- a/library/std/src/f32.rs
+++ b/library/std/src/f32.rs
@@ -306,8 +306,9 @@ impl f32 {
/// ```
/// let x = 2.0_f32;
/// let abs_difference = (x.powi(2) - (x * x)).abs();
- ///
/// assert!(abs_difference <= f32::EPSILON);
+ ///
+ /// assert_eq!(f32::powi(f32::NAN, 0), 1.0);
/// ```
#[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
@@ -329,8 +330,10 @@ impl f32 {
/// ```
/// let x = 2.0_f32;
/// let abs_difference = (x.powf(2.0) - (x * x)).abs();
- ///
/// assert!(abs_difference <= f32::EPSILON);
+ ///
+ /// assert_eq!(f32::powf(1.0, f32::NAN), 1.0);
+ /// assert_eq!(f32::powf(f32::NAN, 0.0), 1.0);
/// ```
#[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs
index 9bb4bfbab2a0f..0de55a15d48e8 100644
--- a/library/std/src/f64.rs
+++ b/library/std/src/f64.rs
@@ -306,8 +306,9 @@ impl f64 {
/// ```
/// let x = 2.0_f64;
/// let abs_difference = (x.powi(2) - (x * x)).abs();
+ /// assert!(abs_difference <= f64::EPSILON);
///
- /// assert!(abs_difference < 1e-10);
+ /// assert_eq!(f64::powi(f64::NAN, 0), 1.0);
/// ```
#[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
@@ -329,8 +330,10 @@ impl f64 {
/// ```
/// let x = 2.0_f64;
/// let abs_difference = (x.powf(2.0) - (x * x)).abs();
+ /// assert!(abs_difference <= f64::EPSILON);
///
- /// assert!(abs_difference < 1e-10);
+ /// assert_eq!(f64::powf(1.0, f64::NAN), 1.0);
+ /// assert_eq!(f64::powf(f64::NAN, 0.0), 1.0);
/// ```
#[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
diff --git a/src/doc/book b/src/doc/book
index 82a4a49789bc9..fa312a343fbff 160000
--- a/src/doc/book
+++ b/src/doc/book
@@ -1 +1 @@
-Subproject commit 82a4a49789bc96db1a1b2a210b4c5ed7c9ef0c0d
+Subproject commit fa312a343fbff01bc6cef393e326817f70719813
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
index d56e0f3a0656b..4ed5a1a4a2a7e 160000
--- a/src/doc/edition-guide
+++ b/src/doc/edition-guide
@@ -1 +1 @@
-Subproject commit d56e0f3a0656b7702ca466d4b191e16c28262b82
+Subproject commit 4ed5a1a4a2a7ecc2e529a5baaef04f7bc7917eda
diff --git a/src/doc/nomicon b/src/doc/nomicon
index 625b200e5b33a..bc22988655446 160000
--- a/src/doc/nomicon
+++ b/src/doc/nomicon
@@ -1 +1 @@
-Subproject commit 625b200e5b33a5af35589db0bc454203a3d46d20
+Subproject commit bc2298865544695c63454fc1f9f98a3dc22e9948
diff --git a/src/doc/reference b/src/doc/reference
index 293af99100377..93b921c7d3213 160000
--- a/src/doc/reference
+++ b/src/doc/reference
@@ -1 +1 @@
-Subproject commit 293af991003772bdccf2d6b980182d84dd055942
+Subproject commit 93b921c7d3213d38d920f7f905a3bec093d2217d
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index f92668a6a9786..2dfca7c4803e2 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -846,7 +846,6 @@ dependencies = [
"dashmap",
"hashbrown",
"rustc-hash 2.0.0",
- "sptr",
"triomphe",
]
@@ -1927,12 +1926,6 @@ dependencies = [
"vfs",
]
-[[package]]
-name = "sptr"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a"
-
[[package]]
name = "stdx"
version = "0.0.0"
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index 1029844cd3ab4..c42ae171d8668 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -4,7 +4,7 @@ exclude = ["crates/proc-macro-srv/proc-macro-test/imp"]
resolver = "2"
[workspace.package]
-rust-version = "1.83"
+rust-version = "1.84"
edition = "2021"
license = "MIT OR Apache-2.0"
authors = ["rust-analyzer team"]
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
index 1327bb3ab59c0..16c7b5ca00a07 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
@@ -1381,6 +1381,9 @@ impl ExprCollector<'_> {
}
}
ast::Stmt::Item(ast::Item::MacroDef(macro_)) => {
+ if self.check_cfg(¯o_).is_none() {
+ return;
+ }
let Some(name) = macro_.name() else {
statements.push(Statement::Item(Item::Other));
return;
@@ -1390,6 +1393,9 @@ impl ExprCollector<'_> {
self.collect_macro_def(statements, macro_id);
}
ast::Stmt::Item(ast::Item::MacroRules(macro_)) => {
+ if self.check_cfg(¯o_).is_none() {
+ return;
+ }
let Some(name) = macro_.name() else {
statements.push(Statement::Item(Item::Other));
return;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs
index f483efa85179b..e136dd18a55e5 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs
@@ -475,7 +475,7 @@ fn outer() {
block scope::tests
name: _
- outer: v
+ outer: vg
crate
outer: v
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 5d67902c8ac12..c30ad0163b9db 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
@@ -445,6 +445,10 @@ fn find_in_dep(
};
cov_mark::hit!(partially_imported);
if info.is_unstable {
+ if !ctx.cfg.allow_unstable {
+ // the item is unstable and we are not allowed to use unstable items
+ continue;
+ }
choice.stability = Unstable;
}
@@ -670,6 +674,7 @@ mod tests {
prefer_prelude: bool,
prefer_absolute: bool,
prefer_no_std: bool,
+ allow_unstable: bool,
expect: Expect,
) {
let (db, pos) = TestDB::with_position(ra_fixture);
@@ -711,7 +716,7 @@ mod tests {
module,
prefix,
ignore_local_imports,
- ImportPathConfig { prefer_no_std, prefer_prelude, prefer_absolute },
+ ImportPathConfig { prefer_no_std, prefer_prelude, prefer_absolute, allow_unstable },
);
format_to!(
res,
@@ -732,7 +737,7 @@ mod tests {
path: &str,
expect: Expect,
) {
- check_found_path_(ra_fixture, path, false, false, false, expect);
+ check_found_path_(ra_fixture, path, false, false, false, false, expect);
}
fn check_found_path_prelude(
@@ -740,7 +745,7 @@ mod tests {
path: &str,
expect: Expect,
) {
- check_found_path_(ra_fixture, path, true, false, false, expect);
+ check_found_path_(ra_fixture, path, true, false, false, false, expect);
}
fn check_found_path_absolute(
@@ -748,7 +753,7 @@ mod tests {
path: &str,
expect: Expect,
) {
- check_found_path_(ra_fixture, path, false, true, false, expect);
+ check_found_path_(ra_fixture, path, false, true, false, false, expect);
}
fn check_found_path_prefer_no_std(
@@ -756,7 +761,15 @@ mod tests {
path: &str,
expect: Expect,
) {
- check_found_path_(ra_fixture, path, false, false, true, expect);
+ check_found_path_(ra_fixture, path, false, false, true, false, expect);
+ }
+
+ fn check_found_path_prefer_no_std_allow_unstable(
+ #[rust_analyzer::rust_fixture] ra_fixture: &str,
+ path: &str,
+ expect: Expect,
+ ) {
+ check_found_path_(ra_fixture, path, false, false, true, true, expect);
}
#[test]
@@ -1951,7 +1964,7 @@ pub mod ops {
#[test]
fn respect_unstable_modules() {
- check_found_path_prefer_no_std(
+ check_found_path_prefer_no_std_allow_unstable(
r#"
//- /main.rs crate:main deps:std,core
extern crate std;
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 ac262950f13c6..34635997bdff3 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
@@ -10,7 +10,6 @@ use rustc_hash::FxHashSet;
use smallvec::SmallVec;
use span::Edition;
use stdx::{format_to, TupleExt};
-use syntax::ToSmolStr;
use triomphe::Arc;
use crate::{
@@ -88,9 +87,9 @@ impl ImportMap {
.iter()
// We've only collected items, whose name cannot be tuple field so unwrapping is fine.
.flat_map(|(&item, (info, _))| {
- info.iter().enumerate().map(move |(idx, info)| {
- (item, info.name.unescaped().display(db.upcast()).to_smolstr(), idx as u32)
- })
+ info.iter()
+ .enumerate()
+ .map(move |(idx, info)| (item, info.name.as_str(), idx as u32))
})
.collect();
importables.sort_by(|(_, l_info, _), (_, r_info, _)| {
@@ -168,7 +167,8 @@ impl ImportMap {
let attr_id = if let Some(import) = import {
match import {
ImportOrExternCrate::ExternCrate(id) => Some(id.into()),
- ImportOrExternCrate::Import(id) => Some(id.import.into()),
+ ImportOrExternCrate::Import(id) => Some(id.use_.into()),
+ ImportOrExternCrate::Glob(id) => Some(id.use_.into()),
}
} else {
match item {
@@ -441,7 +441,7 @@ pub fn search_dependencies(
}
fn search_maps(
- db: &dyn DefDatabase,
+ _db: &dyn DefDatabase,
import_maps: &[Arc],
mut stream: fst::map::Union<'_>,
query: &Query,
@@ -464,11 +464,7 @@ fn search_maps(
.then(|| (item, &import_infos[info_idx as usize]))
})
.filter(|&(_, info)| {
- query.search_mode.check(
- &query.query,
- query.case_sensitive,
- &info.name.unescaped().display(db.upcast()).to_smolstr(),
- )
+ query.search_mode.check(&query.query, query.case_sensitive, info.name.as_str())
});
res.extend(iter.map(TupleExt::head));
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
index 0fec7674109bc..65a39c565611b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
@@ -31,21 +31,62 @@ pub struct PerNsGlobImports {
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum ImportOrExternCrate {
+ Glob(GlobId),
Import(ImportId),
ExternCrate(ExternCrateId),
}
+impl From for ImportOrExternCrate {
+ fn from(value: ImportOrGlob) -> Self {
+ match value {
+ ImportOrGlob::Glob(it) => ImportOrExternCrate::Glob(it),
+ ImportOrGlob::Import(it) => ImportOrExternCrate::Import(it),
+ }
+ }
+}
+
+impl ImportOrExternCrate {
+ pub fn import_or_glob(self) -> Option {
+ match self {
+ ImportOrExternCrate::Import(it) => Some(ImportOrGlob::Import(it)),
+ ImportOrExternCrate::Glob(it) => Some(ImportOrGlob::Glob(it)),
+ _ => None,
+ }
+ }
+
+ pub fn import(self) -> Option {
+ match self {
+ ImportOrExternCrate::Import(it) => Some(it),
+ _ => None,
+ }
+ }
+
+ pub fn glob(self) -> Option {
+ match self {
+ ImportOrExternCrate::Glob(id) => Some(id),
+ _ => None,
+ }
+ }
+
+ pub fn use_(self) -> Option {
+ match self {
+ ImportOrExternCrate::Glob(id) => Some(id.use_),
+ ImportOrExternCrate::Import(id) => Some(id.use_),
+ _ => None,
+ }
+ }
+}
+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub(crate) enum ImportType {
+pub enum ImportOrGlob {
+ Glob(GlobId),
Import(ImportId),
- Glob(UseId),
- ExternCrate(ExternCrateId),
}
-impl ImportOrExternCrate {
+impl ImportOrGlob {
pub fn into_import(self) -> Option {
match self {
- ImportOrExternCrate::Import(it) => Some(it),
+ ImportOrGlob::Import(it) => Some(it),
_ => None,
}
}
@@ -54,12 +95,39 @@ impl ImportOrExternCrate {
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum ImportOrDef {
Import(ImportId),
+ Glob(GlobId),
ExternCrate(ExternCrateId),
Def(ModuleDefId),
}
+
+impl From for ImportOrDef {
+ fn from(value: ImportOrExternCrate) -> Self {
+ match value {
+ ImportOrExternCrate::Import(it) => ImportOrDef::Import(it),
+ ImportOrExternCrate::Glob(it) => ImportOrDef::Glob(it),
+ ImportOrExternCrate::ExternCrate(it) => ImportOrDef::ExternCrate(it),
+ }
+ }
+}
+
+impl From for ImportOrDef {
+ fn from(value: ImportOrGlob) -> Self {
+ match value {
+ ImportOrGlob::Import(it) => ImportOrDef::Import(it),
+ ImportOrGlob::Glob(it) => ImportOrDef::Glob(it),
+ }
+ }
+}
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub struct ImportId {
- pub import: UseId,
+ pub use_: UseId,
+ pub idx: Idx,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
+pub struct GlobId {
+ pub use_: UseId,
pub idx: Idx,
}
@@ -96,8 +164,8 @@ pub struct ItemScope {
// the resolutions of the imports of this scope
use_imports_types: FxHashMap,
- use_imports_values: FxHashMap,
- use_imports_macros: FxHashMap,
+ use_imports_values: FxHashMap,
+ use_imports_macros: FxHashMap,
use_decls: Vec,
extern_crate_decls: Vec,
@@ -162,7 +230,7 @@ impl ItemScope {
.map(move |name| (name, self.get(name)))
}
- pub fn values(&self) -> impl Iterator- )> + '_ {
+ pub fn values(&self) -> impl Iterator
- )> + '_ {
self.values.iter().map(|(n, &i)| (n, i))
}
@@ -172,7 +240,7 @@ impl ItemScope {
self.types.iter().map(|(n, &i)| (n, i))
}
- pub fn macros(&self) -> impl Iterator
- )> + '_ {
+ pub fn macros(&self) -> impl Iterator
- )> + '_ {
self.macros.iter().map(|(n, &i)| (n, i))
}
@@ -180,9 +248,10 @@ impl ItemScope {
self.use_imports_types
.keys()
.copied()
- .filter_map(ImportOrExternCrate::into_import)
+ .filter_map(ImportOrExternCrate::import_or_glob)
.chain(self.use_imports_values.keys().copied())
.chain(self.use_imports_macros.keys().copied())
+ .filter_map(ImportOrGlob::into_import)
.sorted()
.dedup()
}
@@ -192,10 +261,10 @@ impl ItemScope {
let mut def_map;
let mut scope = self;
- while let Some(&m) = scope.use_imports_macros.get(&import) {
+ while let Some(&m) = scope.use_imports_macros.get(&ImportOrGlob::Import(import)) {
match m {
ImportOrDef::Import(i) => {
- let module_id = i.import.lookup(db).container;
+ let module_id = i.use_.lookup(db).container;
def_map = module_id.def_map(db);
scope = &def_map[module_id.local_id].scope;
import = i;
@@ -211,7 +280,7 @@ impl ItemScope {
while let Some(&m) = scope.use_imports_types.get(&ImportOrExternCrate::Import(import)) {
match m {
ImportOrDef::Import(i) => {
- let module_id = i.import.lookup(db).container;
+ let module_id = i.use_.lookup(db).container;
def_map = module_id.def_map(db);
scope = &def_map[module_id.local_id].scope;
import = i;
@@ -224,10 +293,10 @@ impl ItemScope {
}
}
let mut scope = self;
- while let Some(&m) = scope.use_imports_values.get(&import) {
+ while let Some(&m) = scope.use_imports_values.get(&ImportOrGlob::Import(import)) {
match m {
ImportOrDef::Import(i) => {
- let module_id = i.import.lookup(db).container;
+ let module_id = i.use_.lookup(db).container;
def_map = module_id.def_map(db);
scope = &def_map[module_id.local_id].scope;
import = i;
@@ -488,9 +557,13 @@ impl ItemScope {
self.unnamed_trait_imports.get(&tr).map(|trait_| trait_.vis)
}
- pub(crate) fn push_unnamed_trait(&mut self, tr: TraitId, vis: Visibility) {
- // FIXME: import
- self.unnamed_trait_imports.insert(tr, Item { def: (), vis, import: None });
+ pub(crate) fn push_unnamed_trait(
+ &mut self,
+ tr: TraitId,
+ vis: Visibility,
+ import: Option,
+ ) {
+ self.unnamed_trait_imports.insert(tr, Item { def: (), vis, import });
}
pub(crate) fn push_res_with_import(
@@ -498,7 +571,7 @@ impl ItemScope {
glob_imports: &mut PerNsGlobImports,
lookup: (LocalModuleId, Name),
def: PerNs,
- import: Option,
+ import: Option,
) -> bool {
let mut changed = false;
@@ -509,41 +582,22 @@ impl ItemScope {
match existing {
Entry::Vacant(entry) => {
match import {
- Some(ImportType::Glob(_)) => {
+ Some(ImportOrExternCrate::Glob(_)) => {
glob_imports.types.insert(lookup.clone());
}
_ => _ = glob_imports.types.remove(&lookup),
}
- let import = match import {
- Some(ImportType::ExternCrate(extern_crate)) => {
- Some(ImportOrExternCrate::ExternCrate(extern_crate))
- }
- Some(ImportType::Import(import)) => {
- Some(ImportOrExternCrate::Import(import))
- }
- None | Some(ImportType::Glob(_)) => None,
- };
let prev = std::mem::replace(&mut fld.import, import);
if let Some(import) = import {
- self.use_imports_types.insert(
- import,
- match prev {
- Some(ImportOrExternCrate::Import(import)) => {
- ImportOrDef::Import(import)
- }
- Some(ImportOrExternCrate::ExternCrate(import)) => {
- ImportOrDef::ExternCrate(import)
- }
- None => ImportOrDef::Def(fld.def),
- },
- );
+ self.use_imports_types
+ .insert(import, prev.map_or(ImportOrDef::Def(fld.def), Into::into));
}
entry.insert(fld);
changed = true;
}
Entry::Occupied(mut entry) => {
match import {
- Some(ImportType::Glob(..)) => {
+ Some(ImportOrExternCrate::Glob(..)) => {
// Multiple globs may import the same item and they may
// override visibility from previously resolved globs. This is
// currently handled by `DefCollector`, because we need to
@@ -552,28 +606,11 @@ impl ItemScope {
}
_ => {
if glob_imports.types.remove(&lookup) {
- let import = match import {
- Some(ImportType::ExternCrate(extern_crate)) => {
- Some(ImportOrExternCrate::ExternCrate(extern_crate))
- }
- Some(ImportType::Import(import)) => {
- Some(ImportOrExternCrate::Import(import))
- }
- None | Some(ImportType::Glob(_)) => None,
- };
let prev = std::mem::replace(&mut fld.import, import);
if let Some(import) = import {
self.use_imports_types.insert(
import,
- match prev {
- Some(ImportOrExternCrate::Import(import)) => {
- ImportOrDef::Import(import)
- }
- Some(ImportOrExternCrate::ExternCrate(import)) => {
- ImportOrDef::ExternCrate(import)
- }
- None => ImportOrDef::Def(fld.def),
- },
+ prev.map_or(ImportOrDef::Def(fld.def), Into::into),
);
}
cov_mark::hit!(import_shadowed);
@@ -591,44 +628,31 @@ impl ItemScope {
match existing {
Entry::Vacant(entry) => {
match import {
- Some(ImportType::Glob(_)) => {
+ Some(ImportOrExternCrate::Glob(_)) => {
glob_imports.values.insert(lookup.clone());
}
_ => _ = glob_imports.values.remove(&lookup),
}
- let import = match import {
- Some(ImportType::Import(import)) => Some(import),
- _ => None,
- };
+ let import = import.and_then(ImportOrExternCrate::import_or_glob);
let prev = std::mem::replace(&mut fld.import, import);
if let Some(import) = import {
- self.use_imports_values.insert(
- import,
- match prev {
- Some(import) => ImportOrDef::Import(import),
- None => ImportOrDef::Def(fld.def),
- },
- );
+ self.use_imports_values
+ .insert(import, prev.map_or(ImportOrDef::Def(fld.def), Into::into));
}
entry.insert(fld);
changed = true;
}
- Entry::Occupied(mut entry) if !matches!(import, Some(ImportType::Glob(..))) => {
+ Entry::Occupied(mut entry)
+ if !matches!(import, Some(ImportOrExternCrate::Glob(..))) =>
+ {
if glob_imports.values.remove(&lookup) {
cov_mark::hit!(import_shadowed);
- let import = match import {
- Some(ImportType::Import(import)) => Some(import),
- _ => None,
- };
+
+ let import = import.and_then(ImportOrExternCrate::import_or_glob);
let prev = std::mem::replace(&mut fld.import, import);
if let Some(import) = import {
- self.use_imports_values.insert(
- import,
- match prev {
- Some(import) => ImportOrDef::Import(import),
- None => ImportOrDef::Def(fld.def),
- },
- );
+ self.use_imports_values
+ .insert(import, prev.map_or(ImportOrDef::Def(fld.def), Into::into));
}
entry.insert(fld);
changed = true;
@@ -643,43 +667,33 @@ impl ItemScope {
match existing {
Entry::Vacant(entry) => {
match import {
- Some(ImportType::Glob(_)) => {
+ Some(ImportOrExternCrate::Glob(_)) => {
glob_imports.macros.insert(lookup.clone());
}
_ => _ = glob_imports.macros.remove(&lookup),
}
- let import = match import {
- Some(ImportType::Import(import)) => Some(import),
- _ => None,
- };
+ let import = import.and_then(ImportOrExternCrate::import_or_glob);
let prev = std::mem::replace(&mut fld.import, import);
if let Some(import) = import {
self.use_imports_macros.insert(
import,
- match prev {
- Some(import) => ImportOrDef::Import(import),
- None => ImportOrDef::Def(fld.def.into()),
- },
+ prev.map_or_else(|| ImportOrDef::Def(fld.def.into()), Into::into),
);
}
entry.insert(fld);
changed = true;
}
- Entry::Occupied(mut entry) if !matches!(import, Some(ImportType::Glob(..))) => {
+ Entry::Occupied(mut entry)
+ if !matches!(import, Some(ImportOrExternCrate::Glob(..))) =>
+ {
if glob_imports.macros.remove(&lookup) {
cov_mark::hit!(import_shadowed);
- let import = match import {
- Some(ImportType::Import(import)) => Some(import),
- _ => None,
- };
+ let import = import.and_then(ImportOrExternCrate::import_or_glob);
let prev = std::mem::replace(&mut fld.import, import);
if let Some(import) = import {
self.use_imports_macros.insert(
import,
- match prev {
- Some(import) => ImportOrDef::Import(import),
- None => ImportOrDef::Def(fld.def.into()),
- },
+ prev.map_or_else(|| ImportOrDef::Def(fld.def.into()), Into::into),
);
}
entry.insert(fld);
@@ -704,16 +718,27 @@ impl ItemScope {
.map(|def| &mut def.vis)
.chain(self.values.values_mut().map(|def| &mut def.vis))
.chain(self.unnamed_trait_imports.values_mut().map(|def| &mut def.vis))
- .for_each(|vis| {
- *vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit)
+ .for_each(|vis| match vis {
+ &mut Visibility::Module(_, visibility_explicitness) => {
+ *vis = Visibility::Module(this_module, visibility_explicitness)
+ }
+ Visibility::Public => {
+ *vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit)
+ }
});
for mac in self.macros.values_mut() {
if matches!(mac.def, MacroId::ProcMacroId(_) if mac.import.is_none()) {
continue;
}
-
- mac.vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit);
+ match mac.vis {
+ Visibility::Module(_, visibility_explicitness) => {
+ mac.vis = Visibility::Module(this_module, visibility_explicitness)
+ }
+ Visibility::Public => {
+ mac.vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit)
+ }
+ }
}
}
@@ -732,20 +757,25 @@ impl ItemScope {
buf.push_str(" t");
match import {
Some(ImportOrExternCrate::Import(_)) => buf.push('i'),
+ Some(ImportOrExternCrate::Glob(_)) => buf.push('g'),
Some(ImportOrExternCrate::ExternCrate(_)) => buf.push('e'),
None => (),
}
}
if let Some(Item { import, .. }) = def.values {
buf.push_str(" v");
- if import.is_some() {
- buf.push('i');
+ match import {
+ Some(ImportOrGlob::Import(_)) => buf.push('i'),
+ Some(ImportOrGlob::Glob(_)) => buf.push('g'),
+ None => (),
}
}
if let Some(Item { import, .. }) = def.macros {
buf.push_str(" m");
- if import.is_some() {
- buf.push('i');
+ match import {
+ Some(ImportOrGlob::Import(_)) => buf.push('i'),
+ Some(ImportOrGlob::Glob(_)) => buf.push('g'),
+ None => (),
}
}
if def.is_none() {
@@ -828,7 +858,7 @@ impl PerNs {
match def {
ModuleDefId::ModuleId(_) => PerNs::types(def, v, import),
ModuleDefId::FunctionId(_) => {
- PerNs::values(def, v, import.and_then(ImportOrExternCrate::into_import))
+ PerNs::values(def, v, import.and_then(ImportOrExternCrate::import_or_glob))
}
ModuleDefId::AdtId(adt) => match adt {
AdtId::UnionId(_) => PerNs::types(def, v, import),
@@ -843,14 +873,14 @@ impl PerNs {
},
ModuleDefId::EnumVariantId(_) => PerNs::both(def, def, v, import),
ModuleDefId::ConstId(_) | ModuleDefId::StaticId(_) => {
- PerNs::values(def, v, import.and_then(ImportOrExternCrate::into_import))
+ PerNs::values(def, v, import.and_then(ImportOrExternCrate::import_or_glob))
}
ModuleDefId::TraitId(_) => PerNs::types(def, v, import),
ModuleDefId::TraitAliasId(_) => PerNs::types(def, v, import),
ModuleDefId::TypeAliasId(_) => PerNs::types(def, v, import),
ModuleDefId::BuiltinType(_) => PerNs::types(def, v, import),
ModuleDefId::MacroId(mac) => {
- PerNs::macros(mac, v, import.and_then(ImportOrExternCrate::into_import))
+ PerNs::macros(mac, v, import.and_then(ImportOrExternCrate::import_or_glob))
}
}
}
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 afdc49a2dc59a..e83ce6dc42cee 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
@@ -372,6 +372,7 @@ language_item_table! {
DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait, GenericRequirement::Exact(0);
DerefTarget, sym::deref_target, deref_target, Target::AssocTy, GenericRequirement::None;
Receiver, sym::receiver, receiver_trait, Target::Trait, GenericRequirement::None;
+ ReceiverTarget, sym::receiver_target, receiver_target, Target::AssocTy, GenericRequirement::None;
Fn, sym::fn_, fn_trait, Target::Trait, GenericRequirement::Exact(1);
FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1);
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 84c105a0a3467..c78818c642ceb 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -114,6 +114,9 @@ pub struct ImportPathConfig {
pub prefer_prelude: bool,
/// If true, prefer abs path (starting with `::`) where it is available.
pub prefer_absolute: bool,
+ /// If true, paths containing `#[unstable]` segments may be returned, but only if if there is no
+ /// stable path. This does not check, whether the item itself that is being imported is `#[unstable]`.
+ pub allow_unstable: bool,
}
#[derive(Debug)]
@@ -910,6 +913,7 @@ pub enum AssocItemId {
ConstId(ConstId),
TypeAliasId(TypeAliasId),
}
+
// FIXME: not every function, ... is actually an assoc item. maybe we should make
// sure that you can only turn actual assoc items into AssocItemIds. This would
// require not implementing From, and instead having some checked way of
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 1e4b42dff5fb7..06276335b7188 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
@@ -28,7 +28,7 @@ use triomphe::Arc;
use crate::{
attr::Attrs,
db::DefDatabase,
- item_scope::{ImportId, ImportOrExternCrate, ImportType, PerNsGlobImports},
+ item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports},
item_tree::{
self, AttrOwner, FieldsShape, FileItemTreeId, ImportKind, ItemTree, ItemTreeId,
ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, UseTreeKind,
@@ -208,7 +208,7 @@ struct DefCollector<'a> {
def_map: DefMap,
// The dependencies of the current crate, including optional deps like `test`.
deps: FxHashMap,
- glob_imports: FxHashMap>,
+ glob_imports: FxHashMap>,
unresolved_imports: Vec,
indeterminate_imports: Vec<(ImportDirective, PerNs)>,
unresolved_macros: Vec,
@@ -524,11 +524,7 @@ impl DefCollector<'_> {
match per_ns.types {
Some(Item { def: ModuleDefId::ModuleId(m), import, .. }) => {
- // FIXME: This should specifically look for a glob import somehow and record that here
- self.def_map.prelude = Some((
- m,
- import.and_then(ImportOrExternCrate::into_import).map(|it| it.import),
- ));
+ self.def_map.prelude = Some((m, import.and_then(ImportOrExternCrate::use_)));
}
types => {
tracing::debug!(
@@ -845,13 +841,14 @@ impl DefCollector<'_> {
def.values = None;
def.macros = None;
}
- let imp = ImportType::Import(ImportId { import: id, idx: use_tree });
+ let imp = ImportOrExternCrate::Import(ImportId { use_: id, idx: use_tree });
tracing::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
self.update(module_id, &[(name.cloned(), def)], vis, Some(imp));
}
- ImportSource { kind: ImportKind::Glob, id, is_prelude, .. } => {
+ ImportSource { kind: ImportKind::Glob, id, is_prelude, use_tree } => {
tracing::debug!("glob import: {:?}", import);
+ let glob = GlobId { use_: id, idx: use_tree };
match def.take_types() {
Some(ModuleDefId::ModuleId(m)) => {
if is_prelude {
@@ -875,7 +872,12 @@ impl DefCollector<'_> {
.filter(|(_, res)| !res.is_none())
.collect::>();
- self.update(module_id, &items, vis, Some(ImportType::Glob(id)));
+ self.update(
+ module_id,
+ &items,
+ vis,
+ Some(ImportOrExternCrate::Glob(glob)),
+ );
} else {
// glob import from same crate => we do an initial
// import, and then need to propagate any further
@@ -907,11 +909,16 @@ impl DefCollector<'_> {
.filter(|(_, res)| !res.is_none())
.collect::>();
- self.update(module_id, &items, vis, Some(ImportType::Glob(id)));
+ self.update(
+ module_id,
+ &items,
+ vis,
+ Some(ImportOrExternCrate::Glob(glob)),
+ );
// record the glob import in case we add further items
- let glob = self.glob_imports.entry(m.local_id).or_default();
- match glob.iter_mut().find(|(mid, _, _)| *mid == module_id) {
- None => glob.push((module_id, vis, id)),
+ let glob_imports = self.glob_imports.entry(m.local_id).or_default();
+ match glob_imports.iter_mut().find(|(mid, _, _)| *mid == module_id) {
+ None => glob_imports.push((module_id, vis, glob)),
Some((_, old_vis, _)) => {
if let Some(new_vis) = old_vis.max(vis, &self.def_map) {
*old_vis = new_vis;
@@ -944,7 +951,12 @@ impl DefCollector<'_> {
(Some(name), res)
})
.collect::>();
- self.update(module_id, &resolutions, vis, Some(ImportType::Glob(id)));
+ self.update(
+ module_id,
+ &resolutions,
+ vis,
+ Some(ImportOrExternCrate::Glob(glob)),
+ );
}
Some(d) => {
tracing::debug!("glob import {:?} from non-module/enum {:?}", import, d);
@@ -964,7 +976,7 @@ impl DefCollector<'_> {
resolutions: &[(Option, PerNs)],
// Visibility this import will have
vis: Visibility,
- import: Option,
+ import: Option,
) {
self.db.unwind_if_cancelled();
self.update_recursive(module_id, resolutions, vis, import, 0)
@@ -978,7 +990,7 @@ impl DefCollector<'_> {
// All resolutions are imported with this visibility; the visibilities in
// the `PerNs` values are ignored and overwritten
vis: Visibility,
- import: Option,
+ import: Option,
depth: usize,
) {
if GLOB_RECURSION_LIMIT.check(depth).is_err() {
@@ -994,8 +1006,10 @@ impl DefCollector<'_> {
self.push_res_and_update_glob_vis(module_id, name, *res, vis, import);
}
None => {
- let tr = match res.take_types() {
- Some(ModuleDefId::TraitId(tr)) => tr,
+ let (tr, import) = match res.take_types_full() {
+ Some(Item { def: ModuleDefId::TraitId(tr), vis: _, import }) => {
+ (tr, import)
+ }
Some(other) => {
tracing::debug!("non-trait `_` import of {:?}", other);
continue;
@@ -1021,7 +1035,11 @@ impl DefCollector<'_> {
if should_update {
changed = true;
- self.def_map.modules[module_id].scope.push_unnamed_trait(tr, vis);
+ self.def_map.modules[module_id].scope.push_unnamed_trait(
+ tr,
+ vis,
+ import.and_then(ImportOrExternCrate::import),
+ );
}
}
}
@@ -1043,13 +1061,13 @@ impl DefCollector<'_> {
.cloned()
.collect::>();
- for (glob_importing_module, glob_import_vis, use_) in glob_imports {
+ for (glob_importing_module, glob_import_vis, glob) in glob_imports {
let vis = glob_import_vis.min(vis, &self.def_map).unwrap_or(glob_import_vis);
self.update_recursive(
glob_importing_module,
resolutions,
vis,
- Some(ImportType::Glob(use_)),
+ Some(ImportOrExternCrate::Glob(glob)),
depth + 1,
);
}
@@ -1061,7 +1079,7 @@ impl DefCollector<'_> {
name: &Name,
mut defs: PerNs,
vis: Visibility,
- def_import_type: Option,
+ def_import_type: Option,
) -> bool {
// `extern crate crate_name` things can be re-exported as `pub use crate_name`.
// But they cannot be re-exported as `pub use self::crate_name`, `pub use crate::crate_name`
@@ -1074,10 +1092,10 @@ impl DefCollector<'_> {
let Some(ImportOrExternCrate::ExternCrate(_)) = def.import else {
return false;
};
- let Some(ImportType::Import(id)) = def_import_type else {
+ let Some(ImportOrExternCrate::Import(id)) = def_import_type else {
return false;
};
- let use_id = id.import.lookup(self.db).id;
+ let use_id = id.use_.lookup(self.db).id;
let item_tree = use_id.item_tree(self.db);
let use_kind = item_tree[use_id.value].use_tree.kind();
let UseTreeKind::Single { path, .. } = use_kind else {
@@ -1100,7 +1118,7 @@ impl DefCollector<'_> {
let mut changed = false;
- if let Some(ImportType::Glob(_)) = def_import_type {
+ if let Some(ImportOrExternCrate::Glob(_)) = def_import_type {
let prev_defs = self.def_map[module_id].scope.get(name);
// Multiple globs may import the same item and they may override visibility from
@@ -1727,7 +1745,7 @@ impl ModCollector<'_, '_> {
),
)],
vis,
- Some(ImportType::ExternCrate(id)),
+ Some(ImportOrExternCrate::ExternCrate(id)),
);
} else {
if let Some(name) = name {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs
index ab4ffbb2c1e4a..d7e4ca41cd5d5 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs
@@ -4,7 +4,6 @@ use base_db::AnchoredPath;
use hir_expand::{name::Name, HirFileIdExt};
use limit::Limit;
use span::EditionedFileId;
-use syntax::ToSmolStr as _;
use crate::{db::DefDatabase, HirFileId};
@@ -35,7 +34,7 @@ impl ModDir {
let path = match attr_path {
None => {
let mut path = self.dir_path.clone();
- path.push(&name.unescaped().display_no_db().to_smolstr());
+ path.push(name.as_str());
path
}
Some(attr_path) => {
@@ -66,7 +65,7 @@ impl ModDir {
name: &Name,
attr_path: Option<&str>,
) -> Result<(EditionedFileId, bool, ModDir), Box<[String]>> {
- let name = name.unescaped();
+ let name = name.as_str();
let mut candidate_files = ArrayVec::<_, 2>::new();
match attr_path {
@@ -74,16 +73,8 @@ impl ModDir {
candidate_files.push(self.dir_path.join_attr(attr_path, self.root_non_dir_owner))
}
None => {
- candidate_files.push(format!(
- "{}{}.rs",
- self.dir_path.0,
- name.display(db.upcast())
- ));
- candidate_files.push(format!(
- "{}{}/mod.rs",
- self.dir_path.0,
- name.display(db.upcast())
- ));
+ candidate_files.push(format!("{}{}.rs", self.dir_path.0, name));
+ candidate_files.push(format!("{}{}/mod.rs", self.dir_path.0, name));
}
};
@@ -97,7 +88,7 @@ impl ModDir {
let dir_path = if root_dir_owner {
DirPath::empty()
} else {
- DirPath::new(format!("{}/", name.display(db.upcast())))
+ DirPath::new(format!("{}/", name))
};
if let Some(mod_dir) = self.child(dir_path, !root_dir_owner) {
return Ok((
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 318aee04f7b7f..73fc6787bfe81 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
@@ -103,8 +103,8 @@ mod a {
c: t
crate::a::b::c
- A: v
- b: t
+ A: vg
+ b: tg
"#]],
);
}
@@ -256,8 +256,8 @@ pub enum Foo { Bar, Baz }
"#,
expect![[r#"
crate
- Bar: t v
- Baz: t v
+ Bar: tg vg
+ Baz: tg vg
"#]],
);
}
@@ -421,10 +421,10 @@ pub struct NotExported;
"#,
expect![[r#"
crate
- Exported: t v
- PublicItem: t v
- allowed_reexport: t
- exported: t
+ Exported: tg vg
+ PublicItem: tg vg
+ allowed_reexport: tg
+ exported: tg
not_allowed_reexport1: _
not_allowed_reexport2: _
"#]],
@@ -692,7 +692,7 @@ mod b {
b: t
crate::a
- T: t v
+ T: t vg
crate::b
T: v
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs
index 8963a5767942e..ddb9d4a134d33 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs
@@ -18,9 +18,9 @@ pub struct Baz;
"#,
expect![[r#"
crate
- Baz: t v
- Foo: t v
- bar: t
+ Baz: tg vg
+ Foo: tg vg
+ bar: tg
foo: t
crate::foo
@@ -53,20 +53,20 @@ pub use super::*;
"#,
expect![[r#"
crate
- Baz: t v
- Foo: t v
- bar: t
+ Baz: tg vg
+ Foo: tg vg
+ bar: tg
foo: t
crate::foo
- Baz: t v
+ Baz: tg vg
Foo: t v
bar: t
crate::foo::bar
Baz: t v
- Foo: t v
- bar: t
+ Foo: tg vg
+ bar: tg
"#]],
);
}
@@ -91,20 +91,20 @@ pub use super::*;
",
expect![[r#"
crate
- Baz: t v
- bar: t
+ Baz: tg vg
+ bar: tg
foo: t
crate::foo
- Baz: t v
+ Baz: tg vg
PrivateStructFoo: t v
bar: t
crate::foo::bar
Baz: t v
PrivateStructBar: t v
- PrivateStructFoo: t v
- bar: t
+ PrivateStructFoo: tg vg
+ bar: tg
"#]],
);
}
@@ -130,9 +130,9 @@ pub(crate) struct PubCrateStruct;
",
expect![[r#"
crate
- Foo: t
- PubCrateStruct: t v
- bar: t
+ Foo: tg
+ PubCrateStruct: tg vg
+ bar: tg
foo: t
crate::foo
@@ -160,7 +160,7 @@ pub struct Baz;
"#,
expect![[r#"
crate
- Baz: t v
+ Baz: tg vg
"#]],
);
}
@@ -178,7 +178,7 @@ struct Foo;
"#,
expect![[r#"
crate
- Baz: t v
+ Baz: tg vg
"#]],
);
}
@@ -193,8 +193,8 @@ use self::Foo::*;
"#,
expect![[r#"
crate
- Bar: t v
- Baz: t v
+ Bar: tg vg
+ Baz: tg vg
Foo: t
"#]],
);
@@ -210,8 +210,8 @@ use self::Foo::{*};
"#,
expect![[r#"
crate
- Bar: t v
- Baz: t v
+ Bar: tg vg
+ Baz: tg vg
Foo: t
"#]],
);
@@ -359,7 +359,7 @@ use event::Event;
event: t
crate::event
- Event: t v
+ Event: t vg
serenity: t
crate::event::serenity
@@ -388,10 +388,10 @@ use reexport::*;
"#,
expect![[r#"
crate
- Trait: t
+ Trait: tg
defs: t
- function: v
- makro: m
+ function: vg
+ makro: mg
reexport: t
crate::defs
@@ -400,10 +400,10 @@ use reexport::*;
makro: m
crate::reexport
- Trait: t
- function: v
+ Trait: tg
+ function: vg
inner: t
- makro: m
+ makro: mg
crate::reexport::inner
Trait: ti
@@ -442,12 +442,12 @@ mod glob_target {
ShouldBePrivate: t v
crate::outer
- ShouldBePrivate: t v
+ ShouldBePrivate: tg vg
inner_superglob: t
crate::outer::inner_superglob
- ShouldBePrivate: t v
- inner_superglob: t
+ ShouldBePrivate: tg vg
+ inner_superglob: tg
"#]],
);
}
@@ -473,20 +473,20 @@ use reexport_2::*;
"#,
expect![[r#"
crate
- Placeholder: t v
+ Placeholder: tg vg
libs: t
- reexport_1: t
+ reexport_1: tg
reexport_2: t
crate::libs
Placeholder: t v
crate::reexport_2
- Placeholder: t v
+ Placeholder: tg vg
reexport_1: t
crate::reexport_2::reexport_1
- Placeholder: t v
+ Placeholder: tg vg
"#]],
);
}
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 a05c4dcf9bd70..610886d55f40f 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
@@ -97,9 +97,9 @@ macro_rules! structs {
bar: t
crate::bar
- Bar: t
- Foo: t
- bar: t
+ Bar: tg
+ Foo: tg
+ bar: tg
"#]],
);
}
@@ -130,9 +130,9 @@ macro_rules! structs {
bar: t
crate::bar
- Bar: t
- Foo: t
- bar: t
+ Bar: tg
+ Foo: tg
+ bar: tg
"#]],
);
}
@@ -169,9 +169,9 @@ macro_rules! inner {
bar: t
crate::bar
- Bar: t
- Foo: t
- bar: t
+ Bar: tg
+ Foo: tg
+ bar: tg
"#]],
);
}
@@ -794,7 +794,7 @@ pub trait Clone {}
"#,
expect![[r#"
crate
- Clone: t m
+ Clone: tg mg
"#]],
);
}
@@ -1075,9 +1075,9 @@ macro_rules! mbe {
"#,
expect![[r#"
crate
- DummyTrait: m
- attribute_macro: m
- function_like_macro: m
+ DummyTrait: mg
+ attribute_macro: mg
+ function_like_macro: mg
"#]],
);
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs b/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs
index 899dd4afffef6..c2d3f67f17e77 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs
@@ -6,7 +6,7 @@
use bitflags::bitflags;
use crate::{
- item_scope::{ImportId, ImportOrExternCrate, ItemInNs},
+ item_scope::{ImportId, ImportOrExternCrate, ImportOrGlob, ItemInNs},
visibility::Visibility,
MacroId, ModuleDefId,
};
@@ -36,8 +36,8 @@ pub struct Item {
}
pub type TypesItem = Item;
-pub type ValuesItem = Item;
-pub type MacrosItem = Item;
+pub type ValuesItem = Item;
+pub type MacrosItem = Item;
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
pub struct PerNs {
@@ -59,7 +59,7 @@ impl PerNs {
PerNs { types: None, values: None, macros: None }
}
- pub fn values(def: ModuleDefId, vis: Visibility, import: Option) -> PerNs {
+ pub fn values(def: ModuleDefId, vis: Visibility, import: Option) -> PerNs {
PerNs { types: None, values: Some(Item { def, vis, import }), macros: None }
}
@@ -78,13 +78,13 @@ impl PerNs {
values: Some(Item {
def: values,
vis,
- import: import.and_then(ImportOrExternCrate::into_import),
+ import: import.and_then(ImportOrExternCrate::import_or_glob),
}),
macros: None,
}
}
- pub fn macros(def: MacroId, vis: Visibility, import: Option) -> PerNs {
+ pub fn macros(def: MacroId, vis: Visibility, import: Option) -> PerNs {
PerNs { types: None, values: None, macros: Some(Item { def, vis, import }) }
}
@@ -108,7 +108,7 @@ impl PerNs {
self.values.map(|it| it.def)
}
- pub fn take_values_import(self) -> Option<(ModuleDefId, Option)> {
+ pub fn take_values_import(self) -> Option<(ModuleDefId, Option)> {
self.values.map(|it| (it.def, it.import))
}
@@ -116,7 +116,7 @@ impl PerNs {
self.macros.map(|it| it.def)
}
- pub fn take_macros_import(self) -> Option<(MacroId, Option)> {
+ pub fn take_macros_import(self) -> Option<(MacroId, Option)> {
self.macros.map(|it| (it.def, it.import))
}
@@ -159,14 +159,12 @@ impl PerNs {
.map(|it| (ItemInNs::Types(it.def), it.import))
.into_iter()
.chain(
- self.values.map(|it| {
- (ItemInNs::Values(it.def), it.import.map(ImportOrExternCrate::Import))
- }),
+ self.values
+ .map(|it| (ItemInNs::Values(it.def), it.import.map(ImportOrExternCrate::from))),
)
.chain(
- self.macros.map(|it| {
- (ItemInNs::Macros(it.def), it.import.map(ImportOrExternCrate::Import))
- }),
+ self.macros
+ .map(|it| (ItemInNs::Macros(it.def), it.import.map(ImportOrExternCrate::from))),
)
}
}
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 0b9b6da8d5133..8c556d8a8c3f4 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -19,7 +19,7 @@ use crate::{
db::DefDatabase,
generics::{GenericParams, TypeOrConstParamData},
hir::{BindingId, ExprId, LabelId},
- item_scope::{BuiltinShadowMode, ImportId, ImportOrExternCrate, BUILTIN_SCOPE},
+ item_scope::{BuiltinShadowMode, ImportOrExternCrate, ImportOrGlob, BUILTIN_SCOPE},
lang_item::LangItemTarget,
nameres::{DefMap, MacroSubNs, ResolvePathResultPrefixInfo},
path::{ModPath, Path, PathKind},
@@ -107,7 +107,7 @@ pub enum TypeNs {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ResolveValueResult {
- ValueNs(ValueNs, Option),
+ ValueNs(ValueNs, Option),
Partial(TypeNs, usize, Option),
}
@@ -485,7 +485,7 @@ impl Resolver {
db: &dyn DefDatabase,
path: &ModPath,
expected_macro_kind: Option,
- ) -> Option<(MacroId, Option)> {
+ ) -> Option<(MacroId, Option)> {
let (item_map, module) = self.item_scope();
item_map
.resolve_path(db, module, path, BuiltinShadowMode::Other, expected_macro_kind)
@@ -1014,7 +1014,7 @@ impl ModuleItemMap {
}
}
-fn to_value_ns(per_ns: PerNs) -> Option<(ValueNs, Option)> {
+fn to_value_ns(per_ns: PerNs) -> Option<(ValueNs, Option)> {
let (def, import) = per_ns.take_values_import()?;
let res = match def {
ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it),
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
index 89eae862bd96c..f0cf7ebf479f8 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
@@ -23,15 +23,6 @@ pub struct ModPath {
segments: SmallVec<[Name; 1]>,
}
-#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct UnescapedModPath<'a>(&'a ModPath);
-
-impl<'a> UnescapedModPath<'a> {
- pub fn display(&'a self, db: &'a dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a {
- UnescapedDisplay { db, path: self }
- }
-}
-
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum PathKind {
Plain,
@@ -135,9 +126,11 @@ impl ModPath {
_ => None,
}
}
-
- pub fn unescaped(&self) -> UnescapedModPath<'_> {
- UnescapedModPath(self)
+ pub fn display_verbatim<'a>(
+ &'a self,
+ db: &'a dyn crate::db::ExpandDatabase,
+ ) -> impl fmt::Display + 'a {
+ Display { db, path: self, edition: None }
}
pub fn display<'a>(
@@ -145,7 +138,7 @@ impl ModPath {
db: &'a dyn crate::db::ExpandDatabase,
edition: Edition,
) -> impl fmt::Display + 'a {
- Display { db, path: self, edition }
+ Display { db, path: self, edition: Some(edition) }
}
}
@@ -158,23 +151,12 @@ impl Extend for ModPath {
struct Display<'a> {
db: &'a dyn ExpandDatabase,
path: &'a ModPath,
- edition: Edition,
+ edition: Option,
}
impl fmt::Display for Display<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- display_fmt_path(self.db, self.path, f, Escape::IfNeeded(self.edition))
- }
-}
-
-struct UnescapedDisplay<'a> {
- db: &'a dyn ExpandDatabase,
- path: &'a UnescapedModPath<'a>,
-}
-
-impl fmt::Display for UnescapedDisplay<'_> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- display_fmt_path(self.db, self.path.0, f, Escape::No)
+ display_fmt_path(self.db, self.path, f, self.edition)
}
}
@@ -184,16 +166,11 @@ impl From for ModPath {
}
}
-enum Escape {
- No,
- IfNeeded(Edition),
-}
-
fn display_fmt_path(
db: &dyn ExpandDatabase,
path: &ModPath,
f: &mut fmt::Formatter<'_>,
- escaped: Escape,
+ edition: Option,
) -> fmt::Result {
let mut first_segment = true;
let mut add_segment = |s| -> fmt::Result {
@@ -221,10 +198,10 @@ fn display_fmt_path(
f.write_str("::")?;
}
first_segment = false;
- match escaped {
- Escape::IfNeeded(edition) => segment.display(db, edition).fmt(f)?,
- Escape::No => segment.unescaped().display(db).fmt(f)?,
- }
+ match edition {
+ Some(edition) => segment.display(db, edition).fmt(f)?,
+ None => fmt::Display::fmt(segment.as_str(), f)?,
+ };
}
Ok(())
}
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
index cc53d2e34aacb..848870c3a3844 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
@@ -4,8 +4,8 @@ use std::fmt;
use intern::{sym, Symbol};
use span::{Edition, SyntaxContextId};
-use syntax::ast;
use syntax::utils::is_raw_identifier;
+use syntax::{ast, format_smolstr};
/// `Name` is a wrapper around string, which is used in hir for both references
/// and declarations. In theory, names should also carry hygiene info, but we are
@@ -51,33 +51,26 @@ impl PartialEq for Name {
}
}
+impl PartialEq<&Symbol> for Name {
+ fn eq(&self, &sym: &&Symbol) -> bool {
+ self.symbol == *sym
+ }
+}
+
impl PartialEq for Symbol {
fn eq(&self, name: &Name) -> bool {
*self == name.symbol
}
}
-/// Wrapper of `Name` to print the name without "r#" even when it is a raw identifier.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct UnescapedName<'a>(&'a Name);
-
-impl<'a> UnescapedName<'a> {
- pub fn display(self, db: &dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a {
- _ = db;
- UnescapedDisplay { name: self }
- }
- #[doc(hidden)]
- pub fn display_no_db(self) -> impl fmt::Display + 'a {
- UnescapedDisplay { name: self }
+impl PartialEq for &Symbol {
+ fn eq(&self, name: &Name) -> bool {
+ **self == name.symbol
}
}
impl Name {
- /// Note: this is private to make creating name from random string hard.
- /// Hopefully, this should allow us to integrate hygiene cleaner in the
- /// future, and to switch to interned representation of names.
fn new_text(text: &str) -> Name {
- debug_assert!(!text.starts_with("r#"));
Name { symbol: Symbol::intern(text), ctx: () }
}
@@ -87,12 +80,15 @@ impl Name {
// Can't do that for all `SyntaxContextId`s because it breaks Salsa.
ctx.remove_root_edition();
_ = ctx;
- Self::new_text(text)
+ match text.strip_prefix("r#") {
+ Some(text) => Self::new_text(text),
+ None => Self::new_text(text),
+ }
}
pub fn new_root(text: &str) -> Name {
// The edition doesn't matter for hygiene.
- Self::new(text.trim_start_matches("r#"), SyntaxContextId::root(Edition::Edition2015))
+ Self::new(text, SyntaxContextId::root(Edition::Edition2015))
}
pub fn new_tuple_field(idx: usize) -> Name {
@@ -119,12 +115,22 @@ impl Name {
}
pub fn new_lifetime(lt: &ast::Lifetime) -> Name {
- Self::new_text(lt.text().as_str().trim_start_matches("r#"))
+ let text = lt.text();
+ match text.strip_prefix("'r#") {
+ Some(text) => Self::new_text(&format_smolstr!("'{text}")),
+ None => Self::new_text(text.as_str()),
+ }
+ }
+
+ pub fn new_symbol(symbol: Symbol, ctx: SyntaxContextId) -> Self {
+ debug_assert!(!symbol.as_str().starts_with("r#"));
+ _ = ctx;
+ Self { symbol, ctx: () }
}
- /// Resolve a name from the text of token.
- fn resolve(raw_text: &str) -> Name {
- Name::new_text(raw_text.trim_start_matches("r#"))
+ // FIXME: This needs to go once we have hygiene
+ pub fn new_symbol_root(sym: Symbol) -> Self {
+ Self::new_symbol(sym, SyntaxContextId::root(Edition::Edition2015))
}
/// A fake name for things missing in the source code.
@@ -161,22 +167,19 @@ impl Name {
self.symbol.as_str().parse().ok()
}
+ /// Whether this name needs to be escaped in the given edition via `r#`.
+ pub fn needs_escape(&self, edition: Edition) -> bool {
+ is_raw_identifier(self.symbol.as_str(), edition)
+ }
+
/// Returns the text this name represents if it isn't a tuple field.
///
/// Do not use this for user-facing text, use `display` instead to handle editions properly.
+ // FIXME: This should take a database argument to hide the interning
pub fn as_str(&self) -> &str {
self.symbol.as_str()
}
- // FIXME: Remove this
- pub fn unescaped(&self) -> UnescapedName<'_> {
- UnescapedName(self)
- }
-
- pub fn needs_escape(&self, edition: Edition) -> bool {
- is_raw_identifier(self.symbol.as_str(), edition)
- }
-
pub fn display<'a>(
&'a self,
db: &dyn crate::db::ExpandDatabase,
@@ -186,7 +189,7 @@ impl Name {
self.display_no_db(edition)
}
- // FIXME: Remove this
+ // FIXME: Remove this in favor of `display`, see fixme on `as_str`
#[doc(hidden)]
pub fn display_no_db(&self, edition: Edition) -> impl fmt::Display + '_ {
Display { name: self, needs_escaping: is_raw_identifier(self.symbol.as_str(), edition) }
@@ -195,24 +198,6 @@ impl Name {
pub fn symbol(&self) -> &Symbol {
&self.symbol
}
-
- pub fn new_symbol(symbol: Symbol, ctx: SyntaxContextId) -> Self {
- debug_assert!(!symbol.as_str().starts_with("r#"));
- _ = ctx;
- Self { symbol, ctx: () }
- }
-
- // FIXME: This needs to go once we have hygiene
- pub fn new_symbol_root(sym: Symbol) -> Self {
- debug_assert!(!sym.as_str().starts_with("r#"));
- Self { symbol: sym, ctx: () }
- }
-
- // FIXME: Remove this
- #[inline]
- pub fn eq_ident(&self, ident: &str) -> bool {
- self.as_str() == ident.trim_start_matches("r#")
- }
}
struct Display<'a> {
@@ -229,17 +214,6 @@ impl fmt::Display for Display<'_> {
}
}
-struct UnescapedDisplay<'a> {
- name: UnescapedName<'a>,
-}
-
-impl fmt::Display for UnescapedDisplay<'_> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let symbol = self.name.0.symbol.as_str();
- fmt::Display::fmt(symbol, f)
- }
-}
-
pub trait AsName {
fn as_name(&self) -> Name;
}
@@ -248,14 +222,14 @@ impl AsName for ast::NameRef {
fn as_name(&self) -> Name {
match self.as_tuple_field() {
Some(idx) => Name::new_tuple_field(idx),
- None => Name::resolve(&self.text()),
+ None => Name::new_root(&self.text()),
}
}
}
impl AsName for ast::Name {
fn as_name(&self) -> Name {
- Name::resolve(&self.text())
+ Name::new_root(&self.text())
}
}
@@ -270,7 +244,7 @@ impl AsName for ast::NameOrNameRef {
impl AsName for tt::Ident {
fn as_name(&self) -> Name {
- Name::resolve(self.sym.as_str())
+ Name::new_root(self.sym.as_str())
}
}
@@ -288,6 +262,6 @@ impl AsName for ast::FieldKind {
impl AsName for base_db::Dependency {
fn as_name(&self) -> Name {
- Name::new_text(&self.name)
+ Name::new_root(&self.name)
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
index 2b5342314a65a..62feca5f8cbbf 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
@@ -17,7 +17,7 @@ use crate::{
TraitEnvironment, Ty, TyBuilder, TyKind,
};
-static AUTODEREF_RECURSION_LIMIT: Limit = Limit::new(10);
+static AUTODEREF_RECURSION_LIMIT: Limit = Limit::new(20);
#[derive(Debug)]
pub(crate) enum AutoderefKind {
@@ -39,7 +39,7 @@ pub fn autoderef(
) -> impl Iterator
- {
let mut table = InferenceTable::new(db, env);
let ty = table.instantiate_canonical(ty);
- let mut autoderef = Autoderef::new_no_tracking(&mut table, ty, false);
+ let mut autoderef = Autoderef::new_no_tracking(&mut table, ty, false, false);
let mut v = Vec::new();
while let Some((ty, _steps)) = autoderef.next() {
// `ty` may contain unresolved inference variables. Since there's no chance they would be
@@ -49,7 +49,7 @@ pub fn autoderef(
// If the deref chain contains a cycle (e.g. `A` derefs to `B` and `B` derefs to `A`), we
// would revisit some already visited types. Stop here to avoid duplication.
//
- // XXX: The recursion limit for `Autoderef` is currently 10, so `Vec::contains()` shouldn't
+ // XXX: The recursion limit for `Autoderef` is currently 20, so `Vec::contains()` shouldn't
// be too expensive. Replace this duplicate check with `FxHashSet` if it proves to be more
// performant.
if v.contains(&resolved) {
@@ -89,12 +89,18 @@ pub(crate) struct Autoderef<'table, 'db, T = Vec<(AutoderefKind, Ty)>> {
at_start: bool,
steps: T,
explicit: bool,
+ use_receiver_trait: bool,
}
impl<'table, 'db> Autoderef<'table, 'db> {
- pub(crate) fn new(table: &'table mut InferenceTable<'db>, ty: Ty, explicit: bool) -> Self {
+ pub(crate) fn new(
+ table: &'table mut InferenceTable<'db>,
+ ty: Ty,
+ explicit: bool,
+ use_receiver_trait: bool,
+ ) -> Self {
let ty = table.resolve_ty_shallow(&ty);
- Autoderef { table, ty, at_start: true, steps: Vec::new(), explicit }
+ Autoderef { table, ty, at_start: true, steps: Vec::new(), explicit, use_receiver_trait }
}
pub(crate) fn steps(&self) -> &[(AutoderefKind, Ty)] {
@@ -107,9 +113,10 @@ impl<'table, 'db> Autoderef<'table, 'db, usize> {
table: &'table mut InferenceTable<'db>,
ty: Ty,
explicit: bool,
+ use_receiver_trait: bool,
) -> Self {
let ty = table.resolve_ty_shallow(&ty);
- Autoderef { table, ty, at_start: true, steps: 0, explicit }
+ Autoderef { table, ty, at_start: true, steps: 0, explicit, use_receiver_trait }
}
}
@@ -137,7 +144,8 @@ impl Iterator for Autoderef<'_, '_, T> {
return None;
}
- let (kind, new_ty) = autoderef_step(self.table, self.ty.clone(), self.explicit)?;
+ let (kind, new_ty) =
+ autoderef_step(self.table, self.ty.clone(), self.explicit, self.use_receiver_trait)?;
self.steps.push(kind, &self.ty);
self.ty = new_ty;
@@ -150,11 +158,12 @@ pub(crate) fn autoderef_step(
table: &mut InferenceTable<'_>,
ty: Ty,
explicit: bool,
+ use_receiver_trait: bool,
) -> Option<(AutoderefKind, Ty)> {
if let Some(derefed) = builtin_deref(table.db, &ty, explicit) {
Some((AutoderefKind::Builtin, table.resolve_ty_shallow(derefed)))
} else {
- Some((AutoderefKind::Overloaded, deref_by_trait(table, ty)?))
+ Some((AutoderefKind::Overloaded, deref_by_trait(table, ty, use_receiver_trait)?))
}
}
@@ -176,6 +185,7 @@ pub(crate) fn builtin_deref<'ty>(
pub(crate) fn deref_by_trait(
table @ &mut InferenceTable { db, .. }: &mut InferenceTable<'_>,
ty: Ty,
+ use_receiver_trait: bool,
) -> Option {
let _p = tracing::info_span!("deref_by_trait").entered();
if table.resolve_ty_shallow(&ty).inference_var(Interner).is_some() {
@@ -183,14 +193,25 @@ pub(crate) fn deref_by_trait(
return None;
}
- let deref_trait =
- db.lang_item(table.trait_env.krate, LangItem::Deref).and_then(|l| l.as_trait())?;
+ let trait_id = || {
+ if use_receiver_trait {
+ if let Some(receiver) =
+ db.lang_item(table.trait_env.krate, LangItem::Receiver).and_then(|l| l.as_trait())
+ {
+ return Some(receiver);
+ }
+ }
+ // Old rustc versions might not have `Receiver` trait.
+ // Fallback to `Deref` if they don't
+ db.lang_item(table.trait_env.krate, LangItem::Deref).and_then(|l| l.as_trait())
+ };
+ let trait_id = trait_id()?;
let target = db
- .trait_data(deref_trait)
+ .trait_data(trait_id)
.associated_type_by_name(&Name::new_symbol_root(sym::Target.clone()))?;
let projection = {
- let b = TyBuilder::subst_for_def(db, deref_trait, None);
+ let b = TyBuilder::subst_for_def(db, trait_id, None);
if b.remaining() != 1 {
// the Target type + Deref trait should only have one generic parameter,
// namely Deref's Self type
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
index 4991d173b9c42..774991560e9ca 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
@@ -231,8 +231,7 @@ impl<'a> DeclValidator<'a> {
.filter_map(|(pat_id, pat)| match pat {
Pat::Bind { id, .. } => {
let bind_name = &body.bindings[*id].name;
- let mut suggested_text =
- to_lower_snake_case(&bind_name.unescaped().display_no_db().to_smolstr())?;
+ let mut suggested_text = to_lower_snake_case(bind_name.as_str())?;
if is_raw_identifier(&suggested_text, edition) {
suggested_text.insert_str(0, "r#");
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
index 3545bf7677671..ae8fbe2ce6d76 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -34,6 +34,7 @@ use rustc_apfloat::{
ieee::{Half as f16, Quad as f128},
Float,
};
+use rustc_hash::FxHashSet;
use smallvec::SmallVec;
use span::Edition;
use stdx::never;
@@ -87,6 +88,35 @@ pub struct HirFormatter<'a> {
omit_verbose_types: bool,
closure_style: ClosureStyle,
display_target: DisplayTarget,
+ bounds_formatting_ctx: BoundsFormattingCtx,
+}
+
+#[derive(Default)]
+enum BoundsFormattingCtx {
+ Entered {
+ /// We can have recursive bounds like the following case:
+ /// ```rust
+ /// where
+ /// T: Foo,
+ /// T::FooAssoc: Baz<::BarAssoc> + Bar
+ /// ```
+ /// So, record the projection types met while formatting bounds and
+ //. prevent recursing into their bounds to avoid infinite loops.
+ projection_tys_met: FxHashSet,
+ },
+ #[default]
+ Exited,
+}
+
+impl BoundsFormattingCtx {
+ fn contains(&mut self, proj: &ProjectionTy) -> bool {
+ match self {
+ BoundsFormattingCtx::Entered { projection_tys_met } => {
+ projection_tys_met.contains(proj)
+ }
+ BoundsFormattingCtx::Exited => false,
+ }
+ }
}
impl HirFormatter<'_> {
@@ -97,6 +127,30 @@ impl HirFormatter<'_> {
fn end_location_link(&mut self) {
self.fmt.end_location_link();
}
+
+ fn format_bounds_with T>(
+ &mut self,
+ target: ProjectionTy,
+ format_bounds: F,
+ ) -> T {
+ match self.bounds_formatting_ctx {
+ BoundsFormattingCtx::Entered { ref mut projection_tys_met } => {
+ projection_tys_met.insert(target);
+ format_bounds(self)
+ }
+ BoundsFormattingCtx::Exited => {
+ let mut projection_tys_met = FxHashSet::default();
+ projection_tys_met.insert(target);
+ self.bounds_formatting_ctx = BoundsFormattingCtx::Entered { projection_tys_met };
+ let res = format_bounds(self);
+ // Since we want to prevent only the infinite recursions in bounds formatting
+ // and do not want to skip formatting of other separate bounds, clear context
+ // when exiting the formatting of outermost bounds
+ self.bounds_formatting_ctx = BoundsFormattingCtx::Exited;
+ res
+ }
+ }
+ }
}
pub trait HirDisplay {
@@ -220,6 +274,7 @@ pub trait HirDisplay {
closure_style: ClosureStyle::ImplFn,
display_target: DisplayTarget::SourceCode { module_id, allow_opaque },
show_container_bounds: false,
+ bounds_formatting_ctx: Default::default(),
}) {
Ok(()) => {}
Err(HirDisplayError::FmtError) => panic!("Writing to String can't fail!"),
@@ -427,6 +482,7 @@ impl HirDisplayWrapper<'_, T> {
display_target: self.display_target,
closure_style: self.closure_style,
show_container_bounds: self.show_container_bounds,
+ bounds_formatting_ctx: Default::default(),
})
}
@@ -479,42 +535,46 @@ impl HirDisplay for ProjectionTy {
// `::Assoc`
if !f.display_target.is_source_code() {
if let TyKind::Placeholder(idx) = self_ty.kind(Interner) {
- let db = f.db;
- let id = from_placeholder_idx(db, *idx);
- let generics = generics(db.upcast(), id.parent);
-
- let substs = generics.placeholder_subst(db);
- let bounds = db
- .generic_predicates(id.parent)
- .iter()
- .map(|pred| pred.clone().substitute(Interner, &substs))
- .filter(|wc| match wc.skip_binders() {
- WhereClause::Implemented(tr) => {
- match tr.self_type_parameter(Interner).kind(Interner) {
- TyKind::Alias(AliasTy::Projection(proj)) => proj == self,
- _ => false,
+ if !f.bounds_formatting_ctx.contains(self) {
+ let db = f.db;
+ let id = from_placeholder_idx(db, *idx);
+ let generics = generics(db.upcast(), id.parent);
+
+ let substs = generics.placeholder_subst(db);
+ let bounds = db
+ .generic_predicates(id.parent)
+ .iter()
+ .map(|pred| pred.clone().substitute(Interner, &substs))
+ .filter(|wc| match wc.skip_binders() {
+ WhereClause::Implemented(tr) => {
+ matches!(
+ tr.self_type_parameter(Interner).kind(Interner),
+ TyKind::Alias(_)
+ )
}
- }
- WhereClause::TypeOutlives(t) => match t.ty.kind(Interner) {
- TyKind::Alias(AliasTy::Projection(proj)) => proj == self,
- _ => false,
- },
- // We shouldn't be here if these exist
- WhereClause::AliasEq(_) => false,
- WhereClause::LifetimeOutlives(_) => false,
- })
- .collect::>();
- if !bounds.is_empty() {
- return write_bounds_like_dyn_trait_with_prefix(
- f,
- "impl",
- Either::Left(
- &TyKind::Alias(AliasTy::Projection(self.clone())).intern(Interner),
- ),
- &bounds,
- SizedByDefault::NotSized,
- );
- };
+ WhereClause::TypeOutlives(t) => {
+ matches!(t.ty.kind(Interner), TyKind::Alias(_))
+ }
+ // We shouldn't be here if these exist
+ WhereClause::AliasEq(_) => false,
+ WhereClause::LifetimeOutlives(_) => false,
+ })
+ .collect::>();
+ if !bounds.is_empty() {
+ return f.format_bounds_with(self.clone(), |f| {
+ write_bounds_like_dyn_trait_with_prefix(
+ f,
+ "impl",
+ Either::Left(
+ &TyKind::Alias(AliasTy::Projection(self.clone()))
+ .intern(Interner),
+ ),
+ &bounds,
+ SizedByDefault::NotSized,
+ )
+ });
+ }
+ }
}
}
@@ -1159,6 +1219,7 @@ impl HirDisplay for Ty {
prefer_no_std: false,
prefer_prelude: true,
prefer_absolute: false,
+ allow_unstable: true,
},
) {
write!(f, "{}", path.display(f.db.upcast(), f.edition()))?;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
index 2523aba538334..9283c46d0f611 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
@@ -277,7 +277,7 @@ impl CapturedItem {
/// Converts the place to a name that can be inserted into source code.
pub fn place_to_name(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> String {
let body = db.body(owner);
- let mut result = body[self.place.local].name.unescaped().display(db.upcast()).to_string();
+ let mut result = body[self.place.local].name.as_str().to_owned();
for proj in &self.place.projections {
match proj {
ProjectionElem::Deref => {}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
index 2fe90a8a92432..d40816ba8ced2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
@@ -420,7 +420,7 @@ impl InferenceTable<'_> {
let snapshot = self.snapshot();
- let mut autoderef = Autoderef::new(self, from_ty.clone(), false);
+ let mut autoderef = Autoderef::new(self, from_ty.clone(), false, false);
let mut first_error = None;
let mut found = None;
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 6b6c0348dcb4f..b951443897cb0 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
@@ -487,7 +487,7 @@ impl InferenceContext<'_> {
}
Expr::Call { callee, args, .. } => {
let callee_ty = self.infer_expr(*callee, &Expectation::none(), ExprIsRead::Yes);
- let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone(), false);
+ let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone(), false, true);
let (res, derefed_callee) = loop {
let Some((callee_deref_ty, _)) = derefs.next() else {
break (None, callee_ty.clone());
@@ -854,7 +854,7 @@ impl InferenceContext<'_> {
if let Some(derefed) = builtin_deref(self.table.db, &inner_ty, true) {
self.resolve_ty_shallow(derefed)
} else {
- deref_by_trait(&mut self.table, inner_ty)
+ deref_by_trait(&mut self.table, inner_ty, false)
.unwrap_or_else(|| self.err_ty())
}
}
@@ -1718,7 +1718,7 @@ impl InferenceContext<'_> {
receiver_ty: &Ty,
name: &Name,
) -> Option<(Ty, Either, Vec, bool)> {
- let mut autoderef = Autoderef::new(&mut self.table, receiver_ty.clone(), false);
+ let mut autoderef = Autoderef::new(&mut self.table, receiver_ty.clone(), false, false);
let mut private_field = None;
let res = autoderef.by_ref().find_map(|(derefed_ty, _)| {
let (field_id, parameters) = match derefed_ty.kind(Interner) {
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 182032f04812d..1cea67ee96419 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
@@ -528,7 +528,7 @@ impl ReceiverAdjustments {
let mut ty = table.resolve_ty_shallow(&ty);
let mut adjust = Vec::new();
for _ in 0..self.autoderefs {
- match autoderef::autoderef_step(table, ty.clone(), true) {
+ match autoderef::autoderef_step(table, ty.clone(), true, false) {
None => {
never!("autoderef not possible for {:?}", ty);
ty = TyKind::Error.intern(Interner);
@@ -1106,7 +1106,8 @@ fn iterate_method_candidates_by_receiver(
// be found in any of the derefs of receiver_ty, so we have to go through
// that, including raw derefs.
table.run_in_snapshot(|table| {
- let mut autoderef = autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true);
+ let mut autoderef =
+ autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true, true);
while let Some((self_ty, _)) = autoderef.next() {
iterate_inherent_methods(
&self_ty,
@@ -1123,7 +1124,8 @@ fn iterate_method_candidates_by_receiver(
ControlFlow::Continue(())
})?;
table.run_in_snapshot(|table| {
- let mut autoderef = autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true);
+ let mut autoderef =
+ autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true, true);
while let Some((self_ty, _)) = autoderef.next() {
if matches!(self_ty.kind(Interner), TyKind::InferenceVar(_, TyVariableKind::General)) {
// don't try to resolve methods on unknown types
@@ -1709,7 +1711,7 @@ fn autoderef_method_receiver(
ty: Ty,
) -> Vec<(Canonical, ReceiverAdjustments)> {
let mut deref_chain: Vec<_> = Vec::new();
- let mut autoderef = autoderef::Autoderef::new_no_tracking(table, ty, false);
+ let mut autoderef = autoderef::Autoderef::new_no_tracking(table, ty, false, true);
while let Some((ty, derefs)) = autoderef.next() {
deref_chain.push((
autoderef.table.canonicalize(ty),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
index 74acf23b75ab6..8866de22dfb99 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
@@ -1343,7 +1343,7 @@ fn foo(a: &T) {
fn autoderef_visibility_field() {
check(
r#"
-//- minicore: deref
+//- minicore: receiver
mod a {
pub struct Foo(pub char);
pub struct Bar(i32);
@@ -1375,7 +1375,7 @@ fn autoderef_visibility_method() {
cov_mark::check!(autoderef_candidate_not_visible);
check(
r#"
-//- minicore: deref
+//- minicore: receiver
mod a {
pub struct Foo(pub char);
impl Foo {
@@ -1741,7 +1741,7 @@ fn main() {
fn deref_fun_1() {
check_types(
r#"
-//- minicore: deref
+//- minicore: receiver
struct A(T, U);
struct B(T);
@@ -1782,7 +1782,7 @@ fn test() {
fn deref_fun_2() {
check_types(
r#"
-//- minicore: deref
+//- minicore: receiver
struct A(T, U);
struct B(T);
@@ -1903,7 +1903,7 @@ pub fn test(generic_args: impl Into) {
fn bad_inferred_reference_2() {
check_no_mismatches(
r#"
-//- minicore: deref
+//- minicore: receiver
trait ExactSizeIterator {
fn len(&self) -> usize;
}
@@ -2054,7 +2054,7 @@ fn foo() {
fn box_deref_is_builtin() {
check(
r#"
-//- minicore: deref
+//- minicore: receiver
use core::ops::Deref;
#[lang = "owned_box"]
@@ -2087,7 +2087,7 @@ fn test() {
fn manually_drop_deref_is_not_builtin() {
check(
r#"
-//- minicore: manually_drop, deref
+//- minicore: manually_drop, receiver
struct Foo;
impl Foo {
fn foo(&self) {}
@@ -2105,7 +2105,7 @@ fn test() {
fn mismatched_args_due_to_supertraits_with_deref() {
check_no_mismatches(
r#"
-//- minicore: deref
+//- minicore: receiver
use core::ops::Deref;
trait Trait1 {
@@ -2139,3 +2139,34 @@ fn problem_method() {
"#,
);
}
+
+#[test]
+fn receiver_without_deref_impl() {
+ check(
+ r#"
+//- minicore: receiver
+use core::ops::Receiver;
+
+struct Foo;
+
+impl Foo {
+ fn foo1(self: &Bar) -> i32 { 42 }
+ fn foo2(self: Bar) -> bool { true }
+}
+
+struct Bar;
+
+impl Receiver for Bar {
+ type Target = Foo;
+}
+
+fn main() {
+ let bar = Bar;
+ let _v1 = bar.foo1();
+ //^^^ type: i32
+ let _v2 = bar.foo2();
+ //^^^ type: bool
+}
+"#,
+ );
+}
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index db3121d3cd35f..0cbc75726bf39 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -45,7 +45,7 @@ use hir_def::{
body::BodyDiagnostic,
data::{adt::VariantData, TraitFlags},
generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance},
- hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, Pat},
+ hir::{BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, LabelId, Pat},
item_tree::{AttrOwner, FieldParent, ItemTreeFieldId, ItemTreeNode},
lang_item::LangItemTarget,
layout::{self, ReprOptions, TargetDataLayout},
@@ -2470,20 +2470,31 @@ impl Param {
}
pub fn as_local(&self, db: &dyn HirDatabase) -> Option {
- let parent = match self.func {
- Callee::Def(CallableDefId::FunctionId(it)) => DefWithBodyId::FunctionId(it),
- Callee::Closure(closure, _) => db.lookup_intern_closure(closure.into()).0,
- _ => return None,
- };
- let body = db.body(parent);
- if let Some(self_param) = body.self_param.filter(|_| self.idx == 0) {
- Some(Local { parent, binding_id: self_param })
- } else if let Pat::Bind { id, .. } =
- &body[body.params[self.idx - body.self_param.is_some() as usize]]
- {
- Some(Local { parent, binding_id: *id })
- } else {
- None
+ match self.func {
+ Callee::Def(CallableDefId::FunctionId(it)) => {
+ let parent = DefWithBodyId::FunctionId(it);
+ let body = db.body(parent);
+ if let Some(self_param) = body.self_param.filter(|_| self.idx == 0) {
+ Some(Local { parent, binding_id: self_param })
+ } else if let Pat::Bind { id, .. } =
+ &body[body.params[self.idx - body.self_param.is_some() as usize]]
+ {
+ Some(Local { parent, binding_id: *id })
+ } else {
+ None
+ }
+ }
+ Callee::Closure(closure, _) => {
+ let c = db.lookup_intern_closure(closure.into());
+ let body = db.body(c.0);
+ if let Expr::Closure { args, .. } = &body[c.1] {
+ if let Pat::Bind { id, .. } = &body[args[self.idx]] {
+ return Some(Local { parent: c.0, binding_id: *id });
+ }
+ }
+ None
+ }
+ _ => None,
}
}
@@ -2756,6 +2767,15 @@ impl Trait {
traits.iter().map(|tr| Trait::from(*tr)).collect()
}
+ pub fn function(self, db: &dyn HirDatabase, name: impl PartialEq) -> Option {
+ db.trait_data(self.id).items.iter().find(|(n, _)| name == *n).and_then(
+ |&(_, it)| match it {
+ AssocItemId::FunctionId(id) => Some(Function { id }),
+ _ => None,
+ },
+ )
+ }
+
pub fn items(self, db: &dyn HirDatabase) -> Vec {
db.trait_data(self.id).items.iter().map(|(_name, it)| (*it).into()).collect()
}
@@ -4673,6 +4693,10 @@ impl Type {
matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Bool))
}
+ pub fn is_str(&self) -> bool {
+ matches!(self.ty.kind(Interner), TyKind::Str)
+ }
+
pub fn is_never(&self) -> bool {
matches!(self.ty.kind(Interner), TyKind::Never)
}
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index 523bc6f10aab6..09470bed9cfb4 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -1439,8 +1439,20 @@ impl<'db> SemanticsImpl<'db> {
self.analyze(call.syntax())?.resolve_method_call_fallback(self.db, call)
}
- pub fn resolve_known_blanket_dual_impls(&self, call: &ast::MethodCallExpr) -> Option {
- self.analyze(call.syntax())?.resolve_known_blanket_dual_impls(self.db, call)
+ /// Env is used to derive the trait environment
+ // FIXME: better api for the trait environment
+ pub fn resolve_trait_impl_method(
+ &self,
+ env: Type,
+ trait_: Trait,
+ func: Function,
+ subst: impl IntoIterator
- ,
+ ) -> Option {
+ let mut substs = hir_ty::TyBuilder::subst_for_def(self.db, TraitId::from(trait_), None);
+ for s in subst {
+ substs = substs.push(s.ty);
+ }
+ Some(self.db.lookup_impl_method(env.env, func.into(), substs.build()).0.into())
}
fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option {
@@ -1471,6 +1483,8 @@ impl<'db> SemanticsImpl<'db> {
self.analyze(try_expr.syntax())?.resolve_try_expr(self.db, try_expr)
}
+ // This does not resolve the method call to the correct trait impl!
+ // We should probably fix that.
pub fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option {
self.analyze(call.syntax())?.resolve_method_call_as_callable(self.db, call)
}
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 6b78d7a3631fa..b699ccde4128e 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -322,68 +322,6 @@ impl SourceAnalyzer {
}
}
- // If the method is into(), try_into(), parse(), resolve it to from, try_from, from_str.
- pub(crate) fn resolve_known_blanket_dual_impls(
- &self,
- db: &dyn HirDatabase,
- call: &ast::MethodCallExpr,
- ) -> Option {
- // e.g. if the method call is let b = a.into(),
- // - receiver_type is A (type of a)
- // - return_type is B (type of b)
- // We will find the definition of B::from(a: A).
- let callable = self.resolve_method_call_as_callable(db, call)?;
- let (_, receiver_type) = callable.receiver_param(db)?;
- let return_type = callable.return_type();
- let (search_method, substs) = match call.name_ref()?.text().as_str() {
- "into" => {
- let trait_ =
- self.resolver.resolve_known_trait(db.upcast(), &path![core::convert::From])?;
- (
- self.trait_fn(db, trait_, "from")?,
- hir_ty::TyBuilder::subst_for_def(db, trait_, None)
- .push(return_type.ty)
- .push(receiver_type.ty)
- .build(),
- )
- }
- "try_into" => {
- let trait_ = self
- .resolver
- .resolve_known_trait(db.upcast(), &path![core::convert::TryFrom])?;
- (
- self.trait_fn(db, trait_, "try_from")?,
- hir_ty::TyBuilder::subst_for_def(db, trait_, None)
- // If the method is try_into() or parse(), return_type is Result.
- // Get T from type arguments of Result.
- .push(return_type.type_arguments().next()?.ty)
- .push(receiver_type.ty)
- .build(),
- )
- }
- "parse" => {
- let trait_ =
- self.resolver.resolve_known_trait(db.upcast(), &path![core::str::FromStr])?;
- (
- self.trait_fn(db, trait_, "from_str")?,
- hir_ty::TyBuilder::subst_for_def(db, trait_, None)
- .push(return_type.type_arguments().next()?.ty)
- .build(),
- )
- }
- _ => return None,
- };
-
- let found_method = self.resolve_impl_method_or_trait_def(db, search_method, substs);
- // If found_method == search_method, the method in trait itself is resolved.
- // It means the blanket dual impl is not found.
- if found_method == search_method {
- None
- } else {
- Some(found_method.into())
- }
- }
-
pub(crate) fn resolve_expr_as_callable(
&self,
db: &dyn HirDatabase,
@@ -1309,18 +1247,6 @@ impl SourceAnalyzer {
Some((trait_id, fn_id))
}
- fn trait_fn(
- &self,
- db: &dyn HirDatabase,
- trait_id: TraitId,
- method_name: &str,
- ) -> Option {
- db.trait_data(trait_id).items.iter().find_map(|(item_name, item)| match item {
- AssocItemId::FunctionId(t) if item_name.as_str() == method_name => Some(*t),
- _ => None,
- })
- }
-
fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> {
self.infer.as_ref()?.type_of_expr_or_pat(self.expr_id(db, expr)?)
}
diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
index a6b8ed70c363a..2ebd88edae2d7 100644
--- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
@@ -3,7 +3,7 @@
use either::Either;
use hir_def::{
db::DefDatabase,
- item_scope::{ImportId, ImportOrExternCrate},
+ item_scope::{ImportId, ImportOrExternCrate, ImportOrGlob},
per_ns::Item,
src::{HasChildSource, HasSource},
visibility::{Visibility, VisibilityExplicitness},
@@ -55,9 +55,10 @@ impl DeclarationLocation {
}
/// Represents an outstanding module that the symbol collector must collect symbols from.
+#[derive(Debug)]
struct SymbolCollectorWork {
module_id: ModuleId,
- parent: Option,
+ parent: Option,
}
pub struct SymbolCollector<'a> {
@@ -81,7 +82,15 @@ impl<'a> SymbolCollector<'a> {
}
}
+ pub fn new_module(db: &dyn HirDatabase, module: Module) -> Box<[FileSymbol]> {
+ let mut symbol_collector = SymbolCollector::new(db);
+ symbol_collector.collect(module);
+ symbol_collector.finish()
+ }
+
pub fn collect(&mut self, module: Module) {
+ let _p = tracing::info_span!("SymbolCollector::collect", ?module).entered();
+ tracing::info!(?module, "SymbolCollector::collect",);
self.edition = module.krate().edition(self.db);
// The initial work is the root module we're collecting, additional work will
@@ -97,16 +106,12 @@ impl<'a> SymbolCollector<'a> {
self.symbols.into_iter().collect()
}
- pub fn collect_module(db: &dyn HirDatabase, module: Module) -> Box<[FileSymbol]> {
- let mut symbol_collector = SymbolCollector::new(db);
- symbol_collector.collect(module);
- symbol_collector.finish()
- }
-
fn do_work(&mut self, work: SymbolCollectorWork) {
+ let _p = tracing::info_span!("SymbolCollector::do_work", ?work).entered();
+ tracing::info!(?work, "SymbolCollector::do_work");
self.db.unwind_if_cancelled();
- let parent_name = work.parent.and_then(|id| self.def_with_body_id_name(id));
+ let parent_name = work.parent.map(|name| name.as_str().to_smolstr());
self.with_container_name(parent_name, |s| s.collect_from_module(work.module_id));
}
@@ -116,18 +121,18 @@ impl<'a> SymbolCollector<'a> {
ModuleDefId::ModuleId(id) => this.push_module(id, name),
ModuleDefId::FunctionId(id) => {
this.push_decl(id, name, false);
- this.collect_from_body(id);
+ this.collect_from_body(id, Some(name.clone()));
}
ModuleDefId::AdtId(AdtId::StructId(id)) => this.push_decl(id, name, false),
ModuleDefId::AdtId(AdtId::EnumId(id)) => this.push_decl(id, name, false),
ModuleDefId::AdtId(AdtId::UnionId(id)) => this.push_decl(id, name, false),
ModuleDefId::ConstId(id) => {
this.push_decl(id, name, false);
- this.collect_from_body(id);
+ this.collect_from_body(id, Some(name.clone()));
}
ModuleDefId::StaticId(id) => {
this.push_decl(id, name, false);
- this.collect_from_body(id);
+ this.collect_from_body(id, Some(name.clone()));
}
ModuleDefId::TraitId(id) => {
this.push_decl(id, name, false);
@@ -153,24 +158,32 @@ impl<'a> SymbolCollector<'a> {
// Nested trees are very common, so a cache here will hit a lot.
let import_child_source_cache = &mut FxHashMap::default();
- let mut push_import = |this: &mut Self, i: ImportId, name: &Name, def: ModuleDefId| {
+ let is_explicit_import = |vis| match vis {
+ Visibility::Public => true,
+ Visibility::Module(_, VisibilityExplicitness::Explicit) => true,
+ Visibility::Module(_, VisibilityExplicitness::Implicit) => false,
+ };
+
+ let mut push_import = |this: &mut Self, i: ImportId, name: &Name, def: ModuleDefId, vis| {
let source = import_child_source_cache
- .entry(i.import)
- .or_insert_with(|| i.import.child_source(this.db.upcast()));
+ .entry(i.use_)
+ .or_insert_with(|| i.use_.child_source(this.db.upcast()));
let Some(use_tree_src) = source.value.get(i.idx) else { return };
- let Some(name_ptr) = use_tree_src
- .rename()
- .and_then(|rename| rename.name())
- .map(Either::Left)
- .or_else(|| use_tree_src.path()?.segment()?.name_ref().map(Either::Right))
- .map(|it| AstPtr::new(&it))
- else {
+ let rename = use_tree_src.rename().and_then(|rename| rename.name());
+ let name_syntax = match rename {
+ Some(name) => Some(Either::Left(name)),
+ None if is_explicit_import(vis) => {
+ (|| use_tree_src.path()?.segment()?.name_ref().map(Either::Right))()
+ }
+ None => None,
+ };
+ let Some(name_syntax) = name_syntax else {
return;
};
let dec_loc = DeclarationLocation {
hir_file_id: source.file_id,
ptr: SyntaxNodePtr::new(use_tree_src.syntax()),
- name_ptr,
+ name_ptr: AstPtr::new(&name_syntax),
};
this.symbols.insert(FileSymbol {
name: name.symbol().clone(),
@@ -183,23 +196,23 @@ impl<'a> SymbolCollector<'a> {
};
let push_extern_crate =
- |this: &mut Self, i: ExternCrateId, name: &Name, def: ModuleDefId| {
+ |this: &mut Self, i: ExternCrateId, name: &Name, def: ModuleDefId, vis| {
let loc = i.lookup(this.db.upcast());
let source = loc.source(this.db.upcast());
- let Some(name_ptr) = source
- .value
- .rename()
- .and_then(|rename| rename.name())
- .map(Either::Left)
- .or_else(|| source.value.name_ref().map(Either::Right))
- .map(|it| AstPtr::new(&it))
- else {
+ let rename = source.value.rename().and_then(|rename| rename.name());
+
+ let name_syntax = match rename {
+ Some(name) => Some(Either::Left(name)),
+ None if is_explicit_import(vis) => None,
+ None => source.value.name_ref().map(Either::Right),
+ };
+ let Some(name_syntax) = name_syntax else {
return;
};
let dec_loc = DeclarationLocation {
hir_file_id: source.file_id,
ptr: SyntaxNodePtr::new(source.value.syntax()),
- name_ptr,
+ name_ptr: AstPtr::new(&name_syntax),
};
this.symbols.insert(FileSymbol {
name: name.symbol().clone(),
@@ -211,18 +224,6 @@ impl<'a> SymbolCollector<'a> {
});
};
- let is_explicit_import = |vis| {
- match vis {
- Visibility::Module(_, VisibilityExplicitness::Explicit) => true,
- Visibility::Module(_, VisibilityExplicitness::Implicit) => {
- // consider imports in the crate root explicit, as these are visibly
- // crate-wide anyways
- module_id.is_crate_root()
- }
- Visibility::Public => true,
- }
- };
-
let def_map = module_id.def_map(self.db.upcast());
let scope = &def_map[module_id.local_id].scope;
@@ -232,14 +233,14 @@ impl<'a> SymbolCollector<'a> {
for (name, Item { def, vis, import }) in scope.types() {
if let Some(i) = import {
- if is_explicit_import(vis) {
- match i {
- ImportOrExternCrate::Import(i) => push_import(self, i, name, def),
- ImportOrExternCrate::ExternCrate(i) => {
- push_extern_crate(self, i, name, def)
- }
+ match i {
+ ImportOrExternCrate::Import(i) => push_import(self, i, name, def, vis),
+ ImportOrExternCrate::Glob(_) => (),
+ ImportOrExternCrate::ExternCrate(i) => {
+ push_extern_crate(self, i, name, def, vis)
}
}
+
continue;
}
// self is a declaration
@@ -248,8 +249,9 @@ impl<'a> SymbolCollector<'a> {
for (name, Item { def, vis, import }) in scope.macros() {
if let Some(i) = import {
- if is_explicit_import(vis) {
- push_import(self, i, name, def.into());
+ match i {
+ ImportOrGlob::Import(i) => push_import(self, i, name, def.into(), vis),
+ ImportOrGlob::Glob(_) => (),
}
continue;
}
@@ -259,8 +261,9 @@ impl<'a> SymbolCollector<'a> {
for (name, Item { def, vis, import }) in scope.values() {
if let Some(i) = import {
- if is_explicit_import(vis) {
- push_import(self, i, name, def);
+ match i {
+ ImportOrGlob::Import(i) => push_import(self, i, name, def, vis),
+ ImportOrGlob::Glob(_) => (),
}
continue;
}
@@ -269,7 +272,7 @@ impl<'a> SymbolCollector<'a> {
}
for const_id in scope.unnamed_consts() {
- self.collect_from_body(const_id);
+ self.collect_from_body(const_id, None);
}
for (name, id) in scope.legacy_macros() {
@@ -285,7 +288,7 @@ impl<'a> SymbolCollector<'a> {
}
}
- fn collect_from_body(&mut self, body_id: impl Into) {
+ fn collect_from_body(&mut self, body_id: impl Into, name: Option) {
let body_id = body_id.into();
let body = self.db.body(body_id);
@@ -294,7 +297,7 @@ impl<'a> SymbolCollector<'a> {
for (id, _) in def_map.modules() {
self.work.push(SymbolCollectorWork {
module_id: def_map.module_id(id),
- parent: Some(body_id),
+ parent: name.clone(),
});
}
}
@@ -333,24 +336,6 @@ impl<'a> SymbolCollector<'a> {
}
}
- fn def_with_body_id_name(&self, body_id: DefWithBodyId) -> Option {
- match body_id {
- DefWithBodyId::FunctionId(id) => {
- Some(self.db.function_data(id).name.display_no_db(self.edition).to_smolstr())
- }
- DefWithBodyId::StaticId(id) => {
- Some(self.db.static_data(id).name.display_no_db(self.edition).to_smolstr())
- }
- DefWithBodyId::ConstId(id) => {
- Some(self.db.const_data(id).name.as_ref()?.display_no_db(self.edition).to_smolstr())
- }
- DefWithBodyId::VariantId(id) => {
- Some(self.db.enum_variant_data(id).name.display_no_db(self.edition).to_smolstr())
- }
- DefWithBodyId::InTypeConstId(_) => Some("in type const".into()),
- }
- }
-
fn push_assoc_item(&mut self, assoc_item_id: AssocItemId, name: &Name) {
match assoc_item_id {
AssocItemId::FunctionId(id) => self.push_decl(id, name, true),
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs b/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs
index 82d8db4258924..fb533077d9626 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs
@@ -28,6 +28,7 @@ impl AssistConfig {
prefer_no_std: self.prefer_no_std,
prefer_prelude: self.prefer_prelude,
prefer_absolute: self.prefer_absolute,
+ allow_unstable: true,
}
}
}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
index a5c5b08d5b0c7..eb784cd1226fd 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
@@ -159,7 +159,7 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext<'_>
};
// Verify this is `bool::then` that is being called.
let func = ctx.sema.resolve_method_call(&mcall)?;
- if !func.name(ctx.sema.db).eq_ident("then") {
+ if func.name(ctx.sema.db) != sym::then {
return None;
}
let assoc = func.as_assoc_item(ctx.sema.db)?;
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
index bb04a43cf9615..d34cf895cd90a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
@@ -343,11 +343,9 @@ fn compute_closure_type_params(
let mut mentioned_names = mentioned_generic_params
.iter()
.filter_map(|param| match param {
- hir::GenericParam::TypeParam(param) => {
- Some(param.name(ctx.db()).unescaped().display(ctx.db()).to_smolstr())
- }
+ hir::GenericParam::TypeParam(param) => Some(param.name(ctx.db()).as_str().to_smolstr()),
hir::GenericParam::ConstParam(param) => {
- Some(param.name(ctx.db()).unescaped().display(ctx.db()).to_smolstr())
+ Some(param.name(ctx.db()).as_str().to_smolstr())
}
hir::GenericParam::LifetimeParam(_) => None,
})
@@ -390,7 +388,7 @@ fn compute_closure_type_params(
let has_name = syntax
.descendants()
.filter_map(ast::NameOrNameRef::cast)
- .any(|name| mentioned_names.contains(&*name.text()));
+ .any(|name| mentioned_names.contains(name.text().trim_start_matches("r#")));
let mut has_new_params = false;
if has_name {
syntax
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
index 615b5d3f98b55..d4f2ea3bd941b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -170,7 +170,7 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &Va
),
_ => false,
})
- .any(|(name, _)| name.eq_ident(variant_name.text().as_str()))
+ .any(|(name, _)| name.as_str() == variant_name.text().trim_start_matches("r#"))
}
fn extract_generic_params(
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
index 97321f4ec1ef0..7b6f76d00452e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
@@ -1672,8 +1672,8 @@ macro_rules! vec {
() => {Vec}
}
fn main() {
- let $0vec = vec![];
- let _ = vec;
+ let $0items = vec![];
+ let _ = items;
}
"#,
"Extract into variable",
@@ -1696,8 +1696,8 @@ macro_rules! vec {
() => {Vec}
}
fn main() {
- const $0VEC: Vec = vec![];
- let _ = VEC;
+ const $0ITEMS: Vec = vec![];
+ let _ = ITEMS;
}
"#,
"Extract into constant",
@@ -1720,8 +1720,8 @@ macro_rules! vec {
() => {Vec}
}
fn main() {
- static $0VEC: Vec = vec![];
- let _ = VEC;
+ static $0ITEMS: Vec = vec![];
+ let _ = ITEMS;
}
"#,
"Extract into static",
@@ -2019,8 +2019,8 @@ impl Vec {
}
fn foo(s: &mut S) {
- let $0vec = &mut s.vec;
- vec.push(0);
+ let $0items = &mut s.vec;
+ items.push(0);
}"#,
"Extract into variable",
);
@@ -2106,8 +2106,8 @@ impl Vec {
}
fn foo(f: &mut Y) {
- let $0vec = &mut f.field.field.vec;
- vec.push(0);
+ let $0items = &mut f.field.field.vec;
+ items.push(0);
}"#,
"Extract into variable",
);
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs
index 7a92d8911bf85..47e4a68293f0c 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs
@@ -48,7 +48,7 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>)
let (_, def) = module
.scope(ctx.db(), None)
.into_iter()
- .find(|(name, _)| name.eq_ident(name_ref.text().as_str()))?;
+ .find(|(name, _)| name.as_str() == name_ref.text().trim_start_matches("r#"))?;
let ScopeDef::ModuleDef(def) = def else {
return None;
};
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs
index 8a7a06b380f51..10915f8aafb8d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs
@@ -2,7 +2,7 @@ use ide_db::{
assists::{AssistId, AssistKind},
base_db::AnchoredPathBuf,
};
-use syntax::{ast, AstNode};
+use syntax::{ast, AstNode, ToSmolStr};
use crate::{
assist_context::{AssistContext, Assists},
@@ -39,7 +39,7 @@ pub(crate) fn move_from_mod_rs(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
}
let target = source_file.syntax().text_range();
- let module_name = module.name(ctx.db())?.unescaped().display(ctx.db()).to_string();
+ let module_name = module.name(ctx.db())?.as_str().to_smolstr();
let path = format!("../{module_name}.rs");
let dst = AnchoredPathBuf { anchor: ctx.file_id().into(), path };
acc.add(
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs
index 9692b70592912..bbf18e21948eb 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs
@@ -61,7 +61,7 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext<'_>) ->
.string_value_unescape()
.is_none() =>
{
- format_to!(buf, "{}/", name.unescaped().display(db))
+ format_to!(buf, "{}/", name.as_str())
}
_ => (),
}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs
index 2925e2334b44d..7b38c795dc80f 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs
@@ -2,7 +2,7 @@ use ide_db::{
assists::{AssistId, AssistKind},
base_db::AnchoredPathBuf,
};
-use syntax::{ast, AstNode};
+use syntax::{ast, AstNode, ToSmolStr};
use crate::{
assist_context::{AssistContext, Assists},
@@ -39,7 +39,7 @@ pub(crate) fn move_to_mod_rs(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
}
let target = source_file.syntax().text_range();
- let module_name = module.name(ctx.db())?.unescaped().display(ctx.db()).to_string();
+ let module_name = module.name(ctx.db())?.as_str().to_smolstr();
let path = format!("./{module_name}/mod.rs");
let dst = AnchoredPathBuf { anchor: ctx.file_id().into(), path };
acc.add(
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs
index 849b8a42c6949..2a8465f634cfb 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs
@@ -208,7 +208,7 @@ fn find_trait_method(
if let Some(hir::AssocItem::Function(method)) =
trait_.items(db).into_iter().find(|item: &hir::AssocItem| {
item.name(db)
- .map(|name| name.eq_ident(trait_method_name.text().as_str()))
+ .map(|name| name.as_str() == trait_method_name.text().trim_start_matches("r#"))
.unwrap_or(false)
})
{
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs
index 972303c2a0416..a79a82be45079 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs
@@ -110,7 +110,7 @@ fn compute_fields_ranks(
.fields(ctx.db())
.into_iter()
.enumerate()
- .map(|(idx, field)| (field.name(ctx.db()).unescaped().display(ctx.db()).to_string(), idx))
+ .map(|(idx, field)| (field.name(ctx.db()).as_str().to_owned(), idx))
.collect();
Some(res)
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
index eb1d538f8743a..c3404173eafe6 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
@@ -122,7 +122,7 @@ fn compute_item_ranks(
.iter()
.flat_map(|i| i.name(ctx.db()))
.enumerate()
- .map(|(idx, name)| (name.unescaped().display(ctx.db()).to_string(), idx))
+ .map(|(idx, name)| (name.as_str().to_owned(), idx))
.collect(),
)
}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
index 40669c65c5766..a22e7b272ea05 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
@@ -188,9 +188,6 @@ impl Completions {
resolution: hir::ScopeDef,
doc_aliases: Vec,
) {
- if !ctx.check_stability(resolution.attrs(ctx.db).as_deref()) {
- return;
- }
let is_private_editable = match ctx.def_is_visible(&resolution) {
Visible::Yes => false,
Visible::Editable => true,
@@ -216,9 +213,6 @@ impl Completions {
local_name: hir::Name,
resolution: hir::ScopeDef,
) {
- if !ctx.check_stability(resolution.attrs(ctx.db).as_deref()) {
- return;
- }
let is_private_editable = match ctx.def_is_visible(&resolution) {
Visible::Yes => false,
Visible::Editable => true,
@@ -241,7 +235,7 @@ impl Completions {
path_ctx: &PathCompletionCtx,
e: hir::Enum,
) {
- if !ctx.check_stability(Some(&e.attrs(ctx.db))) {
+ if !ctx.check_stability_and_hidden(e) {
return;
}
e.variants(ctx.db)
@@ -257,9 +251,6 @@ impl Completions {
local_name: hir::Name,
doc_aliases: Vec,
) {
- if !ctx.check_stability(Some(&module.attrs(ctx.db))) {
- return;
- }
self.add_path_resolution(
ctx,
path_ctx,
@@ -276,9 +267,6 @@ impl Completions {
mac: hir::Macro,
local_name: hir::Name,
) {
- if !ctx.check_stability(Some(&mac.attrs(ctx.db))) {
- return;
- }
let is_private_editable = match ctx.is_visible(&mac) {
Visible::Yes => false,
Visible::Editable => true,
@@ -302,9 +290,6 @@ impl Completions {
func: hir::Function,
local_name: Option,
) {
- if !ctx.check_stability(Some(&func.attrs(ctx.db))) {
- return;
- }
let is_private_editable = match ctx.is_visible(&func) {
Visible::Yes => false,
Visible::Editable => true,
@@ -332,9 +317,6 @@ impl Completions {
receiver: Option,
local_name: Option,
) {
- if !ctx.check_stability(Some(&func.attrs(ctx.db))) {
- return;
- }
let is_private_editable = match ctx.is_visible(&func) {
Visible::Yes => false,
Visible::Editable => true,
@@ -362,9 +344,6 @@ impl Completions {
func: hir::Function,
import: LocatedImport,
) {
- if !ctx.check_stability(Some(&func.attrs(ctx.db))) {
- return;
- }
let is_private_editable = match ctx.is_visible(&func) {
Visible::Yes => false,
Visible::Editable => true,
@@ -387,9 +366,6 @@ impl Completions {
}
pub(crate) fn add_const(&mut self, ctx: &CompletionContext<'_>, konst: hir::Const) {
- if !ctx.check_stability(Some(&konst.attrs(ctx.db))) {
- return;
- }
let is_private_editable = match ctx.is_visible(&konst) {
Visible::Yes => false,
Visible::Editable => true,
@@ -406,9 +382,6 @@ impl Completions {
ctx: &CompletionContext<'_>,
type_alias: hir::TypeAlias,
) {
- if !ctx.check_stability(Some(&type_alias.attrs(ctx.db))) {
- return;
- }
let is_private_editable = match ctx.is_visible(&type_alias) {
Visible::Yes => false,
Visible::Editable => true,
@@ -438,7 +411,7 @@ impl Completions {
variant: hir::Variant,
path: hir::ModPath,
) {
- if !ctx.check_stability(Some(&variant.attrs(ctx.db))) {
+ if !ctx.check_stability_and_hidden(variant) {
return;
}
if let Some(builder) =
@@ -455,7 +428,7 @@ impl Completions {
variant: hir::Variant,
local_name: Option,
) {
- if !ctx.check_stability(Some(&variant.attrs(ctx.db))) {
+ if !ctx.check_stability_and_hidden(variant) {
return;
}
if let PathCompletionCtx { kind: PathKind::Pat { pat_ctx }, .. } = path_ctx {
@@ -479,9 +452,6 @@ impl Completions {
field: hir::Field,
ty: &hir::Type,
) {
- if !ctx.check_stability(Some(&field.attrs(ctx.db))) {
- return;
- }
let is_private_editable = match ctx.is_visible(&field) {
Visible::Yes => false,
Visible::Editable => true,
@@ -506,12 +476,18 @@ impl Completions {
path: Option,
local_name: Option,
) {
- if !ctx.check_stability(Some(&strukt.attrs(ctx.db))) {
- return;
- }
- if let Some(builder) =
- render_struct_literal(RenderContext::new(ctx), path_ctx, strukt, path, local_name)
- {
+ let is_private_editable = match ctx.is_visible(&strukt) {
+ Visible::Yes => false,
+ Visible::Editable => true,
+ Visible::No => return,
+ };
+ if let Some(builder) = render_struct_literal(
+ RenderContext::new(ctx).private_editable(is_private_editable),
+ path_ctx,
+ strukt,
+ path,
+ local_name,
+ ) {
self.add(builder.build(ctx.db));
}
}
@@ -523,10 +499,17 @@ impl Completions {
path: Option,
local_name: Option,
) {
- if !ctx.check_stability(Some(&un.attrs(ctx.db))) {
- return;
- }
- let item = render_union_literal(RenderContext::new(ctx), un, path, local_name);
+ let is_private_editable = match ctx.is_visible(&un) {
+ Visible::Yes => false,
+ Visible::Editable => true,
+ Visible::No => return,
+ };
+ let item = render_union_literal(
+ RenderContext::new(ctx).private_editable(is_private_editable),
+ un,
+ path,
+ local_name,
+ );
self.add_opt(item);
}
@@ -571,7 +554,7 @@ impl Completions {
variant: hir::Variant,
local_name: Option,
) {
- if !ctx.check_stability(Some(&variant.attrs(ctx.db))) {
+ if !ctx.check_stability_and_hidden(variant) {
return;
}
self.add_opt(render_variant_pat(
@@ -591,7 +574,7 @@ impl Completions {
variant: hir::Variant,
path: hir::ModPath,
) {
- if !ctx.check_stability(Some(&variant.attrs(ctx.db))) {
+ if !ctx.check_stability_and_hidden(variant) {
return;
}
let path = Some(&path);
@@ -612,10 +595,17 @@ impl Completions {
strukt: hir::Struct,
local_name: Option,
) {
- if !ctx.check_stability(Some(&strukt.attrs(ctx.db))) {
- return;
- }
- self.add_opt(render_struct_pat(RenderContext::new(ctx), pattern_ctx, strukt, local_name));
+ let is_private_editable = match ctx.is_visible(&strukt) {
+ Visible::Yes => false,
+ Visible::Editable => true,
+ Visible::No => return,
+ };
+ self.add_opt(render_struct_pat(
+ RenderContext::new(ctx).private_editable(is_private_editable),
+ pattern_ctx,
+ strukt,
+ local_name,
+ ));
}
pub(crate) fn suggest_name(&mut self, ctx: &CompletionContext<'_>, name: &str) {
@@ -660,7 +650,7 @@ fn enum_variants_with_paths(
if let Some(path) = ctx.module.find_path(
ctx.db,
hir::ModuleDef::from(variant),
- ctx.config.import_path_config(),
+ ctx.config.import_path_config(ctx.is_nightly),
) {
// Variants with trivial paths are already added by the existing completion logic,
// so we should avoid adding these twice
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
index 7679d9076ded2..d12654665ce95 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
@@ -42,31 +42,38 @@ pub(crate) fn complete_dot(
item.detail("expr.await");
item.add_to(acc, ctx.db);
- // Completions that skip `.await`, e.g. `.await.foo()`.
- let dot_access_kind = match &dot_access.kind {
- DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
- DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
- }
- it @ DotAccessKind::Method { .. } => *it,
- };
- let dot_access = DotAccess {
- receiver: dot_access.receiver.clone(),
- receiver_ty: Some(hir::TypeInfo { original: future_output.clone(), adjusted: None }),
- kind: dot_access_kind,
- ctx: dot_access.ctx,
- };
- complete_fields(
- acc,
- ctx,
- &future_output,
- |acc, field, ty| acc.add_field(ctx, &dot_access, Some(await_str.clone()), field, &ty),
- |acc, field, ty| acc.add_tuple_field(ctx, Some(await_str.clone()), field, &ty),
- is_field_access,
- is_method_access_with_parens,
- );
- complete_methods(ctx, &future_output, &traits_in_scope, |func| {
- acc.add_method(ctx, &dot_access, func, Some(await_str.clone()), None)
- });
+ if ctx.config.enable_auto_await {
+ // Completions that skip `.await`, e.g. `.await.foo()`.
+ let dot_access_kind = match &dot_access.kind {
+ DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
+ DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
+ }
+ it @ DotAccessKind::Method { .. } => *it,
+ };
+ let dot_access = DotAccess {
+ receiver: dot_access.receiver.clone(),
+ receiver_ty: Some(hir::TypeInfo {
+ original: future_output.clone(),
+ adjusted: None,
+ }),
+ kind: dot_access_kind,
+ ctx: dot_access.ctx,
+ };
+ complete_fields(
+ acc,
+ ctx,
+ &future_output,
+ |acc, field, ty| {
+ acc.add_field(ctx, &dot_access, Some(await_str.clone()), field, &ty)
+ },
+ |acc, field, ty| acc.add_tuple_field(ctx, Some(await_str.clone()), field, &ty),
+ is_field_access,
+ is_method_access_with_parens,
+ );
+ complete_methods(ctx, &future_output, &traits_in_scope, |func| {
+ acc.add_method(ctx, &dot_access, func, Some(await_str.clone()), None)
+ });
+ }
}
complete_fields(
@@ -82,39 +89,41 @@ pub(crate) fn complete_dot(
acc.add_method(ctx, dot_access, func, None, None)
});
- // FIXME:
- // Checking for the existence of `iter()` is complicated in our setup, because we need to substitute
- // its return type, so we instead check for `<&Self as IntoIterator>::IntoIter`.
- // Does <&receiver_ty as IntoIterator>::IntoIter` exist? Assume `iter` is valid
- let iter = receiver_ty
- .strip_references()
- .add_reference(hir::Mutability::Shared)
- .into_iterator_iter(ctx.db)
- .map(|ty| (ty, SmolStr::new_static("iter()")));
- // Does ::IntoIter` exist?
- let into_iter = || {
- receiver_ty
- .clone()
+ if ctx.config.enable_auto_iter {
+ // FIXME:
+ // Checking for the existence of `iter()` is complicated in our setup, because we need to substitute
+ // its return type, so we instead check for `<&Self as IntoIterator>::IntoIter`.
+ // Does <&receiver_ty as IntoIterator>::IntoIter` exist? Assume `iter` is valid
+ let iter = receiver_ty
+ .strip_references()
+ .add_reference(hir::Mutability::Shared)
.into_iterator_iter(ctx.db)
- .map(|ty| (ty, SmolStr::new_static("into_iter()")))
- };
- if let Some((iter, iter_sym)) = iter.or_else(into_iter) {
- // Skip iterators, e.g. complete `.iter().filter_map()`.
- let dot_access_kind = match &dot_access.kind {
- DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
- DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
- }
- it @ DotAccessKind::Method { .. } => *it,
+ .map(|ty| (ty, SmolStr::new_static("iter()")));
+ // Does ::IntoIter` exist?
+ let into_iter = || {
+ receiver_ty
+ .clone()
+ .into_iterator_iter(ctx.db)
+ .map(|ty| (ty, SmolStr::new_static("into_iter()")))
};
- let dot_access = DotAccess {
- receiver: dot_access.receiver.clone(),
- receiver_ty: Some(hir::TypeInfo { original: iter.clone(), adjusted: None }),
- kind: dot_access_kind,
- ctx: dot_access.ctx,
- };
- complete_methods(ctx, &iter, &traits_in_scope, |func| {
- acc.add_method(ctx, &dot_access, func, Some(iter_sym.clone()), None)
- });
+ if let Some((iter, iter_sym)) = iter.or_else(into_iter) {
+ // Skip iterators, e.g. complete `.iter().filter_map()`.
+ let dot_access_kind = match &dot_access.kind {
+ DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
+ DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
+ }
+ it @ DotAccessKind::Method { .. } => *it,
+ };
+ let dot_access = DotAccess {
+ receiver: dot_access.receiver.clone(),
+ receiver_ty: Some(hir::TypeInfo { original: iter.clone(), adjusted: None }),
+ kind: dot_access_kind,
+ ctx: dot_access.ctx,
+ };
+ complete_methods(ctx, &iter, &traits_in_scope, |func| {
+ acc.add_method(ctx, &dot_access, func, Some(iter_sym.clone()), None)
+ });
+ }
}
}
@@ -1466,4 +1475,34 @@ async fn bar() {
"#,
);
}
+
+ #[test]
+ fn receiver_without_deref_impl_completion() {
+ check_no_kw(
+ r#"
+//- minicore: receiver
+use core::ops::Receiver;
+
+struct Foo;
+
+impl Foo {
+ fn foo(self: Bar) {}
+}
+
+struct Bar;
+
+impl Receiver for Bar {
+ type Target = Foo;
+}
+
+fn main() {
+ let bar = Bar;
+ bar.$0
+}
+"#,
+ expect![[r#"
+ me foo() fn(self: Bar)
+"#]],
+ );
+ }
}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
index db18b531d7c3c..e710175170199 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
@@ -247,7 +247,7 @@ pub(crate) fn complete_expr_path(
.find_path(
ctx.db,
hir::ModuleDef::from(strukt),
- ctx.config.import_path_config(),
+ ctx.config.import_path_config(ctx.is_nightly),
)
.filter(|it| it.len() > 1);
@@ -269,7 +269,7 @@ pub(crate) fn complete_expr_path(
.find_path(
ctx.db,
hir::ModuleDef::from(un),
- ctx.config.import_path_config(),
+ ctx.config.import_path_config(ctx.is_nightly),
)
.filter(|it| it.len() > 1);
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
index 73313eeaa6b79..24243f57b46a0 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
@@ -5,7 +5,7 @@ use ide_db::imports::{
insert_use::ImportScope,
};
use itertools::Itertools;
-use syntax::{ast, AstNode, SyntaxNode, ToSmolStr};
+use syntax::{ast, AstNode, SyntaxNode};
use crate::{
config::AutoImportExclusionType,
@@ -257,7 +257,7 @@ fn import_on_the_fly(
};
let user_input_lowercased = potential_import_name.to_lowercase();
- let import_cfg = ctx.config.import_path_config();
+ let import_cfg = ctx.config.import_path_config(ctx.is_nightly);
import_assets
.search_for_imports(&ctx.sema, import_cfg, ctx.config.insert_use.prefix_kind)
@@ -316,7 +316,7 @@ fn import_on_the_fly_pat_(
ItemInNs::Values(def) => matches!(def, hir::ModuleDef::Const(_)),
};
let user_input_lowercased = potential_import_name.to_lowercase();
- let cfg = ctx.config.import_path_config();
+ let cfg = ctx.config.import_path_config(ctx.is_nightly);
import_assets
.search_for_imports(&ctx.sema, cfg, ctx.config.insert_use.prefix_kind)
@@ -358,7 +358,7 @@ fn import_on_the_fly_method(
let user_input_lowercased = potential_import_name.to_lowercase();
- let cfg = ctx.config.import_path_config();
+ let cfg = ctx.config.import_path_config(ctx.is_nightly);
import_assets
.search_for_imports(&ctx.sema, cfg, ctx.config.insert_use.prefix_kind)
@@ -444,7 +444,7 @@ fn compute_fuzzy_completion_order_key(
cov_mark::hit!(certain_fuzzy_order_test);
let import_name = match proposed_mod_path.segments().last() {
// FIXME: nasty alloc, this is a hot path!
- Some(name) => name.unescaped().display_no_db().to_smolstr().to_ascii_lowercase(),
+ Some(name) => name.as_str().to_ascii_lowercase(),
None => return usize::MAX,
};
match import_name.match_indices(user_input_lowercased).next() {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
index 6d1945c45341d..831f5665f4aa0 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
@@ -31,7 +31,7 @@
//! }
//! ```
-use hir::{db::ExpandDatabase, HasAttrs, MacroFileId, Name};
+use hir::{db::ExpandDatabase, MacroFileId, Name};
use ide_db::text_edit::TextEdit;
use ide_db::{
documentation::HasDocs, path_transform::PathTransform,
@@ -85,7 +85,7 @@ fn complete_trait_impl_name(
name: &Option,
kind: ImplCompletionKind,
) -> Option<()> {
- let item = match name {
+ let macro_file_item = match name {
Some(name) => name.syntax().parent(),
None => {
let token = &ctx.token;
@@ -96,12 +96,12 @@ fn complete_trait_impl_name(
.parent()
}
}?;
- let item = ctx.sema.original_syntax_node_rooted(&item)?;
+ let real_file_item = ctx.sema.original_syntax_node_rooted(¯o_file_item)?;
// item -> ASSOC_ITEM_LIST -> IMPL
- let impl_def = ast::Impl::cast(item.parent()?.parent()?)?;
+ let impl_def = ast::Impl::cast(macro_file_item.parent()?.parent()?)?;
let replacement_range = {
// ctx.sema.original_ast_node(item)?;
- let first_child = item
+ let first_child = real_file_item
.children_with_tokens()
.find(|child| {
!matches!(
@@ -109,7 +109,7 @@ fn complete_trait_impl_name(
SyntaxKind::COMMENT | SyntaxKind::WHITESPACE | SyntaxKind::ATTR
)
})
- .unwrap_or_else(|| SyntaxElement::Node(item.clone()));
+ .unwrap_or_else(|| SyntaxElement::Node(real_file_item.clone()));
TextRange::new(first_child.text_range().start(), ctx.source_range().end())
};
@@ -133,8 +133,11 @@ pub(crate) fn complete_trait_impl_item_by_name(
acc,
ctx,
ImplCompletionKind::All,
- match name_ref {
- Some(name) => name.syntax().text_range(),
+ match name_ref
+ .as_ref()
+ .and_then(|name| ctx.sema.original_syntax_node_rooted(name.syntax()))
+ {
+ Some(name) => name.text_range(),
None => ctx.source_range(),
},
impl_,
@@ -152,7 +155,7 @@ fn complete_trait_impl(
if let Some(hir_impl) = ctx.sema.to_def(impl_def) {
get_missing_assoc_items(&ctx.sema, impl_def)
.into_iter()
- .filter(|item| ctx.check_stability(Some(&item.attrs(ctx.db))))
+ .filter(|item| ctx.check_stability_and_hidden(*item))
.for_each(|item| {
use self::ImplCompletionKind::*;
match (item, kind) {
@@ -359,7 +362,7 @@ fn add_type_alias_impl(
type_alias: hir::TypeAlias,
impl_def: hir::Impl,
) {
- let alias_name = type_alias.name(ctx.db).unescaped().display(ctx.db).to_smolstr();
+ let alias_name = type_alias.name(ctx.db).as_str().to_smolstr();
let label = format_smolstr!("type {alias_name} =");
@@ -516,7 +519,7 @@ fn function_declaration(
mod tests {
use expect_test::expect;
- use crate::tests::{check_edit, check_no_kw};
+ use crate::tests::{check, check_edit, check_no_kw};
#[test]
fn no_completion_inside_fn() {
@@ -1639,4 +1642,51 @@ impl DesugaredAsyncTrait for () {
"#,
);
}
+
+ #[test]
+ fn within_attr_macro() {
+ check(
+ r#"
+//- proc_macros: identity
+trait Trait {
+ fn foo(&self) {}
+ fn bar(&self) {}
+ fn baz(&self) {}
+}
+
+#[proc_macros::identity]
+impl Trait for () {
+ f$0
+}
+ "#,
+ expect![[r#"
+ me fn bar(..)
+ me fn baz(..)
+ me fn foo(..)
+ md proc_macros
+ kw crate::
+ kw self::
+ "#]],
+ );
+ check(
+ r#"
+//- proc_macros: identity
+trait Trait {
+ fn foo(&self) {}
+ fn bar(&self) {}
+ fn baz(&self) {}
+}
+
+#[proc_macros::identity]
+impl Trait for () {
+ fn $0
+}
+ "#,
+ expect![[r#"
+ me fn bar(..)
+ me fn baz(..)
+ me fn foo(..)
+ "#]],
+ );
+ }
}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs
index bafe32942098c..cca6a22f290d2 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs
@@ -7,7 +7,7 @@ use ide_db::{
base_db::{SourceRootDatabase, VfsPath},
FxHashSet, RootDatabase, SymbolKind,
};
-use syntax::{ast, AstNode, SyntaxKind, ToSmolStr};
+use syntax::{ast, AstNode, SyntaxKind};
use crate::{context::CompletionContext, CompletionItem, Completions};
@@ -140,9 +140,7 @@ fn directory_to_look_for_submodules(
module_chain_to_containing_module_file(module, db)
.into_iter()
.filter_map(|module| module.name(db))
- .try_fold(base_directory, |path, name| {
- path.join(&name.unescaped().display_no_db().to_smolstr())
- })
+ .try_fold(base_directory, |path, name| path.join(name.as_str()))
}
fn module_chain_to_containing_module_file(
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 67ea05e002b73..2c39a8fdfed73 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
@@ -60,7 +60,7 @@ pub(crate) fn complete_postfix(
None => return,
};
- let cfg = ctx.config.import_path_config();
+ let cfg = ctx.config.import_path_config(ctx.is_nightly);
if let Some(drop_trait) = ctx.famous_defs().core_ops_Drop() {
if receiver_ty.impls_trait(ctx.db, drop_trait, &[]) {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs
index 9d62622add206..b384987c51ce1 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs
@@ -52,8 +52,14 @@ pub(crate) fn complete_use_path(
)
};
for (name, def) in module_scope {
- if !ctx.check_stability(def.attrs(ctx.db).as_deref()) {
- continue;
+ if let (Some(attrs), Some(defining_crate)) =
+ (def.attrs(ctx.db), def.krate(ctx.db))
+ {
+ if !ctx.check_stability(Some(&attrs))
+ || ctx.is_doc_hidden(&attrs, defining_crate)
+ {
+ continue;
+ }
}
let is_name_already_imported =
already_imported_names.contains(name.as_str());
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs
index 8b1ce11e8a45f..45aab38e8ea09 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs
@@ -14,6 +14,8 @@ pub struct CompletionConfig<'a> {
pub enable_postfix_completions: bool,
pub enable_imports_on_the_fly: bool,
pub enable_self_on_the_fly: bool,
+ pub enable_auto_iter: bool,
+ pub enable_auto_await: bool,
pub enable_private_editable: bool,
pub enable_term_search: bool,
pub term_search_fuel: u64,
@@ -57,11 +59,12 @@ impl CompletionConfig<'_> {
.flat_map(|snip| snip.prefix_triggers.iter().map(move |trigger| (&**trigger, snip)))
}
- pub fn import_path_config(&self) -> ImportPathConfig {
+ pub fn import_path_config(&self, allow_unstable: bool) -> ImportPathConfig {
ImportPathConfig {
prefer_no_std: self.prefer_no_std,
prefer_prelude: self.prefer_prelude,
prefer_absolute: self.prefer_absolute,
+ allow_unstable,
}
}
}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
index 3a2a4a23a1987..2f1860cbb59af 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -443,7 +443,9 @@ pub(crate) struct CompletionContext<'a> {
/// The module of the `scope`.
pub(crate) module: hir::Module,
/// Whether nightly toolchain is used. Cached since this is looked up a lot.
- is_nightly: bool,
+ pub(crate) is_nightly: bool,
+ /// The edition of the current crate
+ // FIXME: This should probably be the crate of the current token?
pub(crate) edition: Edition,
/// The expected name of what we are completing.
@@ -532,7 +534,7 @@ impl CompletionContext<'_> {
}
}
- /// Checks if an item is visible and not `doc(hidden)` at the completion site.
+ /// Checks if an item is visible, not `doc(hidden)` and stable at the completion site.
pub(crate) fn is_visible(&self, item: &I) -> Visible
where
I: hir::HasVisibility + hir::HasAttrs + hir::HasCrate + Copy,
@@ -568,6 +570,15 @@ impl CompletionContext<'_> {
!attrs.is_unstable() || self.is_nightly
}
+ pub(crate) fn check_stability_and_hidden(&self, item: I) -> bool
+ where
+ I: hir::HasAttrs + hir::HasCrate,
+ {
+ let defining_crate = item.krate(self.db);
+ let attrs = item.attrs(self.db);
+ self.check_stability(Some(&attrs)) && !self.is_doc_hidden(&attrs, defining_crate)
+ }
+
/// Whether the given trait is an operator trait or not.
pub(crate) fn is_ops_trait(&self, trait_: hir::Trait) -> bool {
match trait_.attrs(self.db).lang() {
@@ -645,6 +656,10 @@ impl CompletionContext<'_> {
attrs: &hir::Attrs,
defining_crate: hir::Crate,
) -> Visible {
+ if !self.check_stability(Some(attrs)) {
+ return Visible::No;
+ }
+
if !vis.is_visible_from(self.db, self.module.into()) {
if !self.config.enable_private_editable {
return Visible::No;
@@ -664,7 +679,7 @@ impl CompletionContext<'_> {
}
}
- fn is_doc_hidden(&self, attrs: &hir::Attrs, defining_crate: hir::Crate) -> bool {
+ pub(crate) fn is_doc_hidden(&self, attrs: &hir::Attrs, defining_crate: hir::Crate) -> bool {
// `doc(hidden)` items are only completed within the defining crate.
self.krate != defining_crate && attrs.has_doc_hidden()
}
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 3c4d489c0ff88..f5a50ae81907f 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
@@ -5,7 +5,7 @@ use hir::{ExpandResult, Semantics, Type, TypeInfo, Variant};
use ide_db::{active_parameter::ActiveParameter, RootDatabase};
use itertools::Either;
use syntax::{
- algo::{ancestors_at_offset, find_node_at_offset, non_trivia_sibling},
+ algo::{self, ancestors_at_offset, find_node_at_offset, non_trivia_sibling},
ast::{
self, AttrKind, HasArgList, HasGenericArgs, HasGenericParams, HasLoopBody, HasName,
NameOrNameRef,
@@ -85,6 +85,11 @@ pub(super) fn expand_and_analyze(
})
}
+fn token_at_offset_ignore_whitespace(file: &SyntaxNode, offset: TextSize) -> Option {
+ let token = file.token_at_offset(offset).left_biased()?;
+ algo::skip_whitespace_token(token, Direction::Prev)
+}
+
/// Expand attributes and macro calls at the current cursor position for both the original file
/// and fake file repeatedly. As soon as one of the two expansions fail we stop so the original
/// and speculative states stay in sync.
@@ -125,9 +130,7 @@ fn expand(
// Left biased since there may already be an identifier token there, and we appended to it.
if !sema.might_be_inside_macro_call(&fake_ident_token)
- && original_file
- .token_at_offset(original_offset + relative_offset)
- .left_biased()
+ && token_at_offset_ignore_whitespace(&original_file, original_offset + relative_offset)
.is_some_and(|original_token| !sema.might_be_inside_macro_call(&original_token))
{
// Recursion base case.
@@ -143,9 +146,11 @@ fn expand(
let parent_item =
|item: &ast::Item| item.syntax().ancestors().skip(1).find_map(ast::Item::cast);
+ let original_node = token_at_offset_ignore_whitespace(&original_file, original_offset)
+ .and_then(|token| token.parent_ancestors().find_map(ast::Item::cast));
let ancestor_items = iter::successors(
Option::zip(
- find_node_at_offset::(&original_file, original_offset),
+ original_node,
find_node_at_offset::(
&speculative_file,
fake_ident_token.text_range().start(),
@@ -1590,11 +1595,11 @@ fn pattern_context_for(
}).map(|enum_| enum_.variants(sema.db))
})
}).map(|variants| variants.iter().filter_map(|variant| {
- let variant_name = variant.name(sema.db).unescaped().display(sema.db).to_string();
+ let variant_name = variant.name(sema.db);
let variant_already_present = match_arm_list.arms().any(|arm| {
arm.pat().and_then(|pat| {
- let pat_already_present = pat.syntax().to_string().contains(&variant_name);
+ let pat_already_present = pat.syntax().to_string().contains(variant_name.as_str());
pat_already_present.then_some(pat_already_present)
}).is_some()
});
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
index dc2f9a7680293..41a82409597bd 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
@@ -82,8 +82,7 @@ pub struct CompletionItem {
pub ref_match: Option<(CompletionItemRefMode, TextSize)>,
/// The import data to add to completion's edits.
- /// (ImportPath, LastSegment)
- pub import_to_add: SmallVec<[(String, String); 1]>,
+ pub import_to_add: SmallVec<[String; 1]>,
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
@@ -181,6 +180,8 @@ pub struct CompletionRelevance {
pub postfix_match: Option,
/// This is set for items that are function (associated or method)
pub function: Option,
+ /// true when there is an `await.method()` or `iter().method()` completion.
+ pub is_skipping_completion: bool,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct CompletionRelevanceTraitInfo {
@@ -269,6 +270,7 @@ impl CompletionRelevance {
postfix_match,
trait_,
function,
+ is_skipping_completion,
} = self;
// only applicable for completions within use items
@@ -296,6 +298,12 @@ impl CompletionRelevance {
score -= 5;
}
}
+
+ // Lower rank for completions that skip `await` and `iter()`.
+ if is_skipping_completion {
+ score -= 7;
+ }
+
// lower rank for items that need an import
if requires_import {
score -= 1;
@@ -561,12 +569,7 @@ impl Builder {
let import_to_add = self
.imports_to_add
.into_iter()
- .filter_map(|import| {
- Some((
- import.import_path.display(db, self.edition).to_string(),
- import.import_path.segments().last()?.display(db, self.edition).to_string(),
- ))
- })
+ .map(|import| import.import_path.display(db, self.edition).to_string())
.collect();
CompletionItem {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
index 56d7eeaf8ea03..8051d48ca5fe0 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
@@ -10,17 +10,13 @@ mod snippet;
#[cfg(test)]
mod tests;
-use ide_db::text_edit::TextEdit;
use ide_db::{
- helpers::mod_path_to_ast,
- imports::{
- import_assets::NameToImport,
- insert_use::{self, ImportScope},
- },
- items_locator,
+ imports::insert_use::{self, ImportScope},
syntax_helpers::tree_diff::diff,
+ text_edit::TextEdit,
FilePosition, FxHashSet, RootDatabase,
};
+use syntax::ast::make;
use crate::{
completions::Completions,
@@ -272,7 +268,7 @@ pub fn resolve_completion_edits(
db: &RootDatabase,
config: &CompletionConfig<'_>,
FilePosition { file_id, offset }: FilePosition,
- imports: impl IntoIterator
- ,
+ imports: impl IntoIterator
- ,
) -> Option> {
let _p = tracing::info_span!("resolve_completion_edits").entered();
let sema = hir::Semantics::new(db);
@@ -289,27 +285,12 @@ pub fn resolve_completion_edits(
let new_ast = scope.clone_for_update();
let mut import_insert = TextEdit::builder();
- let cfg = config.import_path_config();
-
- imports.into_iter().for_each(|(full_import_path, imported_name)| {
- let items_with_name = items_locator::items_with_name(
- &sema,
- current_crate,
- NameToImport::exact_case_sensitive(imported_name),
- items_locator::AssocSearchMode::Include,
+ imports.into_iter().for_each(|full_import_path| {
+ insert_use::insert_use(
+ &new_ast,
+ make::path_from_text_with_edition(&full_import_path, current_edition),
+ &config.insert_use,
);
- let import = items_with_name
- .filter_map(|candidate| {
- current_module.find_use_path(db, candidate, config.insert_use.prefix_kind, cfg)
- })
- .find(|mod_path| mod_path.display(db, current_edition).to_string() == full_import_path);
- if let Some(import_path) = import {
- insert_use::insert_use(
- &new_ast,
- mod_path_to_ast(&import_path, current_edition),
- &config.insert_use,
- );
- }
});
diff(scope.as_syntax_node(), new_ast.as_syntax_node()).into_text_edit(&mut import_insert);
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
index 61e8114d381aa..dc7eacbfbafdb 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
@@ -130,10 +130,8 @@ pub(crate) fn render_field(
let db = ctx.db();
let is_deprecated = ctx.is_deprecated(field);
let name = field.name(db);
- let (name, escaped_name) = (
- name.unescaped().display(db).to_smolstr(),
- name.display_no_db(ctx.completion.edition).to_smolstr(),
- );
+ let (name, escaped_name) =
+ (name.as_str().to_smolstr(), name.display_no_db(ctx.completion.edition).to_smolstr());
let mut item = CompletionItem::new(
SymbolKind::Field,
ctx.source_range(),
@@ -142,7 +140,8 @@ pub(crate) fn render_field(
);
item.set_relevance(CompletionRelevance {
type_match: compute_type_match(ctx.completion, ty),
- exact_name_match: compute_exact_name_match(ctx.completion, name.as_str()),
+ exact_name_match: compute_exact_name_match(ctx.completion, &name),
+ is_skipping_completion: receiver.is_some(),
..CompletionRelevance::default()
});
item.detail(ty.display(db, ctx.completion.edition).to_string())
@@ -215,6 +214,10 @@ pub(crate) fn render_tuple_field(
);
item.detail(ty.display(ctx.db(), ctx.completion.edition).to_string())
.lookup_by(field.to_string());
+ item.set_relevance(CompletionRelevance {
+ is_skipping_completion: receiver.is_some(),
+ ..ctx.completion_relevance()
+ });
item.build(ctx.db())
}
@@ -298,7 +301,7 @@ pub(crate) fn render_expr(
.unwrap_or_else(|| String::from("..."))
};
- let cfg = ctx.config.import_path_config();
+ let cfg = ctx.config.import_path_config(ctx.is_nightly);
let label = expr.gen_source_code(&ctx.scope, &mut label_formatter, cfg, ctx.edition).ok()?;
@@ -512,7 +515,7 @@ fn render_resolution_simple_(
let mut item = CompletionItem::new(
kind,
ctx.source_range(),
- local_name.unescaped().display(db).to_smolstr(),
+ local_name.as_str().to_smolstr(),
ctx.completion.edition,
);
item.set_relevance(ctx.completion_relevance())
@@ -1335,6 +1338,7 @@ fn main() { let _: m::Spam = S$0 }
is_private_editable: false,
postfix_match: None,
function: None,
+ is_skipping_completion: false,
},
trigger_call_info: true,
},
@@ -1364,6 +1368,7 @@ fn main() { let _: m::Spam = S$0 }
is_private_editable: false,
postfix_match: None,
function: None,
+ is_skipping_completion: false,
},
trigger_call_info: true,
},
@@ -1453,6 +1458,7 @@ fn foo() { A { the$0 } }
is_private_editable: false,
postfix_match: None,
function: None,
+ is_skipping_completion: false,
},
},
]
@@ -1511,6 +1517,7 @@ impl S {
return_type: Other,
},
),
+ is_skipping_completion: false,
},
},
CompletionItem {
@@ -1653,6 +1660,7 @@ fn foo(s: S) { s.$0 }
return_type: Other,
},
),
+ is_skipping_completion: false,
},
},
]
@@ -1864,6 +1872,7 @@ fn f() -> i32 {
is_private_editable: false,
postfix_match: None,
function: None,
+ is_skipping_completion: false,
},
},
]
@@ -2624,6 +2633,7 @@ fn foo(f: Foo) { let _: &u32 = f.b$0 }
return_type: Other,
},
),
+ is_skipping_completion: false,
},
ref_match: "&@107",
},
@@ -2709,6 +2719,7 @@ fn foo() {
is_private_editable: false,
postfix_match: None,
function: None,
+ is_skipping_completion: false,
},
},
]
@@ -2766,6 +2777,7 @@ fn main() {
return_type: Other,
},
),
+ is_skipping_completion: false,
},
ref_match: "&@92",
},
@@ -3140,6 +3152,7 @@ fn main() {
is_private_editable: false,
postfix_match: None,
function: None,
+ is_skipping_completion: false,
},
},
CompletionItem {
@@ -3173,6 +3186,7 @@ fn main() {
is_private_editable: false,
postfix_match: None,
function: None,
+ is_skipping_completion: false,
},
},
]
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs
index 415d87c6239b4..e357ab24d22df 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs
@@ -14,10 +14,8 @@ pub(crate) fn render_const(ctx: RenderContext<'_>, const_: hir::Const) -> Option
fn render(ctx: RenderContext<'_>, const_: hir::Const) -> Option {
let db = ctx.db();
let name = const_.name(db)?;
- let (name, escaped_name) = (
- name.unescaped().display(db).to_smolstr(),
- name.display(db, ctx.completion.edition).to_smolstr(),
- );
+ let (name, escaped_name) =
+ (name.as_str().to_smolstr(), name.display(db, ctx.completion.edition).to_smolstr());
let detail = const_.display(db, ctx.completion.edition).to_string();
let mut item =
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
index 3b97d67169eca..c3354902c3b78 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
@@ -59,13 +59,10 @@ fn render(
let (call, escaped_call) = match &func_kind {
FuncKind::Method(_, Some(receiver)) => (
- format_smolstr!("{}.{}", receiver, name.unescaped().display(ctx.db())),
+ format_smolstr!("{}.{}", receiver, name.as_str()),
format_smolstr!("{}.{}", receiver, name.display(ctx.db(), completion.edition)),
),
- _ => (
- name.unescaped().display(db).to_smolstr(),
- name.display(db, completion.edition).to_smolstr(),
- ),
+ _ => (name.as_str().to_smolstr(), name.display(db, completion.edition).to_smolstr()),
};
let has_self_param = func.self_param(db).is_some();
let mut item = CompletionItem::new(
@@ -126,6 +123,7 @@ fn render(
exact_name_match: compute_exact_name_match(completion, &call),
function,
trait_: trait_info,
+ is_skipping_completion: matches!(func_kind, FuncKind::Method(_, Some(_))),
..ctx.completion_relevance()
});
@@ -151,7 +149,7 @@ fn render(
item.set_documentation(ctx.docs(func))
.set_deprecated(ctx.is_deprecated(func) || ctx.is_deprecated_assoc_item(func))
.detail(detail)
- .lookup_by(name.unescaped().display(db).to_smolstr());
+ .lookup_by(name.as_str().to_smolstr());
if let Some((cap, (self_param, params))) = complete_call_parens {
add_call_parens(
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
index c71356e5300fc..aab54ca5e0146 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
@@ -75,7 +75,7 @@ fn render(
None => (name.clone().into(), name.into(), false),
};
let (qualified_name, escaped_qualified_name) = (
- qualified_name.unescaped().display(ctx.db()).to_string(),
+ qualified_name.display_verbatim(ctx.db()).to_string(),
qualified_name.display(ctx.db(), completion.edition).to_string(),
);
let snippet_cap = ctx.snippet_cap();
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
index 6490171fbb48b..e265e92f9794b 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
@@ -46,21 +46,19 @@ fn render(
ctx.source_range()
};
- let (name, escaped_name) = (
- name.unescaped().display(ctx.db()).to_smolstr(),
- name.display(ctx.db(), completion.edition).to_smolstr(),
- );
+ let (name, escaped_name) =
+ (name.as_str(), name.display(ctx.db(), completion.edition).to_smolstr());
let docs = ctx.docs(macro_);
let docs_str = docs.as_ref().map(Documentation::as_str).unwrap_or_default();
let is_fn_like = macro_.is_fn_like(completion.db);
- let (bra, ket) = if is_fn_like { guess_macro_braces(&name, docs_str) } else { ("", "") };
+ let (bra, ket) = if is_fn_like { guess_macro_braces(name, docs_str) } else { ("", "") };
let needs_bang = is_fn_like && !is_use_path && !has_macro_bang;
let mut item = CompletionItem::new(
SymbolKind::from(macro_.kind(completion.db)),
source_range,
- label(&ctx, needs_bang, bra, ket, &name),
+ label(&ctx, needs_bang, bra, ket, &name.to_smolstr()),
completion.edition,
);
item.set_deprecated(ctx.is_deprecated(macro_))
@@ -71,11 +69,11 @@ fn render(
match ctx.snippet_cap() {
Some(cap) if needs_bang && !has_call_parens => {
let snippet = format!("{escaped_name}!{bra}$0{ket}");
- let lookup = banged_name(&name);
+ let lookup = banged_name(name);
item.insert_snippet(cap, snippet).lookup_by(lookup);
}
_ if needs_bang => {
- item.insert_text(banged_name(&escaped_name)).lookup_by(banged_name(&name));
+ item.insert_text(banged_name(&escaped_name)).lookup_by(banged_name(name));
}
_ => {
cov_mark::hit!(dont_insert_macro_call_parens_unnecessary);
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
index 5675dfb5c6ff2..124abb17b6a1c 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
@@ -31,13 +31,11 @@ pub(crate) fn render_struct_pat(
}
let name = local_name.unwrap_or_else(|| strukt.name(ctx.db()));
- let (name, escaped_name) = (
- name.unescaped().display(ctx.db()).to_smolstr(),
- name.display(ctx.db(), ctx.completion.edition).to_smolstr(),
- );
+ let (name, escaped_name) =
+ (name.as_str(), name.display(ctx.db(), ctx.completion.edition).to_smolstr());
let kind = strukt.kind(ctx.db());
- let label = format_literal_label(name.as_str(), kind, ctx.snippet_cap());
- let lookup = format_literal_lookup(name.as_str(), kind);
+ let label = format_literal_label(name, kind, ctx.snippet_cap());
+ let lookup = format_literal_lookup(name, kind);
let pat = render_pat(&ctx, pattern_ctx, &escaped_name, kind, &visible_fields, fields_omitted)?;
let db = ctx.db();
@@ -61,13 +59,13 @@ pub(crate) fn render_variant_pat(
let (name, escaped_name) = match path {
Some(path) => (
- path.unescaped().display(ctx.db()).to_string().into(),
- path.display(ctx.db(), ctx.completion.edition).to_string().into(),
+ path.display_verbatim(ctx.db()).to_smolstr(),
+ path.display(ctx.db(), ctx.completion.edition).to_smolstr(),
),
None => {
let name = local_name.unwrap_or_else(|| variant.name(ctx.db()));
let it = (
- name.unescaped().display(ctx.db()).to_smolstr(),
+ name.as_str().to_smolstr(),
name.display(ctx.db(), ctx.completion.edition).to_smolstr(),
);
it
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs
index 09eb19201c5b0..1b952f31360c2 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs
@@ -32,14 +32,11 @@ fn render(
let name = type_alias.name(db);
let (name, escaped_name) = if with_eq {
(
- SmolStr::from_iter([&name.unescaped().display(db).to_smolstr(), " = "]),
+ SmolStr::from_iter([&name.as_str().to_smolstr(), " = "]),
SmolStr::from_iter([&name.display_no_db(ctx.completion.edition).to_smolstr(), " = "]),
)
} else {
- (
- name.unescaped().display(db).to_smolstr(),
- name.display_no_db(ctx.completion.edition).to_smolstr(),
- )
+ (name.as_str().to_smolstr(), name.display_no_db(ctx.completion.edition).to_smolstr())
};
let detail = type_alias.display(db, ctx.completion.edition).to_string();
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs
index e053e299d903a..742036265211e 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs
@@ -23,12 +23,12 @@ pub(crate) fn render_union_literal(
let (qualified_name, escaped_qualified_name) = match path {
Some(p) => (
- p.unescaped().display(ctx.db()).to_string(),
- p.display(ctx.db(), ctx.completion.edition).to_string(),
+ p.display_verbatim(ctx.db()).to_smolstr(),
+ p.display(ctx.db(), ctx.completion.edition).to_smolstr(),
),
None => (
- name.unescaped().display(ctx.db()).to_string(),
- name.display(ctx.db(), ctx.completion.edition).to_string(),
+ name.as_str().to_smolstr(),
+ name.display(ctx.db(), ctx.completion.edition).to_smolstr(),
),
};
let label = format_literal_label(
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs b/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs
index 04bb178c658f3..866b83a614603 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs
@@ -164,7 +164,7 @@ impl Snippet {
}
fn import_edits(ctx: &CompletionContext<'_>, requires: &[ModPath]) -> Option> {
- let import_cfg = ctx.config.import_path_config();
+ let import_cfg = ctx.config.import_path_config(ctx.is_nightly);
let resolve = |import| {
let item = ctx.scope.resolve_mod_path(import).next()?;
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
index b7dbf0a6306c6..9d91f95eb65b8 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
@@ -87,6 +87,8 @@ pub(crate) const TEST_CONFIG: CompletionConfig<'_> = CompletionConfig {
fields_to_resolve: CompletionFieldsToResolve::empty(),
exclude_flyimport: vec![],
exclude_traits: &[],
+ enable_auto_await: true,
+ enable_auto_iter: true,
};
pub(crate) fn completion_list(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String {
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 e117dbf4bdf0b..663a038580d55 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
@@ -1965,3 +1965,24 @@ fn bar() {
"#]],
);
}
+
+#[test]
+fn doc_hidden_enum_variant() {
+ check(
+ r#"
+//- /foo.rs crate:foo
+pub enum Enum {
+ #[doc(hidden)] Hidden,
+ Visible,
+}
+
+//- /lib.rs crate:lib deps:foo
+fn foo() {
+ let _ = foo::Enum::$0;
+}
+ "#,
+ expect![[r#"
+ ev Visible Visible
+ "#]],
+ );
+}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs
index d491e438feffc..2e7c53def7fc5 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs
@@ -1390,6 +1390,41 @@ pub struct FooStruct {}
);
}
+#[test]
+fn flyimport_pattern_unstable_path() {
+ check(
+ r#"
+//- /main.rs crate:main deps:std
+fn function() {
+ let foo$0
+}
+//- /std.rs crate:std
+#[unstable]
+pub mod unstable {
+ pub struct FooStruct {}
+}
+"#,
+ expect![""],
+ );
+ check(
+ r#"
+//- toolchain:nightly
+//- /main.rs crate:main deps:std
+fn function() {
+ let foo$0
+}
+//- /std.rs crate:std
+#[unstable]
+pub mod unstable {
+ pub struct FooStruct {}
+}
+"#,
+ expect![[r#"
+ st FooStruct (use std::unstable::FooStruct)
+ "#]],
+ );
+}
+
#[test]
fn flyimport_pattern_unstable_item_on_nightly() {
check(
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs
index 04b3a47a64dab..593b1edde5cc5 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs
@@ -451,3 +451,20 @@ marco_rules! m { () => {} }
"#]],
);
}
+
+#[test]
+fn use_tree_doc_hidden() {
+ check(
+ r#"
+//- /foo.rs crate:foo
+#[doc(hidden)] pub struct Hidden;
+pub struct Visible;
+
+//- /lib.rs crate:lib deps:foo
+use foo::$0;
+ "#,
+ expect![[r#"
+ st Visible Visible
+ "#]],
+ );
+}
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 49d26dfe25c12..d12bda0816fd3 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
@@ -794,7 +794,7 @@ impl NameRefClass {
hir::AssocItem::TypeAlias(it) => Some(it),
_ => None,
})
- .find(|alias| alias.name(sema.db).eq_ident(name_ref.text().as_str()))
+ .find(|alias| alias.name(sema.db).as_str() == name_ref.text().trim_start_matches("r#"))
{
// No substitution, this can only occur in type position.
return Some(NameRefClass::Definition(Definition::TypeAlias(ty), None));
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs
index 9e3506d6f53b7..2f4d07446f2c1 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs
@@ -46,6 +46,10 @@ impl FamousDefs<'_, '_> {
self.find_trait("core:cmp:Ord")
}
+ pub fn core_convert_FromStr(&self) -> Option {
+ self.find_trait("core:str:FromStr")
+ }
+
pub fn core_convert_From(&self) -> Option {
self.find_trait("core:convert:From")
}
@@ -54,6 +58,14 @@ impl FamousDefs<'_, '_> {
self.find_trait("core:convert:Into")
}
+ pub fn core_convert_TryFrom(&self) -> Option {
+ self.find_trait("core:convert:TryFrom")
+ }
+
+ pub fn core_convert_TryInto(&self) -> Option {
+ self.find_trait("core:convert:TryInto")
+ }
+
pub fn core_convert_Index(&self) -> Option {
self.find_trait("core:ops:Index")
}
@@ -130,6 +142,13 @@ impl FamousDefs<'_, '_> {
self.find_macro("core:unimplemented")
}
+ pub fn core_fmt_Display(&self) -> Option {
+ self.find_trait("core:fmt:Display")
+ }
+
+ pub fn alloc_string_ToString(&self) -> Option {
+ self.find_trait("alloc:string:ToString")
+ }
pub fn builtin_crates(&self) -> impl Iterator
- {
IntoIterator::into_iter([
self.std(),
@@ -202,14 +221,15 @@ impl FamousDefs<'_, '_> {
for segment in path {
module = module.children(db).find_map(|child| {
let name = child.name(db)?;
- if name.eq_ident(segment) {
+ if name.as_str() == segment {
Some(child)
} else {
None
}
})?;
}
- let def = module.scope(db, None).into_iter().find(|(name, _def)| name.eq_ident(trait_))?.1;
+ let def =
+ module.scope(db, None).into_iter().find(|(name, _def)| name.as_str() == trait_)?.1;
Some(def)
}
}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
index a045c22c2dff1..f045e44dd318b 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
@@ -319,6 +319,7 @@ impl Ctx<'_> {
prefer_no_std: false,
prefer_prelude: true,
prefer_absolute: false,
+ allow_unstable: true,
};
let found_path = self.target_module.find_path(
self.source_scope.db.upcast(),
@@ -378,6 +379,7 @@ impl Ctx<'_> {
prefer_no_std: false,
prefer_prelude: true,
prefer_absolute: false,
+ allow_unstable: true,
};
let found_path =
self.target_module.find_path(self.source_scope.db.upcast(), def, cfg)?;
@@ -417,6 +419,7 @@ impl Ctx<'_> {
prefer_no_std: false,
prefer_prelude: true,
prefer_absolute: false,
+ allow_unstable: true,
};
let found_path = self.target_module.find_path(
self.source_scope.db.upcast(),
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 42efbd68e33d3..59914bedde434 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
@@ -263,13 +263,12 @@ fn rename_mod(
// - Module has submodules defined in separate files
let dir_paths = match (is_mod_rs, has_detached_child, module.name(sema.db)) {
// Go up one level since the anchor is inside the dir we're trying to rename
- (true, _, Some(mod_name)) => Some((
- format!("../{}", mod_name.unescaped().display(sema.db)),
- format!("../{new_name}"),
- )),
+ (true, _, Some(mod_name)) => {
+ Some((format!("../{}", mod_name.as_str()), format!("../{new_name}")))
+ }
// The anchor is on the same level as target dir
(false, true, Some(mod_name)) => {
- Some((mod_name.unescaped().display(sema.db).to_string(), new_name.to_owned()))
+ Some((mod_name.as_str().to_owned(), new_name.to_owned()))
}
_ => None,
};
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
index a75aba137be6c..7fc563a424104 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
@@ -625,7 +625,7 @@ impl<'a> FindUsages<'a> {
let _p = tracing::info_span!("collect_possible_aliases").entered();
let db = sema.db;
- let container_name = container.name(db).unescaped().display(db).to_smolstr();
+ let container_name = container.name(db).as_str().to_smolstr();
let search_scope = Definition::from(container).search_scope(db);
let mut seen = FxHashSet::default();
let mut completed = FxHashSet::default();
@@ -925,12 +925,8 @@ impl<'a> FindUsages<'a> {
.or_else(|| ty.as_builtin().map(|builtin| builtin.name()))
})
};
- // We need to unescape the name in case it is written without "r#" in earlier
- // editions of Rust where it isn't a keyword.
- self.def
- .name(sema.db)
- .or_else(self_kw_refs)
- .map(|it| it.unescaped().display(sema.db).to_smolstr())
+ // We need to search without the `r#`, hence `as_str` access.
+ self.def.name(sema.db).or_else(self_kw_refs).map(|it| it.as_str().to_smolstr())
}
};
let name = match &name {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
index c94644eeb89be..e5ce10a771ef9 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
@@ -143,7 +143,7 @@ fn library_symbols(db: &dyn SymbolsDatabase, source_root_id: SourceRootId) -> Ar
fn module_symbols(db: &dyn SymbolsDatabase, module: Module) -> Arc {
let _p = tracing::info_span!("module_symbols").entered();
- Arc::new(SymbolIndex::new(SymbolCollector::collect_module(db.upcast(), module)))
+ Arc::new(SymbolIndex::new(SymbolCollector::new_module(db.upcast(), module)))
}
pub fn crate_symbols(db: &dyn SymbolsDatabase, krate: Crate) -> Box<[Arc]> {
@@ -284,13 +284,15 @@ impl SymbolIndex {
builder.insert(key, value).unwrap();
}
- // FIXME: fst::Map should ideally have a way to shrink the backing buffer without the unwrap dance
- let map = fst::Map::new({
- let mut buf = builder.into_inner().unwrap();
- buf.shrink_to_fit();
- buf
- })
- .unwrap();
+ let map = builder
+ .into_inner()
+ .and_then(|mut buf| {
+ fst::Map::new({
+ buf.shrink_to_fit();
+ buf
+ })
+ })
+ .unwrap();
SymbolIndex { symbols, map }
}
@@ -491,7 +493,7 @@ pub(self) use crate::Trait as IsThisJustATrait;
.modules(&db)
.into_iter()
.map(|module_id| {
- let mut symbols = SymbolCollector::collect_module(&db, module_id);
+ let mut symbols = SymbolCollector::new_module(&db, module_id);
symbols.sort_by_key(|it| it.name.as_str().to_owned());
(module_id, symbols)
})
@@ -518,7 +520,7 @@ struct Duplicate;
.modules(&db)
.into_iter()
.map(|module_id| {
- let mut symbols = SymbolCollector::collect_module(&db, module_id);
+ let mut symbols = SymbolCollector::new_module(&db, module_id);
symbols.sort_by_key(|it| it.name.as_str().to_owned());
(module_id, symbols)
})
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
index 557c95f704b98..0a7141c19b6b5 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
@@ -31,6 +31,12 @@ const USELESS_NAME_PREFIXES: &[&str] = &["from_", "with_", "into_"];
/// `Result` -> `User`
const WRAPPER_TYPES: &[&str] = &["Box", "Arc", "Rc", "Option", "Result"];
+/// Generic types replaced by a plural of their first argument.
+///
+/// # Examples
+/// `Vec` -> "names"
+const SEQUENCE_TYPES: &[&str] = &["Vec", "VecDeque", "LinkedList"];
+
/// Prefixes to strip from methods names
///
/// # Examples
@@ -378,6 +384,11 @@ fn name_of_type(ty: &hir::Type, db: &RootDatabase, edition: Edition) -> Option
Option, db: &RootDatabase, edition: Edition) -> SmolStr {
+ let items_str = SmolStr::new_static("items");
+ let Some(inner_ty) = inner_ty else {
+ return items_str;
+ };
+ let Some(name) = name_of_type(inner_ty, db, edition) else {
+ return items_str;
+ };
+
+ if name.ends_with(['s', 'x', 'y']) {
+ // Given a type called e.g. "Boss", "Fox" or "Story", don't try to
+ // create a plural.
+ items_str
+ } else {
+ SmolStr::new(format!("{name}s"))
+ }
+}
+
fn trait_name(trait_: &hir::Trait, db: &RootDatabase, edition: Edition) -> Option {
let name = trait_.name(db).display(db, edition).to_string();
if USELESS_TRAITS.contains(&name.as_str()) {
@@ -897,6 +928,58 @@ fn foo() { $0(bar())$0; }
);
}
+ #[test]
+ fn vec_value() {
+ check(
+ r#"
+struct Vec {};
+struct Seed;
+fn bar() -> Vec {}
+fn foo() { $0(bar())$0; }
+"#,
+ "seeds",
+ );
+ }
+
+ #[test]
+ fn vec_value_ends_with_s() {
+ check(
+ r#"
+struct Vec {};
+struct Boss;
+fn bar() -> Vec {}
+fn foo() { $0(bar())$0; }
+"#,
+ "items",
+ );
+ }
+
+ #[test]
+ fn vecdeque_value() {
+ check(
+ r#"
+struct VecDeque {};
+struct Seed;
+fn bar() -> VecDeque {}
+fn foo() { $0(bar())$0; }
+"#,
+ "seeds",
+ );
+ }
+
+ #[test]
+ fn slice_value() {
+ check(
+ r#"
+struct Vec {};
+struct Seed;
+fn bar() -> &[Seed] {}
+fn foo() { $0(bar())$0; }
+"#,
+ "seeds",
+ );
+ }
+
#[test]
fn ref_call() {
check(
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
index 535777dfcbea6..7dce95592b819 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
+++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
@@ -1007,6 +1007,39 @@
is_alias: false,
is_assoc: false,
},
+ FileSymbol {
+ name: "ThisStruct",
+ def: Adt(
+ Struct(
+ Struct {
+ id: StructId(
+ 4,
+ ),
+ },
+ ),
+ ),
+ loc: DeclarationLocation {
+ hir_file_id: EditionedFileId(
+ FileId(
+ 1,
+ ),
+ Edition2021,
+ ),
+ ptr: SyntaxNodePtr {
+ kind: USE_TREE,
+ range: 85..125,
+ },
+ name_ptr: AstPtr(
+ SyntaxNodePtr {
+ kind: NAME,
+ range: 115..125,
+ },
+ ),
+ },
+ container_name: None,
+ is_alias: false,
+ is_assoc: false,
+ },
],
),
]
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs b/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs
index 515bc418cb467..2fdd8358637df 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs
@@ -26,7 +26,7 @@ impl TryEnum {
_ => return None,
};
TryEnum::ALL.iter().find_map(|&var| {
- if enum_.name(sema.db).eq_ident(var.type_name()) {
+ if enum_.name(sema.db).as_str() == var.type_name() {
return Some(var);
}
None
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
index dca889d1a8efe..f22041ebe233b 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
@@ -147,6 +147,7 @@ pub(crate) fn json_in_items(
prefer_no_std: config.prefer_no_std,
prefer_prelude: config.prefer_prelude,
prefer_absolute: config.prefer_absolute,
+ allow_unstable: true,
};
if !scope_has("Serialize") {
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 fd1044e51bc23..938b7182bc946 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
@@ -128,6 +128,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option, d: &hir::TypedHole) -> Option
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
+ allow_unstable: ctx.is_nightly,
},
ctx.edition,
)
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 13591dfb2eebd..f3109b9bb73a2 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
@@ -112,7 +112,7 @@ fn fixes(
// shouldn't occur
_ => continue 'crates,
};
- match current.children.iter().find(|(name, _)| name.eq_ident(seg)) {
+ match current.children.iter().find(|(name, _)| name.as_str() == seg) {
Some((_, &child)) => current = &crate_def_map[child],
None => continue 'crates,
}
@@ -161,7 +161,7 @@ fn fixes(
// try finding a parent that has an inline tree from here on
let mut current = module;
for s in stack.iter().rev() {
- match module.children.iter().find(|(name, _)| name.eq_ident(s)) {
+ match module.children.iter().find(|(name, _)| name.as_str() == s) {
Some((_, child)) => {
current = &crate_def_map[*child];
}
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 1e99d7ad6e68a..50c91a69602c1 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -83,7 +83,7 @@ use either::Either;
use hir::{db::ExpandDatabase, diagnostics::AnyDiagnostic, Crate, HirFileId, InFile, Semantics};
use ide_db::{
assists::{Assist, AssistId, AssistKind, AssistResolveStrategy},
- base_db::SourceDatabase,
+ base_db::{ReleaseChannel, SourceDatabase},
generated::lints::{Lint, LintGroup, CLIPPY_LINT_GROUPS, DEFAULT_LINTS, DEFAULT_LINT_GROUPS},
imports::insert_use::InsertUseConfig,
label::Label,
@@ -276,6 +276,7 @@ struct DiagnosticsContext<'a> {
sema: Semantics<'a, RootDatabase>,
resolve: &'a AssistResolveStrategy,
edition: Edition,
+ is_nightly: bool,
}
impl DiagnosticsContext<'_> {
@@ -368,7 +369,11 @@ pub fn semantic_diagnostics(
let module = sema.file_to_module_def(file_id);
- let ctx = DiagnosticsContext { config, sema, resolve, edition: file_id.edition() };
+ let is_nightly = matches!(
+ module.and_then(|m| db.toolchain_channel(m.krate().into())),
+ Some(ReleaseChannel::Nightly) | None
+ );
+ let ctx = DiagnosticsContext { config, sema, resolve, edition: file_id.edition(), is_nightly };
let mut diags = Vec::new();
match module {
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
index 4edc3633fbe65..4bead14e31d4d 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
@@ -673,6 +673,7 @@ impl Match {
prefer_no_std: false,
prefer_prelude: true,
prefer_absolute: false,
+ allow_unstable: true,
};
let mod_path = module.find_path(sema.db, module_def, cfg).ok_or_else(|| {
match_error!("Failed to render template path `{}` at match location")
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 bc9843f3f35a2..cfd8919730ad2 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
@@ -413,8 +413,7 @@ fn rewrite_url_link(db: &RootDatabase, def: Definition, target: &str) -> Option<
fn mod_path_of_def(db: &RootDatabase, def: Definition) -> Option {
def.canonical_module_path(db).map(|it| {
let mut path = String::new();
- it.flat_map(|it| it.name(db))
- .for_each(|name| format_to!(path, "{}/", name.unescaped().display(db)));
+ it.flat_map(|it| it.name(db)).for_each(|name| format_to!(path, "{}/", name.as_str()));
path
})
}
@@ -590,10 +589,10 @@ fn filename_and_frag_for_def(
let res = match def {
Definition::Adt(adt) => match adt {
Adt::Struct(s) => {
- format!("struct.{}.html", s.name(db).unescaped().display(db.upcast()))
+ format!("struct.{}.html", s.name(db).as_str())
}
- Adt::Enum(e) => format!("enum.{}.html", e.name(db).unescaped().display(db.upcast())),
- Adt::Union(u) => format!("union.{}.html", u.name(db).unescaped().display(db.upcast())),
+ Adt::Enum(e) => format!("enum.{}.html", e.name(db).as_str()),
+ Adt::Union(u) => format!("union.{}.html", u.name(db).as_str()),
},
Definition::Crate(_) => String::from("index.html"),
Definition::Module(m) => match m.name(db) {
@@ -603,48 +602,48 @@ fn filename_and_frag_for_def(
Some(kw) => {
format!("keyword.{}.html", kw)
}
- None => format!("{}/index.html", name.unescaped().display(db.upcast())),
+ None => format!("{}/index.html", name.as_str()),
}
}
None => String::from("index.html"),
},
Definition::Trait(t) => {
- format!("trait.{}.html", t.name(db).unescaped().display(db.upcast()))
+ format!("trait.{}.html", t.name(db).as_str())
}
Definition::TraitAlias(t) => {
- format!("traitalias.{}.html", t.name(db).unescaped().display(db.upcast()))
+ format!("traitalias.{}.html", t.name(db).as_str())
}
Definition::TypeAlias(t) => {
- format!("type.{}.html", t.name(db).unescaped().display(db.upcast()))
+ format!("type.{}.html", t.name(db).as_str())
}
Definition::BuiltinType(t) => {
- format!("primitive.{}.html", t.name().unescaped().display(db.upcast()))
+ format!("primitive.{}.html", t.name().as_str())
}
Definition::Function(f) => {
- format!("fn.{}.html", f.name(db).unescaped().display(db.upcast()))
+ format!("fn.{}.html", f.name(db).as_str())
}
Definition::Variant(ev) => {
format!(
"enum.{}.html#variant.{}",
- ev.parent_enum(db).name(db).unescaped().display(db.upcast()),
- ev.name(db).unescaped().display(db.upcast())
+ ev.parent_enum(db).name(db).as_str(),
+ ev.name(db).as_str()
)
}
Definition::Const(c) => {
- format!("const.{}.html", c.name(db)?.unescaped().display(db.upcast()))
+ format!("const.{}.html", c.name(db)?.as_str())
}
Definition::Static(s) => {
- format!("static.{}.html", s.name(db).unescaped().display(db.upcast()))
+ format!("static.{}.html", s.name(db).as_str())
}
Definition::Macro(mac) => match mac.kind(db) {
hir::MacroKind::Declarative
| hir::MacroKind::BuiltIn
| hir::MacroKind::Attr
| hir::MacroKind::ProcMacro => {
- format!("macro.{}.html", mac.name(db).unescaped().display(db.upcast()))
+ format!("macro.{}.html", mac.name(db).as_str())
}
hir::MacroKind::Derive => {
- format!("derive.{}.html", mac.name(db).unescaped().display(db.upcast()))
+ format!("derive.{}.html", mac.name(db).as_str())
}
},
Definition::Field(field) => {
@@ -654,11 +653,7 @@ fn filename_and_frag_for_def(
hir::VariantDef::Variant(it) => Definition::Variant(it),
};
let (_, file, _) = filename_and_frag_for_def(db, def)?;
- return Some((
- def,
- file,
- Some(format!("structfield.{}", field.name(db).unescaped().display(db.upcast()))),
- ));
+ return Some((def, file, Some(format!("structfield.{}", field.name(db).as_str()))));
}
Definition::SelfType(impl_) => {
let adt = impl_.self_ty(db).as_adt()?.into();
@@ -667,7 +662,7 @@ fn filename_and_frag_for_def(
return Some((adt, file, Some(String::from("impl"))));
}
Definition::ExternCrateDecl(it) => {
- format!("{}/index.html", it.name(db).unescaped().display(db.upcast()))
+ format!("{}/index.html", it.name(db).as_str())
}
Definition::Local(_)
| Definition::GenericParam(_)
@@ -699,16 +694,16 @@ fn get_assoc_item_fragment(db: &dyn HirDatabase, assoc_item: hir::AssocItem) ->
// Rustdoc makes this decision based on whether a method 'has defaultness'.
// Currently this is only the case for provided trait methods.
if is_trait_method && !function.has_body(db) {
- format!("tymethod.{}", function.name(db).unescaped().display(db.upcast()))
+ format!("tymethod.{}", function.name(db).as_str())
} else {
- format!("method.{}", function.name(db).unescaped().display(db.upcast()))
+ format!("method.{}", function.name(db).as_str())
}
}
AssocItem::Const(constant) => {
- format!("associatedconstant.{}", constant.name(db)?.unescaped().display(db.upcast()))
+ format!("associatedconstant.{}", constant.name(db)?.as_str())
}
AssocItem::TypeAlias(ty) => {
- format!("associatedtype.{}", ty.name(db).unescaped().display(db.upcast()))
+ format!("associatedtype.{}", ty.name(db).as_str())
}
})
}
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 f804cc3677274..d18732a6b846b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -5,10 +5,14 @@ use crate::{
navigation_target::{self, ToNav},
FilePosition, NavigationTarget, RangeInfo, TryToNav, UpmappingResult,
};
-use hir::{AsAssocItem, AssocItem, FileRange, InFile, MacroFileIdExt, ModuleDef, Semantics};
+use hir::{
+ sym, AsAssocItem, AssocItem, CallableKind, FileRange, HasCrate, InFile, MacroFileIdExt,
+ ModuleDef, Semantics,
+};
use ide_db::{
base_db::{AnchoredPath, FileLoader, SourceDatabase},
defs::{Definition, IdentClass},
+ famous_defs::FamousDefs,
helpers::pick_best_token,
RootDatabase, SymbolKind,
};
@@ -129,15 +133,74 @@ pub(crate) fn goto_definition(
Some(RangeInfo::new(original_token.text_range(), navs))
}
-// If the token is into(), try_into(), parse(), search the definition of From, TryFrom, FromStr.
+// If the token is into(), try_into(), search the definition of From, TryFrom.
fn find_definition_for_known_blanket_dual_impls(
sema: &Semantics<'_, RootDatabase>,
original_token: &SyntaxToken,
) -> Option> {
let method_call = ast::MethodCallExpr::cast(original_token.parent()?.parent()?)?;
- let target_method = sema.resolve_known_blanket_dual_impls(&method_call)?;
+ let callable = sema.resolve_method_call_as_callable(&method_call)?;
+ let CallableKind::Function(f) = callable.kind() else { return None };
+ let assoc = f.as_assoc_item(sema.db)?;
+
+ let return_type = callable.return_type();
+ let fd = FamousDefs(sema, return_type.krate(sema.db));
+
+ let t = match assoc.container(sema.db) {
+ hir::AssocItemContainer::Trait(t) => t,
+ hir::AssocItemContainer::Impl(impl_)
+ if impl_.self_ty(sema.db).is_str() && f.name(sema.db) == sym::parse =>
+ {
+ let t = fd.core_convert_FromStr()?;
+ let t_f = t.function(sema.db, &sym::from_str)?;
+ return sema
+ .resolve_trait_impl_method(
+ return_type.clone(),
+ t,
+ t_f,
+ [return_type.type_arguments().next()?],
+ )
+ .map(|f| def_to_nav(sema.db, f.into()));
+ }
+ hir::AssocItemContainer::Impl(_) => return None,
+ };
- let def = Definition::from(target_method);
+ let fn_name = f.name(sema.db);
+ let f = if fn_name == sym::into && fd.core_convert_Into() == Some(t) {
+ let dual = fd.core_convert_From()?;
+ let dual_f = dual.function(sema.db, &sym::from)?;
+ sema.resolve_trait_impl_method(
+ return_type.clone(),
+ dual,
+ dual_f,
+ [return_type, callable.receiver_param(sema.db)?.1],
+ )?
+ } else if fn_name == sym::try_into && fd.core_convert_TryInto() == Some(t) {
+ let dual = fd.core_convert_TryFrom()?;
+ let dual_f = dual.function(sema.db, &sym::try_from)?;
+ sema.resolve_trait_impl_method(
+ return_type.clone(),
+ dual,
+ dual_f,
+ // Extract the `T` from `Result`
+ [return_type.type_arguments().next()?, callable.receiver_param(sema.db)?.1],
+ )?
+ } else if fn_name == sym::to_string && fd.alloc_string_ToString() == Some(t) {
+ let dual = fd.core_fmt_Display()?;
+ let dual_f = dual.function(sema.db, &sym::fmt)?;
+ sema.resolve_trait_impl_method(
+ return_type.clone(),
+ dual,
+ dual_f,
+ [callable.receiver_param(sema.db)?.1.strip_reference()],
+ )?
+ } else {
+ return None;
+ };
+ // Assert that we got a trait impl function, if we are back in a trait definition we didn't
+ // succeed
+ let _t = f.as_assoc_item(sema.db)?.implemented_trait(sema.db)?;
+ let def = Definition::from(f);
Some(def_to_nav(sema.db, def))
}
@@ -3168,18 +3231,45 @@ fn f() {
r#"
//- minicore: from, str
struct A;
-
impl FromStr for A {
type Error = String;
-
fn from_str(value: &str) -> Result {
//^^^^^^^^
Ok(A)
}
}
-
fn f() {
let a: Result = "aaaaaa".parse$0();
+}
+ "#,
+ );
+ }
+
+ #[test]
+ fn to_string_call_to_display_definition() {
+ check(
+ r#"
+//- minicore:fmt
+//- /alloc.rs crate:alloc
+pub mod string {
+ pub struct String;
+ pub trait ToString {
+ fn to_string(&self) -> String;
+ }
+
+ impl ToString for T {
+ fn to_string(&self) -> String { String }
+ }
+}
+//- /lib.rs crate:lib deps:alloc
+use alloc::string::ToString;
+struct A;
+impl core::fmt::Display for A {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {}
+ // ^^^
+}
+fn f() {
+ A.to_string$0();
}
"#,
);
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index 18a3fed07ece1..9d4c103fc2e01 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -346,7 +346,7 @@ fn hover_offset(
.unique()
.reduce(|mut acc: HoverResult, HoverResult { markup, actions }| {
acc.actions.extend(actions);
- acc.markup = Markup::from(format!("{}\n---\n{markup}", acc.markup));
+ acc.markup = Markup::from(format!("{}\n\n---\n{markup}", acc.markup));
acc
})
.map(|mut res: HoverResult| {
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 46242b75dd0b9..40f3406b72d37 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -1082,7 +1082,19 @@ fn render_memory_layout(
if config.niches {
if let Some(niches) = layout.niches() {
- format_to!(label, "niches = {niches}, ");
+ if niches > 1024 {
+ if niches.is_power_of_two() {
+ format_to!(label, "niches = 2{}, ", pwr2_to_exponent(niches));
+ } else if is_pwr2plus1(niches) {
+ format_to!(label, "niches = 2{} + 1, ", pwr2_to_exponent(niches - 1));
+ } else if is_pwr2minus1(niches) {
+ format_to!(label, "niches = 2{} - 1, ", pwr2_to_exponent(niches + 1));
+ } else {
+ format_to!(label, "niches = a lot, ");
+ }
+ } else {
+ format_to!(label, "niches = {niches}, ");
+ }
}
}
label.pop(); // ' '
@@ -1210,3 +1222,74 @@ fn render_dyn_compatibility(
}
}
}
+
+fn is_pwr2minus1(val: u128) -> bool {
+ val == u128::MAX || (val + 1).is_power_of_two()
+}
+
+fn is_pwr2plus1(val: u128) -> bool {
+ val != 0 && (val - 1).is_power_of_two()
+}
+
+/// Formats a power of two as an exponent of two, i.e. 16 => ⁴. Note that `num` MUST be a power
+/// of 2, or this function will panic.
+fn pwr2_to_exponent(num: u128) -> String {
+ const DIGITS: [char; 10] = ['⁰', '¹', '²', '³', '⁴', '⁵', '⁶', '⁷', '⁸', '⁹'];
+ assert_eq!(num.count_ones(), 1);
+ num.trailing_zeros()
+ .to_string()
+ .chars()
+ .map(|c| c.to_digit(10).unwrap() as usize)
+ .map(|idx| DIGITS[idx])
+ .collect::()
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ const TESTERS: [u128; 10] = [0, 1, 2, 3, 4, 255, 256, 257, u128::MAX - 1, u128::MAX];
+
+ #[test]
+ fn test_is_pwr2minus1() {
+ const OUTCOMES: [bool; 10] =
+ [true, true, false, true, false, true, false, false, false, true];
+ for (test, expected) in TESTERS.iter().zip(OUTCOMES) {
+ let actual = is_pwr2minus1(*test);
+ assert_eq!(actual, expected, "is_pwr2minu1({test}) gave {actual}, expected {expected}");
+ }
+ }
+
+ #[test]
+ fn test_is_pwr2plus1() {
+ const OUTCOMES: [bool; 10] =
+ [false, false, true, true, false, false, false, true, false, false];
+ for (test, expected) in TESTERS.iter().zip(OUTCOMES) {
+ let actual = is_pwr2plus1(*test);
+ assert_eq!(actual, expected, "is_pwr2plus1({test}) gave {actual}, expected {expected}");
+ }
+ }
+
+ #[test]
+ fn test_pwr2_to_exponent() {
+ const TESTERS: [u128; 9] = [
+ 1,
+ 2,
+ 4,
+ 8,
+ 16,
+ 9223372036854775808,
+ 18446744073709551616,
+ 36893488147419103232,
+ 170141183460469231731687303715884105728,
+ ];
+ const OUTCOMES: [&str; 9] = ["⁰", "¹", "²", "³", "⁴", "⁶³", "⁶⁴", "⁶⁵", "¹²⁷"];
+ for (test, expected) in TESTERS.iter().zip(OUTCOMES) {
+ let actual = pwr2_to_exponent(*test);
+ assert_eq!(
+ actual, expected,
+ "pwr2_to_exponent({test}) returned {actual}, expected {expected}",
+ );
+ }
+ }
+}
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 014b751f95b0c..8c32cc9720af4 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -303,6 +303,7 @@ m!(ab$0c);
---
Outer
+
---
```rust
@@ -1357,7 +1358,7 @@ fn hover_enum_limit() {
---
- size = 12 (0xC), align = 4, niches = 4294967288
+ size = 12 (0xC), align = 4, niches = a lot
"#]],
);
}
@@ -4401,6 +4402,7 @@ fn main() {
---
size = 8, align = 8, niches = 1
+
---
```rust
@@ -10094,6 +10096,7 @@ fn bar() {
```rust
let field: i32
```
+
---
```rust
@@ -10128,6 +10131,7 @@ fn bar() {
---
size = 4, align = 4
+
---
```rust
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
index 6d83a747d7669..1f723c85df7aa 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -209,7 +209,7 @@ fn hints(
) {
closing_brace::hints(hints, sema, config, file_id, node.clone());
if let Some(any_has_generic_args) = ast::AnyHasGenericArgs::cast(node.clone()) {
- generic_param::hints(hints, sema, config, any_has_generic_args);
+ generic_param::hints(hints, famous_defs, config, any_has_generic_args);
}
match_ast! {
@@ -300,22 +300,23 @@ pub struct InlayHintsConfig {
pub closing_brace_hints_min_lines: Option,
pub fields_to_resolve: InlayFieldsToResolve,
}
+
impl InlayHintsConfig {
- fn lazy_text_edit(&self, finish: impl FnOnce() -> TextEdit) -> Lazy {
+ fn lazy_text_edit(&self, finish: impl FnOnce() -> TextEdit) -> LazyProperty {
if self.fields_to_resolve.resolve_text_edits {
- Lazy::Lazy
+ LazyProperty::Lazy
} else {
let edit = finish();
never!(edit.is_empty(), "inlay hint produced an empty text edit");
- Lazy::Computed(edit)
+ LazyProperty::Computed(edit)
}
}
- fn lazy_tooltip(&self, finish: impl FnOnce() -> InlayTooltip) -> Lazy {
+ fn lazy_tooltip(&self, finish: impl FnOnce() -> InlayTooltip) -> LazyProperty {
if self.fields_to_resolve.resolve_hint_tooltip
&& self.fields_to_resolve.resolve_label_tooltip
{
- Lazy::Lazy
+ LazyProperty::Lazy
} else {
let tooltip = finish();
never!(
@@ -326,7 +327,20 @@ impl InlayHintsConfig {
.is_empty(),
"inlay hint produced an empty tooltip"
);
- Lazy::Computed(tooltip)
+ LazyProperty::Computed(tooltip)
+ }
+ }
+
+ /// This always reports a resolvable location, so only use this when it is very likely for a
+ /// location link to actually resolve but where computing `finish` would be costly.
+ fn lazy_location_opt(
+ &self,
+ finish: impl FnOnce() -> Option,
+ ) -> Option> {
+ if self.fields_to_resolve.resolve_label_location {
+ Some(LazyProperty::Lazy)
+ } else {
+ finish().map(LazyProperty::Computed)
}
}
}
@@ -441,7 +455,7 @@ pub struct InlayHint {
/// The actual label to show in the inlay hint.
pub label: InlayHintLabel,
/// Text edit to apply when "accepting" this inlay hint.
- pub text_edit: Option>,
+ pub text_edit: Option>,
/// Range to recompute inlay hints when trying to resolve for this hint. If this is none, the
/// hint does not support resolving.
pub resolve_parent: Option,
@@ -449,15 +463,15 @@ pub struct InlayHint {
/// A type signaling that a value is either computed, or is available for computation.
#[derive(Clone, Debug)]
-pub enum Lazy {
+pub enum LazyProperty {
Computed(T),
Lazy,
}
-impl Lazy {
+impl LazyProperty {
pub fn computed(self) -> Option {
match self {
- Lazy::Computed(it) => Some(it),
+ LazyProperty::Computed(it) => Some(it),
_ => None,
}
}
@@ -508,8 +522,8 @@ pub struct InlayHintLabel {
impl InlayHintLabel {
pub fn simple(
s: impl Into,
- tooltip: Option>,
- linked_location: Option,
+ tooltip: Option>,
+ linked_location: Option>,
) -> InlayHintLabel {
InlayHintLabel {
parts: smallvec![InlayHintLabelPart { text: s.into(), linked_location, tooltip }],
@@ -593,16 +607,16 @@ pub struct InlayHintLabelPart {
/// refers to (not necessarily the location itself).
/// When setting this, no tooltip must be set on the containing hint, or VS Code will display
/// them both.
- pub linked_location: Option,
+ pub linked_location: Option>,
/// The tooltip to show when hovering over the inlay hint, this may invoke other actions like
/// hover requests to show.
- pub tooltip: Option>,
+ pub tooltip: Option>,
}
impl std::hash::Hash for InlayHintLabelPart {
fn hash(&self, state: &mut H) {
self.text.hash(state);
- self.linked_location.hash(state);
+ self.linked_location.is_some().hash(state);
self.tooltip.is_some().hash(state);
}
}
@@ -610,7 +624,9 @@ impl std::hash::Hash for InlayHintLabelPart {
impl fmt::Debug for InlayHintLabelPart {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
- Self { text, linked_location: None, tooltip: None | Some(Lazy::Lazy) } => text.fmt(f),
+ Self { text, linked_location: None, tooltip: None | Some(LazyProperty::Lazy) } => {
+ text.fmt(f)
+ }
Self { text, linked_location, tooltip } => f
.debug_struct("InlayHintLabelPart")
.field("text", text)
@@ -618,8 +634,10 @@ impl fmt::Debug for InlayHintLabelPart {
.field(
"tooltip",
&tooltip.as_ref().map_or("", |it| match it {
- Lazy::Computed(InlayTooltip::String(it) | InlayTooltip::Markdown(it)) => it,
- Lazy::Lazy => "",
+ LazyProperty::Computed(
+ InlayTooltip::String(it) | InlayTooltip::Markdown(it),
+ ) => it,
+ LazyProperty::Lazy => "",
}),
)
.finish(),
@@ -632,7 +650,8 @@ struct InlayHintLabelBuilder<'a> {
db: &'a RootDatabase,
result: InlayHintLabel,
last_part: String,
- location: Option,
+ resolve: bool,
+ location: Option>,
}
impl fmt::Write for InlayHintLabelBuilder<'_> {
@@ -645,11 +664,16 @@ impl HirWrite for InlayHintLabelBuilder<'_> {
fn start_location_link(&mut self, def: ModuleDefId) {
never!(self.location.is_some(), "location link is already started");
self.make_new_part();
- let Some(location) = ModuleDef::from(def).try_to_nav(self.db) else { return };
- let location = location.call_site();
- let location =
- FileRange { file_id: location.file_id, range: location.focus_or_full_range() };
- self.location = Some(location);
+
+ self.location = Some(if self.resolve {
+ LazyProperty::Lazy
+ } else {
+ LazyProperty::Computed({
+ let Some(location) = ModuleDef::from(def).try_to_nav(self.db) else { return };
+ let location = location.call_site();
+ FileRange { file_id: location.file_id, range: location.focus_or_full_range() }
+ })
+ });
}
fn end_location_link(&mut self) {
@@ -735,6 +759,7 @@ fn label_of_ty(
last_part: String::new(),
location: None,
result: InlayHintLabel::default(),
+ resolve: config.fields_to_resolve.resolve_label_location,
};
let _ = rec(sema, famous_defs, config.max_length, ty, &mut label_builder, config, edition);
let r = label_builder.finish();
@@ -783,7 +808,7 @@ fn ty_to_text_edit(
ty: &hir::Type,
offset_to_insert: TextSize,
prefix: impl Into,
-) -> Option> {
+) -> Option> {
// FIXME: Limit the length and bail out on excess somehow?
let rendered = sema
.scope(node_for_hint)
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
index ab5464156f0a7..01a1a4545c478 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
@@ -1203,6 +1203,40 @@ fn f5>(it: G) {
let l = it.f();
//^ ()
}
+"#,
+ );
+ }
+
+ #[test]
+ fn regression_19007() {
+ check_types(
+ r#"
+trait Foo {
+ type Assoc;
+
+ fn foo(&self) -> Self::Assoc;
+}
+
+trait Bar {
+ type Target;
+}
+
+trait Baz {}
+
+struct Struct {
+ field: T,
+}
+
+impl Struct
+where
+ T: Foo,
+ T::Assoc: Baz<::Target> + Bar,
+{
+ fn f(&self) {
+ let x = self.field.foo();
+ //^ impl Baz<<::Assoc as Bar>::Target> + Bar
+ }
+}
"#,
);
}
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs
index 429ddd31cbd0a..e9b728bcaa75d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs
@@ -22,11 +22,7 @@ pub(super) fn hints(
return None;
}
- let linked_location =
- famous_defs.core_marker_Sized().and_then(|it| it.try_to_nav(sema.db)).map(|it| {
- let n = it.call_site();
- FileRange { file_id: n.file_id, range: n.focus_or_full_range() }
- });
+ let sized_trait = famous_defs.core_marker_Sized();
for param in params.type_or_const_params() {
match param {
@@ -48,7 +44,17 @@ pub(super) fn hints(
}
hint.parts.push(InlayHintLabelPart {
text: "Sized".to_owned(),
- linked_location,
+ linked_location: sized_trait.and_then(|it| {
+ config.lazy_location_opt(|| {
+ it.try_to_nav(sema.db).map(|it| {
+ let n = it.call_site();
+ FileRange {
+ file_id: n.file_id,
+ range: n.focus_or_full_range(),
+ }
+ })
+ })
+ }),
tooltip: None,
});
if has_bounds {
@@ -134,12 +140,14 @@ fn foo() {}
InlayHintLabelPart {
text: "Sized",
linked_location: Some(
- FileRangeWrapper {
- file_id: FileId(
- 1,
- ),
- range: 135..140,
- },
+ Computed(
+ FileRangeWrapper {
+ file_id: FileId(
+ 1,
+ ),
+ range: 135..140,
+ },
+ ),
),
tooltip: "",
},
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
index 7fa7ab1a94d63..8471547727fed 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
@@ -81,7 +81,10 @@ mod tests {
use crate::{
fixture,
- inlay_hints::tests::{check_expect, check_with_config, DISABLED_CONFIG, TEST_CONFIG},
+ inlay_hints::{
+ tests::{check_expect, check_with_config, DISABLED_CONFIG, TEST_CONFIG},
+ LazyProperty,
+ },
InlayHintsConfig,
};
@@ -99,7 +102,7 @@ mod tests {
let (analysis, file_id) = fixture::file(ra_fixture);
let mut inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap();
inlay_hints.iter_mut().flat_map(|hint| &mut hint.label.parts).for_each(|hint| {
- if let Some(loc) = &mut hint.linked_location {
+ if let Some(LazyProperty::Computed(loc)) = &mut hint.linked_location {
loc.range = TextRange::empty(TextSize::from(0));
}
});
@@ -134,12 +137,14 @@ fn main() {
InlayHintLabelPart {
text: "B",
linked_location: Some(
- FileRangeWrapper {
- file_id: FileId(
- 0,
- ),
- range: 63..64,
- },
+ Computed(
+ FileRangeWrapper {
+ file_id: FileId(
+ 0,
+ ),
+ range: 63..64,
+ },
+ ),
),
tooltip: "",
},
@@ -151,12 +156,14 @@ fn main() {
InlayHintLabelPart {
text: "A",
linked_location: Some(
- FileRangeWrapper {
- file_id: FileId(
- 0,
- ),
- range: 7..8,
- },
+ Computed(
+ FileRangeWrapper {
+ file_id: FileId(
+ 0,
+ ),
+ range: 7..8,
+ },
+ ),
),
tooltip: "",
},
@@ -213,12 +220,14 @@ fn main() {
InlayHintLabelPart {
text: "C",
linked_location: Some(
- FileRangeWrapper {
- file_id: FileId(
- 0,
- ),
- range: 51..52,
- },
+ Computed(
+ FileRangeWrapper {
+ file_id: FileId(
+ 0,
+ ),
+ range: 51..52,
+ },
+ ),
),
tooltip: "",
},
@@ -230,12 +239,14 @@ fn main() {
InlayHintLabelPart {
text: "B",
linked_location: Some(
- FileRangeWrapper {
- file_id: FileId(
- 0,
- ),
- range: 29..30,
- },
+ Computed(
+ FileRangeWrapper {
+ file_id: FileId(
+ 0,
+ ),
+ range: 29..30,
+ },
+ ),
),
tooltip: "",
},
@@ -276,12 +287,14 @@ fn main() {
InlayHintLabelPart {
text: "C",
linked_location: Some(
- FileRangeWrapper {
- file_id: FileId(
- 0,
- ),
- range: 51..52,
- },
+ Computed(
+ FileRangeWrapper {
+ file_id: FileId(
+ 0,
+ ),
+ range: 51..52,
+ },
+ ),
),
tooltip: "",
},
@@ -293,12 +306,14 @@ fn main() {
InlayHintLabelPart {
text: "B",
linked_location: Some(
- FileRangeWrapper {
- file_id: FileId(
- 0,
- ),
- range: 29..30,
- },
+ Computed(
+ FileRangeWrapper {
+ file_id: FileId(
+ 0,
+ ),
+ range: 29..30,
+ },
+ ),
),
tooltip: "",
},
@@ -340,12 +355,14 @@ fn main() {
InlayHintLabelPart {
text: "B",
linked_location: Some(
- FileRangeWrapper {
- file_id: FileId(
- 0,
- ),
- range: 23..24,
- },
+ Computed(
+ FileRangeWrapper {
+ file_id: FileId(
+ 0,
+ ),
+ range: 23..24,
+ },
+ ),
),
tooltip: "",
},
@@ -353,12 +370,14 @@ fn main() {
InlayHintLabelPart {
text: "X",
linked_location: Some(
- FileRangeWrapper {
- file_id: FileId(
- 0,
- ),
- range: 55..56,
- },
+ Computed(
+ FileRangeWrapper {
+ file_id: FileId(
+ 0,
+ ),
+ range: 55..56,
+ },
+ ),
),
tooltip: "",
},
@@ -371,12 +390,14 @@ fn main() {
InlayHintLabelPart {
text: "A",
linked_location: Some(
- FileRangeWrapper {
- file_id: FileId(
- 0,
- ),
- range: 7..8,
- },
+ Computed(
+ FileRangeWrapper {
+ file_id: FileId(
+ 0,
+ ),
+ range: 7..8,
+ },
+ ),
),
tooltip: "",
},
@@ -384,12 +405,14 @@ fn main() {
InlayHintLabelPart {
text: "X",
linked_location: Some(
- FileRangeWrapper {
- file_id: FileId(
- 0,
- ),
- range: 55..56,
- },
+ Computed(
+ FileRangeWrapper {
+ file_id: FileId(
+ 0,
+ ),
+ range: 55..56,
+ },
+ ),
),
tooltip: "",
},
@@ -435,12 +458,14 @@ fn main() {
InlayHintLabelPart {
text: "Iterator",
linked_location: Some(
- FileRangeWrapper {
- file_id: FileId(
- 1,
- ),
- range: 0..0,
- },
+ Computed(
+ FileRangeWrapper {
+ file_id: FileId(
+ 1,
+ ),
+ range: 0..0,
+ },
+ ),
),
tooltip: "",
},
@@ -448,12 +473,14 @@ fn main() {
InlayHintLabelPart {
text: "Item",
linked_location: Some(
- FileRangeWrapper {
- file_id: FileId(
- 1,
- ),
- range: 0..0,
- },
+ Computed(
+ FileRangeWrapper {
+ file_id: FileId(
+ 1,
+ ),
+ range: 0..0,
+ },
+ ),
),
tooltip: "",
},
@@ -467,12 +494,14 @@ fn main() {
InlayHintLabelPart {
text: "Iterator",
linked_location: Some(
- FileRangeWrapper {
- file_id: FileId(
- 1,
- ),
- range: 0..0,
- },
+ Computed(
+ FileRangeWrapper {
+ file_id: FileId(
+ 1,
+ ),
+ range: 0..0,
+ },
+ ),
),
tooltip: "",
},
@@ -480,12 +509,14 @@ fn main() {
InlayHintLabelPart {
text: "Item",
linked_location: Some(
- FileRangeWrapper {
- file_id: FileId(
- 1,
- ),
- range: 0..0,
- },
+ Computed(
+ FileRangeWrapper {
+ file_id: FileId(
+ 1,
+ ),
+ range: 0..0,
+ },
+ ),
),
tooltip: "",
},
@@ -499,12 +530,14 @@ fn main() {
InlayHintLabelPart {
text: "Iterator",
linked_location: Some(
- FileRangeWrapper {
- file_id: FileId(
- 1,
- ),
- range: 0..0,
- },
+ Computed(
+ FileRangeWrapper {
+ file_id: FileId(
+ 1,
+ ),
+ range: 0..0,
+ },
+ ),
),
tooltip: "",
},
@@ -512,12 +545,14 @@ fn main() {
InlayHintLabelPart {
text: "Item",
linked_location: Some(
- FileRangeWrapper {
- file_id: FileId(
- 1,
- ),
- range: 0..0,
- },
+ Computed(
+ FileRangeWrapper {
+ file_id: FileId(
+ 1,
+ ),
+ range: 0..0,
+ },
+ ),
),
tooltip: "",
},
@@ -531,12 +566,14 @@ fn main() {
InlayHintLabelPart {
text: "MyIter",
linked_location: Some(
- FileRangeWrapper {
- file_id: FileId(
- 0,
- ),
- range: 0..0,
- },
+ Computed(
+ FileRangeWrapper {
+ file_id: FileId(
+ 0,
+ ),
+ range: 0..0,
+ },
+ ),
),
tooltip: "",
},
@@ -577,12 +614,14 @@ fn main() {
InlayHintLabelPart {
text: "Struct",
linked_location: Some(
- FileRangeWrapper {
- file_id: FileId(
- 0,
- ),
- range: 7..13,
- },
+ Computed(
+ FileRangeWrapper {
+ file_id: FileId(
+ 0,
+ ),
+ range: 7..13,
+ },
+ ),
),
tooltip: "",
},
@@ -594,12 +633,14 @@ fn main() {
InlayHintLabelPart {
text: "Struct",
linked_location: Some(
- FileRangeWrapper {
- file_id: FileId(
- 0,
- ),
- range: 7..13,
- },
+ Computed(
+ FileRangeWrapper {
+ file_id: FileId(
+ 0,
+ ),
+ range: 7..13,
+ },
+ ),
),
tooltip: "",
},
@@ -611,12 +652,14 @@ fn main() {
InlayHintLabelPart {
text: "Struct",
linked_location: Some(
- FileRangeWrapper {
- file_id: FileId(
- 0,
- ),
- range: 7..13,
- },
+ Computed(
+ FileRangeWrapper {
+ file_id: FileId(
+ 0,
+ ),
+ range: 7..13,
+ },
+ ),
),
tooltip: "",
},
@@ -628,12 +671,14 @@ fn main() {
InlayHintLabelPart {
text: "self",
linked_location: Some(
- FileRangeWrapper {
- file_id: FileId(
- 0,
- ),
- range: 42..46,
- },
+ Computed(
+ FileRangeWrapper {
+ file_id: FileId(
+ 0,
+ ),
+ range: 42..46,
+ },
+ ),
),
tooltip: "",
},
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
index 90b8be64a46d2..3767d34e2c7a9 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
@@ -11,7 +11,10 @@ use syntax::{
match_ast, SyntaxKind, SyntaxNode, T,
};
-use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind};
+use crate::{
+ inlay_hints::LazyProperty, InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig,
+ InlayKind,
+};
pub(super) fn hints(
acc: &mut Vec,
@@ -141,7 +144,7 @@ pub(super) fn hints(
acc.push(InlayHint {
range: closing_token.text_range(),
kind: InlayKind::ClosingBrace,
- label: InlayHintLabel::simple(label, None, linked_location),
+ label: InlayHintLabel::simple(label, None, linked_location.map(LazyProperty::Computed)),
text_edit: None,
position: InlayHintPosition::After,
pad_left: true,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
index 906f2acf0c445..3e91618d08e6f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
@@ -53,10 +53,6 @@ pub(super) fn hints(
let last = captures.len() - 1;
for (idx, capture) in captures.into_iter().enumerate() {
let local = capture.local();
- let source = local.primary_source(sema.db);
-
- // force cache the source file, otherwise sema lookup will potentially panic
- _ = sema.parse_or_expand(source.file());
let label = format!(
"{}{}",
@@ -73,8 +69,17 @@ pub(super) fn hints(
}
hint.label.append_part(InlayHintLabelPart {
text: label,
- linked_location: source.name().and_then(|name| {
- name.syntax().original_file_range_opt(sema.db).map(TupleExt::head).map(Into::into)
+ linked_location: config.lazy_location_opt(|| {
+ let source = local.primary_source(sema.db);
+
+ // force cache the source file, otherwise sema lookup will potentially panic
+ _ = sema.parse_or_expand(source.file());
+ source.name().and_then(|name| {
+ name.syntax()
+ .original_file_range_opt(sema.db)
+ .map(TupleExt::head)
+ .map(Into::into)
+ })
}),
tooltip: None,
});
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs
index 037b328d971fc..762a4c2655181 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs
@@ -1,17 +1,19 @@
//! Implementation of inlay hints for generic parameters.
-use ide_db::{active_parameter::generic_def_for_node, RootDatabase};
+use ide_db::{active_parameter::generic_def_for_node, famous_defs::FamousDefs};
use syntax::{
ast::{self, AnyHasGenericArgs, HasGenericArgs, HasName},
AstNode,
};
-use crate::{inlay_hints::GenericParameterHints, InlayHint, InlayHintsConfig, InlayKind};
+use crate::{
+ inlay_hints::GenericParameterHints, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind,
+};
-use super::param_name::{is_argument_similar_to_param_name, render_label};
+use super::param_name::is_argument_similar_to_param_name;
pub(crate) fn hints(
acc: &mut Vec,
- sema: &hir::Semantics<'_, RootDatabase>,
+ FamousDefs(sema, krate): &FamousDefs<'_, '_>,
config: &InlayHintsConfig,
node: AnyHasGenericArgs,
) -> Option<()> {
@@ -45,12 +47,23 @@ pub(crate) fn hints(
return None;
}
- let name = param.name(sema.db);
- let param_name = name.as_str();
+ let allowed = match (param, &arg) {
+ (hir::GenericParam::TypeParam(_), ast::GenericArg::TypeArg(_)) => type_hints,
+ (hir::GenericParam::ConstParam(_), ast::GenericArg::ConstArg(_)) => const_hints,
+ (hir::GenericParam::LifetimeParam(_), ast::GenericArg::LifetimeArg(_)) => {
+ lifetime_hints
+ }
+ _ => false,
+ };
+ if !allowed {
+ return None;
+ }
+
+ let param_name = param.name(sema.db);
let should_hide = {
let argument = get_string_representation(&arg)?;
- is_argument_similar_to_param_name(&argument, param_name)
+ is_argument_similar_to_param_name(&argument, param_name.as_str())
};
if should_hide {
@@ -59,30 +72,28 @@ pub(crate) fn hints(
let range = sema.original_range_opt(arg.syntax())?.range;
- let source_syntax = match param {
- hir::GenericParam::TypeParam(it) => {
- if !type_hints || !matches!(arg, ast::GenericArg::TypeArg(_)) {
- return None;
- }
- sema.source(it.merge())?.value.syntax().clone()
- }
- hir::GenericParam::ConstParam(it) => {
- if !const_hints || !matches!(arg, ast::GenericArg::ConstArg(_)) {
- return None;
- }
- let syntax = sema.source(it.merge())?.value.syntax().clone();
- let const_param = ast::ConstParam::cast(syntax)?;
- const_param.name()?.syntax().clone()
- }
- hir::GenericParam::LifetimeParam(it) => {
- if !lifetime_hints || !matches!(arg, ast::GenericArg::LifetimeArg(_)) {
- return None;
- }
- sema.source(it)?.value.syntax().clone()
- }
- };
- let linked_location = sema.original_range_opt(&source_syntax);
- let label = render_label(param_name, config, linked_location);
+ let colon = if config.render_colons { ":" } else { "" };
+ let label = InlayHintLabel::simple(
+ format!("{}{colon}", param_name.display(sema.db, krate.edition(sema.db))),
+ None,
+ config.lazy_location_opt(|| {
+ let source_syntax = match param {
+ hir::GenericParam::TypeParam(it) => {
+ sema.source(it.merge()).map(|it| it.value.syntax().clone())
+ }
+ hir::GenericParam::ConstParam(it) => {
+ let syntax = sema.source(it.merge())?.value.syntax().clone();
+ let const_param = ast::ConstParam::cast(syntax)?;
+ const_param.name().map(|it| it.syntax().clone())
+ }
+ hir::GenericParam::LifetimeParam(it) => {
+ sema.source(it).map(|it| it.value.syntax().clone())
+ }
+ };
+ let linked_location = source_syntax.and_then(|it| sema.original_range_opt(&it));
+ linked_location.map(Into::into)
+ }),
+ );
Some(InlayHint {
range,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs
index 1358d3722f897..27c7c3d498187 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs
@@ -49,7 +49,7 @@ pub(super) fn hints(
if mir.locals[place.local].ty.adt_id(ChalkTyInterner).is_none() {
continue; // Arguably only ADTs have significant drop impls
}
- let Some(binding) = local_to_binding.get(place.local) else {
+ let Some(&binding_idx) = local_to_binding.get(place.local) else {
continue; // Ignore temporary values
};
let range = match terminator.span {
@@ -91,25 +91,26 @@ pub(super) fn hints(
},
MirSpan::Unknown => continue,
};
- let binding_source = source_map
- .patterns_for_binding(*binding)
- .first()
- .and_then(|d| source_map.pat_syntax(*d).ok())
- .and_then(|d| {
- Some(FileRange {
- file_id: d.file_id.file_id()?.into(),
- range: d.value.text_range(),
- })
- });
- let binding = &hir.bindings[*binding];
+ let binding = &hir.bindings[binding_idx];
let name = binding.name.display_no_db(file_id.edition()).to_smolstr();
if name.starts_with(" i32 { x + y }
//! _ = max(/*x*/4, /*y*/4);
//! ```
-use std::fmt::Display;
use either::Either;
use hir::{Callable, Semantics};
@@ -20,7 +19,7 @@ use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, Inla
pub(super) fn hints(
acc: &mut Vec,
- FamousDefs(sema, _): &FamousDefs<'_, '_>,
+ FamousDefs(sema, krate): &FamousDefs<'_, '_>,
config: &InlayHintsConfig,
_file_id: EditionedFileId,
expr: ast::Expr,
@@ -37,23 +36,29 @@ pub(super) fn hints(
.filter_map(|(p, arg)| {
// Only annotate hints for expressions that exist in the original file
let range = sema.original_range_opt(arg.syntax())?;
- let source = sema.source(p)?;
- let (param_name, name_syntax) = match source.value.as_ref() {
- Either::Left(pat) => (pat.name()?, pat.name()),
- Either::Right(param) => match param.pat()? {
- ast::Pat::IdentPat(it) => (it.name()?, it.name()),
- _ => return None,
- },
- };
- Some((name_syntax, param_name, arg, range))
+ let param_name = p.name(sema.db)?;
+ Some((p, param_name, arg, range))
})
.filter(|(_, param_name, arg, _)| {
- !should_hide_param_name_hint(sema, &callable, ¶m_name.text(), arg)
+ !should_hide_param_name_hint(sema, &callable, param_name.as_str(), arg)
})
.map(|(param, param_name, _, hir::FileRange { range, .. })| {
- let linked_location = param.and_then(|name| sema.original_range_opt(name.syntax()));
-
- let label = render_label(¶m_name, config, linked_location);
+ let colon = if config.render_colons { ":" } else { "" };
+ let label = InlayHintLabel::simple(
+ format!("{}{colon}", param_name.display(sema.db, krate.edition(sema.db))),
+ None,
+ config.lazy_location_opt(|| {
+ let source = sema.source(param)?;
+ let name_syntax = match source.value.as_ref() {
+ Either::Left(pat) => pat.name(),
+ Either::Right(param) => match param.pat()? {
+ ast::Pat::IdentPat(it) => it.name(),
+ _ => None,
+ },
+ }?;
+ sema.original_range_opt(name_syntax.syntax()).map(Into::into)
+ }),
+ );
InlayHint {
range,
kind: InlayKind::Parameter,
@@ -70,16 +75,6 @@ pub(super) fn hints(
Some(())
}
-pub(super) fn render_label(
- param_name: impl Display,
- config: &InlayHintsConfig,
- linked_location: Option,
-) -> InlayHintLabel {
- let colon = if config.render_colons { ":" } else { "" };
-
- InlayHintLabel::simple(format!("{param_name}{colon}"), None, linked_location.map(Into::into))
-}
-
fn get_callable(
sema: &Semantics<'_, RootDatabase>,
expr: &ast::Expr,
@@ -124,9 +119,7 @@ fn should_hide_param_name_hint(
}
let fn_name = match callable.kind() {
- hir::CallableKind::Function(it) => {
- Some(it.name(sema.db).unescaped().display_no_db().to_smolstr())
- }
+ hir::CallableKind::Function(it) => Some(it.name(sema.db).as_str().to_smolstr()),
_ => None,
};
let fn_name = fn_name.as_deref();
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index 346e2862b0fdd..e942f5a6aac78 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -91,7 +91,8 @@ pub use crate::{
inlay_hints::{
AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints,
GenericParameterHints, InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart,
- InlayHintPosition, InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints,
+ InlayHintPosition, InlayHintsConfig, InlayKind, InlayTooltip, LazyProperty,
+ LifetimeElisionHints,
},
join_lines::JoinLinesConfig,
markup::Markup,
@@ -671,7 +672,7 @@ impl Analysis {
&self,
config: &CompletionConfig<'_>,
position: FilePosition,
- imports: impl IntoIterator- + std::panic::UnwindSafe,
+ imports: impl IntoIterator
- + std::panic::UnwindSafe,
) -> Cancellable> {
Ok(self
.with_db(|db| ide_completion::resolve_completion_edits(db, config, position, imports))?
diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs
index ba739df3092b3..07dfd83c4eb7f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs
@@ -263,7 +263,7 @@ fn find_definitions(
.and_then(|def| {
// if the name differs from the definitions name it has to be an alias
if def
- .name(sema.db).is_some_and(|it| !it.eq_ident(name_ref.text().as_str()))
+ .name(sema.db).is_some_and(|it| it.as_str() != name_ref.text().trim_start_matches("r#"))
{
Err(format_err!("Renaming aliases is currently unsupported"))
} else {
diff --git a/src/tools/rust-analyzer/crates/intern/Cargo.toml b/src/tools/rust-analyzer/crates/intern/Cargo.toml
index 5e7ee54c6af77..c0358ef929b4d 100644
--- a/src/tools/rust-analyzer/crates/intern/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/intern/Cargo.toml
@@ -19,7 +19,6 @@ dashmap.workspace = true
hashbrown.workspace = true
rustc-hash.workspace = true
triomphe.workspace = true
-sptr = "0.3.2"
[lints]
workspace = true
diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol.rs b/src/tools/rust-analyzer/crates/intern/src/symbol.rs
index 200b14027f804..b3bf285edfb11 100644
--- a/src/tools/rust-analyzer/crates/intern/src/symbol.rs
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol.rs
@@ -13,7 +13,6 @@ use std::{
use dashmap::{DashMap, SharedValue};
use hashbrown::{hash_map::RawEntryMut, HashMap};
use rustc_hash::FxHasher;
-use sptr::Strict;
use triomphe::Arc;
pub mod symbols;
@@ -84,7 +83,7 @@ impl TaggedArcPtr {
#[inline]
pub(crate) unsafe fn try_as_arc_owned(self) -> Option>>> {
// Unpack the tag from the alignment niche
- let tag = Strict::addr(self.packed.as_ptr()) & Self::BOOL_BITS;
+ let tag = self.packed.as_ptr().addr() & Self::BOOL_BITS;
if tag != 0 {
// Safety: We checked that the tag is non-zero -> true, so we are pointing to the data offset of an `Arc`
Some(ManuallyDrop::new(unsafe {
@@ -99,40 +98,18 @@ impl TaggedArcPtr {
fn pack_arc(ptr: NonNull<*const str>) -> NonNull<*const str> {
let packed_tag = true as usize;
- // can't use this strict provenance stuff here due to trait methods not being const
- // unsafe {
- // // Safety: The pointer is derived from a non-null
- // NonNull::new_unchecked(Strict::map_addr(ptr.as_ptr(), |addr| {
- // // Safety:
- // // - The pointer is `NonNull` => it's address is `NonZero`
- // // - `P::BITS` least significant bits are always zero (`Pointer` contract)
- // // - `T::BITS <= P::BITS` (from `Self::ASSERTION`)
- // //
- // // Thus `addr >> T::BITS` is guaranteed to be non-zero.
- // //
- // // `{non_zero} | packed_tag` can't make the value zero.
-
- // (addr >> Self::BOOL_BITS) | packed_tag
- // }))
- // }
- // so what follows is roughly what the above looks like but inlined
-
- let self_addr = ptr.as_ptr() as *const *const str as usize;
- let addr = self_addr | packed_tag;
- let dest_addr = addr as isize;
- let offset = dest_addr.wrapping_sub(self_addr as isize);
-
- // SAFETY: The resulting pointer is guaranteed to be NonNull as we only modify the niche bytes
- unsafe { NonNull::new_unchecked(ptr.as_ptr().cast::().wrapping_offset(offset).cast()) }
+ unsafe {
+ // Safety: The pointer is derived from a non-null and bit-oring it with true (1) will
+ // not make it null.
+ NonNull::new_unchecked(ptr.as_ptr().map_addr(|addr| addr | packed_tag))
+ }
}
#[inline]
pub(crate) fn pointer(self) -> NonNull<*const str> {
// SAFETY: The resulting pointer is guaranteed to be NonNull as we only modify the niche bytes
unsafe {
- NonNull::new_unchecked(Strict::map_addr(self.packed.as_ptr(), |addr| {
- addr & !Self::BOOL_BITS
- }))
+ NonNull::new_unchecked(self.packed.as_ptr().map_addr(|addr| addr & !Self::BOOL_BITS))
}
}
diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
index b3b46421b50fb..9bc78ff87b8aa 100644
--- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
@@ -240,8 +240,10 @@ define_symbols! {
format_unsafe_arg,
format,
freeze,
+ from,
From,
FromStr,
+ from_str,
from_output,
from_residual,
from_usize,
@@ -273,6 +275,8 @@ define_symbols! {
index_mut,
index,
Index,
+ into,
+ Into,
into_future,
into_iter,
IntoFuture,
@@ -361,6 +365,7 @@ define_symbols! {
panic_nounwind,
panic,
Param,
+ parse,
partial_ord,
PartialEq,
PartialOrd,
@@ -389,6 +394,7 @@ define_symbols! {
RangeToInclusive,
Ready,
receiver,
+ receiver_target,
recursion_limit,
register_attr,
register_tool,
@@ -454,13 +460,17 @@ define_symbols! {
termination,
test_case,
test,
+ then,
thiscall,
+ to_string,
trace_macros,
transmute_opts,
transmute_trait,
transparent,
+ try_into,
Try,
TryFrom,
+ try_from,
tuple_trait,
u128,
u16,
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 00446b27cf2f3..5654c04a59287 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -256,6 +256,24 @@ impl ProjectFolders {
fsc.add_file_set(file_set_roots)
}
+ for ws in workspaces.iter() {
+ let mut file_set_roots: Vec = vec![];
+ let mut entries = vec![];
+
+ for buildfile in ws.buildfiles() {
+ file_set_roots.push(VfsPath::from(buildfile.to_owned()));
+ entries.push(buildfile.to_owned());
+ }
+
+ if !file_set_roots.is_empty() {
+ let entry = vfs::loader::Entry::Files(entries);
+ res.watch.push(res.load.len());
+ res.load.push(entry);
+ local_filesets.push(fsc.len() as u64);
+ fsc.add_file_set(file_set_roots)
+ }
+ }
+
if let Some(user_config_path) = user_config_dir_path {
let ratoml_path = {
let mut p = user_config_path.to_path_buf();
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 c7614849e015b..59293ee3f9659 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
@@ -392,12 +392,12 @@ impl server::Span for RaSpanServer {
fn line(&mut self, _span: Self::Span) -> usize {
// FIXME requires db to resolve line index, THIS IS NOT INCREMENTAL
- 0
+ 1
}
fn column(&mut self, _span: Self::Span) -> usize {
// FIXME requires db to resolve line index, THIS IS NOT INCREMENTAL
- 0
+ 1
}
}
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 466eb14b55ea5..409cf3cc78134 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
@@ -291,11 +291,11 @@ impl server::Span for TokenIdServer {
}
fn line(&mut self, _span: Self::Span) -> usize {
- 0
+ 1
}
fn column(&mut self, _span: Self::Span) -> usize {
- 0
+ 1
}
}
diff --git a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
index 6a88cf022dfb0..a396396761041 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
@@ -63,7 +63,7 @@ use crate::{ManifestPath, TargetKind};
pub struct ProjectJson {
/// e.g. `path/to/sysroot`
pub(crate) sysroot: Option,
- /// e.g. `path/to/sysroot/lib/rustlib/src/rust`
+ /// e.g. `path/to/sysroot/lib/rustlib/src/rust/library`
pub(crate) sysroot_src: Option,
project_root: AbsPathBuf,
/// The path to the rust-project.json file. May be None if this
diff --git a/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs
index 4bf9b59e7d038..e472da0c89b0d 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs
@@ -19,7 +19,7 @@ pub fn get(
let rustc_cfgs = match rustc_cfgs {
Ok(cfgs) => cfgs,
Err(e) => {
- tracing::error!(?e, "failed to get rustc cfgs");
+ tracing::warn!(?e, "failed to get rustc cfgs");
return vec![];
}
};
diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
index f98d983ac0608..dcd62753cb2f9 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -524,6 +524,17 @@ impl ProjectWorkspace {
}
}
+ pub fn buildfiles(&self) -> Vec {
+ match &self.kind {
+ ProjectWorkspaceKind::Json(project) => project
+ .crates()
+ .filter_map(|(_, krate)| krate.build.as_ref().map(|build| build.build_file.clone()))
+ .map(|build_file| self.workspace_root().join(build_file))
+ .collect(),
+ _ => vec![],
+ }
+ }
+
pub fn find_sysroot_proc_macro_srv(&self) -> anyhow::Result {
self.sysroot.discover_proc_macro_srv()
}
@@ -568,27 +579,15 @@ impl ProjectWorkspace {
match &self.kind {
ProjectWorkspaceKind::Json(project) => project
.crates()
- .map(|(_, krate)| {
- // FIXME: PackageRoots dont allow specifying files, only directories
- let build_file = krate
- .build
- .as_ref()
- .map(|build| self.workspace_root().join(&build.build_file))
- .as_deref()
- .and_then(AbsPath::parent)
- .map(ToOwned::to_owned);
-
- PackageRoot {
- is_local: krate.is_workspace_member,
- include: krate
- .include
- .iter()
- .cloned()
- .chain(build_file)
- .chain(self.extra_includes.iter().cloned())
- .collect(),
- exclude: krate.exclude.clone(),
- }
+ .map(|(_, krate)| PackageRoot {
+ is_local: krate.is_workspace_member,
+ include: krate
+ .include
+ .iter()
+ .cloned()
+ .chain(self.extra_includes.iter().cloned())
+ .collect(),
+ exclude: krate.exclude.clone(),
})
.collect::>()
.into_iter()
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 bcaec52019591..18c27c844964b 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
@@ -465,6 +465,7 @@ impl flags::AnalysisStats {
prefer_no_std: false,
prefer_prelude: true,
prefer_absolute: false,
+ allow_unstable: true,
},
Edition::LATEST,
)
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index 3dc4379258fa1..44325fa1a29e6 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -453,6 +453,10 @@ config_data! {
///
/// In `match` arms it completes a comma instead.
completion_addSemicolonToUnit: bool = true,
+ /// Toggles the additional completions that automatically show method calls and field accesses with `await` prefixed to them when completing on a future.
+ completion_autoAwait_enable: bool = true,
+ /// Toggles the additional completions that automatically show method calls with `iter()` or `into_iter()` prefixed to them when completing on a type that has them.
+ completion_autoIter_enable: bool = true,
/// Toggles the additional completions that automatically add imports when completed.
/// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
completion_autoimport_enable: bool = true,
@@ -1484,6 +1488,8 @@ impl Config {
enable_imports_on_the_fly: self.completion_autoimport_enable(source_root).to_owned()
&& self.caps.completion_item_edit_resolve(),
enable_self_on_the_fly: self.completion_autoself_enable(source_root).to_owned(),
+ enable_auto_iter: *self.completion_autoIter_enable(source_root),
+ enable_auto_await: *self.completion_autoAwait_enable(source_root),
enable_private_editable: self.completion_privateEditable_enable(source_root).to_owned(),
full_function_signatures: self
.completion_fullFunctionSignatures_enable(source_root)
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 22f06d68d80d1..2309f94a7429b 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
@@ -88,6 +88,17 @@ pub(crate) enum FlycheckConfig {
},
}
+impl FlycheckConfig {
+ pub(crate) fn invocation_strategy_once(&self) -> bool {
+ match self {
+ FlycheckConfig::CargoCommand { .. } => false,
+ FlycheckConfig::CustomCommand { invocation_strategy, .. } => {
+ *invocation_strategy == InvocationStrategy::Once
+ }
+ }
+ }
+}
+
impl fmt::Display for FlycheckConfig {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
index 98efc637c2c81..84ba89d9f31f9 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
@@ -291,9 +291,15 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
let file_id = state.vfs.read().0.file_id(&vfs_path);
if let Some(file_id) = file_id {
let world = state.snapshot();
+ let invocation_strategy_once = state.config.flycheck(None).invocation_strategy_once();
let may_flycheck_workspace = state.config.flycheck_workspace(None);
let mut updated = false;
let task = move || -> std::result::Result<(), ide::Cancelled> {
+ if invocation_strategy_once {
+ let saved_file = vfs_path.as_path().map(|p| p.to_owned());
+ world.flycheck[0].restart_workspace(saved_file.clone());
+ }
+
let target = TargetSpec::for_file(&world, file_id)?.and_then(|it| {
let tgt_kind = it.target_kind();
let (tgt_name, root, package) = match it {
@@ -320,16 +326,15 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
// the user opted into package checks then
let package_check_allowed = target.is_some() || !may_flycheck_workspace;
if package_check_allowed {
- let workspace =
- world.workspaces.iter().enumerate().find(|(_, ws)| match &ws.kind {
- project_model::ProjectWorkspaceKind::Cargo { cargo, .. }
- | project_model::ProjectWorkspaceKind::DetachedFile {
- cargo: Some((cargo, _, _)),
- ..
- } => *cargo.workspace_root() == root,
- _ => false,
- });
- if let Some((idx, _)) = workspace {
+ let workspace = world.workspaces.iter().position(|ws| match &ws.kind {
+ project_model::ProjectWorkspaceKind::Cargo { cargo, .. }
+ | project_model::ProjectWorkspaceKind::DetachedFile {
+ cargo: Some((cargo, _, _)),
+ ..
+ } => *cargo.workspace_root() == root,
+ _ => false,
+ });
+ if let Some(idx) = workspace {
world.flycheck[idx].restart_for_package(package, target);
}
}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
index 190015d7faad8..39cbf53eaa21d 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
@@ -1154,10 +1154,7 @@ pub(crate) fn handle_completion_resolve(
.resolve_completion_edits(
&forced_resolve_completions_config,
position,
- resolve_data
- .imports
- .into_iter()
- .map(|import| (import.full_import_path, import.imported_name)),
+ resolve_data.imports.into_iter().map(|import| import.full_import_path),
)?
.into_iter()
.flat_map(|edit| edit.into_iter().map(|indel| to_proto::text_edit(&line_index, indel)))
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
index fcfd06679bf2b..5cdc51a1c1995 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -176,6 +176,8 @@ fn integrated_completion_benchmark() {
fields_to_resolve: CompletionFieldsToResolve::empty(),
exclude_flyimport: vec![],
exclude_traits: &[],
+ enable_auto_await: true,
+ enable_auto_iter: true,
};
let position =
FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -226,6 +228,8 @@ fn integrated_completion_benchmark() {
fields_to_resolve: CompletionFieldsToResolve::empty(),
exclude_flyimport: vec![],
exclude_traits: &[],
+ enable_auto_await: true,
+ enable_auto_iter: true,
};
let position =
FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -274,6 +278,8 @@ fn integrated_completion_benchmark() {
fields_to_resolve: CompletionFieldsToResolve::empty(),
exclude_flyimport: vec![],
exclude_traits: &[],
+ enable_auto_await: true,
+ enable_auto_iter: true,
};
let position =
FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
index 61ec576dd4f90..ccffa7a671e66 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
@@ -142,9 +142,8 @@ fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8;
hasher.update(prefix);
hasher.update(u32::from(*text_size).to_le_bytes());
}
- for (import_path, import_name) in &item.import_to_add {
+ for import_path in &item.import_to_add {
hasher.update(import_path);
- hasher.update(import_name);
}
hasher.finalize()
}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs
index 134de92feab3a..ca4372aa83f8d 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs
@@ -850,7 +850,6 @@ pub struct InlayHintResolveData {
#[derive(Debug, Serialize, Deserialize)]
pub struct CompletionImport {
pub full_import_path: String,
- pub imported_name: String,
}
#[derive(Debug, Deserialize, Default)]
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
index a5516e7f9d4fe..bff53cf98b7b8 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -11,8 +11,8 @@ use ide::{
Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionFieldsToResolve,
CompletionItem, CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange,
FileSystemEdit, Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel,
- InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayKind, Markup,
- NavigationTarget, ReferenceCategory, RenameError, Runnable, Severity, SignatureHelp,
+ InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayKind, LazyProperty,
+ Markup, NavigationTarget, ReferenceCategory, RenameError, Runnable, Severity, SignatureHelp,
SnippetEdit, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize,
};
use ide_db::{assists, rust_doc::format_docs, FxHasher};
@@ -394,10 +394,7 @@ fn completion_item(
item.import_to_add
.clone()
.into_iter()
- .map(|(import_path, import_name)| lsp_ext::CompletionImport {
- full_import_path: import_path,
- imported_name: import_name,
- })
+ .map(|import_path| lsp_ext::CompletionImport { full_import_path: import_path })
.collect()
} else {
Vec::new()
@@ -549,12 +546,11 @@ pub(crate) fn inlay_hint(
) -> Cancellable {
let hint_needs_resolve = |hint: &InlayHint| -> Option {
hint.resolve_parent.filter(|_| {
- hint.text_edit.is_some()
- || hint
- .label
- .parts
- .iter()
- .any(|part| part.linked_location.is_some() || part.tooltip.is_some())
+ hint.text_edit.as_ref().is_some_and(LazyProperty::is_lazy)
+ || hint.label.parts.iter().any(|part| {
+ part.linked_location.as_ref().is_some_and(LazyProperty::is_lazy)
+ || part.tooltip.as_ref().is_some_and(LazyProperty::is_lazy)
+ })
})
};
@@ -569,22 +565,21 @@ pub(crate) fn inlay_hint(
});
let mut something_to_resolve = false;
- let text_edits = if snap
- .config
- .visual_studio_code_version()
- .is_none_or(|version| VersionReq::parse(">=1.86.0").unwrap().matches(version))
- && resolve_range_and_hash.is_some()
- && fields_to_resolve.resolve_text_edits
- {
- something_to_resolve |= inlay_hint.text_edit.is_some();
- None
- } else {
- inlay_hint
- .text_edit
- .take()
- .and_then(|it| it.computed())
- .map(|it| text_edit_vec(line_index, it))
- };
+ let text_edits = inlay_hint
+ .text_edit
+ .take()
+ .and_then(|it| match it {
+ LazyProperty::Computed(it) => Some(it),
+ LazyProperty::Lazy => {
+ something_to_resolve |=
+ snap.config.visual_studio_code_version().is_none_or(|version| {
+ VersionReq::parse(">=1.86.0").unwrap().matches(version)
+ }) && resolve_range_and_hash.is_some()
+ && fields_to_resolve.resolve_text_edits;
+ None
+ }
+ })
+ .map(|it| text_edit_vec(line_index, it));
let (label, tooltip) = inlay_hint_label(
snap,
fields_to_resolve,
@@ -637,22 +632,23 @@ fn inlay_hint_label(
let (label, tooltip) = match &*label.parts {
[InlayHintLabelPart { linked_location: None, .. }] => {
let InlayHintLabelPart { text, tooltip, .. } = label.parts.pop().unwrap();
- let hint_tooltip = if needs_resolve && fields_to_resolve.resolve_hint_tooltip {
- *something_to_resolve |= tooltip.is_some();
- None
- } else {
- match tooltip.and_then(|it| it.computed()) {
- Some(ide::InlayTooltip::String(s)) => {
- Some(lsp_types::InlayHintTooltip::String(s))
- }
- Some(ide::InlayTooltip::Markdown(s)) => {
- Some(lsp_types::InlayHintTooltip::MarkupContent(lsp_types::MarkupContent {
- kind: lsp_types::MarkupKind::Markdown,
- value: s,
- }))
- }
- None => None,
+ let tooltip = tooltip.and_then(|it| match it {
+ LazyProperty::Computed(it) => Some(it),
+ LazyProperty::Lazy => {
+ *something_to_resolve |=
+ needs_resolve && fields_to_resolve.resolve_hint_tooltip;
+ None
}
+ });
+ let hint_tooltip = match tooltip {
+ Some(ide::InlayTooltip::String(s)) => Some(lsp_types::InlayHintTooltip::String(s)),
+ Some(ide::InlayTooltip::Markdown(s)) => {
+ Some(lsp_types::InlayHintTooltip::MarkupContent(lsp_types::MarkupContent {
+ kind: lsp_types::MarkupKind::Markdown,
+ value: s,
+ }))
+ }
+ None => None,
};
(lsp_types::InlayHintLabel::String(text), hint_tooltip)
}
@@ -661,31 +657,38 @@ fn inlay_hint_label(
.parts
.into_iter()
.map(|part| {
- let tooltip = if needs_resolve && fields_to_resolve.resolve_label_tooltip {
- *something_to_resolve |= part.tooltip.is_some();
- None
- } else {
- match part.tooltip.and_then(|it| it.computed()) {
- Some(ide::InlayTooltip::String(s)) => {
- Some(lsp_types::InlayHintLabelPartTooltip::String(s))
- }
- Some(ide::InlayTooltip::Markdown(s)) => {
- Some(lsp_types::InlayHintLabelPartTooltip::MarkupContent(
- lsp_types::MarkupContent {
- kind: lsp_types::MarkupKind::Markdown,
- value: s,
- },
- ))
- }
- None => None,
+ let tooltip = part.tooltip.and_then(|it| match it {
+ LazyProperty::Computed(it) => Some(it),
+ LazyProperty::Lazy => {
+ *something_to_resolve |= fields_to_resolve.resolve_label_tooltip;
+ None
}
+ });
+ let tooltip = match tooltip {
+ Some(ide::InlayTooltip::String(s)) => {
+ Some(lsp_types::InlayHintLabelPartTooltip::String(s))
+ }
+ Some(ide::InlayTooltip::Markdown(s)) => {
+ Some(lsp_types::InlayHintLabelPartTooltip::MarkupContent(
+ lsp_types::MarkupContent {
+ kind: lsp_types::MarkupKind::Markdown,
+ value: s,
+ },
+ ))
+ }
+ None => None,
};
- let location = if needs_resolve && fields_to_resolve.resolve_label_location {
- *something_to_resolve |= part.linked_location.is_some();
- None
- } else {
- part.linked_location.map(|range| location(snap, range)).transpose()?
- };
+ let location = part
+ .linked_location
+ .and_then(|it| match it {
+ LazyProperty::Computed(it) => Some(it),
+ LazyProperty::Lazy => {
+ *something_to_resolve |= fields_to_resolve.resolve_label_location;
+ None
+ }
+ })
+ .map(|range| location(snap, range))
+ .transpose()?;
Ok(lsp_types::InlayHintLabelPart {
value: part.text,
tooltip,
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 dca231604fa13..ff027ac5848b3 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
@@ -411,6 +411,11 @@ pub fn path_from_text(text: &str) -> ast::Path {
ast_from_text(&format!("fn main() {{ let test: {text}; }}"))
}
+// FIXME: should not be pub
+pub fn path_from_text_with_edition(text: &str, edition: Edition) -> ast::Path {
+ ast_from_text_with_edition(&format!("fn main() {{ let test: {text}; }}"), edition)
+}
+
pub fn use_tree_glob() -> ast::UseTree {
ast_from_text("use *;")
}
@@ -1230,7 +1235,12 @@ pub fn token_tree(
#[track_caller]
fn ast_from_text(text: &str) -> N {
- let parse = SourceFile::parse(text, Edition::CURRENT);
+ ast_from_text_with_edition(text, Edition::CURRENT)
+}
+
+#[track_caller]
+fn ast_from_text_with_edition(text: &str, edition: Edition) -> N {
+ let parse = SourceFile::parse(text, edition);
let node = match parse.tree().syntax().descendants().find_map(N::cast) {
Some(it) => it,
None => {
diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
index fd06736a25248..4ed68d18e8071 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
@@ -53,6 +53,7 @@
//! pin:
//! pointee: copy, send, sync, ord, hash, unpin
//! range:
+//! receiver: deref
//! result:
//! send: sized
//! size_of: sized
@@ -513,10 +514,26 @@ pub mod ops {
fn deref_mut(&mut self) -> &mut Self::Target;
}
// endregion:deref_mut
+
+ // region:receiver
+ #[lang = "receiver"]
+ pub trait Receiver {
+ #[lang = "receiver_target"]
+ type Target: ?Sized;
+ }
+
+ impl Receiver for P
+ where
+ P: Deref,
+ {
+ type Target = T;
+ }
+ // endregion:receiver
}
pub use self::deref::{
Deref,
DerefMut, // :deref_mut
+ Receiver, // :receiver
};
// endregion:deref
diff --git a/src/tools/rust-analyzer/docs/dev/README.md b/src/tools/rust-analyzer/docs/dev/README.md
index 3ba492e095974..c990212d585d2 100644
--- a/src/tools/rust-analyzer/docs/dev/README.md
+++ b/src/tools/rust-analyzer/docs/dev/README.md
@@ -269,19 +269,13 @@ Note: we tag releases by dates, releasing a patch release on the same day should
## Permissions
-There are three sets of people with extra permissions:
+There are two sets of people with extra permissions:
-* rust-analyzer GitHub organization [**admins**](https://github.com/orgs/rust-analyzer/people?query=role:owner) (which include current t-compiler leads).
- Admins have full access to the org.
-* [**review**](https://github.com/orgs/rust-analyzer/teams/review) team in the organization.
- Reviewers have `r+` access to all of organization's repositories and publish rights on crates.io.
- They also have direct commit access, but all changes should via bors queue.
+* The [rust-lang](https://github.com/rust-lang) team [t-rust-analyzer](https://github.com/rust-lang/team/blob/master/teams/rust-analyzer.toml).
+ This team has write access to the repository and merge queue permissions (note the repo itself is managed by infra admins).
It's ok to self-approve if you think you know what you are doing!
- bors should automatically sync the permissions.
Feel free to request a review or assign any PR to a reviewer with the relevant expertise to bring the work to their attention.
Don't feel pressured to review assigned PRs though.
- If you don't feel like reviewing for whatever reason, someone else will pick the review up!
-* [**triage**](https://github.com/orgs/rust-analyzer/teams/triage) team in the organization.
- This team can label and close issues.
-
-Note that at the time being you need to be a member of the org yourself to view the links.
+ If you don't feel like reviewing for whatever reason, someone else will pick the review up (but please speak up if you don't feel like it)!
+* The [rust-lang](https://github.com/rust-lang) team [t-rust-analyzer-contributors]([https://github.com/orgs/rust-analyzer/teams/triage](https://github.com/rust-lang/team/blob/master/teams/rust-analyzer-contributors.toml)).
+ This team has general triaging permissions allowing to label, close and re-open issues.
diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
index a632fc6f5fb87..c7ee4e402363c 100644
--- a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
+++ b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
@@ -1,5 +1,5 @@