Merge pull request #19511 from snprajwal/fixmes chore: clean up some FIXMEs
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8935c5f..fa08fc2 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml
@@ -188,12 +188,16 @@ name: Rust Cross runs-on: ubuntu-latest + strategy: + matrix: + target: [powerpc-unknown-linux-gnu, x86_64-unknown-linux-musl, wasm32-unknown-unknown] + include: + # The rust-analyzer binary is not expected to compile on WASM, but the IDE + # crate should + - target: wasm32-unknown-unknown + ide-only: true env: - targets: "powerpc-unknown-linux-gnu x86_64-unknown-linux-musl" - # The rust-analyzer binary is not expected to compile on WASM, but the IDE - # crate should - targets_ide: "wasm32-unknown-unknown" - RUSTFLAGS: "-D warnings" + RUSTFLAGS: "-Dwarnings" steps: - name: Checkout repository @@ -202,19 +206,15 @@ - name: Install Rust toolchain run: | rustup update --no-self-update stable - rustup target add ${{ env.targets }} ${{ env.targets_ide }} + rustup target add ${{ matrix.target }} # - name: Cache Dependencies # uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 - - name: Check - run: | - for target in ${{ env.targets }}; do - cargo check --target=$target --all-targets - done - for target in ${{ env.targets_ide }}; do - cargo check -p ide --target=$target --all-targets - done + - run: cargo check --target=${{ matrix.target }} --all-targets -p ide + if: ${{ matrix.ide-only }} + - run: cargo check --target=${{ matrix.target }} --all-targets + if: ${{ !matrix.ide-only }} typescript: needs: changes
diff --git a/Cargo.lock b/Cargo.lock index b6a32d5..0d509f5 100644 --- a/Cargo.lock +++ b/Cargo.lock
@@ -1083,9 +1083,9 @@ [[package]] name = "jod-thread" -version = "0.1.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b23360e99b8717f20aaa4598f5a6541efbe30630039fbc7706cf954a87947ae" +checksum = "a037eddb7d28de1d0fc42411f501b53b75838d313908078d6698d064f3029b24" [[package]] name = "kqueue"
diff --git a/crates/base-db/src/change.rs b/crates/base-db/src/change.rs index 114b4cb..da2fb27 100644 --- a/crates/base-db/src/change.rs +++ b/crates/base-db/src/change.rs
@@ -34,10 +34,6 @@ } impl FileChange { - pub fn new() -> Self { - FileChange::default() - } - pub fn set_roots(&mut self, roots: Vec<SourceRoot>) { self.roots = Some(roots); }
diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs index 83857cf..9fbeace 100644 --- a/crates/base-db/src/lib.rs +++ b/crates/base-db/src/lib.rs
@@ -303,6 +303,19 @@ pub toolchain: Option<Version>, } +impl CrateWorkspaceData { + pub fn is_atleast_187(&self) -> bool { + const VERSION_187: Version = Version { + major: 1, + minor: 87, + patch: 0, + pre: Prerelease::EMPTY, + build: BuildMetadata::EMPTY, + }; + self.toolchain.as_ref().map_or(false, |v| *v >= VERSION_187) + } +} + fn toolchain_channel(db: &dyn RootQueryDb, krate: Crate) -> Option<ReleaseChannel> { krate.workspace_data(db).toolchain.as_ref().and_then(|v| ReleaseChannel::from_str(&v.pre)) }
diff --git a/crates/hir-def/src/dyn_map.rs b/crates/hir-def/src/dyn_map.rs index b17a2b0..eed1490 100644 --- a/crates/hir-def/src/dyn_map.rs +++ b/crates/hir-def/src/dyn_map.rs
@@ -112,6 +112,10 @@ } impl<K, V, P> Key<K, V, P> { + #[allow( + clippy::new_without_default, + reason = "this a const fn, so it can't be default yet. See <https://github.com/rust-lang/rust/issues/63065>" + )] pub(crate) const fn new() -> Key<K, V, P> { Key { _phantom: PhantomData } } @@ -148,16 +152,11 @@ } } +#[derive(Default)] pub struct DynMap { pub(crate) map: Map, } -impl Default for DynMap { - fn default() -> Self { - DynMap { map: Map::new() } - } -} - #[repr(transparent)] pub struct KeyMap<KEY> { map: DynMap,
diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs index c56b857..1791a1c 100644 --- a/crates/hir-def/src/expr_store/lower.rs +++ b/crates/hir-def/src/expr_store/lower.rs
@@ -2053,7 +2053,7 @@ f: ast::FormatArgsExpr, syntax_ptr: AstPtr<ast::Expr>, ) -> ExprId { - let mut args = FormatArgumentsCollector::new(); + let mut args = FormatArgumentsCollector::default(); f.args().for_each(|arg| { args.add(FormatArgument { kind: match arg.name() { @@ -2321,54 +2321,99 @@ zero_pad, debug_hex, } = &placeholder.format_options; - let fill = self.alloc_expr_desugared(Expr::Literal(Literal::Char(fill.unwrap_or(' ')))); - let align = { - let align = LangItem::FormatAlignment.ty_rel_path( - self.db, - self.krate, - match alignment { - Some(FormatAlignment::Left) => Name::new_symbol_root(sym::Left.clone()), - Some(FormatAlignment::Right) => Name::new_symbol_root(sym::Right.clone()), - Some(FormatAlignment::Center) => Name::new_symbol_root(sym::Center.clone()), - None => Name::new_symbol_root(sym::Unknown.clone()), - }, - ); - match align { - Some(path) => self.alloc_expr_desugared(Expr::Path(path)), - None => self.missing_expr(), - } - }; - // This needs to match `Flag` in library/core/src/fmt/rt.rs. - let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32) - | (((sign == Some(FormatSign::Minus)) as u32) << 1) - | ((alternate as u32) << 2) - | ((zero_pad as u32) << 3) - | (((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 4) - | (((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5); - let flags = self.alloc_expr_desugared(Expr::Literal(Literal::Uint( - flags as u128, - Some(BuiltinUint::U32), - ))); - let precision = self.make_count(precision, argmap); - let width = self.make_count(width, argmap); + let precision_expr = self.make_count(precision, argmap); + let width_expr = self.make_count(width, argmap); - let format_placeholder_new = { - let format_placeholder_new = LangItem::FormatPlaceholder.ty_rel_path( - self.db, - self.krate, - Name::new_symbol_root(sym::new.clone()), - ); - match format_placeholder_new { - Some(path) => self.alloc_expr_desugared(Expr::Path(path)), - None => self.missing_expr(), - } - }; + if self.krate.workspace_data(self.db).is_atleast_187() { + // These need to match the constants in library/core/src/fmt/rt.rs. + let align = match alignment { + Some(FormatAlignment::Left) => 0, + Some(FormatAlignment::Right) => 1, + Some(FormatAlignment::Center) => 2, + None => 3, + }; + // This needs to match `Flag` in library/core/src/fmt/rt.rs. + let flags = fill.unwrap_or(' ') as u32 + | ((sign == Some(FormatSign::Plus)) as u32) << 21 + | ((sign == Some(FormatSign::Minus)) as u32) << 22 + | (alternate as u32) << 23 + | (zero_pad as u32) << 24 + | ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 25 + | ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 26 + | (width.is_some() as u32) << 27 + | (precision.is_some() as u32) << 28 + | align << 29 + | 1 << 31; // Highest bit always set. + let flags = self.alloc_expr_desugared(Expr::Literal(Literal::Uint( + flags as u128, + Some(BuiltinUint::U32), + ))); - self.alloc_expr_desugared(Expr::Call { - callee: format_placeholder_new, - args: Box::new([position, fill, align, flags, precision, width]), - }) + let position = RecordLitField { + name: Name::new_symbol_root(sym::position.clone()), + expr: position, + }; + let flags = + RecordLitField { name: Name::new_symbol_root(sym::flags.clone()), expr: flags }; + let precision = RecordLitField { + name: Name::new_symbol_root(sym::precision.clone()), + expr: precision_expr, + }; + let width = RecordLitField { + name: Name::new_symbol_root(sym::width.clone()), + expr: width_expr, + }; + self.alloc_expr_desugared(Expr::RecordLit { + path: LangItem::FormatPlaceholder.path(self.db, self.krate).map(Box::new), + fields: Box::new([position, flags, precision, width]), + spread: None, + }) + } else { + let format_placeholder_new = { + let format_placeholder_new = LangItem::FormatPlaceholder.ty_rel_path( + self.db, + self.krate, + Name::new_symbol_root(sym::new.clone()), + ); + match format_placeholder_new { + Some(path) => self.alloc_expr_desugared(Expr::Path(path)), + None => self.missing_expr(), + } + }; + // This needs to match `Flag` in library/core/src/fmt/rt.rs. + let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32) + | (((sign == Some(FormatSign::Minus)) as u32) << 1) + | ((alternate as u32) << 2) + | ((zero_pad as u32) << 3) + | (((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 4) + | (((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5); + let flags = self.alloc_expr_desugared(Expr::Literal(Literal::Uint( + flags as u128, + Some(BuiltinUint::U32), + ))); + let fill = self.alloc_expr_desugared(Expr::Literal(Literal::Char(fill.unwrap_or(' ')))); + let align = { + let align = LangItem::FormatAlignment.ty_rel_path( + self.db, + self.krate, + match alignment { + Some(FormatAlignment::Left) => Name::new_symbol_root(sym::Left.clone()), + Some(FormatAlignment::Right) => Name::new_symbol_root(sym::Right.clone()), + Some(FormatAlignment::Center) => Name::new_symbol_root(sym::Center.clone()), + None => Name::new_symbol_root(sym::Unknown.clone()), + }, + ); + match align { + Some(path) => self.alloc_expr_desugared(Expr::Path(path)), + None => self.missing_expr(), + } + }; + self.alloc_expr_desugared(Expr::Call { + callee: format_placeholder_new, + args: Box::new([position, fill, align, flags, precision_expr, width_expr]), + }) + } } /// Generate a hir expression for a format_args Count.
diff --git a/crates/hir-def/src/hir/format_args.rs b/crates/hir-def/src/hir/format_args.rs index 821ec56..ca51f49 100644 --- a/crates/hir-def/src/hir/format_args.rs +++ b/crates/hir-def/src/hir/format_args.rs
@@ -460,10 +460,6 @@ } } - pub fn new() -> Self { - Default::default() - } - pub fn add(&mut self, arg: FormatArgument) -> usize { let index = self.arguments.len(); if let Some(name) = arg.kind.ident() {
diff --git a/crates/hir-def/src/macro_expansion_tests/mbe.rs b/crates/hir-def/src/macro_expansion_tests/mbe.rs index ddf1a21..f990309 100644 --- a/crates/hir-def/src/macro_expansion_tests/mbe.rs +++ b/crates/hir-def/src/macro_expansion_tests/mbe.rs
@@ -1979,3 +1979,51 @@ "#]], ); } + +#[test] +fn semicolon_does_not_glue() { + check( + r#" +macro_rules! bug { + ($id: expr) => { + true + }; + ($id: expr; $($attr: ident),*) => { + true + }; + ($id: expr; $($attr: ident),*; $norm: expr) => { + true + }; + ($id: expr; $($attr: ident),*;; $print: expr) => { + true + }; + ($id: expr; $($attr: ident),*; $norm: expr; $print: expr) => { + true + }; +} + +let _ = bug!(a;;;test); + "#, + expect![[r#" +macro_rules! bug { + ($id: expr) => { + true + }; + ($id: expr; $($attr: ident),*) => { + true + }; + ($id: expr; $($attr: ident),*; $norm: expr) => { + true + }; + ($id: expr; $($attr: ident),*;; $print: expr) => { + true + }; + ($id: expr; $($attr: ident),*; $norm: expr; $print: expr) => { + true + }; +} + +let _ = true; + "#]], + ); +}
diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs b/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs index 1bbed01..cb4fcd8 100644 --- a/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs +++ b/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
@@ -582,8 +582,8 @@ } impl <A: Arbitrary> $crate::arbitrary::Arbitrary for Vec<A> { - type Parameters = RangedParams1<A::Parameters>; - type Strategy = VecStrategy<A::Strategy>; + type Parameters = RangedParams1<A::Parameters> ; + type Strategy = VecStrategy<A::Strategy> ; fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { { let product_unpack![range, a] = args; vec(any_with::<A>(a), range)
diff --git a/crates/hir-expand/src/change.rs b/crates/hir-expand/src/change.rs index 3f5b8fd..6873cb7 100644 --- a/crates/hir-expand/src/change.rs +++ b/crates/hir-expand/src/change.rs
@@ -14,10 +14,6 @@ } impl ChangeWithProcMacros { - pub fn new() -> Self { - Self::default() - } - pub fn apply(self, db: &mut impl ExpandDatabase) { let crates_id_map = self.source_change.apply(db); if let Some(proc_macros) = self.proc_macros {
diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index d089d4c..9dc08dd 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs
@@ -208,7 +208,8 @@ }, None => RenderedExpandError { message: format!( - "internal error: proc-macro map is missing error entry for crate {def_crate:?}" + "internal error: proc-macro map is missing error entry for crate {:?}", + def_crate ), error: true, kind: RenderedExpandError::GENERAL_KIND,
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 0bd605c..0448ecd 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs
@@ -1534,10 +1534,6 @@ None => return (self.err_ty(), None), } }; - let Some(mod_path) = path.mod_path() else { - never!("resolver should always resolve lang item paths"); - return (self.err_ty(), None); - }; return match resolution { TypeNs::AdtId(AdtId::StructId(strukt)) => { let substs = path_ctx.substs_from_path(strukt.into(), true); @@ -1567,6 +1563,10 @@ let Some(remaining_idx) = unresolved else { drop(ctx); + let Some(mod_path) = path.mod_path() else { + never!("resolver should always resolve lang item paths"); + return (self.err_ty(), None); + }; return self.resolve_variant_on_alias(ty, None, mod_path); }; @@ -1630,6 +1630,10 @@ (ty, variant) } TypeNs::TypeAliasId(it) => { + let Some(mod_path) = path.mod_path() else { + never!("resolver should always resolve lang item paths"); + return (self.err_ty(), None); + }; let substs = path_ctx.substs_from_path_segment(it.into(), true, None); drop(ctx); let ty = self.db.ty(it.into());
diff --git a/crates/hir-ty/src/infer/cast.rs b/crates/hir-ty/src/infer/cast.rs index d3de86f..0670a4e 100644 --- a/crates/hir-ty/src/infer/cast.rs +++ b/crates/hir-ty/src/infer/cast.rs
@@ -50,7 +50,7 @@ None } } - TyKind::Raw(m, ty) => Some(Self::Ptr(table.resolve_ty_shallow(ty), *m)), + TyKind::Raw(m, ty) => Some(Self::Ptr(ty.clone(), *m)), TyKind::Function(_) => Some(Self::FnPtr), _ => None, } @@ -105,9 +105,8 @@ F: FnMut(ExprId, Vec<Adjustment>), G: FnMut(ExprId), { - table.resolve_obligations_as_possible(); - self.expr_ty = table.resolve_ty_shallow(&self.expr_ty); - self.cast_ty = table.resolve_ty_shallow(&self.cast_ty); + self.expr_ty = table.eagerly_normalize_and_resolve_shallow_in(self.expr_ty.clone()); + self.cast_ty = table.eagerly_normalize_and_resolve_shallow_in(self.cast_ty.clone()); if self.expr_ty.contains_unknown() || self.cast_ty.contains_unknown() { return Ok(()); @@ -153,7 +152,7 @@ (None, Some(t_cast)) => match self.expr_ty.kind(Interner) { TyKind::FnDef(..) => { let sig = self.expr_ty.callable_sig(table.db).expect("FnDef had no sig"); - let sig = table.normalize_associated_types_in(sig); + let sig = table.eagerly_normalize_and_resolve_shallow_in(sig); let fn_ptr = TyKind::Function(sig.to_fn_ptr()).intern(Interner); if let Ok((adj, _)) = table.coerce(&self.expr_ty, &fn_ptr, CoerceNever::Yes) { @@ -165,7 +164,6 @@ (CastTy::FnPtr, t_cast) } TyKind::Ref(mutbl, _, inner_ty) => { - let inner_ty = table.resolve_ty_shallow(inner_ty); return match t_cast { CastTy::Int(_) | CastTy::Float => match inner_ty.kind(Interner) { TyKind::Scalar( @@ -180,13 +178,13 @@ }, // array-ptr-cast CastTy::Ptr(t, m) => { - let t = table.resolve_ty_shallow(&t); + let t = table.eagerly_normalize_and_resolve_shallow_in(t); if !table.is_sized(&t) { return Err(CastError::IllegalCast); } self.check_ref_cast( table, - &inner_ty, + inner_ty, *mutbl, &t, m, @@ -359,7 +357,7 @@ } } -#[derive(PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] enum PointerKind { // thin pointer Thin, @@ -373,8 +371,7 @@ } fn pointer_kind(ty: &Ty, table: &mut InferenceTable<'_>) -> Result<Option<PointerKind>, ()> { - let ty = table.resolve_ty_shallow(ty); - let ty = table.normalize_associated_types_in(ty); + let ty = table.eagerly_normalize_and_resolve_shallow_in(ty.clone()); if table.is_sized(&ty) { return Ok(Some(PointerKind::Thin));
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs index fe9f76e..d0c9b23 100644 --- a/crates/hir-ty/src/infer/unify.rs +++ b/crates/hir-ty/src/infer/unify.rs
@@ -364,6 +364,64 @@ ) } + /// Works almost same as [`Self::normalize_associated_types_in`], but this also resolves shallow + /// the inference variables + pub(crate) fn eagerly_normalize_and_resolve_shallow_in<T>(&mut self, ty: T) -> T + where + T: HasInterner<Interner = Interner> + TypeFoldable<Interner>, + { + fn eagerly_resolve_ty<const N: usize>( + table: &mut InferenceTable<'_>, + ty: Ty, + mut tys: SmallVec<[Ty; N]>, + ) -> Ty { + if tys.contains(&ty) { + return ty; + } + tys.push(ty.clone()); + + match ty.kind(Interner) { + TyKind::Alias(AliasTy::Projection(proj_ty)) => { + let ty = table.normalize_projection_ty(proj_ty.clone()); + eagerly_resolve_ty(table, ty, tys) + } + TyKind::InferenceVar(..) => { + let ty = table.resolve_ty_shallow(&ty); + eagerly_resolve_ty(table, ty, tys) + } + _ => ty, + } + } + + fold_tys_and_consts( + ty, + |e, _| match e { + Either::Left(ty) => { + Either::Left(eagerly_resolve_ty::<8>(self, ty, SmallVec::new())) + } + Either::Right(c) => Either::Right(match &c.data(Interner).value { + chalk_ir::ConstValue::Concrete(cc) => match &cc.interned { + crate::ConstScalar::UnevaluatedConst(c_id, subst) => { + // FIXME: same as `normalize_associated_types_in` + if subst.len(Interner) == 0 { + if let Ok(eval) = self.db.const_eval(*c_id, subst.clone(), None) { + eval + } else { + unknown_const(c.data(Interner).ty.clone()) + } + } else { + unknown_const(c.data(Interner).ty.clone()) + } + } + _ => c, + }, + _ => c, + }), + }, + DebruijnIndex::INNERMOST, + ) + } + pub(crate) fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty { let var = self.new_type_var(); let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() }; @@ -918,7 +976,26 @@ /// Check if given type is `Sized` or not pub(crate) fn is_sized(&mut self, ty: &Ty) -> bool { + fn short_circuit_trivial_tys(ty: &Ty) -> Option<bool> { + match ty.kind(Interner) { + TyKind::Scalar(..) + | TyKind::Ref(..) + | TyKind::Raw(..) + | TyKind::Never + | TyKind::FnDef(..) + | TyKind::Array(..) + | TyKind::Function(..) => Some(true), + TyKind::Slice(..) | TyKind::Str | TyKind::Dyn(..) => Some(false), + _ => None, + } + } + let mut ty = ty.clone(); + ty = self.eagerly_normalize_and_resolve_shallow_in(ty); + if let Some(sized) = short_circuit_trivial_tys(&ty) { + return sized; + } + { let mut structs = SmallVec::<[_; 8]>::new(); // Must use a loop here and not recursion because otherwise users will conduct completely @@ -937,26 +1014,16 @@ // Structs can have DST as its last field and such cases are not handled // as unsized by the chalk, so we do this manually. ty = last_field_ty; + ty = self.eagerly_normalize_and_resolve_shallow_in(ty); + if let Some(sized) = short_circuit_trivial_tys(&ty) { + return sized; + } } else { break; }; } } - // Early return for some obvious types - if matches!( - ty.kind(Interner), - TyKind::Scalar(..) - | TyKind::Ref(..) - | TyKind::Raw(..) - | TyKind::Never - | TyKind::FnDef(..) - | TyKind::Array(..) - | TyKind::Function(_) - ) { - return true; - } - let Some(sized) = self .db .lang_item(self.trait_env.krate, LangItem::Sized)
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index afa1f6d..651ec15 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs
@@ -570,10 +570,17 @@ source_map: &hir_def::expr_store::BodySourceMap, ) -> Option<AnyDiagnostic> { let expr_syntax = |expr| { - source_map.expr_syntax(expr).inspect_err(|_| stdx::never!("synthetic syntax")).ok() + source_map + .expr_syntax(expr) + .inspect_err(|_| stdx::never!("inference diagnostic in desugared expr")) + .ok() }; - let pat_syntax = - |pat| source_map.pat_syntax(pat).inspect_err(|_| stdx::never!("synthetic syntax")).ok(); + let pat_syntax = |pat| { + source_map + .pat_syntax(pat) + .inspect_err(|_| stdx::never!("inference diagnostic in desugared pattern")) + .ok() + }; let expr_or_pat_syntax = |id| match id { ExprOrPatId::ExprId(expr) => expr_syntax(expr), ExprOrPatId::PatId(pat) => pat_syntax(pat),
diff --git a/crates/ide-assists/src/handlers/add_braces.rs b/crates/ide-assists/src/handlers/add_braces.rs index d8db7cc..b6e3b0a 100644 --- a/crates/ide-assists/src/handlers/add_braces.rs +++ b/crates/ide-assists/src/handlers/add_braces.rs
@@ -39,7 +39,7 @@ }, expr.syntax().text_range(), |builder| { - let make = SyntaxFactory::new(); + let make = SyntaxFactory::with_mappings(); let mut editor = builder.make_editor(expr.syntax()); let block_expr = make.block_expr(None, Some(expr.clone()));
diff --git a/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 4cabf4b..777e40e 100644 --- a/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/crates/ide-assists/src/handlers/add_missing_match_arms.rs
@@ -77,7 +77,7 @@ let cfg = ctx.config.import_path_config(); - let make = SyntaxFactory::new(); + let make = SyntaxFactory::with_mappings(); let module = ctx.sema.scope(expr.syntax())?.module(); let (mut missing_pats, is_non_exhaustive, has_hidden_variants): ( @@ -467,7 +467,7 @@ let fields = var.fields(db); let pat: ast::Pat = match var.kind(db) { hir::StructKind::Tuple => { - let mut name_generator = suggest_name::NameGenerator::new(); + let mut name_generator = suggest_name::NameGenerator::default(); let pats = fields.into_iter().map(|f| { let name = name_generator.for_type(&f.ty(db), db, edition); match name {
diff --git a/crates/ide-assists/src/handlers/add_turbo_fish.rs b/crates/ide-assists/src/handlers/add_turbo_fish.rs index 4901962..245aa3a 100644 --- a/crates/ide-assists/src/handlers/add_turbo_fish.rs +++ b/crates/ide-assists/src/handlers/add_turbo_fish.rs
@@ -141,7 +141,7 @@ |builder| { builder.trigger_parameter_hints(); - let make = SyntaxFactory::new(); + let make = SyntaxFactory::with_mappings(); let mut editor = match &turbofish_target { Either::Left(it) => builder.make_editor(it.syntax()), Either::Right(it) => builder.make_editor(it.syntax()),
diff --git a/crates/ide-assists/src/handlers/apply_demorgan.rs b/crates/ide-assists/src/handlers/apply_demorgan.rs index daab992..e03b4ab 100644 --- a/crates/ide-assists/src/handlers/apply_demorgan.rs +++ b/crates/ide-assists/src/handlers/apply_demorgan.rs
@@ -64,7 +64,7 @@ _ => return None, }; - let make = SyntaxFactory::new(); + let make = SyntaxFactory::with_mappings(); let demorganed = bin_expr.clone_subtree(); let mut editor = SyntaxEditor::new(demorganed.syntax().clone()); @@ -111,7 +111,7 @@ "Apply De Morgan's law", op_range, |builder| { - let make = SyntaxFactory::new(); + let make = SyntaxFactory::with_mappings(); let paren_expr = bin_expr.syntax().parent().and_then(ast::ParenExpr::cast); let neg_expr = paren_expr .clone() @@ -194,7 +194,7 @@ label, op_range, |builder| { - let make = SyntaxFactory::new(); + let make = SyntaxFactory::with_mappings(); let mut editor = builder.make_editor(method_call.syntax()); // replace the method name let new_name = match name.text().as_str() {
diff --git a/crates/ide-assists/src/handlers/convert_bool_then.rs b/crates/ide-assists/src/handlers/convert_bool_then.rs index f3210a6..ba5488e 100644 --- a/crates/ide-assists/src/handlers/convert_bool_then.rs +++ b/crates/ide-assists/src/handlers/convert_bool_then.rs
@@ -98,7 +98,7 @@ let closure_body = ast::Expr::cast(edit.new_root().clone()).unwrap(); let mut editor = builder.make_editor(expr.syntax()); - let make = SyntaxFactory::new(); + let make = SyntaxFactory::with_mappings(); let closure_body = match closure_body { ast::Expr::BlockExpr(block) => unwrap_trivial_block(block), e => e, @@ -216,7 +216,7 @@ let closure_body = ast::BlockExpr::cast(edit.new_root().clone()).unwrap(); let mut editor = builder.make_editor(mcall.syntax()); - let make = SyntaxFactory::new(); + let make = SyntaxFactory::with_mappings(); let cond = match &receiver { ast::Expr::ParenExpr(expr) => expr.expr().unwrap_or(receiver),
diff --git a/crates/ide-assists/src/handlers/convert_for_to_while_let.rs b/crates/ide-assists/src/handlers/convert_for_to_while_let.rs index 801a57b..51b16ca 100644 --- a/crates/ide-assists/src/handlers/convert_for_to_while_let.rs +++ b/crates/ide-assists/src/handlers/convert_for_to_while_let.rs
@@ -51,7 +51,7 @@ "Replace this for loop with `while let`", for_loop.syntax().text_range(), |builder| { - let make = SyntaxFactory::new(); + let make = SyntaxFactory::with_mappings(); let mut editor = builder.make_editor(for_loop.syntax()); let (iterable, method) = if impls_core_iter(&ctx.sema, &iterable) {
diff --git a/crates/ide-assists/src/handlers/extract_variable.rs b/crates/ide-assists/src/handlers/extract_variable.rs index 95ea8b3..f44f4ba 100644 --- a/crates/ide-assists/src/handlers/extract_variable.rs +++ b/crates/ide-assists/src/handlers/extract_variable.rs
@@ -170,7 +170,7 @@ |edit| { let (var_name, expr_replace) = kind.get_name_and_expr(ctx, &to_extract); - let make = SyntaxFactory::new(); + let make = SyntaxFactory::with_mappings(); let mut editor = edit.make_editor(&expr_replace); let pat_name = make.name(&var_name);
diff --git a/crates/ide-assists/src/handlers/flip_binexpr.rs b/crates/ide-assists/src/handlers/flip_binexpr.rs index 94d7b73..2ac9fd8 100644 --- a/crates/ide-assists/src/handlers/flip_binexpr.rs +++ b/crates/ide-assists/src/handlers/flip_binexpr.rs
@@ -48,7 +48,7 @@ op_token.text_range(), |builder| { let mut editor = builder.make_editor(&expr.syntax().parent().unwrap()); - let make = SyntaxFactory::new(); + let make = SyntaxFactory::with_mappings(); if let FlipAction::FlipAndReplaceOp(binary_op) = action { editor.replace(op_token, make.token(binary_op)) };
diff --git a/crates/ide-assists/src/handlers/flip_comma.rs b/crates/ide-assists/src/handlers/flip_comma.rs index 25e514b..7045e4b 100644 --- a/crates/ide-assists/src/handlers/flip_comma.rs +++ b/crates/ide-assists/src/handlers/flip_comma.rs
@@ -101,7 +101,7 @@ ] .concat(); - let make = SyntaxFactory::new(); + let make = SyntaxFactory::with_mappings(); let new_token_tree = make.token_tree(tree.left_delimiter_token().unwrap().kind(), result); (new_token_tree, make.finish_with_mappings()) }
diff --git a/crates/ide-assists/src/handlers/generate_enum_variant.rs b/crates/ide-assists/src/handlers/generate_enum_variant.rs index 8a20a2d..4c45412 100644 --- a/crates/ide-assists/src/handlers/generate_enum_variant.rs +++ b/crates/ide-assists/src/handlers/generate_enum_variant.rs
@@ -60,7 +60,7 @@ acc.add(AssistId::generate("generate_enum_variant"), "Generate variant", target, |builder| { let mut editor = builder.make_editor(enum_node.syntax()); - let make = SyntaxFactory::new(); + let make = SyntaxFactory::with_mappings(); let field_list = parent.make_field_list(ctx, &make); let variant = make.variant(None, make.name(&name_ref.text()), field_list, None); if let Some(it) = enum_node.variant_list() {
diff --git a/crates/ide-assists/src/handlers/inline_local_variable.rs b/crates/ide-assists/src/handlers/inline_local_variable.rs index f1a3f72..297a53a 100644 --- a/crates/ide-assists/src/handlers/inline_local_variable.rs +++ b/crates/ide-assists/src/handlers/inline_local_variable.rs
@@ -91,7 +91,7 @@ } } - let make = SyntaxFactory::new(); + let make = SyntaxFactory::with_mappings(); for (name, should_wrap) in wrap_in_parens { let replacement = if should_wrap {
diff --git a/crates/ide-assists/src/handlers/introduce_named_type_parameter.rs b/crates/ide-assists/src/handlers/introduce_named_type_parameter.rs index 9c39a7a..37dc92b 100644 --- a/crates/ide-assists/src/handlers/introduce_named_type_parameter.rs +++ b/crates/ide-assists/src/handlers/introduce_named_type_parameter.rs
@@ -24,7 +24,7 @@ let fn_ = param.syntax().ancestors().nth(2).and_then(ast::Fn::cast)?; let type_bound_list = impl_trait_type.type_bound_list()?; - let make = SyntaxFactory::new(); + let make = SyntaxFactory::with_mappings(); let target = fn_.syntax().text_range(); acc.add( AssistId::refactor_rewrite("introduce_named_type_parameter"),
diff --git a/crates/ide-assists/src/handlers/remove_parentheses.rs b/crates/ide-assists/src/handlers/remove_parentheses.rs index f5b3e00..9349c53 100644 --- a/crates/ide-assists/src/handlers/remove_parentheses.rs +++ b/crates/ide-assists/src/handlers/remove_parentheses.rs
@@ -54,7 +54,7 @@ None => false, }; if need_to_add_ws { - let make = SyntaxFactory::new(); + let make = SyntaxFactory::with_mappings(); editor.insert(Position::before(parens.syntax()), make.whitespace(" ")); editor.add_mappings(make.finish_with_mappings()); }
diff --git a/crates/ide-assists/src/handlers/replace_if_let_with_match.rs b/crates/ide-assists/src/handlers/replace_if_let_with_match.rs index 734bd17..2b356a1 100644 --- a/crates/ide-assists/src/handlers/replace_if_let_with_match.rs +++ b/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
@@ -105,7 +105,7 @@ format!("Replace if{let_} with match"), available_range, move |builder| { - let make = SyntaxFactory::new(); + let make = SyntaxFactory::with_mappings(); let match_expr = { let else_arm = make_else_arm(ctx, &make, else_block, &cond_bodies); let make_match_arm = |(pat, body): (_, ast::BlockExpr)| { @@ -253,7 +253,7 @@ format!("Replace match with if{let_}"), match_expr.syntax().text_range(), move |builder| { - let make = SyntaxFactory::new(); + let make = SyntaxFactory::with_mappings(); let make_block_expr = |expr: ast::Expr| { // Blocks with modifiers (unsafe, async, etc.) are parsed as BlockExpr, but are // formatted without enclosing braces. If we encounter such block exprs,
diff --git a/crates/ide-assists/src/handlers/replace_let_with_if_let.rs b/crates/ide-assists/src/handlers/replace_let_with_if_let.rs index fd17231..c92a494 100644 --- a/crates/ide-assists/src/handlers/replace_let_with_if_let.rs +++ b/crates/ide-assists/src/handlers/replace_let_with_if_let.rs
@@ -43,7 +43,7 @@ target, |builder| { let mut editor = builder.make_editor(let_stmt.syntax()); - let make = SyntaxFactory::new(); + let make = SyntaxFactory::with_mappings(); let ty = ctx.sema.type_of_expr(&init); let pat = if let_stmt.let_else().is_some() { // Do not add the wrapper type that implements `Try`,
diff --git a/crates/ide-assists/src/handlers/unwrap_return_type.rs b/crates/ide-assists/src/handlers/unwrap_return_type.rs index 8804fea..1c4c373 100644 --- a/crates/ide-assists/src/handlers/unwrap_return_type.rs +++ b/crates/ide-assists/src/handlers/unwrap_return_type.rs
@@ -67,7 +67,7 @@ acc.add(kind.assist_id(), kind.label(), type_ref.syntax().text_range(), |builder| { let mut editor = builder.make_editor(&parent); - let make = SyntaxFactory::new(); + let make = SyntaxFactory::with_mappings(); let mut exprs_to_unwrap = Vec::new(); let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_unwrap, e);
diff --git a/crates/ide-assists/src/handlers/wrap_return_type.rs b/crates/ide-assists/src/handlers/wrap_return_type.rs index a044068..64251ed 100644 --- a/crates/ide-assists/src/handlers/wrap_return_type.rs +++ b/crates/ide-assists/src/handlers/wrap_return_type.rs
@@ -77,7 +77,7 @@ type_ref.syntax().text_range(), |builder| { let mut editor = builder.make_editor(&parent); - let make = SyntaxFactory::new(); + let make = SyntaxFactory::with_mappings(); let alias = wrapper_alias(ctx, &make, &core_wrapper, type_ref, kind.symbol()); let new_return_ty = alias.unwrap_or_else(|| match kind { WrapperKind::Option => make.ty_option(type_ref.clone()),
diff --git a/crates/ide-completion/src/completions/item_list.rs b/crates/ide-completion/src/completions/item_list.rs index 4ae00cc..58e7f58 100644 --- a/crates/ide-completion/src/completions/item_list.rs +++ b/crates/ide-completion/src/completions/item_list.rs
@@ -114,6 +114,7 @@ add_keyword("trait", "trait $1 {\n $0\n}"); if no_vis_qualifiers { add_keyword("impl", "impl $1 {\n $0\n}"); + add_keyword("impl for", "impl $1 for $2 {\n $0\n}"); } } @@ -144,6 +145,7 @@ add_keyword("use", "use $0"); if no_vis_qualifiers { add_keyword("impl", "impl $1 {\n $0\n}"); + add_keyword("impl for", "impl $1 for $2 {\n $0\n}"); } }
diff --git a/crates/ide-completion/src/completions/keyword.rs b/crates/ide-completion/src/completions/keyword.rs index 14b0d54..0397424 100644 --- a/crates/ide-completion/src/completions/keyword.rs +++ b/crates/ide-completion/src/completions/keyword.rs
@@ -56,6 +56,7 @@ kw extern kw fn kw impl + kw impl for kw trait "#]], );
diff --git a/crates/ide-completion/src/completions/pattern.rs b/crates/ide-completion/src/completions/pattern.rs index 59ef94d..ea3511d 100644 --- a/crates/ide-completion/src/completions/pattern.rs +++ b/crates/ide-completion/src/completions/pattern.rs
@@ -48,7 +48,7 @@ // Suggest name only in let-stmt and fn param if pattern_ctx.should_suggest_name { - let mut name_generator = suggest_name::NameGenerator::new(); + let mut name_generator = suggest_name::NameGenerator::default(); if let Some(suggested) = ctx .expected_type .as_ref()
diff --git a/crates/ide-completion/src/tests/expression.rs b/crates/ide-completion/src/tests/expression.rs index 98da2cb..b30ac43 100644 --- a/crates/ide-completion/src/tests/expression.rs +++ b/crates/ide-completion/src/tests/expression.rs
@@ -171,6 +171,7 @@ kw if kw if let kw impl + kw impl for kw let kw letm kw loop @@ -249,6 +250,7 @@ kw if kw if let kw impl + kw impl for kw let kw letm kw loop @@ -300,6 +302,7 @@ kw if kw if let kw impl + kw impl for kw let kw letm kw loop @@ -375,6 +378,7 @@ kw if kw if let kw impl + kw impl for kw let kw letm kw loop @@ -961,6 +965,7 @@ kw if kw if let kw impl + kw impl for kw let kw letm kw loop @@ -1003,6 +1008,7 @@ kw if kw if let kw impl + kw impl for kw let kw letm kw loop @@ -1095,6 +1101,7 @@ kw if kw if let kw impl + kw impl for kw let kw letm kw loop @@ -1137,6 +1144,7 @@ kw if kw if let kw impl + kw impl for kw let kw letm kw loop @@ -1179,6 +1187,7 @@ kw if kw if let kw impl + kw impl for kw let kw letm kw loop @@ -1231,6 +1240,7 @@ kw if kw if let kw impl + kw impl for kw let kw letm kw loop @@ -1285,6 +1295,7 @@ kw if kw if let kw impl + kw impl for kw let kw letm kw loop @@ -1529,6 +1540,7 @@ kw if kw if let kw impl + kw impl for kw let kw letm kw loop @@ -2001,6 +2013,7 @@ kw if kw if let kw impl + kw impl for kw let kw letm kw loop @@ -2073,6 +2086,7 @@ kw if kw if let kw impl + kw impl for kw let kw letm kw loop
diff --git a/crates/ide-completion/src/tests/item.rs b/crates/ide-completion/src/tests/item.rs index be2c37d..5568903 100644 --- a/crates/ide-completion/src/tests/item.rs +++ b/crates/ide-completion/src/tests/item.rs
@@ -284,6 +284,7 @@ kw if kw if let kw impl + kw impl for kw let kw letm kw loop
diff --git a/crates/ide-completion/src/tests/item_list.rs b/crates/ide-completion/src/tests/item_list.rs index 841c421..fcdf10c 100644 --- a/crates/ide-completion/src/tests/item_list.rs +++ b/crates/ide-completion/src/tests/item_list.rs
@@ -16,6 +16,7 @@ kw extern kw fn kw impl + kw impl for kw mod kw pub kw pub(crate) @@ -50,6 +51,7 @@ kw extern kw fn kw impl + kw impl for kw mod kw pub kw pub(crate) @@ -83,6 +85,7 @@ kw extern kw fn kw impl + kw impl for kw mod kw pub kw pub(crate) @@ -122,6 +125,7 @@ kw extern kw fn kw impl + kw impl for kw trait "#]], ); @@ -385,6 +389,7 @@ kw extern kw fn kw impl + kw impl for kw mod kw pub kw pub(crate)
diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs index 70caeac..15518e9 100644 --- a/crates/ide-completion/src/tests/special.rs +++ b/crates/ide-completion/src/tests/special.rs
@@ -1008,6 +1008,7 @@ kw if kw if let kw impl + kw impl for kw let kw letm kw loop @@ -1059,6 +1060,7 @@ kw if kw if let kw impl + kw impl for kw let kw letm kw loop @@ -1184,6 +1186,7 @@ kw if kw if let kw impl + kw impl for kw let kw letm kw loop @@ -1441,6 +1444,7 @@ kw if kw if let kw impl + kw impl for kw let kw letm kw loop
diff --git a/crates/ide-db/src/prime_caches/topologic_sort.rs b/crates/ide-db/src/prime_caches/topologic_sort.rs index 7353d71..c8a0386 100644 --- a/crates/ide-db/src/prime_caches/topologic_sort.rs +++ b/crates/ide-db/src/prime_caches/topologic_sort.rs
@@ -7,14 +7,20 @@ nodes: FxHashMap<T, Entry<T>>, } +// this implementation has different bounds on T than would be implied by #[derive(Default)] +impl<T> Default for TopologicSortIterBuilder<T> +where + T: Copy + Eq + PartialEq + Hash, +{ + fn default() -> Self { + Self { nodes: Default::default() } + } +} + impl<T> TopologicSortIterBuilder<T> where T: Copy + Eq + PartialEq + Hash, { - fn new() -> Self { - Self { nodes: Default::default() } - } - fn get_or_create_entry(&mut self, item: T) -> &mut Entry<T> { self.nodes.entry(item).or_default() } @@ -54,7 +60,7 @@ T: Copy + Eq + PartialEq + Hash, { pub(crate) fn builder() -> TopologicSortIterBuilder<T> { - TopologicSortIterBuilder::new() + TopologicSortIterBuilder::default() } pub(crate) fn pending(&self) -> usize {
diff --git a/crates/ide-db/src/source_change.rs b/crates/ide-db/src/source_change.rs index 741dc6b..b1b58d6 100644 --- a/crates/ide-db/src/source_change.rs +++ b/crates/ide-db/src/source_change.rs
@@ -469,7 +469,7 @@ } fn add_snippet_annotation(&mut self, kind: AnnotationSnippet) -> SyntaxAnnotation { - let annotation = SyntaxAnnotation::new(); + let annotation = SyntaxAnnotation::default(); self.snippet_annotations.push((kind, annotation)); self.source_change.is_snippet = true; annotation
diff --git a/crates/ide-db/src/syntax_helpers/suggest_name.rs b/crates/ide-db/src/syntax_helpers/suggest_name.rs index 6801856..51ce9b4 100644 --- a/crates/ide-db/src/syntax_helpers/suggest_name.rs +++ b/crates/ide-db/src/syntax_helpers/suggest_name.rs
@@ -96,21 +96,16 @@ } impl NameGenerator { - /// Create a new empty generator - pub fn new() -> Self { - Self { pool: FxHashMap::default() } - } - /// Create a new generator with existing names. When suggesting a name, it will /// avoid conflicts with existing names. pub fn new_with_names<'a>(existing_names: impl Iterator<Item = &'a str>) -> Self { - let mut generator = Self::new(); + let mut generator = Self::default(); existing_names.for_each(|name| generator.insert(name)); generator } pub fn new_from_scope_locals(scope: Option<SemanticsScope<'_>>) -> Self { - let mut generator = Self::new(); + let mut generator = Self::default(); if let Some(scope) = scope { scope.process_all_names(&mut |name, scope| { if let hir::ScopeDef::Local(_) = scope { @@ -471,7 +466,7 @@ frange.range, "selection is not an expression(yet contained in one)" ); - let name = NameGenerator::new().for_variable(&expr, &sema); + let name = NameGenerator::default().for_variable(&expr, &sema); assert_eq!(&name, expected); } @@ -1118,7 +1113,7 @@ #[test] fn conflicts_with_existing_names() { - let mut generator = NameGenerator::new(); + let mut generator = NameGenerator::default(); assert_eq!(generator.suggest_name("a"), "a"); assert_eq!(generator.suggest_name("a"), "a1"); assert_eq!(generator.suggest_name("a"), "a2");
diff --git a/crates/ide-diagnostics/src/handlers/invalid_cast.rs b/crates/ide-diagnostics/src/handlers/invalid_cast.rs index 82cd1f2f..b56255b 100644 --- a/crates/ide-diagnostics/src/handlers/invalid_cast.rs +++ b/crates/ide-diagnostics/src/handlers/invalid_cast.rs
@@ -440,8 +440,9 @@ q as *const [i32]; //^^^^^^^^^^^^^^^^^ error: cannot cast thin pointer `*const i32` to fat pointer `*const [i32]` + // FIXME: This should emit diagnostics but disabled to prevent many false positives let t: *mut (dyn Trait + 'static) = 0 as *mut _; - //^^^^^^^^^^^ error: cannot cast `usize` to a fat pointer `*mut _` + let mut fail: *const str = 0 as *const str; //^^^^^^^^^^^^^^^ error: cannot cast `usize` to a fat pointer `*const str` let mut fail2: *const str = 0isize as *const str; @@ -1164,4 +1165,47 @@ "#, ); } + + #[test] + fn regression_19431() { + check_diagnostics( + r#" +//- minicore: coerce_unsized +struct Dst([u8]); + +struct Struct { + body: Dst, +} + +trait Field { + type Type: ?Sized; +} + +impl Field for Struct { + type Type = Dst; +} + +trait KnownLayout { + type MaybeUninit: ?Sized; + type PointerMetadata; +} + +impl<T> KnownLayout for [T] { + type MaybeUninit = [T]; + type PointerMetadata = usize; +} + +impl KnownLayout for Dst { + type MaybeUninit = Dst; + type PointerMetadata = <[u8] as KnownLayout>::PointerMetadata; +} + +struct ZerocopyKnownLayoutMaybeUninit(<<Struct as Field>::Type as KnownLayout>::MaybeUninit); + +fn test(ptr: *mut ZerocopyKnownLayoutMaybeUninit) -> *mut <<Struct as Field>::Type as KnownLayout>::MaybeUninit { + ptr as *mut _ +} +"#, + ); + } }
diff --git a/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/crates/ide-diagnostics/src/handlers/type_mismatch.rs index e1124c9..591213d 100644 --- a/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -231,7 +231,7 @@ .and_then(Either::<ast::ReturnExpr, ast::StmtList>::cast)?; editor = builder.make_editor(parent.syntax()); - let make = SyntaxFactory::new(); + let make = SyntaxFactory::with_mappings(); match parent { Either::Left(ret_expr) => {
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index a01afd2..258d80e 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs
@@ -627,7 +627,7 @@ return Some((def, file, Some(format!("variant.{}", ev.name(db).as_str())))); } Definition::Const(c) => { - format!("const.{}.html", c.name(db)?.as_str()) + format!("constant.{}.html", c.name(db)?.as_str()) } Definition::Static(s) => { format!("static.{}.html", s.name(db).as_str())
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs index 4811f1f..7766897 100644 --- a/crates/ide/src/expand_macro.rs +++ b/crates/ide/src/expand_macro.rs
@@ -677,4 +677,26 @@ crate::Foo;"#]], ); } + + #[test] + fn semi_glueing() { + check( + r#" +macro_rules! __log_value { + ($key:ident :$capture:tt =) => {}; +} + +macro_rules! __log { + ($key:tt $(:$capture:tt)? $(= $value:expr)?; $($arg:tt)+) => { + __log_value!($key $(:$capture)* = $($value)*); + }; +} + +__log!(written:%; "Test"$0); + "#, + expect![[r#" + __log! + "#]], + ); + } }
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 8eca23e..13b161e 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs
@@ -238,7 +238,7 @@ file_set.insert(file_id, VfsPath::new_virtual_path("/main.rs".to_owned())); let source_root = SourceRoot::new_local(file_set); - let mut change = ChangeWithProcMacros::new(); + let mut change = ChangeWithProcMacros::default(); change.set_roots(vec![source_root]); let mut crate_graph = CrateGraphBuilder::default(); // FIXME: cfg options @@ -753,7 +753,7 @@ frange: FileRange, ) -> Cancellable<Vec<Assist>> { let include_fixes = match &assist_config.allowed { - Some(it) => it.iter().any(|&it| it == AssistKind::QuickFix), + Some(it) => it.contains(&AssistKind::QuickFix), None => true, };
diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs index 1244132..057d635 100644 --- a/crates/ide/src/static_index.rs +++ b/crates/ide/src/static_index.rs
@@ -1,17 +1,17 @@ //! This module provides `StaticIndex` which is used for powering //! read-only code browsers and emitting LSIF +use arrayvec::ArrayVec; use hir::{Crate, HirFileIdExt, Module, Semantics, db::HirDatabase}; use ide_db::{ FileId, FileRange, FxHashMap, FxHashSet, RootDatabase, base_db::{RootQueryDb, SourceDatabase, VfsPath}, - defs::Definition, + defs::{Definition, IdentClass}, documentation::Documentation, famous_defs::FamousDefs, - helpers::get_definition, }; use span::Edition; -use syntax::{AstNode, SyntaxKind::*, SyntaxNode, T, TextRange}; +use syntax::{AstNode, SyntaxKind::*, SyntaxNode, SyntaxToken, T, TextRange}; use crate::navigation_target::UpmappingResult; use crate::{ @@ -126,6 +126,22 @@ ) } +// FIXME: This is a weird function +fn get_definitions( + sema: &Semantics<'_, RootDatabase>, + token: SyntaxToken, +) -> Option<ArrayVec<Definition, 2>> { + for token in sema.descend_into_macros_exact(token) { + let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops); + if let Some(defs) = def { + if !defs.is_empty() { + return Some(defs); + } + } + } + None +} + pub enum VendoredLibrariesConfig<'a> { Included { workspace_root: &'a VfsPath }, Excluded, @@ -257,11 +273,14 @@ for token in tokens { let range = token.text_range(); let node = token.parent().unwrap(); - let def = match get_definition(&sema, token.clone()) { - Some(it) => it, + match get_definitions(&sema, token.clone()) { + Some(it) => { + for i in it { + add_token(i, range, &node); + } + } None => continue, }; - add_token(def, range, &node); } self.files.push(result); } @@ -308,7 +327,7 @@ #[cfg(test)] mod tests { use crate::{StaticIndex, fixture}; - use ide_db::{FileRange, FxHashSet, base_db::VfsPath}; + use ide_db::{FileRange, FxHashMap, FxHashSet, base_db::VfsPath}; use syntax::TextSize; use super::VendoredLibrariesConfig; @@ -363,6 +382,71 @@ } } + #[track_caller] + fn check_references( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + vendored_libs_config: VendoredLibrariesConfig<'_>, + ) { + let (analysis, ranges) = fixture::annotations_without_marker(ra_fixture); + let s = StaticIndex::compute(&analysis, vendored_libs_config); + let mut range_set: FxHashMap<_, i32> = ranges.iter().map(|it| (it.0, 0)).collect(); + + // Make sure that all references have at least one range. We use a HashMap instead of a + // a HashSet so that we can have more than one reference at the same range. + for (_, t) in s.tokens.iter() { + for r in &t.references { + if r.is_definition { + continue; + } + if r.range.range.start() == TextSize::from(0) { + // ignore whole file range corresponding to module definition + continue; + } + match range_set.entry(r.range) { + std::collections::hash_map::Entry::Occupied(mut entry) => { + let count = entry.get_mut(); + *count += 1; + } + std::collections::hash_map::Entry::Vacant(_) => { + panic!("additional reference {r:?}"); + } + } + } + } + for (range, count) in range_set.iter() { + if *count == 0 { + panic!("unfound reference {range:?}"); + } + } + } + + #[test] + fn field_initialization() { + check_references( + r#" +struct Point { + x: f64, + //^^^ + y: f64, + //^^^ +} + fn foo() { + let x = 5.; + let y = 10.; + let mut p = Point { x, y }; + //^^^^^ ^ ^ + p.x = 9.; + //^ ^ + p.y = 10.; + //^ ^ + } +"#, + VendoredLibrariesConfig::Included { + workspace_root: &VfsPath::new_virtual_path("/workspace".to_owned()), + }, + ); + } + #[test] fn struct_and_enum() { check_all_ranges( @@ -387,6 +471,17 @@ workspace_root: &VfsPath::new_virtual_path("/workspace".to_owned()), }, ); + + check_references( + r#" +struct Foo; +enum E { X(Foo) } + // ^^^ +"#, + VendoredLibrariesConfig::Included { + workspace_root: &VfsPath::new_virtual_path("/workspace".to_owned()), + }, + ); } #[test]
diff --git a/crates/ide/src/view_crate_graph.rs b/crates/ide/src/view_crate_graph.rs index e878c9a..4696fef 100644 --- a/crates/ide/src/view_crate_graph.rs +++ b/crates/ide/src/view_crate_graph.rs
@@ -1,4 +1,5 @@ use dot::{Id, LabelText}; +use ide_db::base_db::salsa::plumbing::AsId; use ide_db::{ FxHashMap, RootDatabase, base_db::{ @@ -78,7 +79,8 @@ } fn node_id(&'a self, n: &Crate) -> Id<'a> { - Id::new(format!("_{:?}", n)).unwrap() + let id = n.as_id().as_u32(); + Id::new(format!("_{:?}", id)).unwrap() } fn node_shape(&'a self, _node: &Crate) -> Option<LabelText<'a>> {
diff --git a/crates/intern/src/lib.rs b/crates/intern/src/lib.rs index 6548bb1..e990490 100644 --- a/crates/intern/src/lib.rs +++ b/crates/intern/src/lib.rs
@@ -177,7 +177,10 @@ map: OnceLock<InternMap<T>>, } -#[allow(clippy::new_without_default)] // this a const fn, so it can't be default +#[allow( + clippy::new_without_default, + reason = "this a const fn, so it can't be default yet. See <https://github.com/rust-lang/rust/issues/63065>" +)] impl<T: ?Sized> InternStorage<T> { pub const fn new() -> Self { Self { map: OnceLock::new() }
diff --git a/crates/intern/src/symbol/symbols.rs b/crates/intern/src/symbol/symbols.rs index 4841f48..a9ed185 100644 --- a/crates/intern/src/symbol/symbols.rs +++ b/crates/intern/src/symbol/symbols.rs
@@ -161,6 +161,7 @@ bitxor_assign, bitxor, bool, + bootstrap, box_free, Box, boxed, @@ -525,4 +526,8 @@ ignore_flyimport, ignore_flyimport_methods, ignore_methods, + position, + flags, + precision, + width, }
diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs index c85eda7..c50e63d 100644 --- a/crates/load-cargo/src/lib.rs +++ b/crates/load-cargo/src/lib.rs
@@ -426,7 +426,7 @@ ) -> RootDatabase { let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<u16>().ok()); let mut db = RootDatabase::new(lru_cap); - let mut analysis_change = ChangeWithProcMacros::new(); + let mut analysis_change = ChangeWithProcMacros::default(); db.enable_proc_attr_macros();
diff --git a/crates/mbe/src/expander/transcriber.rs b/crates/mbe/src/expander/transcriber.rs index 1459243..e2340b4 100644 --- a/crates/mbe/src/expander/transcriber.rs +++ b/crates/mbe/src/expander/transcriber.rs
@@ -390,8 +390,13 @@ match ctx.bindings.get_fragment(v, id, &mut ctx.nesting, marker) { Ok(fragment) => { match fragment { - Fragment::Tokens(tt) => builder.extend_with_tt(tt.strip_invisible()), - Fragment::TokensOwned(tt) => builder.extend_with_tt(tt.view().strip_invisible()), + // rustc spacing is not like ours. Ours is like proc macros', it dictates how puncts will actually be joined. + // rustc uses them mostly for pretty printing. So we have to deviate a bit from what rustc does here. + // Basically, a metavariable can never be joined with whatever after it. + Fragment::Tokens(tt) => builder.extend_with_tt_alone(tt.strip_invisible()), + Fragment::TokensOwned(tt) => { + builder.extend_with_tt_alone(tt.view().strip_invisible()) + } Fragment::Expr(sub) => { let sub = sub.strip_invisible(); let mut span = id; @@ -403,7 +408,7 @@ if wrap_in_parens { builder.open(tt::DelimiterKind::Parenthesis, span); } - builder.extend_with_tt(sub); + builder.extend_with_tt_alone(sub); if wrap_in_parens { builder.close(span); }
diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs index 7be49cb..8a2f124 100644 --- a/crates/mbe/src/parser.rs +++ b/crates/mbe/src/parser.rs
@@ -6,7 +6,10 @@ use arrayvec::ArrayVec; use intern::{Symbol, sym}; use span::{Edition, Span, SyntaxContext}; -use tt::iter::{TtElement, TtIter}; +use tt::{ + MAX_GLUED_PUNCT_LEN, + iter::{TtElement, TtIter}, +}; use crate::ParseError; @@ -96,7 +99,7 @@ delimiter: tt::Delimiter<Span>, }, Literal(tt::Literal<Span>), - Punct(Box<ArrayVec<tt::Punct<Span>, 3>>), + Punct(Box<ArrayVec<tt::Punct<Span>, MAX_GLUED_PUNCT_LEN>>), Ident(tt::Ident<Span>), } @@ -151,7 +154,7 @@ pub(crate) enum Separator { Literal(tt::Literal<Span>), Ident(tt::Ident<Span>), - Puncts(ArrayVec<tt::Punct<Span>, 3>), + Puncts(ArrayVec<tt::Punct<Span>, MAX_GLUED_PUNCT_LEN>), } // Note that when we compare a Separator, we just care about its textual value.
diff --git a/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs b/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs index 749a776..dfdbb4c 100644 --- a/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs +++ b/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs
@@ -90,7 +90,7 @@ #[proc_macro_derive(DeriveEmpty)] pub fn derive_empty(_item: TokenStream) -> TokenStream { - TokenStream::new() + TokenStream::default() } #[proc_macro_derive(DerivePanic)]
diff --git a/crates/proc-macro-srv/src/proc_macros.rs b/crates/proc-macro-srv/src/proc_macros.rs index 42474ab..1853270 100644 --- a/crates/proc-macro-srv/src/proc_macros.rs +++ b/crates/proc-macro-srv/src/proc_macros.rs
@@ -26,7 +26,7 @@ let parsed_body = crate::server_impl::TokenStream::with_subtree(macro_body); let parsed_attributes = attributes - .map_or_else(crate::server_impl::TokenStream::new, |attr| { + .map_or_else(crate::server_impl::TokenStream::default, |attr| { crate::server_impl::TokenStream::with_subtree(attr) });
diff --git a/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index 6254018..1d845da 100644 --- a/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
@@ -212,7 +212,7 @@ base: Option<Self::TokenStream>, trees: Vec<bridge::TokenTree<Self::TokenStream, Self::Span, Self::Symbol>>, ) -> Self::TokenStream { - let mut builder = TokenStreamBuilder::new(); + let mut builder = TokenStreamBuilder::default(); if let Some(base) = base { builder.push(base); } @@ -227,7 +227,7 @@ base: Option<Self::TokenStream>, streams: Vec<Self::TokenStream>, ) -> Self::TokenStream { - let mut builder = TokenStreamBuilder::new(); + let mut builder = TokenStreamBuilder::default(); if let Some(base) = base { builder.push(base); }
diff --git a/crates/proc-macro-srv/src/server_impl/token_id.rs b/crates/proc-macro-srv/src/server_impl/token_id.rs index d0c7f23..ca9d329 100644 --- a/crates/proc-macro-srv/src/server_impl/token_id.rs +++ b/crates/proc-macro-srv/src/server_impl/token_id.rs
@@ -190,7 +190,7 @@ base: Option<Self::TokenStream>, trees: Vec<bridge::TokenTree<Self::TokenStream, Self::Span, Self::Symbol>>, ) -> Self::TokenStream { - let mut builder = TokenStreamBuilder::new(); + let mut builder = TokenStreamBuilder::default(); if let Some(base) = base { builder.push(base); } @@ -205,7 +205,7 @@ base: Option<Self::TokenStream>, streams: Vec<Self::TokenStream>, ) -> Self::TokenStream { - let mut builder = TokenStreamBuilder::new(); + let mut builder = TokenStreamBuilder::default(); if let Some(base) = base { builder.push(base); }
diff --git a/crates/proc-macro-srv/src/server_impl/token_stream.rs b/crates/proc-macro-srv/src/server_impl/token_stream.rs index a3cf76d..4946a4f 100644 --- a/crates/proc-macro-srv/src/server_impl/token_stream.rs +++ b/crates/proc-macro-srv/src/server_impl/token_stream.rs
@@ -9,6 +9,13 @@ pub(super) token_trees: Vec<tt::TokenTree<S>>, } +// #[derive(Default)] would mean that `S: Default`. +impl<S> Default for TokenStream<S> { + fn default() -> Self { + Self { token_trees: Default::default() } + } +} + impl<S: std::fmt::Debug + Copy> std::fmt::Debug for TokenStream<S> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("TokenStream") @@ -17,17 +24,7 @@ } } -impl<S> Default for TokenStream<S> { - fn default() -> Self { - Self { token_trees: vec![] } - } -} - impl<S: Copy> TokenStream<S> { - pub(crate) fn new() -> Self { - TokenStream::default() - } - pub(crate) fn with_subtree(subtree: TopSubtree<S>) -> Self { let delimiter_kind = subtree.top_subtree().delimiter.kind; let mut token_trees = subtree.0; @@ -145,10 +142,6 @@ } impl<S: Copy> TokenStreamBuilder<S> { - pub(super) fn new() -> TokenStreamBuilder<S> { - TokenStreamBuilder { acc: TokenStream::new() } - } - pub(super) fn push(&mut self, stream: TokenStream<S>) { self.acc.token_trees.extend(stream.token_trees) } @@ -157,3 +150,9 @@ self.acc } } + +impl<S: Copy> Default for TokenStreamBuilder<S> { + fn default() -> Self { + Self { acc: TokenStream::default() } + } +}
diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs index 9711932..d304c97 100644 --- a/crates/project-model/src/cargo_workspace.rs +++ b/crates/project-model/src/cargo_workspace.rs
@@ -108,7 +108,10 @@ pub invocation_strategy: InvocationStrategy, /// Optional path to use instead of `target` when building pub target_dir: Option<Utf8PathBuf>, + /// Gate `#[test]` behind `#[cfg(test)]` pub set_test: bool, + /// Load the project without any dependencies + pub no_deps: bool, } pub type Package = Idx<PackageData>; @@ -308,6 +311,7 @@ current_dir: &AbsPath, config: &CargoMetadataConfig, sysroot: &Sysroot, + no_deps: bool, locked: bool, progress: &dyn Fn(String), ) -> anyhow::Result<(cargo_metadata::Metadata, Option<anyhow::Error>)> { @@ -316,8 +320,8 @@ current_dir, config, sysroot, + no_deps, locked, - false, progress, ); if let Ok((_, Some(ref e))) = res { @@ -335,8 +339,8 @@ current_dir: &AbsPath, config: &CargoMetadataConfig, sysroot: &Sysroot, - locked: bool, no_deps: bool, + locked: bool, progress: &dyn Fn(String), ) -> anyhow::Result<(cargo_metadata::Metadata, Option<anyhow::Error>)> { let cargo = sysroot.tool(Tool::Cargo, current_dir);
diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs index 7e8db8d..6ed030a 100644 --- a/crates/project-model/src/sysroot.rs +++ b/crates/project-model/src/sysroot.rs
@@ -300,6 +300,7 @@ rust_lib_src_dir, &cargo_config, self, + false, // Make sure we never attempt to write to the sysroot true, &|_| (),
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index 857ea84..7a139ea 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs
@@ -220,6 +220,7 @@ sysroot, sysroot_src, target, + no_deps, .. } = config; let mut sysroot = match (sysroot, sysroot_src) { @@ -301,6 +302,7 @@ extra_env: extra_env.clone(), }, &sysroot, + *no_deps, false, &|_| (), ) { @@ -343,6 +345,7 @@ extra_env: extra_env.clone(), }, &sysroot, + *no_deps, false, &|_| (), ) @@ -511,6 +514,7 @@ extra_env: config.extra_env.clone(), }, &sysroot, + config.no_deps, false, &|_| (), ) @@ -1660,6 +1664,7 @@ vec![ CfgAtom::Flag(sym::debug_assertions.clone()), CfgAtom::Flag(sym::miri.clone()), + CfgAtom::Flag(sym::bootstrap.clone()), ], vec![CfgAtom::Flag(sym::test.clone())], ),
diff --git a/crates/rust-analyzer/src/cli/rustc_tests.rs b/crates/rust-analyzer/src/cli/rustc_tests.rs index 62cbe85..c042c26 100644 --- a/crates/rust-analyzer/src/cli/rustc_tests.rs +++ b/crates/rust-analyzer/src/cli/rustc_tests.rs
@@ -139,7 +139,7 @@ FxHashMap::default() }; let text = read_to_string(&p).unwrap(); - let mut change = ChangeWithProcMacros::new(); + let mut change = ChangeWithProcMacros::default(); // Ignore unstable tests, since they move too fast and we do not intend to support all of them. let mut ignore_test = text.contains("#![feature"); // Ignore test with extern crates, as this infra don't support them yet.
diff --git a/crates/rust-analyzer/src/cli/scip.rs b/crates/rust-analyzer/src/cli/scip.rs index 1d27b05..d296788 100644 --- a/crates/rust-analyzer/src/cli/scip.rs +++ b/crates/rust-analyzer/src/cli/scip.rs
@@ -128,7 +128,7 @@ }; // Generates symbols from token monikers. - let mut symbol_generator = SymbolGenerator::new(); + let mut symbol_generator = SymbolGenerator::default(); for StaticIndexedFile { file_id, tokens, .. } in si.files { symbol_generator.clear_document_local_state(); @@ -417,16 +417,13 @@ is_inherent_impl: bool, } +#[derive(Default)] struct SymbolGenerator { token_to_symbols: FxHashMap<TokenId, Option<TokenSymbols>>, local_count: usize, } impl SymbolGenerator { - fn new() -> Self { - SymbolGenerator { token_to_symbols: FxHashMap::default(), local_count: 0 } - } - fn clear_document_local_state(&mut self) { self.local_count = 0; }
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 351b2a6..aceacff 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs
@@ -609,6 +609,9 @@ cargo_features: CargoFeaturesDef = CargoFeaturesDef::Selected(vec![]), /// Whether to pass `--no-default-features` to cargo. cargo_noDefaultFeatures: bool = false, + /// Whether to skip fetching dependencies. If set to "true", the analysis is performed + /// entirely offline, and Cargo metadata for dependencies is not fetched. + cargo_noDeps: bool = false, /// Relative path to the sysroot, or "discover" to try to automatically find it via /// "rustc --print sysroot". /// @@ -2027,6 +2030,7 @@ extra_env: self.cargo_extraEnv(source_root).clone(), target_dir: self.target_dir_from_config(source_root), set_test: *self.cfg_setTest(source_root), + no_deps: *self.cargo_noDeps(source_root), } }
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 6fc0ba9..820276e 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs
@@ -299,7 +299,7 @@ FxHashMap::default(); let (change, modified_rust_files, workspace_structure_change) = { - let mut change = ChangeWithProcMacros::new(); + let mut change = ChangeWithProcMacros::default(); let mut guard = self.vfs.write(); let changed_files = guard.0.take_changes(); if changed_files.is_empty() {
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs index 4ad028e..49ebffa 100644 --- a/crates/rust-analyzer/src/integrated_benchmarks.rs +++ b/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -86,7 +86,7 @@ "self.data.cargo_buildScripts_rebuildOnSave", "self. data. cargo_buildScripts_rebuildOnSave", ); - let mut change = ChangeWithProcMacros::new(); + let mut change = ChangeWithProcMacros::default(); change.change_file(file_id, Some(text)); host.apply_change(change); } @@ -149,7 +149,7 @@ let completion_offset = patch(&mut text, "db.struct_data(self.id)", "sel;\ndb.struct_data(self.id)") + "sel".len(); - let mut change = ChangeWithProcMacros::new(); + let mut change = ChangeWithProcMacros::default(); change.change_file(file_id, Some(text)); host.apply_change(change); completion_offset @@ -200,7 +200,7 @@ let completion_offset = patch(&mut text, "sel;\ndb.struct_data(self.id)", ";sel;\ndb.struct_data(self.id)") + ";sel".len(); - let mut change = ChangeWithProcMacros::new(); + let mut change = ChangeWithProcMacros::default(); change.change_file(file_id, Some(text)); host.apply_change(change); completion_offset @@ -250,7 +250,7 @@ let completion_offset = patch(&mut text, "sel;\ndb.struct_data(self.id)", "self.;\ndb.struct_data(self.id)") + "self.".len(); - let mut change = ChangeWithProcMacros::new(); + let mut change = ChangeWithProcMacros::default(); change.change_file(file_id, Some(text)); host.apply_change(change); completion_offset @@ -367,7 +367,7 @@ let _it = stdx::timeit("change"); let mut text = host.analysis().file_text(file_id).unwrap().to_string(); patch(&mut text, "db.struct_data(self.id)", "();\ndb.struct_data(self.id)"); - let mut change = ChangeWithProcMacros::new(); + let mut change = ChangeWithProcMacros::default(); change.change_file(file_id, Some(text)); host.apply_change(change); };
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 283b8f3..b73019b 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs
@@ -413,35 +413,26 @@ .map(|res| res.as_ref().map_err(|e| e.to_string())) .chain(iter::repeat_with(|| Err("proc-macro-srv is not running".into()))); for (client, paths) in proc_macro_clients.zip(paths) { - paths - .into_iter() - .map(move |(crate_id, res)| { - ( - crate_id, - res.map_or_else( - |e| Err((e, true)), - |(crate_name, path)| { - progress(path.to_string()); - client.as_ref().map_err(|it| (it.clone(), true)).and_then( - |client| { - load_proc_macro( - client, - &path, - ignored_proc_macros - .iter() - .find_map(|(name, macros)| { - eq_ignore_underscore(name, &crate_name) - .then_some(&**macros) - }) - .unwrap_or_default(), - ) - }, - ) - }, - ), - ) - }) - .for_each(|(krate, res)| builder.insert(krate, res)); + for (crate_id, res) in paths.iter() { + let expansion_res = match client { + Ok(client) => match res { + Ok((crate_name, path)) => { + progress(path.to_string()); + let ignored_proc_macros = ignored_proc_macros + .iter() + .find_map(|(name, macros)| { + eq_ignore_underscore(name, crate_name).then_some(&**macros) + }) + .unwrap_or_default(); + + load_proc_macro(client, path, ignored_proc_macros) + } + Err(e) => Err((e.clone(), true)), + }, + Err(ref e) => Err((e.clone(), true)), + }; + builder.insert(*crate_id, expansion_res) + } } change.set_proc_macros(builder); @@ -645,7 +636,7 @@ Config::user_config_dir_path().as_deref(), ); - if (self.proc_macro_clients.is_empty() || !same_workspaces) + if (self.proc_macro_clients.len() < self.workspaces.len() || !same_workspaces) && self.config.expand_proc_macros() { info!("Spawning proc-macro servers"); @@ -739,7 +730,7 @@ ws_to_crate_graph(&self.workspaces, self.config.extra_env(None), load) }; - let mut change = ChangeWithProcMacros::new(); + let mut change = ChangeWithProcMacros::default(); if initial_build || !self.config.expand_proc_macros() { if self.config.expand_proc_macros() { change.set_proc_macros(
diff --git a/crates/stdx/Cargo.toml b/crates/stdx/Cargo.toml index 7603330..7bda106 100644 --- a/crates/stdx/Cargo.toml +++ b/crates/stdx/Cargo.toml
@@ -13,7 +13,7 @@ [dependencies] backtrace = { version = "0.3.74", optional = true } -jod-thread = "0.1.2" +jod-thread = "1.0.0" crossbeam-channel.workspace = true itertools.workspace = true tracing.workspace = true
diff --git a/crates/stdx/src/anymap.rs b/crates/stdx/src/anymap.rs index faf2e6c..f55698e 100644 --- a/crates/stdx/src/anymap.rs +++ b/crates/stdx/src/anymap.rs
@@ -1,4 +1,5 @@ //! This file is a port of only the necessary features from <https://github.com/chris-morgan/anymap> version 1.0.0-beta.2 for use within rust-analyzer. +//! //! Copyright © 2014–2022 Chris Morgan. //! COPYING: <https://github.com/chris-morgan/anymap/blob/master/COPYING> //! Note that the license is changed from Blue Oak Model 1.0.0 or MIT or Apache-2.0 to MIT OR Apache-2.0 @@ -20,14 +21,14 @@ use core::hash::Hasher; -/// A hasher designed to eke a little more speed out, given `TypeId`’s known characteristics. +/// A hasher designed to eke a little more speed out, given `TypeId`'s known characteristics. /// -/// Specifically, this is a no-op hasher that expects to be fed a u64’s worth of +/// Specifically, this is a no-op hasher that expects to be fed a u64's worth of /// randomly-distributed bits. It works well for `TypeId` (eliminating start-up time, so that my -/// get_missing benchmark is ~30ns rather than ~900ns, and being a good deal faster after that, so -/// that my insert_and_get_on_260_types benchmark is ~12μs instead of ~21.5μs), but will +/// `get_missing` benchmark is ~30ns rather than ~900ns, and being a good deal faster after that, so +/// that my `insert_and_get_on_260_types` benchmark is ~12μs instead of ~21.5μs), but will /// panic in debug mode and always emit zeros in release mode for any other sorts of inputs, so -/// yeah, don’t use it! 😀 +/// yeah, don't use it! 😀 #[derive(Default)] pub struct TypeIdHasher { value: u64, @@ -36,9 +37,9 @@ impl Hasher for TypeIdHasher { #[inline] fn write(&mut self, bytes: &[u8]) { - // This expects to receive exactly one 64-bit value, and there’s no realistic chance of - // that changing, but I don’t want to depend on something that isn’t expressly part of the - // contract for safety. But I’m OK with release builds putting everything in one bucket + // This expects to receive exactly one 64-bit value, and there's no realistic chance of + // that changing, but I don't want to depend on something that isn't expressly part of the + // contract for safety. But I'm OK with release builds putting everything in one bucket // if it *did* change (and debug builds panicking). debug_assert_eq!(bytes.len(), 8); let _ = bytes.try_into().map(|array| self.value = u64::from_ne_bytes(array)); @@ -59,7 +60,7 @@ /// Raw access to the underlying `HashMap`. /// /// This alias is provided for convenience because of the ugly third generic parameter. -#[allow(clippy::disallowed_types)] // Uses a custom hasher +#[expect(clippy::disallowed_types, reason = "Uses a custom hasher")] pub type RawMap<A> = hash_map::HashMap<TypeId, Box<A>, BuildHasherDefault<TypeIdHasher>>; /// A collection containing zero or one values for any given type and allowing convenient, @@ -73,19 +74,20 @@ /// /// Cumulatively, there are thus six forms of map: /// -/// - <code>[Map]<dyn [core::any::Any]></code>, +/// - `[Map]<dyn [core::any::Any]>`, /// also spelled [`AnyMap`] for convenience. -/// - <code>[Map]<dyn [core::any::Any] + Send></code> -/// - <code>[Map]<dyn [core::any::Any] + Send + Sync></code> +/// - `[Map]<dyn [core::any::Any] + Send>` +/// - `[Map]<dyn [core::any::Any] + Send + Sync>` /// /// ## Example /// -/// (Here using the [`AnyMap`] convenience alias; the first line could use -/// <code>[anymap::Map][Map]::<[core::any::Any]>::new()</code> instead if desired.) +/// (Here, the [`AnyMap`] convenience alias is used; +/// the first line could use `[anymap::Map][Map]::<[core::any::Any]>::new()` +/// instead if desired.) /// /// ``` /// # use stdx::anymap; -#[doc = "let mut data = anymap::AnyMap::new();"] +/// let mut data = anymap::AnyMap::new(); /// assert_eq!(data.get(), None::<&i32>); /// ``` /// @@ -95,29 +97,25 @@ raw: RawMap<A>, } -/// The most common type of `Map`: just using `Any`; <code>[Map]<dyn [Any]></code>. +/// The most common type of `Map`: just using `Any`; `[Map]<dyn [Any]>`. /// /// Why is this a separate type alias rather than a default value for `Map<A>`? -/// `Map::new()` doesn’t seem to be happy to infer that it should go with the default -/// value. It’s a bit sad, really. Ah well, I guess this approach will do. +/// `Map::new()` doesn't seem to be happy to infer that it should go with the default +/// value. It's a bit sad, really. Ah well, I guess this approach will do. pub type AnyMap = Map<dyn Any>; + impl<A: ?Sized + Downcast> Default for Map<A> { #[inline] fn default() -> Map<A> { - Map::new() + Map { raw: RawMap::with_hasher(Default::default()) } } } impl<A: ?Sized + Downcast> Map<A> { - /// Create an empty collection. - #[inline] - pub fn new() -> Map<A> { - Map { raw: RawMap::with_hasher(Default::default()) } - } - /// Returns a reference to the value stored in the collection for the type `T`, /// if it exists. #[inline] + #[must_use] pub fn get<T: IntoBox<A>>(&self) -> Option<&T> { self.raw.get(&TypeId::of::<T>()).map(|any| unsafe { any.downcast_ref_unchecked::<T>() }) } @@ -137,30 +135,30 @@ } /// A view into a single occupied location in an `Map`. -pub struct OccupiedEntry<'a, A: ?Sized + Downcast, V: 'a> { - inner: hash_map::OccupiedEntry<'a, TypeId, Box<A>>, +pub struct OccupiedEntry<'map, A: ?Sized + Downcast, V: 'map> { + inner: hash_map::OccupiedEntry<'map, TypeId, Box<A>>, type_: PhantomData<V>, } /// A view into a single empty location in an `Map`. -pub struct VacantEntry<'a, A: ?Sized + Downcast, V: 'a> { - inner: hash_map::VacantEntry<'a, TypeId, Box<A>>, +pub struct VacantEntry<'map, A: ?Sized + Downcast, V: 'map> { + inner: hash_map::VacantEntry<'map, TypeId, Box<A>>, type_: PhantomData<V>, } /// A view into a single location in an `Map`, which may be vacant or occupied. -pub enum Entry<'a, A: ?Sized + Downcast, V> { +pub enum Entry<'map, A: ?Sized + Downcast, V> { /// An occupied Entry - Occupied(OccupiedEntry<'a, A, V>), + Occupied(OccupiedEntry<'map, A, V>), /// A vacant Entry - Vacant(VacantEntry<'a, A, V>), + Vacant(VacantEntry<'map, A, V>), } -impl<'a, A: ?Sized + Downcast, V: IntoBox<A>> Entry<'a, A, V> { +impl<'map, A: ?Sized + Downcast, V: IntoBox<A>> Entry<'map, A, V> { /// Ensures a value is in the entry by inserting the result of the default function if /// empty, and returns a mutable reference to the value in the entry. #[inline] - pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V { + pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'map mut V { match self { Entry::Occupied(inner) => inner.into_mut(), Entry::Vacant(inner) => inner.insert(default()), @@ -168,20 +166,21 @@ } } -impl<'a, A: ?Sized + Downcast, V: IntoBox<A>> OccupiedEntry<'a, A, V> { - /// Converts the OccupiedEntry into a mutable reference to the value in the entry +impl<'map, A: ?Sized + Downcast, V: IntoBox<A>> OccupiedEntry<'map, A, V> { + /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry /// with a lifetime bound to the collection itself #[inline] - pub fn into_mut(self) -> &'a mut V { + #[must_use] + pub fn into_mut(self) -> &'map mut V { unsafe { self.inner.into_mut().downcast_mut_unchecked() } } } -impl<'a, A: ?Sized + Downcast, V: IntoBox<A>> VacantEntry<'a, A, V> { - /// Sets the value of the entry with the VacantEntry's key, +impl<'map, A: ?Sized + Downcast, V: IntoBox<A>> VacantEntry<'map, A, V> { + /// Sets the value of the entry with the `VacantEntry`'s key, /// and returns a mutable reference to it #[inline] - pub fn insert(self, value: V) -> &'a mut V { + pub fn insert(self, value: V) -> &'map mut V { unsafe { self.inner.insert(value.into_box()).downcast_mut_unchecked() } } } @@ -206,14 +205,13 @@ #[test] fn type_id_hasher() { use core::any::TypeId; - use core::hash::Hash; + use core::hash::Hash as _; fn verify_hashing_with(type_id: TypeId) { let mut hasher = TypeIdHasher::default(); type_id.hash(&mut hasher); - // SAFETY: u64 is valid for all bit patterns. - let _ = hasher.finish(); + _ = hasher.finish(); } - // Pick a variety of types, just to demonstrate it’s all sane. Normal, zero-sized, unsized, &c. + // Pick a variety of types, just to demonstrate it's all sane. Normal, zero-sized, unsized, &c. verify_hashing_with(TypeId::of::<usize>()); verify_hashing_with(TypeId::of::<()>()); verify_hashing_with(TypeId::of::<str>()); @@ -225,34 +223,34 @@ /// Methods for downcasting from an `Any`-like trait object. /// /// This should only be implemented on trait objects for subtraits of `Any`, though you can -/// implement it for other types and it’ll work fine, so long as your implementation is correct. +/// implement it for other types and it'll work fine, so long as your implementation is correct. pub trait Downcast { /// Gets the `TypeId` of `self`. fn type_id(&self) -> TypeId; // Note the bound through these downcast methods is 'static, rather than the inexpressible // concept of Self-but-as-a-trait (where Self is `dyn Trait`). This is sufficient, exceeding - // TypeId’s requirements. Sure, you *can* do CloneAny.downcast_unchecked::<NotClone>() and the - // type system won’t protect you, but that doesn’t introduce any unsafety: the method is + // TypeId's requirements. Sure, you *can* do CloneAny.downcast_unchecked::<NotClone>() and the + // type system won't protect you, but that doesn't introduce any unsafety: the method is // already unsafe because you can specify the wrong type, and if this were exposing safe // downcasting, CloneAny.downcast::<NotClone>() would just return an error, which is just as // correct. // - // Now in theory we could also add T: ?Sized, but that doesn’t play nicely with the common - // implementation, so I’m doing without it. + // Now in theory we could also add T: ?Sized, but that doesn't play nicely with the common + // implementation, so I'm doing without it. /// Downcast from `&Any` to `&T`, without checking the type matches. /// /// # Safety /// - /// The caller must ensure that `T` matches the trait object, on pain of *undefined behaviour*. + /// The caller must ensure that `T` matches the trait object, on pain of *undefined behavior*. unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T; /// Downcast from `&mut Any` to `&mut T`, without checking the type matches. /// /// # Safety /// - /// The caller must ensure that `T` matches the trait object, on pain of *undefined behaviour*. + /// The caller must ensure that `T` matches the trait object, on pain of *undefined behavior*. unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T; } @@ -272,12 +270,12 @@ #[inline] unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T { - unsafe { &*(self as *const Self as *const T) } + unsafe { &*std::ptr::from_ref::<Self>(self).cast::<T>() } } #[inline] unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T { - unsafe { &mut *(self as *mut Self as *mut T) } + unsafe { &mut *std::ptr::from_mut::<Self>(self).cast::<T>() } } }
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs index 982be40d..9a292ea 100644 --- a/crates/stdx/src/lib.rs +++ b/crates/stdx/src/lib.rs
@@ -17,7 +17,7 @@ pub use itertools; #[inline(always)] -pub fn is_ci() -> bool { +pub const fn is_ci() -> bool { option_env!("CI").is_some() } @@ -26,14 +26,14 @@ } #[must_use] -#[allow(clippy::print_stderr)] +#[expect(clippy::print_stderr, reason = "only visible to developers")] pub fn timeit(label: &'static str) -> impl Drop { let start = Instant::now(); - defer(move || eprintln!("{}: {:.2?}", label, start.elapsed())) + defer(move || eprintln!("{}: {:.2}", label, start.elapsed().as_nanos())) } /// Prints backtrace to stderr, useful for debugging. -#[allow(clippy::print_stderr)] +#[expect(clippy::print_stderr, reason = "only visible to developers")] pub fn print_backtrace() { #[cfg(feature = "backtrace")] eprintln!("{:?}", backtrace::Backtrace::new()); @@ -126,6 +126,7 @@ } // Taken from rustc. +#[must_use] pub fn to_camel_case(ident: &str) -> String { ident .trim_matches('_') @@ -156,7 +157,7 @@ camel_cased_component }) - .fold((String::new(), None), |(acc, prev): (_, Option<String>), next| { + .fold((String::new(), None), |(mut acc, prev): (_, Option<String>), next| { // separate two components with an underscore if their boundary cannot // be distinguished using an uppercase/lowercase case distinction let join = prev @@ -166,16 +167,20 @@ Some(!char_has_case(l) && !char_has_case(f)) }) .unwrap_or(false); - (acc + if join { "_" } else { "" } + &next, Some(next)) + acc.push_str(if join { "_" } else { "" }); + acc.push_str(&next); + (acc, Some(next)) }) .0 } // Taken from rustc. -pub fn char_has_case(c: char) -> bool { +#[must_use] +pub const fn char_has_case(c: char) -> bool { c.is_lowercase() || c.is_uppercase() } +#[must_use] pub fn is_upper_snake_case(s: &str) -> bool { s.chars().all(|c| c.is_uppercase() || c == '_' || c.is_numeric()) } @@ -188,6 +193,7 @@ *buf = buf.replace(from, to); } +#[must_use] pub fn trim_indent(mut text: &str) -> String { if text.starts_with('\n') { text = &text[1..]; @@ -249,8 +255,8 @@ impl Drop for JodChild { fn drop(&mut self) { - let _ = self.0.kill(); - let _ = self.0.wait(); + _ = self.0.kill(); + _ = self.0.wait(); } } @@ -259,12 +265,11 @@ command.spawn().map(Self) } + #[must_use] + #[cfg(not(target_arch = "wasm32"))] pub fn into_inner(self) -> std::process::Child { - if cfg!(target_arch = "wasm32") { - panic!("no processes on wasm"); - } // SAFETY: repr transparent, except on WASM - unsafe { std::mem::transmute::<JodChild, std::process::Child>(self) } + unsafe { std::mem::transmute::<Self, std::process::Child>(self) } } }
diff --git a/crates/stdx/src/non_empty_vec.rs b/crates/stdx/src/non_empty_vec.rs index 342194c..faa322d 100644 --- a/crates/stdx/src/non_empty_vec.rs +++ b/crates/stdx/src/non_empty_vec.rs
@@ -8,8 +8,8 @@ impl<T> NonEmptyVec<T> { #[inline] - pub fn new(first: T) -> Self { - NonEmptyVec { first, rest: Vec::new() } + pub const fn new(first: T) -> Self { + Self { first, rest: Vec::new() } } #[inline] @@ -24,7 +24,7 @@ #[inline] pub fn push(&mut self, value: T) { - self.rest.push(value) + self.rest.push(value); } #[inline]
diff --git a/crates/stdx/src/panic_context.rs b/crates/stdx/src/panic_context.rs index a35d50b..b220451 100644 --- a/crates/stdx/src/panic_context.rs +++ b/crates/stdx/src/panic_context.rs
@@ -16,7 +16,7 @@ } pub fn enter(frame: String) -> PanicContext { - #[allow(clippy::print_stderr)] + #[expect(clippy::print_stderr, reason = "already panicking anyway")] fn set_hook() { let default_hook = panic::take_hook(); panic::set_hook(Box::new(move |panic_info| {
diff --git a/crates/stdx/src/process.rs b/crates/stdx/src/process.rs index 3b3955c..2efeed4 100644 --- a/crates/stdx/src/process.rs +++ b/crates/stdx/src/process.rs
@@ -54,6 +54,9 @@ Ok((stdout, stderr)) } +/// # Panics +/// +/// Panics if `cmd` is not configured to have `stdout` and `stderr` as `piped`. pub fn spawn_with_streaming_output( mut cmd: Command, on_stdout_line: &mut dyn FnMut(&str),
diff --git a/crates/stdx/src/rand.rs b/crates/stdx/src/rand.rs index 115a073..e028990 100644 --- a/crates/stdx/src/rand.rs +++ b/crates/stdx/src/rand.rs
@@ -1,8 +1,7 @@ -//! We don't use `rand`, as that's too many things for us. +//! We don't use `rand` because that is too many things for us. //! -//! We currently use oorandom instead, but it's missing these two utilities. -//! Perhaps we should switch to `fastrand`, or our own small PRNG, it's not like -//! we need anything more complicated than xor-shift. +//! `oorandom` is used instead, but it's missing these two utilities. +//! Switching to `fastrand` or our own small PRNG may be good because only xor-shift is needed. pub fn shuffle<T>(slice: &mut [T], mut rand_index: impl FnMut(usize) -> usize) { let mut remaining = slice.len() - 1;
diff --git a/crates/stdx/src/thread.rs b/crates/stdx/src/thread.rs index e577eb4..6c742fe 100644 --- a/crates/stdx/src/thread.rs +++ b/crates/stdx/src/thread.rs
@@ -1,12 +1,12 @@ //! A utility module for working with threads that automatically joins threads upon drop -//! and abstracts over operating system quality of service (QoS) APIs +//! and abstracts over operating system quality of service (`QoS`) APIs //! through the concept of a “thread intent”. //! //! The intent of a thread is frozen at thread creation time, //! i.e. there is no API to change the intent of a thread once it has been spawned. //! //! As a system, rust-analyzer should have the property that -//! old manual scheduling APIs are replaced entirely by QoS. +//! old manual scheduling APIs are replaced entirely by `QoS`. //! To maintain this invariant, we panic when it is clear that //! old scheduling APIs have been used. //! @@ -23,10 +23,12 @@ pub use intent::ThreadIntent; pub use pool::Pool; +/// # Panics +/// +/// Panics if failed to spawn the thread. pub fn spawn<F, T>(intent: ThreadIntent, f: F) -> JoinHandle<T> where - F: FnOnce() -> T, - F: Send + 'static, + F: (FnOnce() -> T) + Send + 'static, T: Send + 'static, { Builder::new(intent).spawn(f).expect("failed to spawn thread") @@ -39,26 +41,29 @@ } impl Builder { - pub fn new(intent: ThreadIntent) -> Builder { - Builder { intent, inner: jod_thread::Builder::new(), allow_leak: false } + #[must_use] + pub fn new(intent: ThreadIntent) -> Self { + Self { intent, inner: jod_thread::Builder::new(), allow_leak: false } } - pub fn name(self, name: String) -> Builder { - Builder { inner: self.inner.name(name), ..self } + #[must_use] + pub fn name(self, name: String) -> Self { + Self { inner: self.inner.name(name), ..self } } - pub fn stack_size(self, size: usize) -> Builder { - Builder { inner: self.inner.stack_size(size), ..self } + #[must_use] + pub fn stack_size(self, size: usize) -> Self { + Self { inner: self.inner.stack_size(size), ..self } } - pub fn allow_leak(self, b: bool) -> Builder { - Builder { allow_leak: b, ..self } + #[must_use] + pub fn allow_leak(self, allow_leak: bool) -> Self { + Self { allow_leak, ..self } } pub fn spawn<F, T>(self, f: F) -> std::io::Result<JoinHandle<T>> where - F: FnOnce() -> T, - F: Send + 'static, + F: (FnOnce() -> T) + Send + 'static, T: Send + 'static, { let inner_handle = self.inner.spawn(move || { @@ -78,6 +83,10 @@ } impl<T> JoinHandle<T> { + /// # Panics + /// + /// Panics if there is no thread to join. + #[must_use] pub fn join(mut self) -> T { self.inner.take().unwrap().join() } @@ -95,6 +104,7 @@ } } +#[expect(clippy::min_ident_chars, reason = "trait impl")] impl<T> fmt::Debug for JoinHandle<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("JoinHandle { .. }")
diff --git a/crates/stdx/src/thread/intent.rs b/crates/stdx/src/thread/intent.rs index 7b65db3..1203bfc 100644 --- a/crates/stdx/src/thread/intent.rs +++ b/crates/stdx/src/thread/intent.rs
@@ -1,9 +1,9 @@ -//! An opaque façade around platform-specific QoS APIs. +//! An opaque façade around platform-specific `QoS` APIs. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] // Please maintain order from least to most priority for the derived `Ord` impl. pub enum ThreadIntent { - /// Any thread which does work that isn’t in the critical path of the user typing + /// Any thread which does work that isn't in the critical path of the user typing /// (e.g. processing Go To Definition). Worker, @@ -34,6 +34,7 @@ const IS_QOS_AVAILABLE: bool = imp::IS_QOS_AVAILABLE; +#[expect(clippy::semicolon_if_nothing_returned, reason = "thin wrapper")] fn set_current_thread_qos_class(class: QoSClass) { imp::set_current_thread_qos_class(class) } @@ -63,7 +64,7 @@ /// /// * **You do not care about how long it takes for work to finish.** /// * **You do not care about work being deferred temporarily.** - /// (e.g. if the device’s battery is in a critical state) + /// (e.g. if the device's battery is in a critical state) /// /// Examples: /// @@ -84,7 +85,7 @@ /// All other work is prioritized over background tasks. Background, - /// TLDR: tasks that don’t block using your app + /// TLDR: tasks that don't block using your app /// /// Contract: /// @@ -110,7 +111,7 @@ /// for tasks using this class. /// /// This QoS class provides a balance between - /// performance, responsiveness and efficiency. + /// performance, responsiveness, and efficiency. Utility, /// TLDR: tasks that block using your app @@ -126,10 +127,10 @@ /// * in a video editor: /// opening a saved project /// * in a browser: - /// loading a list of the user’s bookmarks and top sites + /// loading a list of the user's bookmarks and top sites /// when a new tab is created /// * in a collaborative word processor: - /// running a search on the document’s content + /// running a search on the document's content /// /// Use this QoS class for tasks which were initiated by the user /// and block the usage of your app while they are in progress. @@ -208,7 +209,7 @@ } _ => { - // `pthread_set_qos_class_self_np`’s documentation + // `pthread_set_qos_class_self_np`'s documentation // does not mention any other errors. unreachable!("`pthread_set_qos_class_self_np` returned unexpected error {errno}") } @@ -223,7 +224,7 @@ }; if code != 0 { - // `pthread_get_qos_class_np`’s documentation states that + // `pthread_get_qos_class_np`'s documentation states that // an error value is placed into errno if the return code is not zero. // However, it never states what errors are possible. // Inspecting the source[0] shows that, as of this writing, it always returns zero.
diff --git a/crates/stdx/src/thread/pool.rs b/crates/stdx/src/thread/pool.rs index 0efff38..074cd74 100644 --- a/crates/stdx/src/thread/pool.rs +++ b/crates/stdx/src/thread/pool.rs
@@ -38,7 +38,11 @@ } impl Pool { - pub fn new(threads: usize) -> Pool { + /// # Panics + /// + /// Panics if job panics + #[must_use] + pub fn new(threads: usize) -> Self { const STACK_SIZE: usize = 8 * 1024 * 1024; const INITIAL_INTENT: ThreadIntent = ThreadIntent::Worker; @@ -63,7 +67,7 @@ } extant_tasks.fetch_add(1, Ordering::SeqCst); // discard the panic, we should've logged the backtrace already - _ = panic::catch_unwind(job.f); + drop(panic::catch_unwind(job.f)); extant_tasks.fetch_sub(1, Ordering::SeqCst); } } @@ -73,9 +77,12 @@ handles.push(handle); } - Pool { _handles: handles.into_boxed_slice(), extant_tasks, job_sender } + Self { _handles: handles.into_boxed_slice(), extant_tasks, job_sender } } + /// # Panics + /// + /// Panics if job panics pub fn spawn<F>(&self, intent: ThreadIntent, f: F) where F: FnOnce() + Send + UnwindSafe + 'static, @@ -84,14 +91,20 @@ if cfg!(debug_assertions) { intent.assert_is_used_on_current_thread(); } - f() + f(); }); let job = Job { requested_intent: intent, f }; self.job_sender.send(job).unwrap(); } + #[must_use] pub fn len(&self) -> usize { self.extant_tasks.load(Ordering::SeqCst) } + + #[must_use] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } }
diff --git a/crates/syntax/src/ast/syntax_factory.rs b/crates/syntax/src/ast/syntax_factory.rs index 1c517ac..7142e4f 100644 --- a/crates/syntax/src/ast/syntax_factory.rs +++ b/crates/syntax/src/ast/syntax_factory.rs
@@ -19,8 +19,8 @@ impl SyntaxFactory { /// Creates a new [`SyntaxFactory`], generating mappings between input nodes and generated nodes. - pub fn new() -> Self { - Self { mappings: Some(RefCell::new(SyntaxMapping::new())) } + pub fn with_mappings() -> Self { + Self { mappings: Some(RefCell::new(SyntaxMapping::default())) } } /// Creates a [`SyntaxFactory`] without generating mappings.
diff --git a/crates/syntax/src/syntax_editor.rs b/crates/syntax/src/syntax_editor.rs index 1f72272..5820018 100644 --- a/crates/syntax/src/syntax_editor.rs +++ b/crates/syntax/src/syntax_editor.rs
@@ -33,7 +33,7 @@ impl SyntaxEditor { /// Creates a syntax editor to start editing from `root` pub fn new(root: SyntaxNode) -> Self { - Self { root, changes: vec![], mappings: SyntaxMapping::new(), annotations: vec![] } + Self { root, changes: vec![], mappings: SyntaxMapping::default(), annotations: vec![] } } pub fn add_annotation(&mut self, element: impl Element, annotation: SyntaxAnnotation) { @@ -151,9 +151,8 @@ #[repr(transparent)] pub struct SyntaxAnnotation(NonZeroU32); -impl SyntaxAnnotation { - /// Creates a unique syntax annotation to attach data to. - pub fn new() -> Self { +impl Default for SyntaxAnnotation { + fn default() -> Self { static COUNTER: AtomicU32 = AtomicU32::new(1); // Only consistency within a thread matters, as SyntaxElements are !Send @@ -163,12 +162,6 @@ } } -impl Default for SyntaxAnnotation { - fn default() -> Self { - Self::new() - } -} - /// Position describing where to insert elements #[derive(Debug)] pub struct Position { @@ -411,12 +404,12 @@ let to_replace = root.syntax().descendants().find_map(ast::BinExpr::cast).unwrap(); let mut editor = SyntaxEditor::new(root.syntax().clone()); - let make = SyntaxFactory::new(); + let make = SyntaxFactory::with_mappings(); let name = make::name("var_name"); let name_ref = make::name_ref("var_name").clone_for_update(); - let placeholder_snippet = SyntaxAnnotation::new(); + let placeholder_snippet = SyntaxAnnotation::default(); editor.add_annotation(name.syntax(), placeholder_snippet); editor.add_annotation(name_ref.syntax(), placeholder_snippet); @@ -522,7 +515,7 @@ let second_let = root.syntax().descendants().find_map(ast::LetStmt::cast).unwrap(); let mut editor = SyntaxEditor::new(root.syntax().clone()); - let make = SyntaxFactory::new(); + let make = SyntaxFactory::with_mappings(); let new_block_expr = make.block_expr([], Some(ast::Expr::BlockExpr(inner_block.clone()))); @@ -574,7 +567,7 @@ let inner_block = root.clone(); let mut editor = SyntaxEditor::new(root.syntax().clone()); - let make = SyntaxFactory::new(); + let make = SyntaxFactory::with_mappings(); let new_block_expr = make.block_expr([], Some(ast::Expr::BlockExpr(inner_block.clone())));
diff --git a/crates/syntax/src/syntax_editor/mapping.rs b/crates/syntax/src/syntax_editor/mapping.rs index f71925a..1eaef03 100644 --- a/crates/syntax/src/syntax_editor/mapping.rs +++ b/crates/syntax/src/syntax_editor/mapping.rs
@@ -20,10 +20,6 @@ } impl SyntaxMapping { - pub fn new() -> Self { - Self::default() - } - /// Like [`SyntaxMapping::upmap_child`] but for syntax elements. pub fn upmap_child_element( &self,
diff --git a/crates/test-fixture/src/lib.rs b/crates/test-fixture/src/lib.rs index 0509a39..059397b 100644 --- a/crates/test-fixture/src/lib.rs +++ b/crates/test-fixture/src/lib.rs
@@ -139,7 +139,7 @@ let channel = toolchain.as_deref().unwrap_or("stable"); Version::parse(&format!("1.76.0-{channel}")).unwrap() }); - let mut source_change = FileChange::new(); + let mut source_change = FileChange::default(); let mut files = Vec::new(); let mut crate_graph = CrateGraphBuilder::default();
diff --git a/crates/tt/src/iter.rs b/crates/tt/src/iter.rs index 1d88218..0418c00 100644 --- a/crates/tt/src/iter.rs +++ b/crates/tt/src/iter.rs
@@ -6,7 +6,7 @@ use arrayvec::ArrayVec; use intern::sym; -use crate::{Ident, Leaf, Punct, Spacing, Subtree, TokenTree, TokenTreesView}; +use crate::{Ident, Leaf, MAX_GLUED_PUNCT_LEN, Punct, Spacing, Subtree, TokenTree, TokenTreesView}; #[derive(Clone)] pub struct TtIter<'a, S> { @@ -111,7 +111,7 @@ /// /// This method currently may return a single quotation, which is part of lifetime ident and /// conceptually not a punct in the context of mbe. Callers should handle this. - pub fn expect_glued_punct(&mut self) -> Result<ArrayVec<Punct<S>, 3>, ()> { + pub fn expect_glued_punct(&mut self) -> Result<ArrayVec<Punct<S>, MAX_GLUED_PUNCT_LEN>, ()> { let TtElement::Leaf(&Leaf::Punct(first)) = self.next().ok_or(())? else { return Err(()); }; @@ -145,7 +145,6 @@ } ('-' | '!' | '*' | '/' | '&' | '%' | '^' | '+' | '<' | '=' | '>' | '|', '=', _) | ('-' | '=' | '>', '>', _) - | (_, _, Some(';')) | ('<', '-', _) | (':', ':', _) | ('.', '.', _)
diff --git a/crates/tt/src/lib.rs b/crates/tt/src/lib.rs index 916e00b..36ccb67 100644 --- a/crates/tt/src/lib.rs +++ b/crates/tt/src/lib.rs
@@ -22,6 +22,8 @@ pub use text_size::{TextRange, TextSize}; +pub const MAX_GLUED_PUNCT_LEN: usize = 3; + #[derive(Clone, PartialEq, Debug)] pub struct Lit { pub kind: LitKind, @@ -243,6 +245,23 @@ self.token_trees.extend(tt.0.iter().cloned()); } + /// Like [`Self::extend_with_tt()`], but makes sure the new tokens will never be + /// joint with whatever comes after them. + pub fn extend_with_tt_alone(&mut self, tt: TokenTreesView<'_, S>) { + if let Some((last, before_last)) = tt.0.split_last() { + self.token_trees.reserve(tt.0.len()); + self.token_trees.extend(before_last.iter().cloned()); + let last = if let TokenTree::Leaf(Leaf::Punct(last)) = last { + let mut last = *last; + last.spacing = Spacing::Alone; + TokenTree::Leaf(Leaf::Punct(last)) + } else { + last.clone() + }; + self.token_trees.push(last); + } + } + pub fn expected_delimiters(&self) -> impl Iterator<Item = &Delimiter<S>> { self.unclosed_subtree_indices.iter().rev().map(|&subtree_idx| { let TokenTree::Subtree(subtree) = &self.token_trees[subtree_idx] else {
diff --git a/docs/book/src/configuration_generated.md b/docs/book/src/configuration_generated.md index 0a612d2..860d824 100644 --- a/docs/book/src/configuration_generated.md +++ b/docs/book/src/configuration_generated.md
@@ -130,6 +130,12 @@ Whether to pass `--no-default-features` to cargo. +**rust-analyzer.cargo.noDeps** (default: false) + + Whether to skip fetching dependencies. If set to "true", the analysis is performed +entirely offline, and Cargo metadata for dependencies is not fetched. + + **rust-analyzer.cargo.sysroot** (default: "discover") Relative path to the sysroot, or "discover" to try to automatically find it via
diff --git a/editors/code/language-configuration.json b/editors/code/language-configuration.json index 6619d0c..aacd48b 100644 --- a/editors/code/language-configuration.json +++ b/editors/code/language-configuration.json
@@ -14,9 +14,9 @@ ["(", ")"] ], "autoClosingPairs": [ - { "open": "{", "close": "}" }, - { "open": "[", "close": "]" }, - { "open": "(", "close": ")" }, + { "open": "{", "close": "}", "notIn": ["string"] }, + { "open": "[", "close": "]", "notIn": ["string"] }, + { "open": "(", "close": ")", "notIn": ["string"] }, { "open": "\"", "close": "\"", "notIn": ["string"] }, { "open": "/*", "close": " */", "notIn": ["string"] }, { "open": "`", "close": "`", "notIn": ["string"] },
diff --git a/editors/code/package.json b/editors/code/package.json index 55477b7..a048862 100644 --- a/editors/code/package.json +++ b/editors/code/package.json
@@ -894,6 +894,16 @@ { "title": "cargo", "properties": { + "rust-analyzer.cargo.noDeps": { + "markdownDescription": "Whether to skip fetching dependencies. If set to \"true\", the analysis is performed\nentirely offline, and Cargo metadata for dependencies is not fetched.", + "default": false, + "type": "boolean" + } + } + }, + { + "title": "cargo", + "properties": { "rust-analyzer.cargo.sysroot": { "markdownDescription": "Relative path to the sysroot, or \"discover\" to try to automatically find it via\n\"rustc --print sysroot\".\n\nUnsetting this disables sysroot loading.\n\nThis option does not take effect until rust-analyzer is restarted.", "default": "discover",
diff --git a/xtask/src/publish/notes.rs b/xtask/src/publish/notes.rs index 7245ce2..93592d4 100644 --- a/xtask/src/publish/notes.rs +++ b/xtask/src/publish/notes.rs
@@ -85,7 +85,7 @@ } fn process_list(&mut self) -> anyhow::Result<()> { - let mut nesting = ListNesting::new(); + let mut nesting = ListNesting::default(); while let Some(line) = self.iter.peek() { let line = line.as_deref().map_err(|e| anyhow!("{e}"))?; @@ -385,10 +385,6 @@ struct ListNesting(Vec<ListMarker>); impl ListNesting { - fn new() -> Self { - Self(Vec::<ListMarker>::with_capacity(6)) - } - fn current(&mut self) -> Option<&ListMarker> { self.0.last() } @@ -417,6 +413,12 @@ } } +impl Default for ListNesting { + fn default() -> Self { + Self(Vec::<ListMarker>::with_capacity(6)) + } +} + #[derive(Debug, PartialEq, Eq)] enum ListMarker { Asterisk(usize),