| author | bors <bors@rust-lang.org> 2026-02-09 19:19:04 UTC |
| committer | bors <bors@rust-lang.org> 2026-02-09 19:19:04 UTC |
| log | 18d13b5332916ffca8eadb9106d54b5b434e9978 |
| tree | 78748a881429728991bfd3b6b8312c91ec9d8cb8 |
| parent | 71dc761bfe791895c5997dda654dca1dad817413 |
| parent | 2f16df1832cf21abfcd4f315a75c0b0bb26127ac |
Rollup of 12 pull requests
Successful merges:
- rust-lang/rust#152388 (`rust-analyzer` subtree update)
- rust-lang/rust#151613 (Align `ArrayWindows` trait impls with `Windows`)
- rust-lang/rust#152134 (Set crt_static_allow_dylibs to true for Emscripten target)
- rust-lang/rust#152166 (cleanup some more things in `proc_macro::bridge`)
- rust-lang/rust#152236 (compiletest: `-Zunstable-options` for json targets)
- rust-lang/rust#152287 (Fix an ICE in the vtable iteration for a trait reference in const eval when a supertrait not implemented)
- rust-lang/rust#142957 (std: introduce path normalize methods at top of `std::path`)
- rust-lang/rust#145504 (Add some conversion trait impls)
- rust-lang/rust#152131 (Port rustc_no_implicit_bounds attribute to parser.)
- rust-lang/rust#152315 (fix: rhs_span to rhs_span_new)
- rust-lang/rust#152327 (Check stalled coroutine obligations eagerly)
- rust-lang/rust#152377 (Rename the query system's `JobOwner` to `ActiveJobGuard`, and include `key_hash`)119 files changed, 1906 insertions(+), 979 deletions(-)
compiler/rustc_attr_parsing/src/attributes/crate_level.rs+9| ... | ... | @@ -283,3 +283,12 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcPreserveUbChecksParser { |
| 283 | 283 | const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); |
| 284 | 284 | const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcPreserveUbChecks; |
| 285 | 285 | } |
| 286 | ||
| 287 | pub(crate) struct RustcNoImplicitBoundsParser; | |
| 288 | ||
| 289 | impl<S: Stage> NoArgsAttributeParser<S> for RustcNoImplicitBoundsParser { | |
| 290 | const PATH: &[Symbol] = &[sym::rustc_no_implicit_bounds]; | |
| 291 | const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; | |
| 292 | const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); | |
| 293 | const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoImplicitBounds; | |
| 294 | } |
compiler/rustc_attr_parsing/src/context.rs+1| ... | ... | @@ -282,6 +282,7 @@ attribute_parsers!( |
| 282 | 282 | Single<WithoutArgs<RustcMainParser>>, |
| 283 | 283 | Single<WithoutArgs<RustcNeverReturnsNullPointerParser>>, |
| 284 | 284 | Single<WithoutArgs<RustcNoImplicitAutorefsParser>>, |
| 285 | Single<WithoutArgs<RustcNoImplicitBoundsParser>>, | |
| 285 | 286 | Single<WithoutArgs<RustcNonConstTraitMethodParser>>, |
| 286 | 287 | Single<WithoutArgs<RustcNounwindParser>>, |
| 287 | 288 | Single<WithoutArgs<RustcOffloadKernelParser>>, |
compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs+1-1| ... | ... | @@ -1695,7 +1695,7 @@ fn suggest_ampmut<'tcx>( |
| 1695 | 1695 | && let Either::Left(rhs_stmt_new) = body.stmt_at(*assign) |
| 1696 | 1696 | && let StatementKind::Assign(box (_, rvalue_new)) = &rhs_stmt_new.kind |
| 1697 | 1697 | && let rhs_span_new = rhs_stmt_new.source_info.span |
| 1698 | && let Ok(rhs_str_new) = tcx.sess.source_map().span_to_snippet(rhs_span) | |
| 1698 | && let Ok(rhs_str_new) = tcx.sess.source_map().span_to_snippet(rhs_span_new) | |
| 1699 | 1699 | { |
| 1700 | 1700 | (rvalue, rhs_span, rhs_str) = (rvalue_new, rhs_span_new, rhs_str_new); |
| 1701 | 1701 | } |
compiler/rustc_borrowck/src/lib.rs+5| ... | ... | @@ -121,6 +121,11 @@ fn mir_borrowck( |
| 121 | 121 | let (input_body, _) = tcx.mir_promoted(def); |
| 122 | 122 | debug!("run query mir_borrowck: {}", tcx.def_path_str(def)); |
| 123 | 123 | |
| 124 | // We should eagerly check stalled coroutine obligations from HIR typeck. | |
| 125 | // Not doing so leads to silent normalization failures later, which will | |
| 126 | // fail to register opaque types in the next solver. | |
| 127 | tcx.check_coroutine_obligations(def)?; | |
| 128 | ||
| 124 | 129 | let input_body: &Body<'_> = &input_body.borrow(); |
| 125 | 130 | if let Some(guar) = input_body.tainted_by_errors { |
| 126 | 131 | debug!("Skipping borrowck because of tainted body"); |
compiler/rustc_hir/src/attrs/data_structures.rs+3| ... | ... | @@ -1177,6 +1177,9 @@ pub enum AttributeKind { |
| 1177 | 1177 | /// Represents `#[rustc_no_implicit_autorefs]` |
| 1178 | 1178 | RustcNoImplicitAutorefs, |
| 1179 | 1179 | |
| 1180 | /// Represents `#[rustc_no_implicit_bounds]` | |
| 1181 | RustcNoImplicitBounds, | |
| 1182 | ||
| 1180 | 1183 | /// Represents `#[rustc_non_const_trait_method]`. |
| 1181 | 1184 | RustcNonConstTraitMethod, |
| 1182 | 1185 |
compiler/rustc_hir/src/attrs/encode_cross_crate.rs+1| ... | ... | @@ -137,6 +137,7 @@ impl AttributeKind { |
| 137 | 137 | RustcMustImplementOneOf { .. } => No, |
| 138 | 138 | RustcNeverReturnsNullPointer => Yes, |
| 139 | 139 | RustcNoImplicitAutorefs => Yes, |
| 140 | RustcNoImplicitBounds => No, | |
| 140 | 141 | RustcNonConstTraitMethod => No, // should be reported via other queries like `constness` |
| 141 | 142 | RustcNounwind => No, |
| 142 | 143 | RustcObjcClass { .. } => No, |
compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs+6-4| ... | ... | @@ -4,15 +4,16 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; |
| 4 | 4 | use rustc_errors::codes::*; |
| 5 | 5 | use rustc_errors::struct_span_code_err; |
| 6 | 6 | use rustc_hir as hir; |
| 7 | use rustc_hir::PolyTraitRef; | |
| 7 | use rustc_hir::attrs::AttributeKind; | |
| 8 | 8 | use rustc_hir::def::{DefKind, Res}; |
| 9 | 9 | use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; |
| 10 | use rustc_hir::{PolyTraitRef, find_attr}; | |
| 10 | 11 | use rustc_middle::bug; |
| 11 | 12 | use rustc_middle::ty::{ |
| 12 | 13 | self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, |
| 13 | 14 | TypeVisitor, Upcast, |
| 14 | 15 | }; |
| 15 | use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym}; | |
| 16 | use rustc_span::{ErrorGuaranteed, Ident, Span, kw}; | |
| 16 | 17 | use rustc_trait_selection::traits; |
| 17 | 18 | use smallvec::SmallVec; |
| 18 | 19 | use tracing::{debug, instrument}; |
| ... | ... | @@ -170,7 +171,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { |
| 170 | 171 | let tcx = self.tcx(); |
| 171 | 172 | |
| 172 | 173 | // Skip adding any default bounds if `#![rustc_no_implicit_bounds]` |
| 173 | if tcx.has_attr(CRATE_DEF_ID, sym::rustc_no_implicit_bounds) { | |
| 174 | if find_attr!(tcx.get_all_attrs(CRATE_DEF_ID), AttributeKind::RustcNoImplicitBounds) { | |
| 174 | 175 | return; |
| 175 | 176 | } |
| 176 | 177 | |
| ... | ... | @@ -284,7 +285,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { |
| 284 | 285 | context: ImpliedBoundsContext<'tcx>, |
| 285 | 286 | ) -> bool { |
| 286 | 287 | let collected = collect_bounds(hir_bounds, context, trait_def_id); |
| 287 | !self.tcx().has_attr(CRATE_DEF_ID, sym::rustc_no_implicit_bounds) && !collected.any() | |
| 288 | !find_attr!(self.tcx().get_all_attrs(CRATE_DEF_ID), AttributeKind::RustcNoImplicitBounds) | |
| 289 | && !collected.any() | |
| 288 | 290 | } |
| 289 | 291 | |
| 290 | 292 | fn reject_duplicate_relaxed_bounds(&self, relaxed_bounds: SmallVec<[&PolyTraitRef<'_>; 1]>) { |
compiler/rustc_interface/src/passes.rs+7-11| ... | ... | @@ -1116,18 +1116,14 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { |
| 1116 | 1116 | { |
| 1117 | 1117 | tcx.ensure_ok().mir_drops_elaborated_and_const_checked(def_id); |
| 1118 | 1118 | } |
| 1119 | if tcx.is_coroutine(def_id.to_def_id()) { | |
| 1120 | tcx.ensure_ok().mir_coroutine_witnesses(def_id); | |
| 1121 | let _ = tcx.ensure_ok().check_coroutine_obligations( | |
| 1122 | tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(), | |
| 1119 | if tcx.is_coroutine(def_id.to_def_id()) | |
| 1120 | && (!tcx.is_async_drop_in_place_coroutine(def_id.to_def_id())) | |
| 1121 | { | |
| 1122 | // Eagerly check the unsubstituted layout for cycles. | |
| 1123 | tcx.ensure_ok().layout_of( | |
| 1124 | ty::TypingEnv::post_analysis(tcx, def_id.to_def_id()) | |
| 1125 | .as_query_input(tcx.type_of(def_id).instantiate_identity()), | |
| 1123 | 1126 | ); |
| 1124 | if !tcx.is_async_drop_in_place_coroutine(def_id.to_def_id()) { | |
| 1125 | // Eagerly check the unsubstituted layout for cycles. | |
| 1126 | tcx.ensure_ok().layout_of( | |
| 1127 | ty::TypingEnv::post_analysis(tcx, def_id.to_def_id()) | |
| 1128 | .as_query_input(tcx.type_of(def_id).instantiate_identity()), | |
| 1129 | ); | |
| 1130 | } | |
| 1131 | 1127 | } |
| 1132 | 1128 | }); |
| 1133 | 1129 | }); |
compiler/rustc_middle/src/ty/context/tls.rs+1-2| ... | ... | @@ -16,8 +16,7 @@ pub struct ImplicitCtxt<'a, 'tcx> { |
| 16 | 16 | /// The current `TyCtxt`. |
| 17 | 17 | pub tcx: TyCtxt<'tcx>, |
| 18 | 18 | |
| 19 | /// The current query job, if any. This is updated by `JobOwner::start` in | |
| 20 | /// `ty::query::plumbing` when executing a query. | |
| 19 | /// The current query job, if any. | |
| 21 | 20 | pub query: Option<QueryJobId>, |
| 22 | 21 | |
| 23 | 22 | /// Used to prevent queries from calling too deeply. |
compiler/rustc_passes/src/check_attr.rs+1-1| ... | ... | @@ -330,6 +330,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { |
| 330 | 330 | | AttributeKind::RustcMir(_) |
| 331 | 331 | | AttributeKind::RustcNeverReturnsNullPointer |
| 332 | 332 | | AttributeKind::RustcNoImplicitAutorefs |
| 333 | | AttributeKind::RustcNoImplicitBounds | |
| 333 | 334 | | AttributeKind::RustcNonConstTraitMethod |
| 334 | 335 | | AttributeKind::RustcNounwind |
| 335 | 336 | | AttributeKind::RustcObjcClass { .. } |
| ... | ... | @@ -413,7 +414,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { |
| 413 | 414 | // crate-level attrs, are checked below |
| 414 | 415 | | sym::feature |
| 415 | 416 | | sym::register_tool |
| 416 | | sym::rustc_no_implicit_bounds | |
| 417 | 417 | | sym::test_runner, |
| 418 | 418 | .. |
| 419 | 419 | ] => {} |
compiler/rustc_query_impl/src/execution.rs+23-17| ... | ... | @@ -83,14 +83,18 @@ pub(crate) fn gather_active_jobs_inner<'tcx, K: Copy>( |
| 83 | 83 | Some(()) |
| 84 | 84 | } |
| 85 | 85 | |
| 86 | /// A type representing the responsibility to execute the job in the `job` field. | |
| 87 | /// This will poison the relevant query if dropped. | |
| 88 | struct JobOwner<'tcx, K> | |
| 86 | /// Guard object representing the responsibility to execute a query job and | |
| 87 | /// mark it as completed. | |
| 88 | /// | |
| 89 | /// This will poison the relevant query key if it is dropped without calling | |
| 90 | /// [`Self::complete`]. | |
| 91 | struct ActiveJobGuard<'tcx, K> | |
| 89 | 92 | where |
| 90 | 93 | K: Eq + Hash + Copy, |
| 91 | 94 | { |
| 92 | 95 | state: &'tcx QueryState<'tcx, K>, |
| 93 | 96 | key: K, |
| 97 | key_hash: u64, | |
| 94 | 98 | } |
| 95 | 99 | |
| 96 | 100 | #[cold] |
| ... | ... | @@ -137,20 +141,19 @@ fn handle_cycle_error<'tcx, C: QueryCache, const FLAGS: QueryFlags>( |
| 137 | 141 | } |
| 138 | 142 | } |
| 139 | 143 | |
| 140 | impl<'tcx, K> JobOwner<'tcx, K> | |
| 144 | impl<'tcx, K> ActiveJobGuard<'tcx, K> | |
| 141 | 145 | where |
| 142 | 146 | K: Eq + Hash + Copy, |
| 143 | 147 | { |
| 144 | 148 | /// Completes the query by updating the query cache with the `result`, |
| 145 | /// signals the waiter and forgets the JobOwner, so it won't poison the query | |
| 146 | fn complete<C>(self, cache: &C, key_hash: u64, result: C::Value, dep_node_index: DepNodeIndex) | |
| 149 | /// signals the waiter, and forgets the guard so it won't poison the query. | |
| 150 | fn complete<C>(self, cache: &C, result: C::Value, dep_node_index: DepNodeIndex) | |
| 147 | 151 | where |
| 148 | 152 | C: QueryCache<Key = K>, |
| 149 | 153 | { |
| 150 | let key = self.key; | |
| 151 | let state = self.state; | |
| 152 | ||
| 153 | // Forget ourself so our destructor won't poison the query | |
| 154 | // Forget ourself so our destructor won't poison the query. | |
| 155 | // (Extract fields by value first to make sure we don't leak anything.) | |
| 156 | let Self { state, key, key_hash }: Self = self; | |
| 154 | 157 | mem::forget(self); |
| 155 | 158 | |
| 156 | 159 | // Mark as complete before we remove the job from the active state |
| ... | ... | @@ -174,7 +177,7 @@ where |
| 174 | 177 | } |
| 175 | 178 | } |
| 176 | 179 | |
| 177 | impl<'tcx, K> Drop for JobOwner<'tcx, K> | |
| 180 | impl<'tcx, K> Drop for ActiveJobGuard<'tcx, K> | |
| 178 | 181 | where |
| 179 | 182 | K: Eq + Hash + Copy, |
| 180 | 183 | { |
| ... | ... | @@ -182,11 +185,10 @@ where |
| 182 | 185 | #[cold] |
| 183 | 186 | fn drop(&mut self) { |
| 184 | 187 | // Poison the query so jobs waiting on it panic. |
| 185 | let state = self.state; | |
| 188 | let Self { state, key, key_hash } = *self; | |
| 186 | 189 | let job = { |
| 187 | let key_hash = sharded::make_hash(&self.key); | |
| 188 | 190 | let mut shard = state.active.lock_shard_by_hash(key_hash); |
| 189 | match shard.find_entry(key_hash, equivalent_key(&self.key)) { | |
| 191 | match shard.find_entry(key_hash, equivalent_key(&key)) { | |
| 190 | 192 | Err(_) => panic!(), |
| 191 | 193 | Ok(occupied) => { |
| 192 | 194 | let ((key, value), vacant) = occupied.remove(); |
| ... | ... | @@ -342,11 +344,13 @@ fn execute_job<'tcx, C: QueryCache, const FLAGS: QueryFlags, const INCR: bool>( |
| 342 | 344 | id: QueryJobId, |
| 343 | 345 | dep_node: Option<DepNode>, |
| 344 | 346 | ) -> (C::Value, Option<DepNodeIndex>) { |
| 345 | // Use `JobOwner` so the query will be poisoned if executing it panics. | |
| 346 | let job_owner = JobOwner { state, key }; | |
| 347 | // Set up a guard object that will automatically poison the query if a | |
| 348 | // panic occurs while executing the query (or any intermediate plumbing). | |
| 349 | let job_guard = ActiveJobGuard { state, key, key_hash }; | |
| 347 | 350 | |
| 348 | 351 | debug_assert_eq!(qcx.tcx.dep_graph.is_fully_enabled(), INCR); |
| 349 | 352 | |
| 353 | // Delegate to another function to actually execute the query job. | |
| 350 | 354 | let (result, dep_node_index) = if INCR { |
| 351 | 355 | execute_job_incr(query, qcx, qcx.tcx.dep_graph.data().unwrap(), key, dep_node, id) |
| 352 | 356 | } else { |
| ... | ... | @@ -388,7 +392,9 @@ fn execute_job<'tcx, C: QueryCache, const FLAGS: QueryFlags, const INCR: bool>( |
| 388 | 392 | } |
| 389 | 393 | } |
| 390 | 394 | } |
| 391 | job_owner.complete(cache, key_hash, result, dep_node_index); | |
| 395 | ||
| 396 | // Tell the guard to perform completion bookkeeping, and also to not poison the query. | |
| 397 | job_guard.complete(cache, result, dep_node_index); | |
| 392 | 398 | |
| 393 | 399 | (result, Some(dep_node_index)) |
| 394 | 400 | } |
compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs+7| ... | ... | @@ -19,8 +19,15 @@ pub(crate) fn target() -> Target { |
| 19 | 19 | pre_link_args, |
| 20 | 20 | post_link_args, |
| 21 | 21 | relocation_model: RelocModel::Pic, |
| 22 | // crt_static should always be true for an executable and always false | |
| 23 | // for a shared library. There is no easy way to indicate this and it | |
| 24 | // doesn't seem to matter much so we set crt_static_allows_dylibs to | |
| 25 | // true and leave crt_static as true when linking dynamic libraries. | |
| 26 | // wasi also sets crt_static_allows_dylibs: true so this is at least | |
| 27 | // aligned between wasm targets. | |
| 22 | 28 | crt_static_respected: true, |
| 23 | 29 | crt_static_default: true, |
| 30 | crt_static_allows_dylibs: true, | |
| 24 | 31 | panic_strategy: PanicStrategy::Unwind, |
| 25 | 32 | no_default_libraries: false, |
| 26 | 33 | families: cvs!["unix", "wasm"], |
compiler/rustc_trait_selection/src/traits/vtable.rs+2-6| ... | ... | @@ -12,7 +12,7 @@ use rustc_span::DUMMY_SP; |
| 12 | 12 | use smallvec::{SmallVec, smallvec}; |
| 13 | 13 | use tracing::debug; |
| 14 | 14 | |
| 15 | use crate::traits::{impossible_predicates, is_vtable_safe_method}; | |
| 15 | use crate::traits::is_vtable_safe_method; | |
| 16 | 16 | |
| 17 | 17 | #[derive(Clone, Debug)] |
| 18 | 18 | pub enum VtblSegment<'tcx> { |
| ... | ... | @@ -271,11 +271,7 @@ fn vtable_entries<'tcx>( |
| 271 | 271 | // do not hold for this particular set of type parameters. |
| 272 | 272 | // Note that this method could then never be called, so we |
| 273 | 273 | // do not want to try and codegen it, in that case (see #23435). |
| 274 | let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, args); | |
| 275 | if impossible_predicates( | |
| 276 | tcx, | |
| 277 | predicates.map(|(predicate, _)| predicate).collect(), | |
| 278 | ) { | |
| 274 | if tcx.instantiate_and_check_impossible_predicates((def_id, args)) { | |
| 279 | 275 | debug!("vtable_entries: predicates do not hold"); |
| 280 | 276 | return VtblEntry::Vacant; |
| 281 | 277 | } |
library/core/src/cell.rs+24| ... | ... | @@ -689,6 +689,30 @@ impl<T: CoerceUnsized<U>, U> CoerceUnsized<Cell<U>> for Cell<T> {} |
| 689 | 689 | #[unstable(feature = "dispatch_from_dyn", issue = "none")] |
| 690 | 690 | impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Cell<U>> for Cell<T> {} |
| 691 | 691 | |
| 692 | #[stable(feature = "more_conversion_trait_impls", since = "CURRENT_RUSTC_VERSION")] | |
| 693 | impl<T, const N: usize> AsRef<[Cell<T>; N]> for Cell<[T; N]> { | |
| 694 | #[inline] | |
| 695 | fn as_ref(&self) -> &[Cell<T>; N] { | |
| 696 | self.as_array_of_cells() | |
| 697 | } | |
| 698 | } | |
| 699 | ||
| 700 | #[stable(feature = "more_conversion_trait_impls", since = "CURRENT_RUSTC_VERSION")] | |
| 701 | impl<T, const N: usize> AsRef<[Cell<T>]> for Cell<[T; N]> { | |
| 702 | #[inline] | |
| 703 | fn as_ref(&self) -> &[Cell<T>] { | |
| 704 | &*self.as_array_of_cells() | |
| 705 | } | |
| 706 | } | |
| 707 | ||
| 708 | #[stable(feature = "more_conversion_trait_impls", since = "CURRENT_RUSTC_VERSION")] | |
| 709 | impl<T> AsRef<[Cell<T>]> for Cell<[T]> { | |
| 710 | #[inline] | |
| 711 | fn as_ref(&self) -> &[Cell<T>] { | |
| 712 | self.as_slice_of_cells() | |
| 713 | } | |
| 714 | } | |
| 715 | ||
| 692 | 716 | impl<T> Cell<[T]> { |
| 693 | 717 | /// Returns a `&[Cell<T>]` from a `&Cell<[T]>` |
| 694 | 718 | /// |
library/core/src/mem/maybe_uninit.rs+50| ... | ... | @@ -1532,6 +1532,56 @@ impl<T, const N: usize> MaybeUninit<[T; N]> { |
| 1532 | 1532 | } |
| 1533 | 1533 | } |
| 1534 | 1534 | |
| 1535 | #[stable(feature = "more_conversion_trait_impls", since = "CURRENT_RUSTC_VERSION")] | |
| 1536 | impl<T, const N: usize> From<[MaybeUninit<T>; N]> for MaybeUninit<[T; N]> { | |
| 1537 | #[inline] | |
| 1538 | fn from(arr: [MaybeUninit<T>; N]) -> Self { | |
| 1539 | arr.transpose() | |
| 1540 | } | |
| 1541 | } | |
| 1542 | ||
| 1543 | #[stable(feature = "more_conversion_trait_impls", since = "CURRENT_RUSTC_VERSION")] | |
| 1544 | impl<T, const N: usize> AsRef<[MaybeUninit<T>; N]> for MaybeUninit<[T; N]> { | |
| 1545 | #[inline] | |
| 1546 | fn as_ref(&self) -> &[MaybeUninit<T>; N] { | |
| 1547 | // SAFETY: T and MaybeUninit<T> have the same layout | |
| 1548 | unsafe { &*ptr::from_ref(self).cast() } | |
| 1549 | } | |
| 1550 | } | |
| 1551 | ||
| 1552 | #[stable(feature = "more_conversion_trait_impls", since = "CURRENT_RUSTC_VERSION")] | |
| 1553 | impl<T, const N: usize> AsRef<[MaybeUninit<T>]> for MaybeUninit<[T; N]> { | |
| 1554 | #[inline] | |
| 1555 | fn as_ref(&self) -> &[MaybeUninit<T>] { | |
| 1556 | &*AsRef::<[MaybeUninit<T>; N]>::as_ref(self) | |
| 1557 | } | |
| 1558 | } | |
| 1559 | ||
| 1560 | #[stable(feature = "more_conversion_trait_impls", since = "CURRENT_RUSTC_VERSION")] | |
| 1561 | impl<T, const N: usize> AsMut<[MaybeUninit<T>; N]> for MaybeUninit<[T; N]> { | |
| 1562 | #[inline] | |
| 1563 | fn as_mut(&mut self) -> &mut [MaybeUninit<T>; N] { | |
| 1564 | // SAFETY: T and MaybeUninit<T> have the same layout | |
| 1565 | unsafe { &mut *ptr::from_mut(self).cast() } | |
| 1566 | } | |
| 1567 | } | |
| 1568 | ||
| 1569 | #[stable(feature = "more_conversion_trait_impls", since = "CURRENT_RUSTC_VERSION")] | |
| 1570 | impl<T, const N: usize> AsMut<[MaybeUninit<T>]> for MaybeUninit<[T; N]> { | |
| 1571 | #[inline] | |
| 1572 | fn as_mut(&mut self) -> &mut [MaybeUninit<T>] { | |
| 1573 | &mut *AsMut::<[MaybeUninit<T>; N]>::as_mut(self) | |
| 1574 | } | |
| 1575 | } | |
| 1576 | ||
| 1577 | #[stable(feature = "more_conversion_trait_impls", since = "CURRENT_RUSTC_VERSION")] | |
| 1578 | impl<T, const N: usize> From<MaybeUninit<[T; N]>> for [MaybeUninit<T>; N] { | |
| 1579 | #[inline] | |
| 1580 | fn from(arr: MaybeUninit<[T; N]>) -> Self { | |
| 1581 | arr.transpose() | |
| 1582 | } | |
| 1583 | } | |
| 1584 | ||
| 1535 | 1585 | impl<T, const N: usize> [MaybeUninit<T>; N] { |
| 1536 | 1586 | /// Transposes a `[MaybeUninit<T>; N]` into a `MaybeUninit<[T; N]>`. |
| 1537 | 1587 | /// |
library/core/src/slice/iter.rs+33-1| ... | ... | @@ -2175,7 +2175,7 @@ unsafe impl<T> Sync for ChunksExactMut<'_, T> where T: Sync {} |
| 2175 | 2175 | /// |
| 2176 | 2176 | /// [`array_windows`]: slice::array_windows |
| 2177 | 2177 | /// [slices]: slice |
| 2178 | #[derive(Debug, Clone, Copy)] | |
| 2178 | #[derive(Debug)] | |
| 2179 | 2179 | #[stable(feature = "array_windows", since = "1.94.0")] |
| 2180 | 2180 | #[must_use = "iterators are lazy and do nothing unless consumed"] |
| 2181 | 2181 | pub struct ArrayWindows<'a, T: 'a, const N: usize> { |
| ... | ... | @@ -2189,6 +2189,14 @@ impl<'a, T: 'a, const N: usize> ArrayWindows<'a, T, N> { |
| 2189 | 2189 | } |
| 2190 | 2190 | } |
| 2191 | 2191 | |
| 2192 | // FIXME(#26925) Remove in favor of `#[derive(Clone)]` | |
| 2193 | #[stable(feature = "array_windows", since = "1.94.0")] | |
| 2194 | impl<T, const N: usize> Clone for ArrayWindows<'_, T, N> { | |
| 2195 | fn clone(&self) -> Self { | |
| 2196 | Self { v: self.v } | |
| 2197 | } | |
| 2198 | } | |
| 2199 | ||
| 2192 | 2200 | #[stable(feature = "array_windows", since = "1.94.0")] |
| 2193 | 2201 | impl<'a, T, const N: usize> Iterator for ArrayWindows<'a, T, N> { |
| 2194 | 2202 | type Item = &'a [T; N]; |
| ... | ... | @@ -2224,6 +2232,14 @@ impl<'a, T, const N: usize> Iterator for ArrayWindows<'a, T, N> { |
| 2224 | 2232 | fn last(self) -> Option<Self::Item> { |
| 2225 | 2233 | self.v.last_chunk() |
| 2226 | 2234 | } |
| 2235 | ||
| 2236 | unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { | |
| 2237 | // SAFETY: since the caller guarantees that `idx` is in bounds, | |
| 2238 | // which means that `idx` cannot overflow an `isize`, and the | |
| 2239 | // "slice" created by `cast_array` is a subslice of `self.v` | |
| 2240 | // thus is guaranteed to be valid for the lifetime `'a` of `self.v`. | |
| 2241 | unsafe { &*self.v.as_ptr().add(idx).cast_array() } | |
| 2242 | } | |
| 2227 | 2243 | } |
| 2228 | 2244 | |
| 2229 | 2245 | #[stable(feature = "array_windows", since = "1.94.0")] |
| ... | ... | @@ -2252,6 +2268,22 @@ impl<T, const N: usize> ExactSizeIterator for ArrayWindows<'_, T, N> { |
| 2252 | 2268 | } |
| 2253 | 2269 | } |
| 2254 | 2270 | |
| 2271 | #[unstable(feature = "trusted_len", issue = "37572")] | |
| 2272 | unsafe impl<T, const N: usize> TrustedLen for ArrayWindows<'_, T, N> {} | |
| 2273 | ||
| 2274 | #[stable(feature = "array_windows", since = "1.94.0")] | |
| 2275 | impl<T, const N: usize> FusedIterator for ArrayWindows<'_, T, N> {} | |
| 2276 | ||
| 2277 | #[doc(hidden)] | |
| 2278 | #[unstable(feature = "trusted_random_access", issue = "none")] | |
| 2279 | unsafe impl<T, const N: usize> TrustedRandomAccess for ArrayWindows<'_, T, N> {} | |
| 2280 | ||
| 2281 | #[doc(hidden)] | |
| 2282 | #[unstable(feature = "trusted_random_access", issue = "none")] | |
| 2283 | unsafe impl<T, const N: usize> TrustedRandomAccessNoCoerce for ArrayWindows<'_, T, N> { | |
| 2284 | const MAY_HAVE_SIDE_EFFECT: bool = false; | |
| 2285 | } | |
| 2286 | ||
| 2255 | 2287 | /// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a |
| 2256 | 2288 | /// time), starting at the end of the slice. |
| 2257 | 2289 | /// |
library/proc_macro/src/bridge/client.rs+2-2| ... | ... | @@ -121,7 +121,7 @@ macro_rules! define_client_side { |
| 121 | 121 | } |
| 122 | 122 | } |
| 123 | 123 | } |
| 124 | with_api!(self, define_client_side); | |
| 124 | with_api!(define_client_side, TokenStream, Span, Symbol); | |
| 125 | 125 | |
| 126 | 126 | struct Bridge<'a> { |
| 127 | 127 | /// Reusable buffer (only `clear`-ed, never shrunk), primarily |
| ... | ... | @@ -129,7 +129,7 @@ struct Bridge<'a> { |
| 129 | 129 | cached_buffer: Buffer, |
| 130 | 130 | |
| 131 | 131 | /// Server-side function that the client uses to make requests. |
| 132 | dispatch: closure::Closure<'a, Buffer, Buffer>, | |
| 132 | dispatch: closure::Closure<'a>, | |
| 133 | 133 | |
| 134 | 134 | /// Provided globals for this macro expansion. |
| 135 | 135 | globals: ExpnGlobals<Span>, |
library/proc_macro/src/bridge/closure.rs+11-9| ... | ... | @@ -1,10 +1,12 @@ |
| 1 | //! Closure type (equivalent to `&mut dyn FnMut(A) -> R`) that's `repr(C)`. | |
| 1 | //! Closure type (equivalent to `&mut dyn FnMut(Buffer) -> Buffer`) that's `repr(C)`. | |
| 2 | 2 | |
| 3 | 3 | use std::marker::PhantomData; |
| 4 | 4 | |
| 5 | use super::Buffer; | |
| 6 | ||
| 5 | 7 | #[repr(C)] |
| 6 | pub(super) struct Closure<'a, A, R> { | |
| 7 | call: unsafe extern "C" fn(*mut Env, A) -> R, | |
| 8 | pub(super) struct Closure<'a> { | |
| 9 | call: extern "C" fn(*mut Env, Buffer) -> Buffer, | |
| 8 | 10 | env: *mut Env, |
| 9 | 11 | // Prevent Send and Sync impls. |
| 10 | 12 | // |
| ... | ... | @@ -14,17 +16,17 @@ pub(super) struct Closure<'a, A, R> { |
| 14 | 16 | |
| 15 | 17 | struct Env; |
| 16 | 18 | |
| 17 | impl<'a, A, R, F: FnMut(A) -> R> From<&'a mut F> for Closure<'a, A, R> { | |
| 19 | impl<'a, F: FnMut(Buffer) -> Buffer> From<&'a mut F> for Closure<'a> { | |
| 18 | 20 | fn from(f: &'a mut F) -> Self { |
| 19 | unsafe extern "C" fn call<A, R, F: FnMut(A) -> R>(env: *mut Env, arg: A) -> R { | |
| 21 | extern "C" fn call<F: FnMut(Buffer) -> Buffer>(env: *mut Env, arg: Buffer) -> Buffer { | |
| 20 | 22 | unsafe { (*(env as *mut _ as *mut F))(arg) } |
| 21 | 23 | } |
| 22 | Closure { call: call::<A, R, F>, env: f as *mut _ as *mut Env, _marker: PhantomData } | |
| 24 | Closure { call: call::<F>, env: f as *mut _ as *mut Env, _marker: PhantomData } | |
| 23 | 25 | } |
| 24 | 26 | } |
| 25 | 27 | |
| 26 | impl<'a, A, R> Closure<'a, A, R> { | |
| 27 | pub(super) fn call(&mut self, arg: A) -> R { | |
| 28 | unsafe { (self.call)(self.env, arg) } | |
| 28 | impl<'a> Closure<'a> { | |
| 29 | pub(super) fn call(&mut self, arg: Buffer) -> Buffer { | |
| 30 | (self.call)(self.env, arg) | |
| 29 | 31 | } |
| 30 | 32 | } |
library/proc_macro/src/bridge/mod.rs+54-56| ... | ... | @@ -18,71 +18,67 @@ use crate::{Delimiter, Level}; |
| 18 | 18 | /// Higher-order macro describing the server RPC API, allowing automatic |
| 19 | 19 | /// generation of type-safe Rust APIs, both client-side and server-side. |
| 20 | 20 | /// |
| 21 | /// `with_api!(MySelf, my_macro)` expands to: | |
| 21 | /// `with_api!(my_macro, MyTokenStream, MySpan, MySymbol)` expands to: | |
| 22 | 22 | /// ```rust,ignore (pseudo-code) |
| 23 | 23 | /// my_macro! { |
| 24 | /// fn lit_character(ch: char) -> MySelf::Literal; | |
| 25 | /// fn lit_span(lit: &MySelf::Literal) -> MySelf::Span; | |
| 26 | /// fn lit_set_span(lit: &mut MySelf::Literal, span: MySelf::Span); | |
| 24 | /// fn ts_clone(stream: &MyTokenStream) -> MyTokenStream; | |
| 25 | /// fn span_debug(span: &MySpan) -> String; | |
| 27 | 26 | /// // ... |
| 28 | 27 | /// } |
| 29 | 28 | /// ``` |
| 30 | 29 | /// |
| 31 | /// The first argument serves to customize the argument/return types, | |
| 32 | /// to enable several different usecases: | |
| 33 | /// | |
| 34 | /// If `MySelf` is just `Self`, then the types are only valid inside | |
| 35 | /// a trait or a trait impl, where the trait has associated types | |
| 36 | /// for each of the API types. If non-associated types are desired, | |
| 37 | /// a module name (`self` in practice) can be used instead of `Self`. | |
| 30 | /// The second (`TokenStream`), third (`Span`) and fourth (`Symbol`) | |
| 31 | /// argument serve to customize the argument/return types that need | |
| 32 | /// special handling, to enable several different representations of | |
| 33 | /// these types. | |
| 38 | 34 | macro_rules! with_api { |
| 39 | ($S:ident, $m:ident) => { | |
| 35 | ($m:ident, $TokenStream: path, $Span: path, $Symbol: path) => { | |
| 40 | 36 | $m! { |
| 41 | 37 | fn injected_env_var(var: &str) -> Option<String>; |
| 42 | 38 | fn track_env_var(var: &str, value: Option<&str>); |
| 43 | 39 | fn track_path(path: &str); |
| 44 | fn literal_from_str(s: &str) -> Result<Literal<$S::Span, $S::Symbol>, ()>; | |
| 45 | fn emit_diagnostic(diagnostic: Diagnostic<$S::Span>); | |
| 46 | ||
| 47 | fn ts_drop(stream: $S::TokenStream); | |
| 48 | fn ts_clone(stream: &$S::TokenStream) -> $S::TokenStream; | |
| 49 | fn ts_is_empty(stream: &$S::TokenStream) -> bool; | |
| 50 | fn ts_expand_expr(stream: &$S::TokenStream) -> Result<$S::TokenStream, ()>; | |
| 51 | fn ts_from_str(src: &str) -> $S::TokenStream; | |
| 52 | fn ts_to_string(stream: &$S::TokenStream) -> String; | |
| 40 | fn literal_from_str(s: &str) -> Result<Literal<$Span, $Symbol>, ()>; | |
| 41 | fn emit_diagnostic(diagnostic: Diagnostic<$Span>); | |
| 42 | ||
| 43 | fn ts_drop(stream: $TokenStream); | |
| 44 | fn ts_clone(stream: &$TokenStream) -> $TokenStream; | |
| 45 | fn ts_is_empty(stream: &$TokenStream) -> bool; | |
| 46 | fn ts_expand_expr(stream: &$TokenStream) -> Result<$TokenStream, ()>; | |
| 47 | fn ts_from_str(src: &str) -> $TokenStream; | |
| 48 | fn ts_to_string(stream: &$TokenStream) -> String; | |
| 53 | 49 | fn ts_from_token_tree( |
| 54 | tree: TokenTree<$S::TokenStream, $S::Span, $S::Symbol>, | |
| 55 | ) -> $S::TokenStream; | |
| 50 | tree: TokenTree<$TokenStream, $Span, $Symbol>, | |
| 51 | ) -> $TokenStream; | |
| 56 | 52 | fn ts_concat_trees( |
| 57 | base: Option<$S::TokenStream>, | |
| 58 | trees: Vec<TokenTree<$S::TokenStream, $S::Span, $S::Symbol>>, | |
| 59 | ) -> $S::TokenStream; | |
| 53 | base: Option<$TokenStream>, | |
| 54 | trees: Vec<TokenTree<$TokenStream, $Span, $Symbol>>, | |
| 55 | ) -> $TokenStream; | |
| 60 | 56 | fn ts_concat_streams( |
| 61 | base: Option<$S::TokenStream>, | |
| 62 | streams: Vec<$S::TokenStream>, | |
| 63 | ) -> $S::TokenStream; | |
| 57 | base: Option<$TokenStream>, | |
| 58 | streams: Vec<$TokenStream>, | |
| 59 | ) -> $TokenStream; | |
| 64 | 60 | fn ts_into_trees( |
| 65 | stream: $S::TokenStream | |
| 66 | ) -> Vec<TokenTree<$S::TokenStream, $S::Span, $S::Symbol>>; | |
| 67 | ||
| 68 | fn span_debug(span: $S::Span) -> String; | |
| 69 | fn span_parent(span: $S::Span) -> Option<$S::Span>; | |
| 70 | fn span_source(span: $S::Span) -> $S::Span; | |
| 71 | fn span_byte_range(span: $S::Span) -> Range<usize>; | |
| 72 | fn span_start(span: $S::Span) -> $S::Span; | |
| 73 | fn span_end(span: $S::Span) -> $S::Span; | |
| 74 | fn span_line(span: $S::Span) -> usize; | |
| 75 | fn span_column(span: $S::Span) -> usize; | |
| 76 | fn span_file(span: $S::Span) -> String; | |
| 77 | fn span_local_file(span: $S::Span) -> Option<String>; | |
| 78 | fn span_join(span: $S::Span, other: $S::Span) -> Option<$S::Span>; | |
| 79 | fn span_subspan(span: $S::Span, start: Bound<usize>, end: Bound<usize>) -> Option<$S::Span>; | |
| 80 | fn span_resolved_at(span: $S::Span, at: $S::Span) -> $S::Span; | |
| 81 | fn span_source_text(span: $S::Span) -> Option<String>; | |
| 82 | fn span_save_span(span: $S::Span) -> usize; | |
| 83 | fn span_recover_proc_macro_span(id: usize) -> $S::Span; | |
| 84 | ||
| 85 | fn symbol_normalize_and_validate_ident(string: &str) -> Result<$S::Symbol, ()>; | |
| 61 | stream: $TokenStream | |
| 62 | ) -> Vec<TokenTree<$TokenStream, $Span, $Symbol>>; | |
| 63 | ||
| 64 | fn span_debug(span: $Span) -> String; | |
| 65 | fn span_parent(span: $Span) -> Option<$Span>; | |
| 66 | fn span_source(span: $Span) -> $Span; | |
| 67 | fn span_byte_range(span: $Span) -> Range<usize>; | |
| 68 | fn span_start(span: $Span) -> $Span; | |
| 69 | fn span_end(span: $Span) -> $Span; | |
| 70 | fn span_line(span: $Span) -> usize; | |
| 71 | fn span_column(span: $Span) -> usize; | |
| 72 | fn span_file(span: $Span) -> String; | |
| 73 | fn span_local_file(span: $Span) -> Option<String>; | |
| 74 | fn span_join(span: $Span, other: $Span) -> Option<$Span>; | |
| 75 | fn span_subspan(span: $Span, start: Bound<usize>, end: Bound<usize>) -> Option<$Span>; | |
| 76 | fn span_resolved_at(span: $Span, at: $Span) -> $Span; | |
| 77 | fn span_source_text(span: $Span) -> Option<String>; | |
| 78 | fn span_save_span(span: $Span) -> usize; | |
| 79 | fn span_recover_proc_macro_span(id: usize) -> $Span; | |
| 80 | ||
| 81 | fn symbol_normalize_and_validate_ident(string: &str) -> Result<$Symbol, ()>; | |
| 86 | 82 | } |
| 87 | 83 | }; |
| 88 | 84 | } |
| ... | ... | @@ -126,7 +122,7 @@ pub struct BridgeConfig<'a> { |
| 126 | 122 | input: Buffer, |
| 127 | 123 | |
| 128 | 124 | /// Server-side function that the client uses to make requests. |
| 129 | dispatch: closure::Closure<'a, Buffer, Buffer>, | |
| 125 | dispatch: closure::Closure<'a>, | |
| 130 | 126 | |
| 131 | 127 | /// If 'true', always invoke the default panic hook |
| 132 | 128 | force_show_panics: bool, |
| ... | ... | @@ -146,7 +142,7 @@ macro_rules! declare_tags { |
| 146 | 142 | rpc_encode_decode!(enum ApiTags { $($method),* }); |
| 147 | 143 | } |
| 148 | 144 | } |
| 149 | with_api!(self, declare_tags); | |
| 145 | with_api!(declare_tags, __, __, __); | |
| 150 | 146 | |
| 151 | 147 | /// Helper to wrap associated types to allow trait impl dispatch. |
| 152 | 148 | /// That is, normally a pair of impls for `T::Foo` and `T::Bar` |
| ... | ... | @@ -173,7 +169,7 @@ impl<T, M> Mark for Marked<T, M> { |
| 173 | 169 | self.value |
| 174 | 170 | } |
| 175 | 171 | } |
| 176 | impl<'a, T, M> Mark for &'a Marked<T, M> { | |
| 172 | impl<'a, T> Mark for &'a Marked<T, client::TokenStream> { | |
| 177 | 173 | type Unmarked = &'a T; |
| 178 | 174 | fn mark(_: Self::Unmarked) -> Self { |
| 179 | 175 | unreachable!() |
| ... | ... | @@ -220,6 +216,8 @@ mark_noop! { |
| 220 | 216 | Delimiter, |
| 221 | 217 | LitKind, |
| 222 | 218 | Level, |
| 219 | Bound<usize>, | |
| 220 | Range<usize>, | |
| 223 | 221 | } |
| 224 | 222 | |
| 225 | 223 | rpc_encode_decode!( |
| ... | ... | @@ -318,7 +316,7 @@ macro_rules! compound_traits { |
| 318 | 316 | }; |
| 319 | 317 | } |
| 320 | 318 | |
| 321 | compound_traits!( | |
| 319 | rpc_encode_decode!( | |
| 322 | 320 | enum Bound<T> { |
| 323 | 321 | Included(x), |
| 324 | 322 | Excluded(x), |
| ... | ... | @@ -390,7 +388,7 @@ pub struct Literal<Span, Symbol> { |
| 390 | 388 | pub span: Span, |
| 391 | 389 | } |
| 392 | 390 | |
| 393 | compound_traits!(struct Literal<Sp, Sy> { kind, symbol, suffix, span }); | |
| 391 | compound_traits!(struct Literal<Span, Symbol> { kind, symbol, suffix, span }); | |
| 394 | 392 | |
| 395 | 393 | #[derive(Clone)] |
| 396 | 394 | pub enum TokenTree<TokenStream, Span, Symbol> { |
| ... | ... | @@ -434,6 +432,6 @@ compound_traits!( |
| 434 | 432 | struct ExpnGlobals<Span> { def_site, call_site, mixed_site } |
| 435 | 433 | ); |
| 436 | 434 | |
| 437 | compound_traits!( | |
| 435 | rpc_encode_decode!( | |
| 438 | 436 | struct Range<T> { start, end } |
| 439 | 437 | ); |
library/proc_macro/src/bridge/rpc.rs+26-34| ... | ... | @@ -52,45 +52,37 @@ macro_rules! rpc_encode_decode { |
| 52 | 52 | } |
| 53 | 53 | }; |
| 54 | 54 | (enum $name:ident $(<$($T:ident),+>)? { $($variant:ident $(($field:ident))*),* $(,)? }) => { |
| 55 | impl<S, $($($T: Encode<S>),+)?> Encode<S> for $name $(<$($T),+>)? { | |
| 56 | fn encode(self, w: &mut Buffer, s: &mut S) { | |
| 57 | // HACK(eddyb): `Tag` enum duplicated between the | |
| 58 | // two impls as there's no other place to stash it. | |
| 59 | #[allow(non_camel_case_types)] | |
| 60 | #[repr(u8)] | |
| 61 | enum Tag { $($variant),* } | |
| 62 | ||
| 63 | match self { | |
| 64 | $($name::$variant $(($field))* => { | |
| 65 | (Tag::$variant as u8).encode(w, s); | |
| 66 | $($field.encode(w, s);)* | |
| 67 | })* | |
| 55 | #[allow(non_upper_case_globals, non_camel_case_types)] | |
| 56 | const _: () = { | |
| 57 | #[repr(u8)] enum Tag { $($variant),* } | |
| 58 | ||
| 59 | $(const $variant: u8 = Tag::$variant as u8;)* | |
| 60 | ||
| 61 | impl<S, $($($T: Encode<S>),+)?> Encode<S> for $name $(<$($T),+>)? { | |
| 62 | fn encode(self, w: &mut Buffer, s: &mut S) { | |
| 63 | match self { | |
| 64 | $($name::$variant $(($field))* => { | |
| 65 | $variant.encode(w, s); | |
| 66 | $($field.encode(w, s);)* | |
| 67 | })* | |
| 68 | } | |
| 68 | 69 | } |
| 69 | 70 | } |
| 70 | } | |
| 71 | 71 | |
| 72 | impl<'a, S, $($($T: for<'s> Decode<'a, 's, S>),+)?> Decode<'a, '_, S> | |
| 73 | for $name $(<$($T),+>)? | |
| 74 | { | |
| 75 | fn decode(r: &mut &'a [u8], s: &mut S) -> Self { | |
| 76 | // HACK(eddyb): `Tag` enum duplicated between the | |
| 77 | // two impls as there's no other place to stash it. | |
| 78 | #[allow(non_upper_case_globals, non_camel_case_types)] | |
| 79 | mod tag { | |
| 80 | #[repr(u8)] enum Tag { $($variant),* } | |
| 81 | ||
| 82 | $(pub(crate) const $variant: u8 = Tag::$variant as u8;)* | |
| 83 | } | |
| 84 | ||
| 85 | match u8::decode(r, s) { | |
| 86 | $(tag::$variant => { | |
| 87 | $(let $field = Decode::decode(r, s);)* | |
| 88 | $name::$variant $(($field))* | |
| 89 | })* | |
| 90 | _ => unreachable!(), | |
| 72 | impl<'a, S, $($($T: for<'s> Decode<'a, 's, S>),+)?> Decode<'a, '_, S> | |
| 73 | for $name $(<$($T),+>)? | |
| 74 | { | |
| 75 | fn decode(r: &mut &'a [u8], s: &mut S) -> Self { | |
| 76 | match u8::decode(r, s) { | |
| 77 | $($variant => { | |
| 78 | $(let $field = Decode::decode(r, s);)* | |
| 79 | $name::$variant $(($field))* | |
| 80 | })* | |
| 81 | _ => unreachable!(), | |
| 82 | } | |
| 91 | 83 | } |
| 92 | 84 | } |
| 93 | } | |
| 85 | }; | |
| 94 | 86 | } |
| 95 | 87 | } |
| 96 | 88 |
library/proc_macro/src/bridge/selfless_reify.rs+22-42| ... | ... | @@ -38,47 +38,27 @@ |
| 38 | 38 | |
| 39 | 39 | use std::mem; |
| 40 | 40 | |
| 41 | // FIXME(eddyb) this could be `trait` impls except for the `const fn` requirement. | |
| 42 | macro_rules! define_reify_functions { | |
| 43 | ($( | |
| 44 | fn $name:ident $(<$($param:ident),*>)? | |
| 45 | for $(extern $abi:tt)? fn($($arg:ident: $arg_ty:ty),*) -> $ret_ty:ty; | |
| 46 | )+) => { | |
| 47 | $(pub(super) const fn $name< | |
| 48 | $($($param,)*)? | |
| 49 | F: Fn($($arg_ty),*) -> $ret_ty + Copy | |
| 50 | >(f: F) -> $(extern $abi)? fn($($arg_ty),*) -> $ret_ty { | |
| 51 | // FIXME(eddyb) describe the `F` type (e.g. via `type_name::<F>`) once panic | |
| 52 | // formatting becomes possible in `const fn`. | |
| 53 | const { assert!(size_of::<F>() == 0, "selfless_reify: closure must be zero-sized"); } | |
| 54 | ||
| 55 | $(extern $abi)? fn wrapper< | |
| 56 | $($($param,)*)? | |
| 57 | F: Fn($($arg_ty),*) -> $ret_ty + Copy | |
| 58 | >($($arg: $arg_ty),*) -> $ret_ty { | |
| 59 | let f = unsafe { | |
| 60 | // SAFETY: `F` satisfies all criteria for "out of thin air" | |
| 61 | // reconstructability (see module-level doc comment). | |
| 62 | mem::MaybeUninit::<F>::uninit().assume_init() | |
| 63 | }; | |
| 64 | f($($arg),*) | |
| 65 | } | |
| 66 | let _f_proof = f; | |
| 67 | wrapper::< | |
| 68 | $($($param,)*)? | |
| 69 | F | |
| 70 | > | |
| 71 | })+ | |
| 41 | pub(super) const fn reify_to_extern_c_fn_hrt_bridge< | |
| 42 | R, | |
| 43 | F: Fn(super::BridgeConfig<'_>) -> R + Copy, | |
| 44 | >( | |
| 45 | f: F, | |
| 46 | ) -> extern "C" fn(super::BridgeConfig<'_>) -> R { | |
| 47 | // FIXME(eddyb) describe the `F` type (e.g. via `type_name::<F>`) once panic | |
| 48 | // formatting becomes possible in `const fn`. | |
| 49 | const { | |
| 50 | assert!(size_of::<F>() == 0, "selfless_reify: closure must be zero-sized"); | |
| 72 | 51 | } |
| 73 | } | |
| 74 | ||
| 75 | define_reify_functions! { | |
| 76 | fn _reify_to_extern_c_fn_unary<A, R> for extern "C" fn(arg: A) -> R; | |
| 77 | ||
| 78 | // HACK(eddyb) this abstraction is used with `for<'a> fn(BridgeConfig<'a>) | |
| 79 | // -> T` but that doesn't work with just `reify_to_extern_c_fn_unary` | |
| 80 | // because of the `fn` pointer type being "higher-ranked" (i.e. the | |
| 81 | // `for<'a>` binder). | |
| 82 | // FIXME(eddyb) try to remove the lifetime from `BridgeConfig`, that'd help. | |
| 83 | fn reify_to_extern_c_fn_hrt_bridge<R> for extern "C" fn(bridge: super::BridgeConfig<'_>) -> R; | |
| 52 | extern "C" fn wrapper<R, F: Fn(super::BridgeConfig<'_>) -> R + Copy>( | |
| 53 | bridge: super::BridgeConfig<'_>, | |
| 54 | ) -> R { | |
| 55 | let f = unsafe { | |
| 56 | // SAFETY: `F` satisfies all criteria for "out of thin air" | |
| 57 | // reconstructability (see module-level doc comment). | |
| 58 | mem::conjure_zst::<F>() | |
| 59 | }; | |
| 60 | f(bridge) | |
| 61 | } | |
| 62 | let _f_proof = f; | |
| 63 | wrapper::<R, F> | |
| 84 | 64 | } |
library/proc_macro/src/bridge/server.rs+10-14| ... | ... | @@ -58,12 +58,12 @@ struct Dispatcher<S: Server> { |
| 58 | 58 | server: S, |
| 59 | 59 | } |
| 60 | 60 | |
| 61 | macro_rules! define_server_dispatcher_impl { | |
| 61 | macro_rules! define_server { | |
| 62 | 62 | ( |
| 63 | 63 | $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* |
| 64 | 64 | ) => { |
| 65 | 65 | pub trait Server { |
| 66 | type TokenStream: 'static + Clone; | |
| 66 | type TokenStream: 'static + Clone + Default; | |
| 67 | 67 | type Span: 'static + Copy + Eq + Hash; |
| 68 | 68 | type Symbol: 'static; |
| 69 | 69 | |
| ... | ... | @@ -77,22 +77,20 @@ macro_rules! define_server_dispatcher_impl { |
| 77 | 77 | |
| 78 | 78 | $(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?;)* |
| 79 | 79 | } |
| 80 | } | |
| 81 | } | |
| 82 | with_api!(define_server, Self::TokenStream, Self::Span, Self::Symbol); | |
| 80 | 83 | |
| 84 | macro_rules! define_dispatcher { | |
| 85 | ( | |
| 86 | $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)* | |
| 87 | ) => { | |
| 81 | 88 | // FIXME(eddyb) `pub` only for `ExecutionStrategy` below. |
| 82 | 89 | pub trait DispatcherTrait { |
| 83 | // HACK(eddyb) these are here to allow `Self::$name` to work below. | |
| 84 | type TokenStream; | |
| 85 | type Span; | |
| 86 | type Symbol; | |
| 87 | ||
| 88 | 90 | fn dispatch(&mut self, buf: Buffer) -> Buffer; |
| 89 | 91 | } |
| 90 | 92 | |
| 91 | 93 | impl<S: Server> DispatcherTrait for Dispatcher<S> { |
| 92 | type TokenStream = MarkedTokenStream<S>; | |
| 93 | type Span = MarkedSpan<S>; | |
| 94 | type Symbol = MarkedSymbol<S>; | |
| 95 | ||
| 96 | 94 | fn dispatch(&mut self, mut buf: Buffer) -> Buffer { |
| 97 | 95 | let Dispatcher { handle_store, server } = self; |
| 98 | 96 | |
| ... | ... | @@ -127,7 +125,7 @@ macro_rules! define_server_dispatcher_impl { |
| 127 | 125 | } |
| 128 | 126 | } |
| 129 | 127 | } |
| 130 | with_api!(Self, define_server_dispatcher_impl); | |
| 128 | with_api!(define_dispatcher, MarkedTokenStream<S>, MarkedSpan<S>, MarkedSymbol<S>); | |
| 131 | 129 | |
| 132 | 130 | pub trait ExecutionStrategy { |
| 133 | 131 | fn run_bridge_and_client( |
| ... | ... | @@ -312,7 +310,6 @@ impl client::Client<crate::TokenStream, crate::TokenStream> { |
| 312 | 310 | ) -> Result<S::TokenStream, PanicMessage> |
| 313 | 311 | where |
| 314 | 312 | S: Server, |
| 315 | S::TokenStream: Default, | |
| 316 | 313 | { |
| 317 | 314 | let client::Client { handle_counters, run, _marker } = *self; |
| 318 | 315 | run_server( |
| ... | ... | @@ -338,7 +335,6 @@ impl client::Client<(crate::TokenStream, crate::TokenStream), crate::TokenStream |
| 338 | 335 | ) -> Result<S::TokenStream, PanicMessage> |
| 339 | 336 | where |
| 340 | 337 | S: Server, |
| 341 | S::TokenStream: Default, | |
| 342 | 338 | { |
| 343 | 339 | let client::Client { handle_counters, run, _marker } = *self; |
| 344 | 340 | run_server( |
library/proc_macro/src/lib.rs+1| ... | ... | @@ -27,6 +27,7 @@ |
| 27 | 27 | #![feature(restricted_std)] |
| 28 | 28 | #![feature(rustc_attrs)] |
| 29 | 29 | #![feature(extend_one)] |
| 30 | #![feature(mem_conjure_zst)] | |
| 30 | 31 | #![recursion_limit = "256"] |
| 31 | 32 | #![allow(internal_features)] |
| 32 | 33 | #![deny(ffi_unwind_calls)] |
library/std/src/path.rs+14| ... | ... | @@ -19,6 +19,20 @@ |
| 19 | 19 | //! matter the platform or filesystem. An exception to this is made for Windows |
| 20 | 20 | //! drive letters. |
| 21 | 21 | //! |
| 22 | //! ## Path normalization | |
| 23 | //! | |
| 24 | //! Several methods in this module perform basic path normalization by disregarding | |
| 25 | //! repeated separators, non-leading `.` components, and trailing separators. These include: | |
| 26 | //! - Methods for iteration, such as [`Path::components`] and [`Path::iter`] | |
| 27 | //! - Methods for inspection, such as [`Path::has_root`] | |
| 28 | //! - Comparisons using [`PartialEq`], [`PartialOrd`], and [`Ord`] | |
| 29 | //! | |
| 30 | //! [`Path::join`] and [`PathBuf::push`] also disregard trailing slashes. | |
| 31 | //! | |
| 32 | // FIXME(normalize_lexically): mention normalize_lexically once stable | |
| 33 | //! These methods **do not** resolve `..` components or symlinks. For full normalization | |
| 34 | //! including `..` resolution, use [`Path::canonicalize`] (which does access the filesystem). | |
| 35 | //! | |
| 22 | 36 | //! ## Simple usage |
| 23 | 37 | //! |
| 24 | 38 | //! Path manipulation includes both parsing components from slices and building |
src/tools/compiletest/src/common.rs+3-1| ... | ... | @@ -949,7 +949,9 @@ impl TargetCfgs { |
| 949 | 949 | // actually be changed with `-C` flags. |
| 950 | 950 | for config in query_rustc_output( |
| 951 | 951 | config, |
| 952 | &["--print=cfg", "--target", &config.target], | |
| 952 | // `-Zunstable-options` is necessary when compiletest is running with custom targets | |
| 953 | // (such as synthetic targets used to bless mir-opt tests). | |
| 954 | &["-Zunstable-options", "--print=cfg", "--target", &config.target], | |
| 953 | 955 | Default::default(), |
| 954 | 956 | ) |
| 955 | 957 | .trim() |
src/tools/compiletest/src/directives/directive_names.rs+1| ... | ... | @@ -249,6 +249,7 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ |
| 249 | 249 | "only-unix", |
| 250 | 250 | "only-visionos", |
| 251 | 251 | "only-wasm32", |
| 252 | "only-wasm32-unknown-emscripten", | |
| 252 | 253 | "only-wasm32-unknown-unknown", |
| 253 | 254 | "only-wasm32-wasip1", |
| 254 | 255 | "only-watchos", |
src/tools/compiletest/src/runtest.rs+5| ... | ... | @@ -1670,6 +1670,11 @@ impl<'test> TestCx<'test> { |
| 1670 | 1670 | if self.props.force_host { &*self.config.host } else { &*self.config.target }; |
| 1671 | 1671 | |
| 1672 | 1672 | compiler.arg(&format!("--target={}", target)); |
| 1673 | if target.ends_with(".json") { | |
| 1674 | // `-Zunstable-options` is necessary when compiletest is running with custom targets | |
| 1675 | // (such as synthetic targets used to bless mir-opt tests). | |
| 1676 | compiler.arg("-Zunstable-options"); | |
| 1677 | } | |
| 1673 | 1678 | } |
| 1674 | 1679 | self.set_revision_flags(&mut compiler); |
| 1675 | 1680 |
src/tools/rust-analyzer/Cargo.lock+15-15| ... | ... | @@ -1614,9 +1614,9 @@ dependencies = [ |
| 1614 | 1614 | |
| 1615 | 1615 | [[package]] |
| 1616 | 1616 | name = "num-conv" |
| 1617 | version = "0.1.0" | |
| 1617 | version = "0.2.0" | |
| 1618 | 1618 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 1619 | checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" | |
| 1619 | checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" | |
| 1620 | 1620 | |
| 1621 | 1621 | [[package]] |
| 1622 | 1622 | name = "num-traits" |
| ... | ... | @@ -2453,9 +2453,9 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" |
| 2453 | 2453 | |
| 2454 | 2454 | [[package]] |
| 2455 | 2455 | name = "salsa" |
| 2456 | version = "0.25.2" | |
| 2456 | version = "0.26.0" | |
| 2457 | 2457 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 2458 | checksum = "e2e2aa2fca57727371eeafc975acc8e6f4c52f8166a78035543f6ee1c74c2dcc" | |
| 2458 | checksum = "f77debccd43ba198e9cee23efd7f10330ff445e46a98a2b107fed9094a1ee676" | |
| 2459 | 2459 | dependencies = [ |
| 2460 | 2460 | "boxcar", |
| 2461 | 2461 | "crossbeam-queue", |
| ... | ... | @@ -2478,15 +2478,15 @@ dependencies = [ |
| 2478 | 2478 | |
| 2479 | 2479 | [[package]] |
| 2480 | 2480 | name = "salsa-macro-rules" |
| 2481 | version = "0.25.2" | |
| 2481 | version = "0.26.0" | |
| 2482 | 2482 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 2483 | checksum = "1bfc2a1e7bf06964105515451d728f2422dedc3a112383324a00b191a5c397a3" | |
| 2483 | checksum = "ea07adbf42d91cc076b7daf3b38bc8168c19eb362c665964118a89bc55ef19a5" | |
| 2484 | 2484 | |
| 2485 | 2485 | [[package]] |
| 2486 | 2486 | name = "salsa-macros" |
| 2487 | version = "0.25.2" | |
| 2487 | version = "0.26.0" | |
| 2488 | 2488 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 2489 | checksum = "3d844c1aa34946da46af683b5c27ec1088a3d9d84a2b837a108223fd830220e1" | |
| 2489 | checksum = "d16d4d8b66451b9c75ddf740b7fc8399bc7b8ba33e854a5d7526d18708f67b05" | |
| 2490 | 2490 | dependencies = [ |
| 2491 | 2491 | "proc-macro2", |
| 2492 | 2492 | "quote", |
| ... | ... | @@ -2914,9 +2914,9 @@ dependencies = [ |
| 2914 | 2914 | |
| 2915 | 2915 | [[package]] |
| 2916 | 2916 | name = "time" |
| 2917 | version = "0.3.44" | |
| 2917 | version = "0.3.47" | |
| 2918 | 2918 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 2919 | checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" | |
| 2919 | checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" | |
| 2920 | 2920 | dependencies = [ |
| 2921 | 2921 | "deranged", |
| 2922 | 2922 | "itoa", |
| ... | ... | @@ -2924,22 +2924,22 @@ dependencies = [ |
| 2924 | 2924 | "num-conv", |
| 2925 | 2925 | "num_threads", |
| 2926 | 2926 | "powerfmt", |
| 2927 | "serde", | |
| 2927 | "serde_core", | |
| 2928 | 2928 | "time-core", |
| 2929 | 2929 | "time-macros", |
| 2930 | 2930 | ] |
| 2931 | 2931 | |
| 2932 | 2932 | [[package]] |
| 2933 | 2933 | name = "time-core" |
| 2934 | version = "0.1.6" | |
| 2934 | version = "0.1.8" | |
| 2935 | 2935 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 2936 | checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" | |
| 2936 | checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" | |
| 2937 | 2937 | |
| 2938 | 2938 | [[package]] |
| 2939 | 2939 | name = "time-macros" |
| 2940 | version = "0.2.24" | |
| 2940 | version = "0.2.27" | |
| 2941 | 2941 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 2942 | checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" | |
| 2942 | checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" | |
| 2943 | 2943 | dependencies = [ |
| 2944 | 2944 | "num-conv", |
| 2945 | 2945 | "time-core", |
src/tools/rust-analyzer/Cargo.toml+2-4| ... | ... | @@ -135,13 +135,13 @@ rayon = "1.10.0" |
| 135 | 135 | rowan = "=0.15.17" |
| 136 | 136 | # Ideally we'd not enable the macros feature but unfortunately the `tracked` attribute does not work |
| 137 | 137 | # on impls without it |
| 138 | salsa = { version = "0.25.2", default-features = false, features = [ | |
| 138 | salsa = { version = "0.26", default-features = false, features = [ | |
| 139 | 139 | "rayon", |
| 140 | 140 | "salsa_unstable", |
| 141 | 141 | "macros", |
| 142 | 142 | "inventory", |
| 143 | 143 | ] } |
| 144 | salsa-macros = "0.25.2" | |
| 144 | salsa-macros = "0.26" | |
| 145 | 145 | semver = "1.0.26" |
| 146 | 146 | serde = { version = "1.0.219" } |
| 147 | 147 | serde_derive = { version = "1.0.219" } |
| ... | ... | @@ -192,8 +192,6 @@ unused_lifetimes = "warn" |
| 192 | 192 | unreachable_pub = "warn" |
| 193 | 193 | |
| 194 | 194 | [workspace.lints.clippy] |
| 195 | # FIXME Remove the tidy test once the lint table is stable | |
| 196 | ||
| 197 | 195 | ## lint groups |
| 198 | 196 | complexity = { level = "warn", priority = -1 } |
| 199 | 197 | correctness = { level = "deny", priority = -1 } |
src/tools/rust-analyzer/bench_data/glorious_old_parser+1-17| ... | ... | @@ -724,7 +724,7 @@ impl<'a> Parser<'a> { |
| 724 | 724 | // {foo(bar {}} |
| 725 | 725 | // - ^ |
| 726 | 726 | // | | |
| 727 | // | help: `)` may belong here (FIXME: #58270) | |
| 727 | // | help: `)` may belong here | |
| 728 | 728 | // | |
| 729 | 729 | // unclosed delimiter |
| 730 | 730 | if let Some(sp) = unmatched.unclosed_span { |
| ... | ... | @@ -3217,7 +3217,6 @@ impl<'a> Parser<'a> { |
| 3217 | 3217 | |
| 3218 | 3218 | } |
| 3219 | 3219 | _ => { |
| 3220 | // FIXME Could factor this out into non_fatal_unexpected or something. | |
| 3221 | 3220 | let actual = self.this_token_to_string(); |
| 3222 | 3221 | self.span_err(self.span, &format!("unexpected token: `{}`", actual)); |
| 3223 | 3222 | } |
| ... | ... | @@ -5250,7 +5249,6 @@ impl<'a> Parser<'a> { |
| 5250 | 5249 | } |
| 5251 | 5250 | } |
| 5252 | 5251 | } else { |
| 5253 | // FIXME: Bad copy of attrs | |
| 5254 | 5252 | let old_directory_ownership = |
| 5255 | 5253 | mem::replace(&mut self.directory.ownership, DirectoryOwnership::UnownedViaBlock); |
| 5256 | 5254 | let item = self.parse_item_(attrs.clone(), false, true)?; |
| ... | ... | @@ -5953,23 +5951,14 @@ impl<'a> Parser<'a> { |
| 5953 | 5951 | }); |
| 5954 | 5952 | assoc_ty_bindings.push(span); |
| 5955 | 5953 | } else if self.check_const_arg() { |
| 5956 | // FIXME(const_generics): to distinguish between idents for types and consts, | |
| 5957 | // we should introduce a GenericArg::Ident in the AST and distinguish when | |
| 5958 | // lowering to the HIR. For now, idents for const args are not permitted. | |
| 5959 | ||
| 5960 | 5954 | // Parse const argument. |
| 5961 | 5955 | let expr = if let token::OpenDelim(token::Brace) = self.token { |
| 5962 | 5956 | self.parse_block_expr(None, self.span, BlockCheckMode::Default, ThinVec::new())? |
| 5963 | 5957 | } else if self.token.is_ident() { |
| 5964 | // FIXME(const_generics): to distinguish between idents for types and consts, | |
| 5965 | // we should introduce a GenericArg::Ident in the AST and distinguish when | |
| 5966 | // lowering to the HIR. For now, idents for const args are not permitted. | |
| 5967 | 5958 | return Err( |
| 5968 | 5959 | self.fatal("identifiers may currently not be used for const generics") |
| 5969 | 5960 | ); |
| 5970 | 5961 | } else { |
| 5971 | // FIXME(const_generics): this currently conflicts with emplacement syntax | |
| 5972 | // with negative integer literals. | |
| 5973 | 5962 | self.parse_literal_maybe_minus()? |
| 5974 | 5963 | }; |
| 5975 | 5964 | let value = AnonConst { |
| ... | ... | @@ -5991,9 +5980,6 @@ impl<'a> Parser<'a> { |
| 5991 | 5980 | } |
| 5992 | 5981 | } |
| 5993 | 5982 | |
| 5994 | // FIXME: we would like to report this in ast_validation instead, but we currently do not | |
| 5995 | // preserve ordering of generic parameters with respect to associated type binding, so we | |
| 5996 | // lose that information after parsing. | |
| 5997 | 5983 | if misplaced_assoc_ty_bindings.len() > 0 { |
| 5998 | 5984 | let mut err = self.struct_span_err( |
| 5999 | 5985 | args_lo.to(self.prev_span), |
| ... | ... | @@ -6079,8 +6065,6 @@ impl<'a> Parser<'a> { |
| 6079 | 6065 | bounds, |
| 6080 | 6066 | } |
| 6081 | 6067 | )); |
| 6082 | // FIXME: Decide what should be used here, `=` or `==`. | |
| 6083 | // FIXME: We are just dropping the binders in lifetime_defs on the floor here. | |
| 6084 | 6068 | } else if self.eat(&token::Eq) || self.eat(&token::EqEq) { |
| 6085 | 6069 | let rhs_ty = self.parse_ty()?; |
| 6086 | 6070 | where_clause.predicates.push(ast::WherePredicate::EqPredicate( |
src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs+1-1| ... | ... | @@ -60,7 +60,7 @@ const _: () = { |
| 60 | 60 | } |
| 61 | 61 | } |
| 62 | 62 | |
| 63 | impl zalsa_struct_::HashEqLike<WithoutCrate> for EditionedFileIdData { | |
| 63 | impl zalsa_::HashEqLike<WithoutCrate> for EditionedFileIdData { | |
| 64 | 64 | #[inline] |
| 65 | 65 | fn hash<H: Hasher>(&self, state: &mut H) { |
| 66 | 66 | Hash::hash(self, state); |
src/tools/rust-analyzer/crates/edition/src/lib.rs-2| ... | ... | @@ -16,8 +16,6 @@ impl Edition { |
| 16 | 16 | pub const DEFAULT: Edition = Edition::Edition2015; |
| 17 | 17 | pub const LATEST: Edition = Edition::Edition2024; |
| 18 | 18 | pub const CURRENT: Edition = Edition::Edition2024; |
| 19 | /// The current latest stable edition, note this is usually not the right choice in code. | |
| 20 | pub const CURRENT_FIXME: Edition = Edition::Edition2024; | |
| 21 | 19 | |
| 22 | 20 | pub fn from_u32(u32: u32) -> Edition { |
| 23 | 21 | match u32 { |
src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs+68-14| ... | ... | @@ -426,7 +426,7 @@ pub struct ExprCollector<'db> { |
| 426 | 426 | /// and we need to find the current definition. So we track the number of definitions we saw. |
| 427 | 427 | current_block_legacy_macro_defs_count: FxHashMap<Name, usize>, |
| 428 | 428 | |
| 429 | current_try_block_label: Option<LabelId>, | |
| 429 | current_try_block: Option<TryBlock>, | |
| 430 | 430 | |
| 431 | 431 | label_ribs: Vec<LabelRib>, |
| 432 | 432 | unowned_bindings: Vec<BindingId>, |
| ... | ... | @@ -472,6 +472,13 @@ enum Awaitable { |
| 472 | 472 | No(&'static str), |
| 473 | 473 | } |
| 474 | 474 | |
| 475 | enum TryBlock { | |
| 476 | // `try { ... }` | |
| 477 | Homogeneous { label: LabelId }, | |
| 478 | // `try bikeshed Ty { ... }` | |
| 479 | Heterogeneous { label: LabelId }, | |
| 480 | } | |
| 481 | ||
| 475 | 482 | #[derive(Debug, Default)] |
| 476 | 483 | struct BindingList { |
| 477 | 484 | map: FxHashMap<(Name, HygieneId), BindingId>, |
| ... | ... | @@ -532,7 +539,7 @@ impl<'db> ExprCollector<'db> { |
| 532 | 539 | lang_items: OnceCell::new(), |
| 533 | 540 | store: ExpressionStoreBuilder::default(), |
| 534 | 541 | expander, |
| 535 | current_try_block_label: None, | |
| 542 | current_try_block: None, | |
| 536 | 543 | is_lowering_coroutine: false, |
| 537 | 544 | label_ribs: Vec::new(), |
| 538 | 545 | unowned_bindings: Vec::new(), |
| ... | ... | @@ -1069,7 +1076,9 @@ impl<'db> ExprCollector<'db> { |
| 1069 | 1076 | self.alloc_expr(Expr::Let { pat, expr }, syntax_ptr) |
| 1070 | 1077 | } |
| 1071 | 1078 | ast::Expr::BlockExpr(e) => match e.modifier() { |
| 1072 | Some(ast::BlockModifier::Try(_)) => self.desugar_try_block(e), | |
| 1079 | Some(ast::BlockModifier::Try { try_token: _, bikeshed_token: _, result_type }) => { | |
| 1080 | self.desugar_try_block(e, result_type) | |
| 1081 | } | |
| 1073 | 1082 | Some(ast::BlockModifier::Unsafe(_)) => { |
| 1074 | 1083 | self.collect_block_(e, |id, statements, tail| Expr::Unsafe { |
| 1075 | 1084 | id, |
| ... | ... | @@ -1344,7 +1353,7 @@ impl<'db> ExprCollector<'db> { |
| 1344 | 1353 | .map(|it| this.lower_type_ref_disallow_impl_trait(it)); |
| 1345 | 1354 | |
| 1346 | 1355 | let prev_is_lowering_coroutine = mem::take(&mut this.is_lowering_coroutine); |
| 1347 | let prev_try_block_label = this.current_try_block_label.take(); | |
| 1356 | let prev_try_block = this.current_try_block.take(); | |
| 1348 | 1357 | |
| 1349 | 1358 | let awaitable = if e.async_token().is_some() { |
| 1350 | 1359 | Awaitable::Yes |
| ... | ... | @@ -1369,7 +1378,7 @@ impl<'db> ExprCollector<'db> { |
| 1369 | 1378 | let capture_by = |
| 1370 | 1379 | if e.move_token().is_some() { CaptureBy::Value } else { CaptureBy::Ref }; |
| 1371 | 1380 | this.is_lowering_coroutine = prev_is_lowering_coroutine; |
| 1372 | this.current_try_block_label = prev_try_block_label; | |
| 1381 | this.current_try_block = prev_try_block; | |
| 1373 | 1382 | this.alloc_expr( |
| 1374 | 1383 | Expr::Closure { |
| 1375 | 1384 | args: args.into(), |
| ... | ... | @@ -1686,11 +1695,15 @@ impl<'db> ExprCollector<'db> { |
| 1686 | 1695 | /// Desugar `try { <stmts>; <expr> }` into `'<new_label>: { <stmts>; ::std::ops::Try::from_output(<expr>) }`, |
| 1687 | 1696 | /// `try { <stmts>; }` into `'<new_label>: { <stmts>; ::std::ops::Try::from_output(()) }` |
| 1688 | 1697 | /// and save the `<new_label>` to use it as a break target for desugaring of the `?` operator. |
| 1689 | fn desugar_try_block(&mut self, e: BlockExpr) -> ExprId { | |
| 1698 | fn desugar_try_block(&mut self, e: BlockExpr, result_type: Option<ast::Type>) -> ExprId { | |
| 1690 | 1699 | let try_from_output = self.lang_path(self.lang_items().TryTraitFromOutput); |
| 1691 | 1700 | let label = self.generate_new_name(); |
| 1692 | 1701 | let label = self.alloc_label_desugared(Label { name: label }, AstPtr::new(&e).wrap_right()); |
| 1693 | let old_label = self.current_try_block_label.replace(label); | |
| 1702 | let try_block_info = match result_type { | |
| 1703 | Some(_) => TryBlock::Heterogeneous { label }, | |
| 1704 | None => TryBlock::Homogeneous { label }, | |
| 1705 | }; | |
| 1706 | let old_try_block = self.current_try_block.replace(try_block_info); | |
| 1694 | 1707 | |
| 1695 | 1708 | let ptr = AstPtr::new(&e).upcast(); |
| 1696 | 1709 | let (btail, expr_id) = self.with_labeled_rib(label, HygieneId::ROOT, |this| { |
| ... | ... | @@ -1720,8 +1733,38 @@ impl<'db> ExprCollector<'db> { |
| 1720 | 1733 | unreachable!("block was lowered to non-block"); |
| 1721 | 1734 | }; |
| 1722 | 1735 | *tail = Some(next_tail); |
| 1723 | self.current_try_block_label = old_label; | |
| 1724 | expr_id | |
| 1736 | self.current_try_block = old_try_block; | |
| 1737 | match result_type { | |
| 1738 | Some(ty) => { | |
| 1739 | // `{ let <name>: <ty> = <expr>; <name> }` | |
| 1740 | let name = self.generate_new_name(); | |
| 1741 | let type_ref = self.lower_type_ref_disallow_impl_trait(ty); | |
| 1742 | let binding = self.alloc_binding( | |
| 1743 | name.clone(), | |
| 1744 | BindingAnnotation::Unannotated, | |
| 1745 | HygieneId::ROOT, | |
| 1746 | ); | |
| 1747 | let pat = self.alloc_pat_desugared(Pat::Bind { id: binding, subpat: None }); | |
| 1748 | self.add_definition_to_binding(binding, pat); | |
| 1749 | let tail_expr = | |
| 1750 | self.alloc_expr_desugared_with_ptr(Expr::Path(Path::from(name)), ptr); | |
| 1751 | self.alloc_expr_desugared_with_ptr( | |
| 1752 | Expr::Block { | |
| 1753 | id: None, | |
| 1754 | statements: Box::new([Statement::Let { | |
| 1755 | pat, | |
| 1756 | type_ref: Some(type_ref), | |
| 1757 | initializer: Some(expr_id), | |
| 1758 | else_branch: None, | |
| 1759 | }]), | |
| 1760 | tail: Some(tail_expr), | |
| 1761 | label: None, | |
| 1762 | }, | |
| 1763 | ptr, | |
| 1764 | ) | |
| 1765 | } | |
| 1766 | None => expr_id, | |
| 1767 | } | |
| 1725 | 1768 | } |
| 1726 | 1769 | |
| 1727 | 1770 | /// Desugar `ast::WhileExpr` from: `[opt_ident]: while <cond> <body>` into: |
| ... | ... | @@ -1863,6 +1906,8 @@ impl<'db> ExprCollector<'db> { |
| 1863 | 1906 | /// ControlFlow::Continue(val) => val, |
| 1864 | 1907 | /// ControlFlow::Break(residual) => |
| 1865 | 1908 | /// // If there is an enclosing `try {...}`: |
| 1909 | /// break 'catch_target Residual::into_try_type(residual), | |
| 1910 | /// // If there is an enclosing `try bikeshed Ty {...}`: | |
| 1866 | 1911 | /// break 'catch_target Try::from_residual(residual), |
| 1867 | 1912 | /// // Otherwise: |
| 1868 | 1913 | /// return Try::from_residual(residual), |
| ... | ... | @@ -1873,7 +1918,6 @@ impl<'db> ExprCollector<'db> { |
| 1873 | 1918 | let try_branch = self.lang_path(lang_items.TryTraitBranch); |
| 1874 | 1919 | let cf_continue = self.lang_path(lang_items.ControlFlowContinue); |
| 1875 | 1920 | let cf_break = self.lang_path(lang_items.ControlFlowBreak); |
| 1876 | let try_from_residual = self.lang_path(lang_items.TryTraitFromResidual); | |
| 1877 | 1921 | let operand = self.collect_expr_opt(e.expr()); |
| 1878 | 1922 | let try_branch = self.alloc_expr(try_branch.map_or(Expr::Missing, Expr::Path), syntax_ptr); |
| 1879 | 1923 | let expr = self |
| ... | ... | @@ -1910,13 +1954,23 @@ impl<'db> ExprCollector<'db> { |
| 1910 | 1954 | guard: None, |
| 1911 | 1955 | expr: { |
| 1912 | 1956 | let it = self.alloc_expr(Expr::Path(Path::from(break_name)), syntax_ptr); |
| 1913 | let callee = self | |
| 1914 | .alloc_expr(try_from_residual.map_or(Expr::Missing, Expr::Path), syntax_ptr); | |
| 1957 | let convert_fn = match self.current_try_block { | |
| 1958 | Some(TryBlock::Homogeneous { .. }) => { | |
| 1959 | self.lang_path(lang_items.ResidualIntoTryType) | |
| 1960 | } | |
| 1961 | Some(TryBlock::Heterogeneous { .. }) | None => { | |
| 1962 | self.lang_path(lang_items.TryTraitFromResidual) | |
| 1963 | } | |
| 1964 | }; | |
| 1965 | let callee = | |
| 1966 | self.alloc_expr(convert_fn.map_or(Expr::Missing, Expr::Path), syntax_ptr); | |
| 1915 | 1967 | let result = |
| 1916 | 1968 | self.alloc_expr(Expr::Call { callee, args: Box::new([it]) }, syntax_ptr); |
| 1917 | 1969 | self.alloc_expr( |
| 1918 | match self.current_try_block_label { | |
| 1919 | Some(label) => Expr::Break { expr: Some(result), label: Some(label) }, | |
| 1970 | match self.current_try_block { | |
| 1971 | Some( | |
| 1972 | TryBlock::Heterogeneous { label } | TryBlock::Homogeneous { label }, | |
| 1973 | ) => Expr::Break { expr: Some(result), label: Some(label) }, | |
| 1920 | 1974 | None => Expr::Return { expr: Some(result) }, |
| 1921 | 1975 | }, |
| 1922 | 1976 | syntax_ptr, |
src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs+18| ... | ... | @@ -893,6 +893,24 @@ impl ItemScope { |
| 893 | 893 | self.macros.get_mut(name).expect("tried to update visibility of non-existent macro"); |
| 894 | 894 | res.vis = vis; |
| 895 | 895 | } |
| 896 | ||
| 897 | pub(crate) fn update_def_types(&mut self, name: &Name, def: ModuleDefId, vis: Visibility) { | |
| 898 | let res = self.types.get_mut(name).expect("tried to update def of non-existent type"); | |
| 899 | res.def = def; | |
| 900 | res.vis = vis; | |
| 901 | } | |
| 902 | ||
| 903 | pub(crate) fn update_def_values(&mut self, name: &Name, def: ModuleDefId, vis: Visibility) { | |
| 904 | let res = self.values.get_mut(name).expect("tried to update def of non-existent value"); | |
| 905 | res.def = def; | |
| 906 | res.vis = vis; | |
| 907 | } | |
| 908 | ||
| 909 | pub(crate) fn update_def_macros(&mut self, name: &Name, def: MacroId, vis: Visibility) { | |
| 910 | let res = self.macros.get_mut(name).expect("tried to update def of non-existent macro"); | |
| 911 | res.def = def; | |
| 912 | res.vis = vis; | |
| 913 | } | |
| 896 | 914 | } |
| 897 | 915 | |
| 898 | 916 | impl PerNs { |
src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs+1| ... | ... | @@ -456,6 +456,7 @@ language_item_table! { LangItems => |
| 456 | 456 | TryTraitFromOutput, sym::from_output, FunctionId; |
| 457 | 457 | TryTraitBranch, sym::branch, FunctionId; |
| 458 | 458 | TryTraitFromYeet, sym::from_yeet, FunctionId; |
| 459 | ResidualIntoTryType, sym::into_try_type, FunctionId; | |
| 459 | 460 | |
| 460 | 461 | PointerLike, sym::pointer_like, TraitId; |
| 461 | 462 |
src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs+52-25| ... | ... | @@ -1209,42 +1209,69 @@ impl<'db> DefCollector<'db> { |
| 1209 | 1209 | // `ItemScope::push_res_with_import()`. |
| 1210 | 1210 | if let Some(def) = defs.types |
| 1211 | 1211 | && let Some(prev_def) = prev_defs.types |
| 1212 | && def.def == prev_def.def | |
| 1213 | && self.from_glob_import.contains_type(module_id, name.clone()) | |
| 1214 | && def.vis != prev_def.vis | |
| 1215 | && def.vis.max(self.db, prev_def.vis, &self.def_map) == Some(def.vis) | |
| 1216 | 1212 | { |
| 1217 | changed = true; | |
| 1218 | // This import is being handled here, don't pass it down to | |
| 1219 | // `ItemScope::push_res_with_import()`. | |
| 1220 | defs.types = None; | |
| 1221 | self.def_map.modules[module_id].scope.update_visibility_types(name, def.vis); | |
| 1213 | if def.def == prev_def.def | |
| 1214 | && self.from_glob_import.contains_type(module_id, name.clone()) | |
| 1215 | && def.vis != prev_def.vis | |
| 1216 | && def.vis.max(self.db, prev_def.vis, &self.def_map) == Some(def.vis) | |
| 1217 | { | |
| 1218 | changed = true; | |
| 1219 | // This import is being handled here, don't pass it down to | |
| 1220 | // `ItemScope::push_res_with_import()`. | |
| 1221 | defs.types = None; | |
| 1222 | self.def_map.modules[module_id].scope.update_visibility_types(name, def.vis); | |
| 1223 | } | |
| 1224 | // When the source module's definition changed (e.g., due to an explicit import | |
| 1225 | // shadowing a glob), propagate the new definition to modules that glob-import from it. | |
| 1226 | // We check that the previous definition came from the same glob import to avoid | |
| 1227 | // incorrectly overwriting definitions from different glob sources. | |
| 1228 | // | |
| 1229 | // Note this is not a perfect fix, but it makes | |
| 1230 | // https://github.com/rust-lang/rust-analyzer/issues/19224 work for now until we | |
| 1231 | // implement a proper glob graph | |
| 1232 | else if def.def != prev_def.def && prev_def.import == def_import_type { | |
| 1233 | changed = true; | |
| 1234 | defs.types = None; | |
| 1235 | self.def_map.modules[module_id].scope.update_def_types(name, def.def, def.vis); | |
| 1236 | } | |
| 1222 | 1237 | } |
| 1223 | 1238 | |
| 1224 | 1239 | if let Some(def) = defs.values |
| 1225 | 1240 | && let Some(prev_def) = prev_defs.values |
| 1226 | && def.def == prev_def.def | |
| 1227 | && self.from_glob_import.contains_value(module_id, name.clone()) | |
| 1228 | && def.vis != prev_def.vis | |
| 1229 | && def.vis.max(self.db, prev_def.vis, &self.def_map) == Some(def.vis) | |
| 1230 | 1241 | { |
| 1231 | changed = true; | |
| 1232 | // See comment above. | |
| 1233 | defs.values = None; | |
| 1234 | self.def_map.modules[module_id].scope.update_visibility_values(name, def.vis); | |
| 1242 | if def.def == prev_def.def | |
| 1243 | && self.from_glob_import.contains_value(module_id, name.clone()) | |
| 1244 | && def.vis != prev_def.vis | |
| 1245 | && def.vis.max(self.db, prev_def.vis, &self.def_map) == Some(def.vis) | |
| 1246 | { | |
| 1247 | changed = true; | |
| 1248 | defs.values = None; | |
| 1249 | self.def_map.modules[module_id].scope.update_visibility_values(name, def.vis); | |
| 1250 | } else if def.def != prev_def.def | |
| 1251 | && prev_def.import.map(ImportOrExternCrate::from) == def_import_type | |
| 1252 | { | |
| 1253 | changed = true; | |
| 1254 | defs.values = None; | |
| 1255 | self.def_map.modules[module_id].scope.update_def_values(name, def.def, def.vis); | |
| 1256 | } | |
| 1235 | 1257 | } |
| 1236 | 1258 | |
| 1237 | 1259 | if let Some(def) = defs.macros |
| 1238 | 1260 | && let Some(prev_def) = prev_defs.macros |
| 1239 | && def.def == prev_def.def | |
| 1240 | && self.from_glob_import.contains_macro(module_id, name.clone()) | |
| 1241 | && def.vis != prev_def.vis | |
| 1242 | && def.vis.max(self.db, prev_def.vis, &self.def_map) == Some(def.vis) | |
| 1243 | 1261 | { |
| 1244 | changed = true; | |
| 1245 | // See comment above. | |
| 1246 | defs.macros = None; | |
| 1247 | self.def_map.modules[module_id].scope.update_visibility_macros(name, def.vis); | |
| 1262 | if def.def == prev_def.def | |
| 1263 | && self.from_glob_import.contains_macro(module_id, name.clone()) | |
| 1264 | && def.vis != prev_def.vis | |
| 1265 | && def.vis.max(self.db, prev_def.vis, &self.def_map) == Some(def.vis) | |
| 1266 | { | |
| 1267 | changed = true; | |
| 1268 | defs.macros = None; | |
| 1269 | self.def_map.modules[module_id].scope.update_visibility_macros(name, def.vis); | |
| 1270 | } else if def.def != prev_def.def && prev_def.import == def_import_type { | |
| 1271 | changed = true; | |
| 1272 | defs.macros = None; | |
| 1273 | self.def_map.modules[module_id].scope.update_def_macros(name, def.def, def.vis); | |
| 1274 | } | |
| 1248 | 1275 | } |
| 1249 | 1276 | } |
| 1250 | 1277 |
src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs+11-8| ... | ... | @@ -830,15 +830,18 @@ fn include_bytes_expand( |
| 830 | 830 | span: Span, |
| 831 | 831 | ) -> ExpandResult<tt::TopSubtree> { |
| 832 | 832 | // FIXME: actually read the file here if the user asked for macro expansion |
| 833 | let res = tt::TopSubtree::invisible_from_leaves( | |
| 833 | let underscore = sym::underscore; | |
| 834 | let zero = tt::Literal { | |
| 835 | text_and_suffix: sym::_0_u8, | |
| 834 | 836 | span, |
| 835 | [tt::Leaf::Literal(tt::Literal { | |
| 836 | text_and_suffix: Symbol::empty(), | |
| 837 | span, | |
| 838 | kind: tt::LitKind::ByteStrRaw(1), | |
| 839 | suffix_len: 0, | |
| 840 | })], | |
| 841 | ); | |
| 837 | kind: tt::LitKind::Integer, | |
| 838 | suffix_len: 3, | |
| 839 | }; | |
| 840 | // We don't use a real length since we can't know the file length, so we use an underscore | |
| 841 | // to infer it. | |
| 842 | let res = quote! {span => | |
| 843 | &[#zero; #underscore] | |
| 844 | }; | |
| 842 | 845 | ExpandResult::ok(res) |
| 843 | 846 | } |
| 844 | 847 |
src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs+1-1| ... | ... | @@ -133,7 +133,7 @@ pub fn impl_trait<'db>( |
| 133 | 133 | } |
| 134 | 134 | } |
| 135 | 135 | |
| 136 | #[salsa::tracked(returns(ref), unsafe(non_update_types))] | |
| 136 | #[salsa::tracked(returns(ref))] | |
| 137 | 137 | pub fn predicates<'db>(db: &'db dyn HirDatabase, impl_: BuiltinDeriveImplId) -> GenericPredicates { |
| 138 | 138 | let loc = impl_.loc(db); |
| 139 | 139 | let generic_params = GenericParams::new(db, loc.adt.into()); |
src/tools/rust-analyzer/crates/hir-ty/src/display.rs+95-104| ... | ... | @@ -12,7 +12,6 @@ use either::Either; |
| 12 | 12 | use hir_def::{ |
| 13 | 13 | FindPathConfig, GenericDefId, GenericParamId, HasModule, LocalFieldId, Lookup, ModuleDefId, |
| 14 | 14 | ModuleId, TraitId, |
| 15 | db::DefDatabase, | |
| 16 | 15 | expr_store::{ExpressionStore, path::Path}, |
| 17 | 16 | find_path::{self, PrefixKind}, |
| 18 | 17 | hir::generics::{TypeOrConstParamData, TypeParamProvenance, WherePredicate}, |
| ... | ... | @@ -100,6 +99,9 @@ pub struct HirFormatter<'a, 'db> { |
| 100 | 99 | display_kind: DisplayKind, |
| 101 | 100 | display_target: DisplayTarget, |
| 102 | 101 | bounds_formatting_ctx: BoundsFormattingCtx<'db>, |
| 102 | /// Whether formatting `impl Trait1 + Trait2` or `dyn Trait1 + Trait2` needs parentheses around it, | |
| 103 | /// for example when formatting `&(impl Trait1 + Trait2)`. | |
| 104 | trait_bounds_need_parens: bool, | |
| 103 | 105 | } |
| 104 | 106 | |
| 105 | 107 | // FIXME: To consider, ref and dyn trait lifetimes can be omitted if they are `'_`, path args should |
| ... | ... | @@ -331,6 +333,7 @@ pub trait HirDisplay<'db> { |
| 331 | 333 | show_container_bounds: false, |
| 332 | 334 | display_lifetimes: DisplayLifetime::OnlyNamedOrStatic, |
| 333 | 335 | bounds_formatting_ctx: Default::default(), |
| 336 | trait_bounds_need_parens: false, | |
| 334 | 337 | }) { |
| 335 | 338 | Ok(()) => {} |
| 336 | 339 | Err(HirDisplayError::FmtError) => panic!("Writing to String can't fail!"), |
| ... | ... | @@ -566,6 +569,7 @@ impl<'db, T: HirDisplay<'db>> HirDisplayWrapper<'_, 'db, T> { |
| 566 | 569 | show_container_bounds: self.show_container_bounds, |
| 567 | 570 | display_lifetimes: self.display_lifetimes, |
| 568 | 571 | bounds_formatting_ctx: Default::default(), |
| 572 | trait_bounds_need_parens: false, | |
| 569 | 573 | }) |
| 570 | 574 | } |
| 571 | 575 | |
| ... | ... | @@ -612,7 +616,11 @@ impl<'db, T: HirDisplay<'db> + Internable> HirDisplay<'db> for Interned<T> { |
| 612 | 616 | } |
| 613 | 617 | } |
| 614 | 618 | |
| 615 | fn write_projection<'db>(f: &mut HirFormatter<'_, 'db>, alias: &AliasTy<'db>) -> Result { | |
| 619 | fn write_projection<'db>( | |
| 620 | f: &mut HirFormatter<'_, 'db>, | |
| 621 | alias: &AliasTy<'db>, | |
| 622 | needs_parens_if_multi: bool, | |
| 623 | ) -> Result { | |
| 616 | 624 | if f.should_truncate() { |
| 617 | 625 | return write!(f, "{TYPE_HINT_TRUNCATION}"); |
| 618 | 626 | } |
| ... | ... | @@ -650,6 +658,7 @@ fn write_projection<'db>(f: &mut HirFormatter<'_, 'db>, alias: &AliasTy<'db>) -> |
| 650 | 658 | Either::Left(Ty::new_alias(f.interner, AliasTyKind::Projection, *alias)), |
| 651 | 659 | &bounds, |
| 652 | 660 | SizedByDefault::NotSized, |
| 661 | needs_parens_if_multi, | |
| 653 | 662 | ) |
| 654 | 663 | }); |
| 655 | 664 | } |
| ... | ... | @@ -1056,7 +1065,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> { |
| 1056 | 1065 | return write!(f, "{TYPE_HINT_TRUNCATION}"); |
| 1057 | 1066 | } |
| 1058 | 1067 | |
| 1059 | use TyKind; | |
| 1068 | let trait_bounds_need_parens = mem::replace(&mut f.trait_bounds_need_parens, false); | |
| 1060 | 1069 | match self.kind() { |
| 1061 | 1070 | TyKind::Never => write!(f, "!")?, |
| 1062 | 1071 | TyKind::Str => write!(f, "str")?, |
| ... | ... | @@ -1077,103 +1086,34 @@ impl<'db> HirDisplay<'db> for Ty<'db> { |
| 1077 | 1086 | c.hir_fmt(f)?; |
| 1078 | 1087 | write!(f, "]")?; |
| 1079 | 1088 | } |
| 1080 | kind @ (TyKind::RawPtr(t, m) | TyKind::Ref(_, t, m)) => { | |
| 1081 | if let TyKind::Ref(l, _, _) = kind { | |
| 1082 | f.write_char('&')?; | |
| 1083 | if f.render_region(l) { | |
| 1084 | l.hir_fmt(f)?; | |
| 1085 | f.write_char(' ')?; | |
| 1086 | } | |
| 1087 | match m { | |
| 1088 | rustc_ast_ir::Mutability::Not => (), | |
| 1089 | rustc_ast_ir::Mutability::Mut => f.write_str("mut ")?, | |
| 1090 | } | |
| 1091 | } else { | |
| 1092 | write!( | |
| 1093 | f, | |
| 1094 | "*{}", | |
| 1095 | match m { | |
| 1096 | rustc_ast_ir::Mutability::Not => "const ", | |
| 1097 | rustc_ast_ir::Mutability::Mut => "mut ", | |
| 1098 | } | |
| 1099 | )?; | |
| 1089 | TyKind::Ref(l, t, m) => { | |
| 1090 | f.write_char('&')?; | |
| 1091 | if f.render_region(l) { | |
| 1092 | l.hir_fmt(f)?; | |
| 1093 | f.write_char(' ')?; | |
| 1094 | } | |
| 1095 | match m { | |
| 1096 | rustc_ast_ir::Mutability::Not => (), | |
| 1097 | rustc_ast_ir::Mutability::Mut => f.write_str("mut ")?, | |
| 1100 | 1098 | } |
| 1101 | 1099 | |
| 1102 | // FIXME: all this just to decide whether to use parentheses... | |
| 1103 | let (preds_to_print, has_impl_fn_pred) = match t.kind() { | |
| 1104 | TyKind::Dynamic(bounds, region) => { | |
| 1105 | let contains_impl_fn = | |
| 1106 | bounds.iter().any(|bound| match bound.skip_binder() { | |
| 1107 | ExistentialPredicate::Trait(trait_ref) => { | |
| 1108 | let trait_ = trait_ref.def_id.0; | |
| 1109 | fn_traits(f.lang_items()).any(|it| it == trait_) | |
| 1110 | } | |
| 1111 | _ => false, | |
| 1112 | }); | |
| 1113 | let render_lifetime = f.render_region(region); | |
| 1114 | (bounds.len() + render_lifetime as usize, contains_impl_fn) | |
| 1115 | } | |
| 1116 | TyKind::Alias(AliasTyKind::Opaque, ty) => { | |
| 1117 | let opaque_ty_id = match ty.def_id { | |
| 1118 | SolverDefId::InternedOpaqueTyId(id) => id, | |
| 1119 | _ => unreachable!(), | |
| 1120 | }; | |
| 1121 | let impl_trait_id = db.lookup_intern_impl_trait_id(opaque_ty_id); | |
| 1122 | if let ImplTraitId::ReturnTypeImplTrait(func, _) = impl_trait_id { | |
| 1123 | let data = impl_trait_id.predicates(db); | |
| 1124 | let bounds = | |
| 1125 | || data.iter_instantiated_copied(f.interner, ty.args.as_slice()); | |
| 1126 | let mut len = bounds().count(); | |
| 1127 | ||
| 1128 | // Don't count Sized but count when it absent | |
| 1129 | // (i.e. when explicit ?Sized bound is set). | |
| 1130 | let default_sized = SizedByDefault::Sized { anchor: func.krate(db) }; | |
| 1131 | let sized_bounds = bounds() | |
| 1132 | .filter(|b| { | |
| 1133 | matches!( | |
| 1134 | b.kind().skip_binder(), | |
| 1135 | ClauseKind::Trait(trait_ref) | |
| 1136 | if default_sized.is_sized_trait( | |
| 1137 | trait_ref.def_id().0, | |
| 1138 | db, | |
| 1139 | ), | |
| 1140 | ) | |
| 1141 | }) | |
| 1142 | .count(); | |
| 1143 | match sized_bounds { | |
| 1144 | 0 => len += 1, | |
| 1145 | _ => { | |
| 1146 | len = len.saturating_sub(sized_bounds); | |
| 1147 | } | |
| 1148 | } | |
| 1149 | ||
| 1150 | let contains_impl_fn = bounds().any(|bound| { | |
| 1151 | if let ClauseKind::Trait(trait_ref) = bound.kind().skip_binder() { | |
| 1152 | let trait_ = trait_ref.def_id().0; | |
| 1153 | fn_traits(f.lang_items()).any(|it| it == trait_) | |
| 1154 | } else { | |
| 1155 | false | |
| 1156 | } | |
| 1157 | }); | |
| 1158 | (len, contains_impl_fn) | |
| 1159 | } else { | |
| 1160 | (0, false) | |
| 1161 | } | |
| 1100 | f.trait_bounds_need_parens = true; | |
| 1101 | t.hir_fmt(f)?; | |
| 1102 | f.trait_bounds_need_parens = false; | |
| 1103 | } | |
| 1104 | TyKind::RawPtr(t, m) => { | |
| 1105 | write!( | |
| 1106 | f, | |
| 1107 | "*{}", | |
| 1108 | match m { | |
| 1109 | rustc_ast_ir::Mutability::Not => "const ", | |
| 1110 | rustc_ast_ir::Mutability::Mut => "mut ", | |
| 1162 | 1111 | } |
| 1163 | _ => (0, false), | |
| 1164 | }; | |
| 1165 | ||
| 1166 | if has_impl_fn_pred && preds_to_print <= 2 { | |
| 1167 | return t.hir_fmt(f); | |
| 1168 | } | |
| 1112 | )?; | |
| 1169 | 1113 | |
| 1170 | if preds_to_print > 1 { | |
| 1171 | write!(f, "(")?; | |
| 1172 | t.hir_fmt(f)?; | |
| 1173 | write!(f, ")")?; | |
| 1174 | } else { | |
| 1175 | t.hir_fmt(f)?; | |
| 1176 | } | |
| 1114 | f.trait_bounds_need_parens = true; | |
| 1115 | t.hir_fmt(f)?; | |
| 1116 | f.trait_bounds_need_parens = false; | |
| 1177 | 1117 | } |
| 1178 | 1118 | TyKind::Tuple(tys) => { |
| 1179 | 1119 | if tys.len() == 1 { |
| ... | ... | @@ -1328,7 +1268,9 @@ impl<'db> HirDisplay<'db> for Ty<'db> { |
| 1328 | 1268 | |
| 1329 | 1269 | hir_fmt_generics(f, parameters.as_slice(), Some(def.def_id().0.into()), None)?; |
| 1330 | 1270 | } |
| 1331 | TyKind::Alias(AliasTyKind::Projection, alias_ty) => write_projection(f, &alias_ty)?, | |
| 1271 | TyKind::Alias(AliasTyKind::Projection, alias_ty) => { | |
| 1272 | write_projection(f, &alias_ty, trait_bounds_need_parens)? | |
| 1273 | } | |
| 1332 | 1274 | TyKind::Foreign(alias) => { |
| 1333 | 1275 | let type_alias = db.type_alias_signature(alias.0); |
| 1334 | 1276 | f.start_location_link(alias.0.into()); |
| ... | ... | @@ -1363,6 +1305,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> { |
| 1363 | 1305 | Either::Left(*self), |
| 1364 | 1306 | &bounds, |
| 1365 | 1307 | SizedByDefault::Sized { anchor: krate }, |
| 1308 | trait_bounds_need_parens, | |
| 1366 | 1309 | )?; |
| 1367 | 1310 | } |
| 1368 | 1311 | TyKind::Closure(id, substs) => { |
| ... | ... | @@ -1525,6 +1468,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> { |
| 1525 | 1468 | Either::Left(*self), |
| 1526 | 1469 | &bounds, |
| 1527 | 1470 | SizedByDefault::Sized { anchor: krate }, |
| 1471 | trait_bounds_need_parens, | |
| 1528 | 1472 | )?; |
| 1529 | 1473 | } |
| 1530 | 1474 | }, |
| ... | ... | @@ -1567,6 +1511,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> { |
| 1567 | 1511 | Either::Left(*self), |
| 1568 | 1512 | &bounds_to_display, |
| 1569 | 1513 | SizedByDefault::NotSized, |
| 1514 | trait_bounds_need_parens, | |
| 1570 | 1515 | )?; |
| 1571 | 1516 | } |
| 1572 | 1517 | TyKind::Error(_) => { |
| ... | ... | @@ -1806,11 +1751,11 @@ pub enum SizedByDefault { |
| 1806 | 1751 | } |
| 1807 | 1752 | |
| 1808 | 1753 | impl SizedByDefault { |
| 1809 | fn is_sized_trait(self, trait_: TraitId, db: &dyn DefDatabase) -> bool { | |
| 1754 | fn is_sized_trait(self, trait_: TraitId, interner: DbInterner<'_>) -> bool { | |
| 1810 | 1755 | match self { |
| 1811 | 1756 | Self::NotSized => false, |
| 1812 | Self::Sized { anchor } => { | |
| 1813 | let sized_trait = hir_def::lang_item::lang_items(db, anchor).Sized; | |
| 1757 | Self::Sized { .. } => { | |
| 1758 | let sized_trait = interner.lang_items().Sized; | |
| 1814 | 1759 | Some(trait_) == sized_trait |
| 1815 | 1760 | } |
| 1816 | 1761 | } |
| ... | ... | @@ -1823,16 +1768,62 @@ pub fn write_bounds_like_dyn_trait_with_prefix<'db>( |
| 1823 | 1768 | this: Either<Ty<'db>, Region<'db>>, |
| 1824 | 1769 | predicates: &[Clause<'db>], |
| 1825 | 1770 | default_sized: SizedByDefault, |
| 1771 | needs_parens_if_multi: bool, | |
| 1826 | 1772 | ) -> Result { |
| 1773 | let needs_parens = | |
| 1774 | needs_parens_if_multi && trait_bounds_need_parens(f, this, predicates, default_sized); | |
| 1775 | if needs_parens { | |
| 1776 | write!(f, "(")?; | |
| 1777 | } | |
| 1827 | 1778 | write!(f, "{prefix}")?; |
| 1828 | 1779 | if !predicates.is_empty() |
| 1829 | 1780 | || predicates.is_empty() && matches!(default_sized, SizedByDefault::Sized { .. }) |
| 1830 | 1781 | { |
| 1831 | 1782 | write!(f, " ")?; |
| 1832 | write_bounds_like_dyn_trait(f, this, predicates, default_sized) | |
| 1833 | } else { | |
| 1834 | Ok(()) | |
| 1783 | write_bounds_like_dyn_trait(f, this, predicates, default_sized)?; | |
| 1784 | } | |
| 1785 | if needs_parens { | |
| 1786 | write!(f, ")")?; | |
| 1787 | } | |
| 1788 | Ok(()) | |
| 1789 | } | |
| 1790 | ||
| 1791 | fn trait_bounds_need_parens<'db>( | |
| 1792 | f: &mut HirFormatter<'_, 'db>, | |
| 1793 | this: Either<Ty<'db>, Region<'db>>, | |
| 1794 | predicates: &[Clause<'db>], | |
| 1795 | default_sized: SizedByDefault, | |
| 1796 | ) -> bool { | |
| 1797 | // This needs to be kept in sync with `write_bounds_like_dyn_trait()`. | |
| 1798 | let mut distinct_bounds = 0usize; | |
| 1799 | let mut is_sized = false; | |
| 1800 | for p in predicates { | |
| 1801 | match p.kind().skip_binder() { | |
| 1802 | ClauseKind::Trait(trait_ref) => { | |
| 1803 | let trait_ = trait_ref.def_id().0; | |
| 1804 | if default_sized.is_sized_trait(trait_, f.interner) { | |
| 1805 | is_sized = true; | |
| 1806 | if matches!(default_sized, SizedByDefault::Sized { .. }) { | |
| 1807 | // Don't print +Sized, but rather +?Sized if absent. | |
| 1808 | continue; | |
| 1809 | } | |
| 1810 | } | |
| 1811 | ||
| 1812 | distinct_bounds += 1; | |
| 1813 | } | |
| 1814 | ClauseKind::TypeOutlives(to) if Either::Left(to.0) == this => distinct_bounds += 1, | |
| 1815 | ClauseKind::RegionOutlives(lo) if Either::Right(lo.0) == this => distinct_bounds += 1, | |
| 1816 | _ => {} | |
| 1817 | } | |
| 1835 | 1818 | } |
| 1819 | ||
| 1820 | if let SizedByDefault::Sized { .. } = default_sized | |
| 1821 | && !is_sized | |
| 1822 | { | |
| 1823 | distinct_bounds += 1; | |
| 1824 | } | |
| 1825 | ||
| 1826 | distinct_bounds > 1 | |
| 1836 | 1827 | } |
| 1837 | 1828 | |
| 1838 | 1829 | fn write_bounds_like_dyn_trait<'db>( |
| ... | ... | @@ -1855,7 +1846,7 @@ fn write_bounds_like_dyn_trait<'db>( |
| 1855 | 1846 | match p.kind().skip_binder() { |
| 1856 | 1847 | ClauseKind::Trait(trait_ref) => { |
| 1857 | 1848 | let trait_ = trait_ref.def_id().0; |
| 1858 | if default_sized.is_sized_trait(trait_, f.db) { | |
| 1849 | if default_sized.is_sized_trait(trait_, f.interner) { | |
| 1859 | 1850 | is_sized = true; |
| 1860 | 1851 | if matches!(default_sized, SizedByDefault::Sized { .. }) { |
| 1861 | 1852 | // Don't print +Sized, but rather +?Sized if absent. |
src/tools/rust-analyzer/crates/hir-ty/src/lower.rs+117-6| ... | ... | @@ -831,6 +831,8 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { |
| 831 | 831 | let mut ordered_associated_types = vec![]; |
| 832 | 832 | |
| 833 | 833 | if let Some(principal_trait) = principal { |
| 834 | // Generally we should not elaborate in lowering as this can lead to cycles, but | |
| 835 | // here rustc cycles as well. | |
| 834 | 836 | for clause in elaborate::elaborate( |
| 835 | 837 | interner, |
| 836 | 838 | [Clause::upcast_from( |
| ... | ... | @@ -1897,7 +1899,7 @@ impl<'db> GenericPredicates { |
| 1897 | 1899 | /// Resolve the where clause(s) of an item with generics. |
| 1898 | 1900 | /// |
| 1899 | 1901 | /// Diagnostics are computed only for this item's predicates, not for parents. |
| 1900 | #[salsa::tracked(returns(ref))] | |
| 1902 | #[salsa::tracked(returns(ref), cycle_result=generic_predicates_cycle_result)] | |
| 1901 | 1903 | pub fn query_with_diagnostics( |
| 1902 | 1904 | db: &'db dyn HirDatabase, |
| 1903 | 1905 | def: GenericDefId, |
| ... | ... | @@ -1906,6 +1908,20 @@ impl<'db> GenericPredicates { |
| 1906 | 1908 | } |
| 1907 | 1909 | } |
| 1908 | 1910 | |
| 1911 | /// A cycle can occur from malformed code. | |
| 1912 | fn generic_predicates_cycle_result( | |
| 1913 | _db: &dyn HirDatabase, | |
| 1914 | _: salsa::Id, | |
| 1915 | _def: GenericDefId, | |
| 1916 | ) -> (GenericPredicates, Diagnostics) { | |
| 1917 | ( | |
| 1918 | GenericPredicates::from_explicit_own_predicates(StoredEarlyBinder::bind( | |
| 1919 | Clauses::default().store(), | |
| 1920 | )), | |
| 1921 | None, | |
| 1922 | ) | |
| 1923 | } | |
| 1924 | ||
| 1909 | 1925 | impl GenericPredicates { |
| 1910 | 1926 | #[inline] |
| 1911 | 1927 | pub(crate) fn from_explicit_own_predicates( |
| ... | ... | @@ -2590,11 +2606,13 @@ pub(crate) fn associated_type_by_name_including_super_traits<'db>( |
| 2590 | 2606 | ) -> Option<(TraitRef<'db>, TypeAliasId)> { |
| 2591 | 2607 | let module = trait_ref.def_id.0.module(db); |
| 2592 | 2608 | let interner = DbInterner::new_with(db, module.krate(db)); |
| 2593 | rustc_type_ir::elaborate::supertraits(interner, Binder::dummy(trait_ref)).find_map(|t| { | |
| 2594 | let trait_id = t.as_ref().skip_binder().def_id.0; | |
| 2595 | let assoc_type = trait_id.trait_items(db).associated_type_by_name(name)?; | |
| 2596 | Some((t.skip_binder(), assoc_type)) | |
| 2597 | }) | |
| 2609 | all_supertraits_trait_refs(db, trait_ref.def_id.0) | |
| 2610 | .map(|t| t.instantiate(interner, trait_ref.args)) | |
| 2611 | .find_map(|t| { | |
| 2612 | let trait_id = t.def_id.0; | |
| 2613 | let assoc_type = trait_id.trait_items(db).associated_type_by_name(name)?; | |
| 2614 | Some((t, assoc_type)) | |
| 2615 | }) | |
| 2598 | 2616 | } |
| 2599 | 2617 | |
| 2600 | 2618 | pub fn associated_type_shorthand_candidates( |
| ... | ... | @@ -2723,3 +2741,96 @@ fn named_associated_type_shorthand_candidates<'db, R>( |
| 2723 | 2741 | _ => None, |
| 2724 | 2742 | } |
| 2725 | 2743 | } |
| 2744 | ||
| 2745 | /// During lowering, elaborating supertraits can cause cycles. To avoid that, we have a separate query | |
| 2746 | /// to only collect supertraits. | |
| 2747 | /// | |
| 2748 | /// Technically, it is possible to avoid even more cycles by only collecting the `TraitId` of supertraits | |
| 2749 | /// without their args. However rustc doesn't do that, so we don't either. | |
| 2750 | pub(crate) fn all_supertraits_trait_refs( | |
| 2751 | db: &dyn HirDatabase, | |
| 2752 | trait_: TraitId, | |
| 2753 | ) -> impl ExactSizeIterator<Item = EarlyBinder<'_, TraitRef<'_>>> { | |
| 2754 | let interner = DbInterner::new_no_crate(db); | |
| 2755 | return all_supertraits_trait_refs_query(db, trait_).iter().map(move |trait_ref| { | |
| 2756 | trait_ref.get_with(|(trait_, args)| { | |
| 2757 | TraitRef::new_from_args(interner, (*trait_).into(), args.as_ref()) | |
| 2758 | }) | |
| 2759 | }); | |
| 2760 | ||
| 2761 | #[salsa_macros::tracked(returns(deref), cycle_result = all_supertraits_trait_refs_cycle_result)] | |
| 2762 | pub(crate) fn all_supertraits_trait_refs_query( | |
| 2763 | db: &dyn HirDatabase, | |
| 2764 | trait_: TraitId, | |
| 2765 | ) -> Box<[StoredEarlyBinder<(TraitId, StoredGenericArgs)>]> { | |
| 2766 | let resolver = trait_.resolver(db); | |
| 2767 | let signature = db.trait_signature(trait_); | |
| 2768 | let mut ctx = TyLoweringContext::new( | |
| 2769 | db, | |
| 2770 | &resolver, | |
| 2771 | &signature.store, | |
| 2772 | trait_.into(), | |
| 2773 | LifetimeElisionKind::AnonymousReportError, | |
| 2774 | ); | |
| 2775 | let interner = ctx.interner; | |
| 2776 | ||
| 2777 | let self_param_ty = Ty::new_param( | |
| 2778 | interner, | |
| 2779 | TypeParamId::from_unchecked(TypeOrConstParamId { | |
| 2780 | parent: trait_.into(), | |
| 2781 | local_id: Idx::from_raw(la_arena::RawIdx::from_u32(0)), | |
| 2782 | }), | |
| 2783 | 0, | |
| 2784 | ); | |
| 2785 | ||
| 2786 | let mut supertraits = FxHashSet::default(); | |
| 2787 | supertraits.insert(StoredEarlyBinder::bind(( | |
| 2788 | trait_, | |
| 2789 | GenericArgs::identity_for_item(interner, trait_.into()).store(), | |
| 2790 | ))); | |
| 2791 | ||
| 2792 | for pred in signature.generic_params.where_predicates() { | |
| 2793 | let WherePredicate::TypeBound { target, bound } = pred else { | |
| 2794 | continue; | |
| 2795 | }; | |
| 2796 | let target = &signature.store[*target]; | |
| 2797 | if let TypeRef::TypeParam(param_id) = target | |
| 2798 | && param_id.local_id().into_raw().into_u32() == 0 | |
| 2799 | { | |
| 2800 | // This is `Self`. | |
| 2801 | } else if let TypeRef::Path(path) = target | |
| 2802 | && path.is_self_type() | |
| 2803 | { | |
| 2804 | // Also `Self`. | |
| 2805 | } else { | |
| 2806 | // Not `Self`! | |
| 2807 | continue; | |
| 2808 | } | |
| 2809 | ||
| 2810 | ctx.lower_type_bound(bound, self_param_ty, true).for_each(|(clause, _)| { | |
| 2811 | if let ClauseKind::Trait(trait_ref) = clause.kind().skip_binder() { | |
| 2812 | supertraits.extend( | |
| 2813 | all_supertraits_trait_refs(db, trait_ref.trait_ref.def_id.0).map(|t| { | |
| 2814 | let trait_ref = t.instantiate(interner, trait_ref.trait_ref.args); | |
| 2815 | StoredEarlyBinder::bind((trait_ref.def_id.0, trait_ref.args.store())) | |
| 2816 | }), | |
| 2817 | ); | |
| 2818 | } | |
| 2819 | }); | |
| 2820 | } | |
| 2821 | ||
| 2822 | Box::from_iter(supertraits) | |
| 2823 | } | |
| 2824 | ||
| 2825 | pub(crate) fn all_supertraits_trait_refs_cycle_result( | |
| 2826 | db: &dyn HirDatabase, | |
| 2827 | _: salsa::Id, | |
| 2828 | trait_: TraitId, | |
| 2829 | ) -> Box<[StoredEarlyBinder<(TraitId, StoredGenericArgs)>]> { | |
| 2830 | let interner = DbInterner::new_no_crate(db); | |
| 2831 | Box::new([StoredEarlyBinder::bind(( | |
| 2832 | trait_, | |
| 2833 | GenericArgs::identity_for_item(interner, trait_.into()).store(), | |
| 2834 | ))]) | |
| 2835 | } | |
| 2836 | } |
src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs+1-1| ... | ... | @@ -608,7 +608,7 @@ trait Foo {} |
| 608 | 608 | fn test(f: impl Foo, g: &(impl Foo + ?Sized)) { |
| 609 | 609 | let _: &dyn Foo = &f; |
| 610 | 610 | let _: &dyn Foo = g; |
| 611 | //^ expected &'? (dyn Foo + 'static), got &'? impl Foo + ?Sized | |
| 611 | //^ expected &'? (dyn Foo + 'static), got &'? (impl Foo + ?Sized) | |
| 612 | 612 | } |
| 613 | 613 | "#, |
| 614 | 614 | ); |
src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs+2-2| ... | ... | @@ -111,7 +111,7 @@ fn test( |
| 111 | 111 | b; |
| 112 | 112 | //^ impl Foo |
| 113 | 113 | c; |
| 114 | //^ &impl Foo + ?Sized | |
| 114 | //^ &(impl Foo + ?Sized) | |
| 115 | 115 | d; |
| 116 | 116 | //^ S<impl Foo> |
| 117 | 117 | ref_any; |
| ... | ... | @@ -192,7 +192,7 @@ fn test( |
| 192 | 192 | b; |
| 193 | 193 | //^ fn(impl Foo) -> impl Foo |
| 194 | 194 | c; |
| 195 | } //^ fn(&impl Foo + ?Sized) -> &impl Foo + ?Sized | |
| 195 | } //^ fn(&(impl Foo + ?Sized)) -> &(impl Foo + ?Sized) | |
| 196 | 196 | "#, |
| 197 | 197 | ); |
| 198 | 198 | } |
src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs+43| ... | ... | @@ -2363,6 +2363,7 @@ fn test() { |
| 2363 | 2363 | } |
| 2364 | 2364 | "#, |
| 2365 | 2365 | expect![[r#" |
| 2366 | 46..49 'Foo': Foo<N> | |
| 2366 | 2367 | 93..97 'self': Foo<N> |
| 2367 | 2368 | 108..125 '{ ... }': usize |
| 2368 | 2369 | 118..119 'N': usize |
| ... | ... | @@ -2645,3 +2646,45 @@ where |
| 2645 | 2646 | "#, |
| 2646 | 2647 | ); |
| 2647 | 2648 | } |
| 2649 | ||
| 2650 | #[test] | |
| 2651 | fn issue_21560() { | |
| 2652 | check_no_mismatches( | |
| 2653 | r#" | |
| 2654 | mod bindings { | |
| 2655 | use super::*; | |
| 2656 | pub type HRESULT = i32; | |
| 2657 | } | |
| 2658 | use bindings::*; | |
| 2659 | ||
| 2660 | ||
| 2661 | mod error { | |
| 2662 | use super::*; | |
| 2663 | pub fn nonzero_hresult(hr: HRESULT) -> crate::HRESULT { | |
| 2664 | hr | |
| 2665 | } | |
| 2666 | } | |
| 2667 | pub use error::*; | |
| 2668 | ||
| 2669 | mod hresult { | |
| 2670 | use super::*; | |
| 2671 | pub struct HRESULT(pub i32); | |
| 2672 | } | |
| 2673 | pub use hresult::HRESULT; | |
| 2674 | ||
| 2675 | "#, | |
| 2676 | ); | |
| 2677 | } | |
| 2678 | ||
| 2679 | #[test] | |
| 2680 | fn regression_21577() { | |
| 2681 | check_no_mismatches( | |
| 2682 | r#" | |
| 2683 | pub trait FilterT<F: FilterT<F, V = Self::V> = Self> { | |
| 2684 | type V; | |
| 2685 | ||
| 2686 | fn foo() {} | |
| 2687 | } | |
| 2688 | "#, | |
| 2689 | ); | |
| 2690 | } |
src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs+19-1| ... | ... | @@ -2152,10 +2152,11 @@ async fn main() { |
| 2152 | 2152 | let z: core::ops::ControlFlow<(), _> = try { () }; |
| 2153 | 2153 | let w = const { 92 }; |
| 2154 | 2154 | let t = 'a: { 92 }; |
| 2155 | let u = try bikeshed core::ops::ControlFlow<(), _> { () }; | |
| 2155 | 2156 | } |
| 2156 | 2157 | "#, |
| 2157 | 2158 | expect![[r#" |
| 2158 | 16..193 '{ ...2 }; }': () | |
| 2159 | 16..256 '{ ...) }; }': () | |
| 2159 | 2160 | 26..27 'x': i32 |
| 2160 | 2161 | 30..43 'unsafe { 92 }': i32 |
| 2161 | 2162 | 39..41 '92': i32 |
| ... | ... | @@ -2176,6 +2177,13 @@ async fn main() { |
| 2176 | 2177 | 176..177 't': i32 |
| 2177 | 2178 | 180..190 ''a: { 92 }': i32 |
| 2178 | 2179 | 186..188 '92': i32 |
| 2180 | 200..201 'u': ControlFlow<(), ()> | |
| 2181 | 204..253 'try bi...{ () }': ControlFlow<(), ()> | |
| 2182 | 204..253 'try bi...{ () }': fn from_output<ControlFlow<(), ()>>(<ControlFlow<(), ()> as Try>::Output) -> ControlFlow<(), ()> | |
| 2183 | 204..253 'try bi...{ () }': ControlFlow<(), ()> | |
| 2184 | 204..253 'try bi...{ () }': ControlFlow<(), ()> | |
| 2185 | 204..253 'try bi...{ () }': ControlFlow<(), ()> | |
| 2186 | 249..251 '()': () | |
| 2179 | 2187 | "#]], |
| 2180 | 2188 | ) |
| 2181 | 2189 | } |
| ... | ... | @@ -4056,3 +4064,13 @@ fn foo() { |
| 4056 | 4064 | "#]], |
| 4057 | 4065 | ); |
| 4058 | 4066 | } |
| 4067 | ||
| 4068 | #[test] | |
| 4069 | fn include_bytes_len_mismatch() { | |
| 4070 | check_no_mismatches( | |
| 4071 | r#" | |
| 4072 | //- minicore: include_bytes | |
| 4073 | static S: &[u8; 158] = include_bytes!("/foo/bar/baz.txt"); | |
| 4074 | "#, | |
| 4075 | ); | |
| 4076 | } |
src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs+6-4| ... | ... | @@ -219,14 +219,16 @@ fn test() { |
| 219 | 219 | |
| 220 | 220 | #[test] |
| 221 | 221 | fn infer_try_block() { |
| 222 | // FIXME: We should test more cases, but it currently doesn't work, since | |
| 223 | // our labeled block type inference is broken. | |
| 224 | 222 | check_types( |
| 225 | 223 | r#" |
| 226 | //- minicore: try, option | |
| 224 | //- minicore: try, option, result, from | |
| 227 | 225 | fn test() { |
| 228 | 226 | let x: Option<_> = try { Some(2)?; }; |
| 229 | 227 | //^ Option<()> |
| 228 | let homogeneous = try { Ok::<(), u32>(())?; "hi" }; | |
| 229 | //^^^^^^^^^^^ Result<&'? str, u32> | |
| 230 | let heterogeneous = try bikeshed Result<_, u64> { 1 }; | |
| 231 | //^^^^^^^^^^^^^ Result<i32, u64> | |
| 230 | 232 | } |
| 231 | 233 | "#, |
| 232 | 234 | ); |
| ... | ... | @@ -4819,7 +4821,7 @@ fn allowed3(baz: impl Baz<Assoc = Qux<impl Foo>>) {} |
| 4819 | 4821 | 431..433 '{}': () |
| 4820 | 4822 | 447..450 'baz': impl Baz<Assoc = impl Foo> |
| 4821 | 4823 | 480..482 '{}': () |
| 4822 | 500..503 'baz': impl Baz<Assoc = &'a impl Foo + 'a> | |
| 4824 | 500..503 'baz': impl Baz<Assoc = &'a (impl Foo + 'a)> | |
| 4823 | 4825 | 544..546 '{}': () |
| 4824 | 4826 | 560..563 'baz': impl Baz<Assoc = Qux<impl Foo>> |
| 4825 | 4827 | 598..600 '{}': () |
src/tools/rust-analyzer/crates/hir-ty/src/utils.rs+8-17| ... | ... | @@ -22,6 +22,7 @@ use crate::{ |
| 22 | 22 | TargetFeatures, |
| 23 | 23 | db::HirDatabase, |
| 24 | 24 | layout::{Layout, TagEncoding}, |
| 25 | lower::all_supertraits_trait_refs, | |
| 25 | 26 | mir::pad16, |
| 26 | 27 | }; |
| 27 | 28 | |
| ... | ... | @@ -62,23 +63,13 @@ pub fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[T |
| 62 | 63 | |
| 63 | 64 | /// Returns an iterator over the whole super trait hierarchy (including the |
| 64 | 65 | /// trait itself). |
| 65 | pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> { | |
| 66 | // we need to take care a bit here to avoid infinite loops in case of cycles | |
| 67 | // (i.e. if we have `trait A: B; trait B: A;`) | |
| 68 | ||
| 69 | let mut result = smallvec![trait_]; | |
| 70 | let mut i = 0; | |
| 71 | while let Some(&t) = result.get(i) { | |
| 72 | // yeah this is quadratic, but trait hierarchies should be flat | |
| 73 | // enough that this doesn't matter | |
| 74 | direct_super_traits_cb(db, t, |tt| { | |
| 75 | if !result.contains(&tt) { | |
| 76 | result.push(tt); | |
| 77 | } | |
| 78 | }); | |
| 79 | i += 1; | |
| 80 | } | |
| 81 | result | |
| 66 | pub fn all_super_traits(db: &dyn HirDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> { | |
| 67 | let mut supertraits = all_supertraits_trait_refs(db, trait_) | |
| 68 | .map(|trait_ref| trait_ref.skip_binder().def_id.0) | |
| 69 | .collect::<SmallVec<[_; _]>>(); | |
| 70 | supertraits.sort_unstable(); | |
| 71 | supertraits.dedup(); | |
| 72 | supertraits | |
| 82 | 73 | } |
| 83 | 74 | |
| 84 | 75 | fn direct_super_traits_cb(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) { |
src/tools/rust-analyzer/crates/hir/src/display.rs+2| ... | ... | @@ -587,6 +587,7 @@ impl<'db> HirDisplay<'db> for TypeParam { |
| 587 | 587 | Either::Left(ty), |
| 588 | 588 | &predicates, |
| 589 | 589 | SizedByDefault::Sized { anchor: krate }, |
| 590 | false, | |
| 590 | 591 | ); |
| 591 | 592 | } |
| 592 | 593 | }, |
| ... | ... | @@ -614,6 +615,7 @@ impl<'db> HirDisplay<'db> for TypeParam { |
| 614 | 615 | Either::Left(ty), |
| 615 | 616 | &predicates, |
| 616 | 617 | default_sized, |
| 618 | false, | |
| 617 | 619 | )?; |
| 618 | 620 | } |
| 619 | 621 | Ok(()) |
src/tools/rust-analyzer/crates/hir/src/lib.rs+4| ... | ... | @@ -4233,6 +4233,10 @@ impl Local { |
| 4233 | 4233 | self.parent(db).module(db) |
| 4234 | 4234 | } |
| 4235 | 4235 | |
| 4236 | pub fn as_id(self) -> u32 { | |
| 4237 | self.binding_id.into_raw().into_u32() | |
| 4238 | } | |
| 4239 | ||
| 4236 | 4240 | pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { |
| 4237 | 4241 | let def = self.parent; |
| 4238 | 4242 | let infer = InferenceResult::for_body(db, def); |
src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs+15-4| ... | ... | @@ -18,7 +18,6 @@ use hir_ty::{ |
| 18 | 18 | use itertools::Itertools; |
| 19 | 19 | use rustc_hash::FxHashSet; |
| 20 | 20 | use rustc_type_ir::inherent::Ty as _; |
| 21 | use span::Edition; | |
| 22 | 21 | |
| 23 | 22 | use crate::{ |
| 24 | 23 | Adt, AssocItem, GenericDef, GenericParam, HasAttrs, HasVisibility, Impl, ModuleDef, ScopeDef, |
| ... | ... | @@ -367,7 +366,11 @@ pub(super) fn free_function<'a, 'lt, 'db, DB: HirDatabase>( |
| 367 | 366 | let ret_ty = it.ret_type_with_args(db, generics.iter().cloned()); |
| 368 | 367 | // Filter out private and unsafe functions |
| 369 | 368 | if !it.is_visible_from(db, module) |
| 370 | || it.is_unsafe_to_call(db, None, Edition::CURRENT_FIXME) | |
| 369 | || it.is_unsafe_to_call( | |
| 370 | db, | |
| 371 | None, | |
| 372 | crate::Crate::from(ctx.scope.resolver().krate()).edition(db), | |
| 373 | ) | |
| 371 | 374 | || it.is_unstable(db) |
| 372 | 375 | || ctx.config.enable_borrowcheck && ret_ty.contains_reference(db) |
| 373 | 376 | || ret_ty.is_raw_ptr() |
| ... | ... | @@ -473,7 +476,11 @@ pub(super) fn impl_method<'a, 'lt, 'db, DB: HirDatabase>( |
| 473 | 476 | |
| 474 | 477 | // Filter out private and unsafe functions |
| 475 | 478 | if !it.is_visible_from(db, module) |
| 476 | || it.is_unsafe_to_call(db, None, Edition::CURRENT_FIXME) | |
| 479 | || it.is_unsafe_to_call( | |
| 480 | db, | |
| 481 | None, | |
| 482 | crate::Crate::from(ctx.scope.resolver().krate()).edition(db), | |
| 483 | ) | |
| 477 | 484 | || it.is_unstable(db) |
| 478 | 485 | { |
| 479 | 486 | return None; |
| ... | ... | @@ -667,7 +674,11 @@ pub(super) fn impl_static_method<'a, 'lt, 'db, DB: HirDatabase>( |
| 667 | 674 | |
| 668 | 675 | // Filter out private and unsafe functions |
| 669 | 676 | if !it.is_visible_from(db, module) |
| 670 | || it.is_unsafe_to_call(db, None, Edition::CURRENT_FIXME) | |
| 677 | || it.is_unsafe_to_call( | |
| 678 | db, | |
| 679 | None, | |
| 680 | crate::Crate::from(ctx.scope.resolver().krate()).edition(db), | |
| 681 | ) | |
| 671 | 682 | || it.is_unstable(db) |
| 672 | 683 | { |
| 673 | 684 | return None; |
src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs+1| ... | ... | @@ -155,6 +155,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< |
| 155 | 155 | &scope, |
| 156 | 156 | mod_path_to_ast(&import_path, edition), |
| 157 | 157 | &ctx.config.insert_use, |
| 158 | edition, | |
| 158 | 159 | ); |
| 159 | 160 | }, |
| 160 | 161 | ); |
src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs+1-1| ... | ... | @@ -132,7 +132,7 @@ pub(crate) fn convert_closure_to_fn(acc: &mut Assists, ctx: &AssistContext<'_>) |
| 132 | 132 | ); |
| 133 | 133 | } |
| 134 | 134 | |
| 135 | if block.try_token().is_none() | |
| 135 | if block.try_block_modifier().is_none() | |
| 136 | 136 | && block.unsafe_token().is_none() |
| 137 | 137 | && block.label().is_none() |
| 138 | 138 | && block.const_token().is_none() |
src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs+1-1| ... | ... | @@ -859,7 +859,7 @@ impl FunctionBody { |
| 859 | 859 | ast::BlockExpr(block_expr) => { |
| 860 | 860 | let (constness, block) = match block_expr.modifier() { |
| 861 | 861 | Some(ast::BlockModifier::Const(_)) => (true, block_expr), |
| 862 | Some(ast::BlockModifier::Try(_)) => (false, block_expr), | |
| 862 | Some(ast::BlockModifier::Try { .. }) => (false, block_expr), | |
| 863 | 863 | Some(ast::BlockModifier::Label(label)) if label.lifetime().is_some() => (false, block_expr), |
| 864 | 864 | _ => continue, |
| 865 | 865 | }; |
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs+23-8| ... | ... | @@ -1147,14 +1147,7 @@ fn fn_arg_type( |
| 1147 | 1147 | if ty.is_reference() || ty.is_mutable_reference() { |
| 1148 | 1148 | let famous_defs = &FamousDefs(&ctx.sema, ctx.sema.scope(fn_arg.syntax())?.krate()); |
| 1149 | 1149 | convert_reference_type(ty.strip_references(), ctx.db(), famous_defs) |
| 1150 | .map(|conversion| { | |
| 1151 | conversion | |
| 1152 | .convert_type( | |
| 1153 | ctx.db(), | |
| 1154 | target_module.krate(ctx.db()).to_display_target(ctx.db()), | |
| 1155 | ) | |
| 1156 | .to_string() | |
| 1157 | }) | |
| 1150 | .map(|conversion| conversion.convert_type(ctx.db(), target_module).to_string()) | |
| 1158 | 1151 | .or_else(|| ty.display_source_code(ctx.db(), target_module.into(), true).ok()) |
| 1159 | 1152 | } else { |
| 1160 | 1153 | ty.display_source_code(ctx.db(), target_module.into(), true).ok() |
| ... | ... | @@ -3187,6 +3180,28 @@ fn main() { |
| 3187 | 3180 | r#" |
| 3188 | 3181 | fn main() { |
| 3189 | 3182 | s.self$0(); |
| 3183 | } | |
| 3184 | "#, | |
| 3185 | ); | |
| 3186 | } | |
| 3187 | ||
| 3188 | #[test] | |
| 3189 | fn regression_21288() { | |
| 3190 | check_assist( | |
| 3191 | generate_function, | |
| 3192 | r#" | |
| 3193 | //- minicore: copy | |
| 3194 | fn foo() { | |
| 3195 | $0bar(&|x| true) | |
| 3196 | } | |
| 3197 | "#, | |
| 3198 | r#" | |
| 3199 | fn foo() { | |
| 3200 | bar(&|x| true) | |
| 3201 | } | |
| 3202 | ||
| 3203 | fn bar(arg: impl Fn(_) -> bool) { | |
| 3204 | ${0:todo!()} | |
| 3190 | 3205 | } |
| 3191 | 3206 | "#, |
| 3192 | 3207 | ); |
src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs+3-3| ... | ... | @@ -226,15 +226,15 @@ fn generate_getter_from_info( |
| 226 | 226 | ) |
| 227 | 227 | } else { |
| 228 | 228 | (|| { |
| 229 | let krate = ctx.sema.scope(record_field_info.field_ty.syntax())?.krate(); | |
| 230 | let famous_defs = &FamousDefs(&ctx.sema, krate); | |
| 229 | let module = ctx.sema.scope(record_field_info.field_ty.syntax())?.module(); | |
| 230 | let famous_defs = &FamousDefs(&ctx.sema, module.krate(ctx.db())); | |
| 231 | 231 | ctx.sema |
| 232 | 232 | .resolve_type(&record_field_info.field_ty) |
| 233 | 233 | .and_then(|ty| convert_reference_type(ty, ctx.db(), famous_defs)) |
| 234 | 234 | .map(|conversion| { |
| 235 | 235 | cov_mark::hit!(convert_reference_type); |
| 236 | 236 | ( |
| 237 | conversion.convert_type(ctx.db(), krate.to_display_target(ctx.db())), | |
| 237 | conversion.convert_type(ctx.db(), module), | |
| 238 | 238 | conversion.getter(record_field_info.field_name.to_string()), |
| 239 | 239 | ) |
| 240 | 240 | }) |
src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs+154-9| ... | ... | @@ -1,6 +1,7 @@ |
| 1 | use itertools::Itertools; | |
| 1 | use itertools::{Itertools, chain}; | |
| 2 | 2 | use syntax::{ |
| 3 | 3 | SyntaxKind::WHITESPACE, |
| 4 | TextRange, | |
| 4 | 5 | ast::{ |
| 5 | 6 | AstNode, BlockExpr, ElseBranch, Expr, IfExpr, MatchArm, Pat, edit::AstNodeEdit, make, |
| 6 | 7 | prec::ExprPrecedence, syntax_factory::SyntaxFactory, |
| ... | ... | @@ -44,13 +45,26 @@ pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext<'_>) |
| 44 | 45 | cov_mark::hit!(move_guard_inapplicable_in_arm_body); |
| 45 | 46 | return None; |
| 46 | 47 | } |
| 47 | let space_before_guard = guard.syntax().prev_sibling_or_token(); | |
| 48 | let rest_arms = rest_arms(&match_arm, ctx.selection_trimmed())?; | |
| 49 | let space_before_delete = chain( | |
| 50 | guard.syntax().prev_sibling_or_token(), | |
| 51 | rest_arms.iter().filter_map(|it| it.syntax().prev_sibling_or_token()), | |
| 52 | ); | |
| 48 | 53 | let space_after_arrow = match_arm.fat_arrow_token()?.next_sibling_or_token(); |
| 49 | 54 | |
| 50 | let guard_condition = guard.condition()?.reset_indent(); | |
| 51 | 55 | let arm_expr = match_arm.expr()?; |
| 52 | let then_branch = crate::utils::wrap_block(&arm_expr); | |
| 53 | let if_expr = make::expr_if(guard_condition, then_branch, None).indent(arm_expr.indent_level()); | |
| 56 | let if_branch = chain([&match_arm], &rest_arms) | |
| 57 | .rfold(None, |else_branch, arm| { | |
| 58 | if let Some(guard) = arm.guard() { | |
| 59 | let then_branch = crate::utils::wrap_block(&arm.expr()?); | |
| 60 | let guard_condition = guard.condition()?.reset_indent(); | |
| 61 | Some(make::expr_if(guard_condition, then_branch, else_branch).into()) | |
| 62 | } else { | |
| 63 | arm.expr().map(|it| crate::utils::wrap_block(&it).into()) | |
| 64 | } | |
| 65 | })? | |
| 66 | .indent(arm_expr.indent_level()); | |
| 67 | let ElseBranch::IfExpr(if_expr) = if_branch else { return None }; | |
| 54 | 68 | |
| 55 | 69 | let target = guard.syntax().text_range(); |
| 56 | 70 | acc.add( |
| ... | ... | @@ -59,10 +73,13 @@ pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext<'_>) |
| 59 | 73 | target, |
| 60 | 74 | |builder| { |
| 61 | 75 | let mut edit = builder.make_editor(match_arm.syntax()); |
| 62 | if let Some(element) = space_before_guard | |
| 63 | && element.kind() == WHITESPACE | |
| 64 | { | |
| 65 | edit.delete(element); | |
| 76 | for element in space_before_delete { | |
| 77 | if element.kind() == WHITESPACE { | |
| 78 | edit.delete(element); | |
| 79 | } | |
| 80 | } | |
| 81 | for rest_arm in &rest_arms { | |
| 82 | edit.delete(rest_arm.syntax()); | |
| 66 | 83 | } |
| 67 | 84 | if let Some(element) = space_after_arrow |
| 68 | 85 | && element.kind() == WHITESPACE |
| ... | ... | @@ -221,6 +238,25 @@ pub(crate) fn move_arm_cond_to_match_guard( |
| 221 | 238 | ) |
| 222 | 239 | } |
| 223 | 240 | |
| 241 | fn rest_arms(match_arm: &MatchArm, selection: TextRange) -> Option<Vec<MatchArm>> { | |
| 242 | match_arm | |
| 243 | .parent_match() | |
| 244 | .match_arm_list()? | |
| 245 | .arms() | |
| 246 | .skip_while(|it| it != match_arm) | |
| 247 | .skip(1) | |
| 248 | .take_while(move |it| { | |
| 249 | selection.is_empty() || crate::utils::is_selected(it, selection, false) | |
| 250 | }) | |
| 251 | .take_while(move |it| { | |
| 252 | it.pat() | |
| 253 | .zip(match_arm.pat()) | |
| 254 | .is_some_and(|(a, b)| a.syntax().text() == b.syntax().text()) | |
| 255 | }) | |
| 256 | .collect::<Vec<_>>() | |
| 257 | .into() | |
| 258 | } | |
| 259 | ||
| 224 | 260 | // Parses an if-else-if chain to get the conditions and the then branches until we encounter an else |
| 225 | 261 | // branch or the end. |
| 226 | 262 | fn parse_if_chain(if_expr: IfExpr) -> Option<(Vec<(Expr, BlockExpr)>, Option<BlockExpr>)> { |
| ... | ... | @@ -344,6 +380,115 @@ fn main() { |
| 344 | 380 | ); |
| 345 | 381 | } |
| 346 | 382 | |
| 383 | #[test] | |
| 384 | fn move_multiple_guard_to_arm_body_works() { | |
| 385 | check_assist( | |
| 386 | move_guard_to_arm_body, | |
| 387 | r#" | |
| 388 | fn main() { | |
| 389 | match 92 { | |
| 390 | x @ 0..30 $0if x % 3 == 0 => false, | |
| 391 | x @ 0..30 if x % 2 == 0 => true, | |
| 392 | _ => false | |
| 393 | } | |
| 394 | } | |
| 395 | "#, | |
| 396 | r#" | |
| 397 | fn main() { | |
| 398 | match 92 { | |
| 399 | x @ 0..30 => if x % 3 == 0 { | |
| 400 | false | |
| 401 | } else if x % 2 == 0 { | |
| 402 | true | |
| 403 | }, | |
| 404 | _ => false | |
| 405 | } | |
| 406 | } | |
| 407 | "#, | |
| 408 | ); | |
| 409 | ||
| 410 | check_assist( | |
| 411 | move_guard_to_arm_body, | |
| 412 | r#" | |
| 413 | fn main() { | |
| 414 | match 92 { | |
| 415 | x @ 0..30 $0if x % 3 == 0 => false, | |
| 416 | x @ 0..30 if x % 2 == 0 => true, | |
| 417 | x @ 0..30 => false, | |
| 418 | _ => true | |
| 419 | } | |
| 420 | } | |
| 421 | "#, | |
| 422 | r#" | |
| 423 | fn main() { | |
| 424 | match 92 { | |
| 425 | x @ 0..30 => if x % 3 == 0 { | |
| 426 | false | |
| 427 | } else if x % 2 == 0 { | |
| 428 | true | |
| 429 | } else { | |
| 430 | false | |
| 431 | }, | |
| 432 | _ => true | |
| 433 | } | |
| 434 | } | |
| 435 | "#, | |
| 436 | ); | |
| 437 | ||
| 438 | check_assist( | |
| 439 | move_guard_to_arm_body, | |
| 440 | r#" | |
| 441 | fn main() { | |
| 442 | match 92 { | |
| 443 | x @ 0..30 if x % 3 == 0 => false, | |
| 444 | x @ 0..30 $0if x % 2 == 0$0 => true, | |
| 445 | x @ 0..30 => false, | |
| 446 | _ => true | |
| 447 | } | |
| 448 | } | |
| 449 | "#, | |
| 450 | r#" | |
| 451 | fn main() { | |
| 452 | match 92 { | |
| 453 | x @ 0..30 if x % 3 == 0 => false, | |
| 454 | x @ 0..30 => if x % 2 == 0 { | |
| 455 | true | |
| 456 | }, | |
| 457 | x @ 0..30 => false, | |
| 458 | _ => true | |
| 459 | } | |
| 460 | } | |
| 461 | "#, | |
| 462 | ); | |
| 463 | ||
| 464 | check_assist( | |
| 465 | move_guard_to_arm_body, | |
| 466 | r#" | |
| 467 | fn main() { | |
| 468 | match 92 { | |
| 469 | x @ 0..30 $0if x % 3 == 0 => false, | |
| 470 | x @ 0..30 $0if x % 2 == 0 => true, | |
| 471 | x @ 0..30 => false, | |
| 472 | _ => true | |
| 473 | } | |
| 474 | } | |
| 475 | "#, | |
| 476 | r#" | |
| 477 | fn main() { | |
| 478 | match 92 { | |
| 479 | x @ 0..30 => if x % 3 == 0 { | |
| 480 | false | |
| 481 | } else if x % 2 == 0 { | |
| 482 | true | |
| 483 | }, | |
| 484 | x @ 0..30 => false, | |
| 485 | _ => true | |
| 486 | } | |
| 487 | } | |
| 488 | "#, | |
| 489 | ); | |
| 490 | } | |
| 491 | ||
| 347 | 492 | #[test] |
| 348 | 493 | fn move_guard_to_block_arm_body_works() { |
| 349 | 494 | check_assist( |
src/tools/rust-analyzer/crates/ide-assists/src/utils.rs+22-18| ... | ... | @@ -4,8 +4,7 @@ use std::slice; |
| 4 | 4 | |
| 5 | 5 | pub(crate) use gen_trait_fn_body::gen_trait_fn_body; |
| 6 | 6 | use hir::{ |
| 7 | DisplayTarget, HasAttrs as HirHasAttrs, HirDisplay, InFile, ModuleDef, PathResolution, | |
| 8 | Semantics, | |
| 7 | HasAttrs as HirHasAttrs, HirDisplay, InFile, ModuleDef, PathResolution, Semantics, | |
| 9 | 8 | db::{ExpandDatabase, HirDatabase}, |
| 10 | 9 | }; |
| 11 | 10 | use ide_db::{ |
| ... | ... | @@ -836,13 +835,12 @@ enum ReferenceConversionType { |
| 836 | 835 | } |
| 837 | 836 | |
| 838 | 837 | impl<'db> ReferenceConversion<'db> { |
| 839 | pub(crate) fn convert_type( | |
| 840 | &self, | |
| 841 | db: &'db dyn HirDatabase, | |
| 842 | display_target: DisplayTarget, | |
| 843 | ) -> ast::Type { | |
| 838 | pub(crate) fn convert_type(&self, db: &'db dyn HirDatabase, module: hir::Module) -> ast::Type { | |
| 844 | 839 | let ty = match self.conversion { |
| 845 | ReferenceConversionType::Copy => self.ty.display(db, display_target).to_string(), | |
| 840 | ReferenceConversionType::Copy => self | |
| 841 | .ty | |
| 842 | .display_source_code(db, module.into(), true) | |
| 843 | .unwrap_or_else(|_| "_".to_owned()), | |
| 846 | 844 | ReferenceConversionType::AsRefStr => "&str".to_owned(), |
| 847 | 845 | ReferenceConversionType::AsRefSlice => { |
| 848 | 846 | let type_argument_name = self |
| ... | ... | @@ -850,8 +848,8 @@ impl<'db> ReferenceConversion<'db> { |
| 850 | 848 | .type_arguments() |
| 851 | 849 | .next() |
| 852 | 850 | .unwrap() |
| 853 | .display(db, display_target) | |
| 854 | .to_string(); | |
| 851 | .display_source_code(db, module.into(), true) | |
| 852 | .unwrap_or_else(|_| "_".to_owned()); | |
| 855 | 853 | format!("&[{type_argument_name}]") |
| 856 | 854 | } |
| 857 | 855 | ReferenceConversionType::Dereferenced => { |
| ... | ... | @@ -860,8 +858,8 @@ impl<'db> ReferenceConversion<'db> { |
| 860 | 858 | .type_arguments() |
| 861 | 859 | .next() |
| 862 | 860 | .unwrap() |
| 863 | .display(db, display_target) | |
| 864 | .to_string(); | |
| 861 | .display_source_code(db, module.into(), true) | |
| 862 | .unwrap_or_else(|_| "_".to_owned()); | |
| 865 | 863 | format!("&{type_argument_name}") |
| 866 | 864 | } |
| 867 | 865 | ReferenceConversionType::Option => { |
| ... | ... | @@ -870,16 +868,22 @@ impl<'db> ReferenceConversion<'db> { |
| 870 | 868 | .type_arguments() |
| 871 | 869 | .next() |
| 872 | 870 | .unwrap() |
| 873 | .display(db, display_target) | |
| 874 | .to_string(); | |
| 871 | .display_source_code(db, module.into(), true) | |
| 872 | .unwrap_or_else(|_| "_".to_owned()); | |
| 875 | 873 | format!("Option<&{type_argument_name}>") |
| 876 | 874 | } |
| 877 | 875 | ReferenceConversionType::Result => { |
| 878 | 876 | let mut type_arguments = self.ty.type_arguments(); |
| 879 | let first_type_argument_name = | |
| 880 | type_arguments.next().unwrap().display(db, display_target).to_string(); | |
| 881 | let second_type_argument_name = | |
| 882 | type_arguments.next().unwrap().display(db, display_target).to_string(); | |
| 877 | let first_type_argument_name = type_arguments | |
| 878 | .next() | |
| 879 | .unwrap() | |
| 880 | .display_source_code(db, module.into(), true) | |
| 881 | .unwrap_or_else(|_| "_".to_owned()); | |
| 882 | let second_type_argument_name = type_arguments | |
| 883 | .next() | |
| 884 | .unwrap() | |
| 885 | .display_source_code(db, module.into(), true) | |
| 886 | .unwrap_or_else(|_| "_".to_owned()); | |
| 883 | 887 | format!("Result<&{first_type_argument_name}, &{second_type_argument_name}>") |
| 884 | 888 | } |
| 885 | 889 | }; |
src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs+52-1| ... | ... | @@ -151,6 +151,10 @@ pub(crate) fn complete_postfix( |
| 151 | 151 | .add_to(acc, ctx.db); |
| 152 | 152 | } |
| 153 | 153 | }, |
| 154 | _ if is_in_cond => { | |
| 155 | postfix_snippet("let", "let", &format!("let $1 = {receiver_text}")) | |
| 156 | .add_to(acc, ctx.db); | |
| 157 | } | |
| 154 | 158 | _ if matches!(second_ancestor.kind(), STMT_LIST | EXPR_STMT) => { |
| 155 | 159 | postfix_snippet("let", "let", &format!("let $0 = {receiver_text};")) |
| 156 | 160 | .add_to(acc, ctx.db); |
| ... | ... | @@ -253,7 +257,6 @@ pub(crate) fn complete_postfix( |
| 253 | 257 | &format!("while {receiver_text} {{\n $0\n}}"), |
| 254 | 258 | ) |
| 255 | 259 | .add_to(acc, ctx.db); |
| 256 | postfix_snippet("not", "!expr", &format!("!{receiver_text}")).add_to(acc, ctx.db); | |
| 257 | 260 | } else if let Some(trait_) = ctx.famous_defs().core_iter_IntoIterator() |
| 258 | 261 | && receiver_ty.impls_trait(ctx.db, trait_, &[]) |
| 259 | 262 | { |
| ... | ... | @@ -266,6 +269,10 @@ pub(crate) fn complete_postfix( |
| 266 | 269 | } |
| 267 | 270 | } |
| 268 | 271 | |
| 272 | if receiver_ty.is_bool() || receiver_ty.is_unknown() { | |
| 273 | postfix_snippet("not", "!expr", &format!("!{receiver_text}")).add_to(acc, ctx.db); | |
| 274 | } | |
| 275 | ||
| 269 | 276 | let block_should_be_wrapped = if let ast::Expr::BlockExpr(block) = dot_receiver { |
| 270 | 277 | block.modifier().is_some() || !block.is_standalone() |
| 271 | 278 | } else { |
| ... | ... | @@ -585,6 +592,31 @@ fn main() { |
| 585 | 592 | ); |
| 586 | 593 | } |
| 587 | 594 | |
| 595 | #[test] | |
| 596 | fn postfix_completion_works_in_if_condition() { | |
| 597 | check( | |
| 598 | r#" | |
| 599 | fn foo(cond: bool) { | |
| 600 | if cond.$0 | |
| 601 | } | |
| 602 | "#, | |
| 603 | expect![[r#" | |
| 604 | sn box Box::new(expr) | |
| 605 | sn call function(expr) | |
| 606 | sn const const {} | |
| 607 | sn dbg dbg!(expr) | |
| 608 | sn dbgr dbg!(&expr) | |
| 609 | sn deref *expr | |
| 610 | sn let let | |
| 611 | sn not !expr | |
| 612 | sn ref &expr | |
| 613 | sn refm &mut expr | |
| 614 | sn return return expr | |
| 615 | sn unsafe unsafe {} | |
| 616 | "#]], | |
| 617 | ); | |
| 618 | } | |
| 619 | ||
| 588 | 620 | #[test] |
| 589 | 621 | fn postfix_type_filtering() { |
| 590 | 622 | check( |
| ... | ... | @@ -744,6 +776,25 @@ fn main() { |
| 744 | 776 | ); |
| 745 | 777 | } |
| 746 | 778 | |
| 779 | #[test] | |
| 780 | fn iflet_fallback_cond() { | |
| 781 | check_edit( | |
| 782 | "let", | |
| 783 | r#" | |
| 784 | fn main() { | |
| 785 | let bar = 2; | |
| 786 | if bar.$0 | |
| 787 | } | |
| 788 | "#, | |
| 789 | r#" | |
| 790 | fn main() { | |
| 791 | let bar = 2; | |
| 792 | if let $1 = bar | |
| 793 | } | |
| 794 | "#, | |
| 795 | ); | |
| 796 | } | |
| 797 | ||
| 747 | 798 | #[test] |
| 748 | 799 | fn option_letelse() { |
| 749 | 800 | check_edit( |
src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs+7-2| ... | ... | @@ -146,9 +146,14 @@ pub fn insert_use(scope: &ImportScope, path: ast::Path, cfg: &InsertUseConfig) { |
| 146 | 146 | insert_use_with_alias_option(scope, path, cfg, None); |
| 147 | 147 | } |
| 148 | 148 | |
| 149 | pub fn insert_use_as_alias(scope: &ImportScope, path: ast::Path, cfg: &InsertUseConfig) { | |
| 149 | pub fn insert_use_as_alias( | |
| 150 | scope: &ImportScope, | |
| 151 | path: ast::Path, | |
| 152 | cfg: &InsertUseConfig, | |
| 153 | edition: span::Edition, | |
| 154 | ) { | |
| 150 | 155 | let text: &str = "use foo as _"; |
| 151 | let parse = syntax::SourceFile::parse(text, span::Edition::CURRENT_FIXME); | |
| 156 | let parse = syntax::SourceFile::parse(text, edition); | |
| 152 | 157 | let node = parse |
| 153 | 158 | .tree() |
| 154 | 159 | .syntax() |
src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs+3-3| ... | ... | @@ -49,7 +49,7 @@ pub fn is_closure_or_blk_with_modif(expr: &ast::Expr) -> bool { |
| 49 | 49 | block_expr.modifier(), |
| 50 | 50 | Some( |
| 51 | 51 | ast::BlockModifier::Async(_) |
| 52 | | ast::BlockModifier::Try(_) | |
| 52 | | ast::BlockModifier::Try { .. } | |
| 53 | 53 | | ast::BlockModifier::Const(_) |
| 54 | 54 | ) |
| 55 | 55 | ) |
| ... | ... | @@ -148,7 +148,7 @@ pub fn walk_patterns_in_expr(start: &ast::Expr, cb: &mut dyn FnMut(ast::Pat)) { |
| 148 | 148 | block_expr.modifier(), |
| 149 | 149 | Some( |
| 150 | 150 | ast::BlockModifier::Async(_) |
| 151 | | ast::BlockModifier::Try(_) | |
| 151 | | ast::BlockModifier::Try { .. } | |
| 152 | 152 | | ast::BlockModifier::Const(_) |
| 153 | 153 | ) |
| 154 | 154 | ) |
| ... | ... | @@ -291,7 +291,7 @@ pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) { |
| 291 | 291 | match b.modifier() { |
| 292 | 292 | Some( |
| 293 | 293 | ast::BlockModifier::Async(_) |
| 294 | | ast::BlockModifier::Try(_) | |
| 294 | | ast::BlockModifier::Try { .. } | |
| 295 | 295 | | ast::BlockModifier::Const(_), |
| 296 | 296 | ) => return cb(expr), |
| 297 | 297 |
src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs+29-21| ... | ... | @@ -206,17 +206,18 @@ impl NameGenerator { |
| 206 | 206 | expr: &ast::Expr, |
| 207 | 207 | sema: &Semantics<'_, RootDatabase>, |
| 208 | 208 | ) -> Option<SmolStr> { |
| 209 | let edition = sema.scope(expr.syntax())?.krate().edition(sema.db); | |
| 209 | 210 | // `from_param` does not benefit from stripping it need the largest |
| 210 | 211 | // context possible so we check firstmost |
| 211 | if let Some(name) = from_param(expr, sema) { | |
| 212 | if let Some(name) = from_param(expr, sema, edition) { | |
| 212 | 213 | return Some(self.suggest_name(&name)); |
| 213 | 214 | } |
| 214 | 215 | |
| 215 | 216 | let mut next_expr = Some(expr.clone()); |
| 216 | 217 | while let Some(expr) = next_expr { |
| 217 | let name = from_call(&expr) | |
| 218 | .or_else(|| from_type(&expr, sema)) | |
| 219 | .or_else(|| from_field_name(&expr)); | |
| 218 | let name = from_call(&expr, edition) | |
| 219 | .or_else(|| from_type(&expr, sema, edition)) | |
| 220 | .or_else(|| from_field_name(&expr, edition)); | |
| 220 | 221 | if let Some(name) = name { |
| 221 | 222 | return Some(self.suggest_name(&name)); |
| 222 | 223 | } |
| ... | ... | @@ -270,7 +271,7 @@ impl NameGenerator { |
| 270 | 271 | } |
| 271 | 272 | } |
| 272 | 273 | |
| 273 | fn normalize(name: &str) -> Option<SmolStr> { | |
| 274 | fn normalize(name: &str, edition: syntax::Edition) -> Option<SmolStr> { | |
| 274 | 275 | let name = to_lower_snake_case(name).to_smolstr(); |
| 275 | 276 | |
| 276 | 277 | if USELESS_NAMES.contains(&name.as_str()) { |
| ... | ... | @@ -281,16 +282,16 @@ fn normalize(name: &str) -> Option<SmolStr> { |
| 281 | 282 | return None; |
| 282 | 283 | } |
| 283 | 284 | |
| 284 | if !is_valid_name(&name) { | |
| 285 | if !is_valid_name(&name, edition) { | |
| 285 | 286 | return None; |
| 286 | 287 | } |
| 287 | 288 | |
| 288 | 289 | Some(name) |
| 289 | 290 | } |
| 290 | 291 | |
| 291 | fn is_valid_name(name: &str) -> bool { | |
| 292 | fn is_valid_name(name: &str, edition: syntax::Edition) -> bool { | |
| 292 | 293 | matches!( |
| 293 | super::LexedStr::single_token(syntax::Edition::CURRENT_FIXME, name), | |
| 294 | super::LexedStr::single_token(edition, name), | |
| 294 | 295 | Some((syntax::SyntaxKind::IDENT, _error)) |
| 295 | 296 | ) |
| 296 | 297 | } |
| ... | ... | @@ -304,11 +305,11 @@ fn is_useless_method(method: &ast::MethodCallExpr) -> bool { |
| 304 | 305 | } |
| 305 | 306 | } |
| 306 | 307 | |
| 307 | fn from_call(expr: &ast::Expr) -> Option<SmolStr> { | |
| 308 | from_func_call(expr).or_else(|| from_method_call(expr)) | |
| 308 | fn from_call(expr: &ast::Expr, edition: syntax::Edition) -> Option<SmolStr> { | |
| 309 | from_func_call(expr, edition).or_else(|| from_method_call(expr, edition)) | |
| 309 | 310 | } |
| 310 | 311 | |
| 311 | fn from_func_call(expr: &ast::Expr) -> Option<SmolStr> { | |
| 312 | fn from_func_call(expr: &ast::Expr, edition: syntax::Edition) -> Option<SmolStr> { | |
| 312 | 313 | let call = match expr { |
| 313 | 314 | ast::Expr::CallExpr(call) => call, |
| 314 | 315 | _ => return None, |
| ... | ... | @@ -318,10 +319,10 @@ fn from_func_call(expr: &ast::Expr) -> Option<SmolStr> { |
| 318 | 319 | _ => return None, |
| 319 | 320 | }; |
| 320 | 321 | let ident = func.path()?.segment()?.name_ref()?.ident_token()?; |
| 321 | normalize(ident.text()) | |
| 322 | normalize(ident.text(), edition) | |
| 322 | 323 | } |
| 323 | 324 | |
| 324 | fn from_method_call(expr: &ast::Expr) -> Option<SmolStr> { | |
| 325 | fn from_method_call(expr: &ast::Expr, edition: syntax::Edition) -> Option<SmolStr> { | |
| 325 | 326 | let method = match expr { |
| 326 | 327 | ast::Expr::MethodCallExpr(call) => call, |
| 327 | 328 | _ => return None, |
| ... | ... | @@ -340,10 +341,14 @@ fn from_method_call(expr: &ast::Expr) -> Option<SmolStr> { |
| 340 | 341 | } |
| 341 | 342 | } |
| 342 | 343 | |
| 343 | normalize(name) | |
| 344 | normalize(name, edition) | |
| 344 | 345 | } |
| 345 | 346 | |
| 346 | fn from_param(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option<SmolStr> { | |
| 347 | fn from_param( | |
| 348 | expr: &ast::Expr, | |
| 349 | sema: &Semantics<'_, RootDatabase>, | |
| 350 | edition: Edition, | |
| 351 | ) -> Option<SmolStr> { | |
| 347 | 352 | let arg_list = expr.syntax().parent().and_then(ast::ArgList::cast)?; |
| 348 | 353 | let args_parent = arg_list.syntax().parent()?; |
| 349 | 354 | let func = match_ast! { |
| ... | ... | @@ -362,7 +367,7 @@ fn from_param(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option<Sm |
| 362 | 367 | let param = func.params().into_iter().nth(idx)?; |
| 363 | 368 | let pat = sema.source(param)?.value.right()?.pat()?; |
| 364 | 369 | let name = var_name_from_pat(&pat)?; |
| 365 | normalize(&name.to_smolstr()) | |
| 370 | normalize(&name.to_smolstr(), edition) | |
| 366 | 371 | } |
| 367 | 372 | |
| 368 | 373 | fn var_name_from_pat(pat: &ast::Pat) -> Option<ast::Name> { |
| ... | ... | @@ -374,10 +379,13 @@ fn var_name_from_pat(pat: &ast::Pat) -> Option<ast::Name> { |
| 374 | 379 | } |
| 375 | 380 | } |
| 376 | 381 | |
| 377 | fn from_type(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option<SmolStr> { | |
| 382 | fn from_type( | |
| 383 | expr: &ast::Expr, | |
| 384 | sema: &Semantics<'_, RootDatabase>, | |
| 385 | edition: Edition, | |
| 386 | ) -> Option<SmolStr> { | |
| 378 | 387 | let ty = sema.type_of_expr(expr)?.adjusted(); |
| 379 | 388 | let ty = ty.remove_ref().unwrap_or(ty); |
| 380 | let edition = sema.scope(expr.syntax())?.krate().edition(sema.db); | |
| 381 | 389 | |
| 382 | 390 | name_of_type(&ty, sema.db, edition) |
| 383 | 391 | } |
| ... | ... | @@ -417,7 +425,7 @@ fn name_of_type<'db>( |
| 417 | 425 | } else { |
| 418 | 426 | return None; |
| 419 | 427 | }; |
| 420 | normalize(&name) | |
| 428 | normalize(&name, edition) | |
| 421 | 429 | } |
| 422 | 430 | |
| 423 | 431 | fn sequence_name<'db>( |
| ... | ... | @@ -450,13 +458,13 @@ fn trait_name(trait_: &hir::Trait, db: &RootDatabase, edition: Edition) -> Optio |
| 450 | 458 | Some(name) |
| 451 | 459 | } |
| 452 | 460 | |
| 453 | fn from_field_name(expr: &ast::Expr) -> Option<SmolStr> { | |
| 461 | fn from_field_name(expr: &ast::Expr, edition: syntax::Edition) -> Option<SmolStr> { | |
| 454 | 462 | let field = match expr { |
| 455 | 463 | ast::Expr::FieldExpr(field) => field, |
| 456 | 464 | _ => return None, |
| 457 | 465 | }; |
| 458 | 466 | let ident = field.name_ref()?.ident_token()?; |
| 459 | normalize(ident.text()) | |
| 467 | normalize(ident.text(), edition) | |
| 460 | 468 | } |
| 461 | 469 | |
| 462 | 470 | #[cfg(test)] |
src/tools/rust-analyzer/crates/ide/src/goto_definition.rs+3-3| ... | ... | @@ -332,7 +332,7 @@ pub(crate) fn find_fn_or_blocks( |
| 332 | 332 | ast::BlockExpr(blk) => { |
| 333 | 333 | match blk.modifier() { |
| 334 | 334 | Some(ast::BlockModifier::Async(_)) => blk.syntax().clone(), |
| 335 | Some(ast::BlockModifier::Try(_)) if token_kind != T![return] => blk.syntax().clone(), | |
| 335 | Some(ast::BlockModifier::Try { .. }) if token_kind != T![return] => blk.syntax().clone(), | |
| 336 | 336 | _ => continue, |
| 337 | 337 | } |
| 338 | 338 | }, |
| ... | ... | @@ -404,8 +404,8 @@ fn nav_for_exit_points( |
| 404 | 404 | let blk_in_file = InFile::new(file_id, blk.into()); |
| 405 | 405 | Some(expr_to_nav(db, blk_in_file, Some(async_tok))) |
| 406 | 406 | }, |
| 407 | Some(ast::BlockModifier::Try(_)) if token_kind != T![return] => { | |
| 408 | let try_tok = blk.try_token()?.text_range(); | |
| 407 | Some(ast::BlockModifier::Try { .. }) if token_kind != T![return] => { | |
| 408 | let try_tok = blk.try_block_modifier()?.try_token()?.text_range(); | |
| 409 | 409 | let blk_in_file = InFile::new(file_id, blk.into()); |
| 410 | 410 | Some(expr_to_nav(db, blk_in_file, Some(try_tok))) |
| 411 | 411 | }, |
src/tools/rust-analyzer/crates/ide/src/highlight_related.rs+1-1| ... | ... | @@ -473,7 +473,7 @@ pub(crate) fn highlight_exit_points( |
| 473 | 473 | }, |
| 474 | 474 | ast::BlockExpr(blk) => match blk.modifier() { |
| 475 | 475 | Some(ast::BlockModifier::Async(t)) => hl_exit_points(sema, Some(t), blk.into()), |
| 476 | Some(ast::BlockModifier::Try(t)) if token.kind() != T![return] => { | |
| 476 | Some(ast::BlockModifier::Try { try_token: t, .. }) if token.kind() != T![return] => { | |
| 477 | 477 | hl_exit_points(sema, Some(t), blk.into()) |
| 478 | 478 | }, |
| 479 | 479 | _ => continue, |
src/tools/rust-analyzer/crates/ide/src/hover/render.rs+1-1| ... | ... | @@ -74,7 +74,7 @@ pub(super) fn try_expr( |
| 74 | 74 | ast::Fn(fn_) => sema.to_def(&fn_)?.ret_type(sema.db), |
| 75 | 75 | ast::Item(__) => return None, |
| 76 | 76 | ast::ClosureExpr(closure) => sema.type_of_expr(&closure.body()?)?.original, |
| 77 | ast::BlockExpr(block_expr) => if matches!(block_expr.modifier(), Some(ast::BlockModifier::Async(_) | ast::BlockModifier::Try(_)| ast::BlockModifier::Const(_))) { | |
| 77 | ast::BlockExpr(block_expr) => if matches!(block_expr.modifier(), Some(ast::BlockModifier::Async(_) | ast::BlockModifier::Try { .. } | ast::BlockModifier::Const(_))) { | |
| 78 | 78 | sema.type_of_expr(&block_expr.into())?.original |
| 79 | 79 | } else { |
| 80 | 80 | continue; |
src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs+17| ... | ... | @@ -1382,4 +1382,21 @@ fn f<'a>() { |
| 1382 | 1382 | "#]], |
| 1383 | 1383 | ); |
| 1384 | 1384 | } |
| 1385 | ||
| 1386 | #[test] | |
| 1387 | fn ref_multi_trait_impl_trait() { | |
| 1388 | check_with_config( | |
| 1389 | InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, | |
| 1390 | r#" | |
| 1391 | //- minicore: sized | |
| 1392 | trait Eq {} | |
| 1393 | trait Ord {} | |
| 1394 | ||
| 1395 | fn foo(argument: &(impl Eq + Ord)) { | |
| 1396 | let x = argument; | |
| 1397 | // ^ &(impl Eq + Ord) | |
| 1398 | } | |
| 1399 | "#, | |
| 1400 | ); | |
| 1401 | } | |
| 1385 | 1402 | } |
src/tools/rust-analyzer/crates/ide/src/lib.rs+5-1| ... | ... | @@ -67,7 +67,7 @@ use ide_db::{ |
| 67 | 67 | FxHashMap, FxIndexSet, LineIndexDatabase, |
| 68 | 68 | base_db::{ |
| 69 | 69 | CrateOrigin, CrateWorkspaceData, Env, FileSet, RootQueryDb, SourceDatabase, VfsPath, |
| 70 | salsa::{Cancelled, Database}, | |
| 70 | salsa::{CancellationToken, Cancelled, Database}, | |
| 71 | 71 | }, |
| 72 | 72 | prime_caches, symbol_index, |
| 73 | 73 | }; |
| ... | ... | @@ -947,6 +947,10 @@ impl Analysis { |
| 947 | 947 | // We use `attach_db_allow_change()` and not `attach_db()` because fixture injection can change the database. |
| 948 | 948 | hir::attach_db_allow_change(&self.db, || Cancelled::catch(|| f(&self.db))) |
| 949 | 949 | } |
| 950 | ||
| 951 | pub fn cancellation_token(&self) -> CancellationToken { | |
| 952 | self.db.cancellation_token() | |
| 953 | } | |
| 950 | 954 | } |
| 951 | 955 | |
| 952 | 956 | #[test] |
src/tools/rust-analyzer/crates/ide/src/signature_help.rs+2-2| ... | ... | @@ -1975,8 +1975,8 @@ trait Sub: Super + Super { |
| 1975 | 1975 | fn f() -> impl Sub<$0 |
| 1976 | 1976 | "#, |
| 1977 | 1977 | expect![[r#" |
| 1978 | trait Sub<SubTy = …, SuperTy = …> | |
| 1979 | ^^^^^^^^^ ----------- | |
| 1978 | trait Sub<SuperTy = …, SubTy = …> | |
| 1979 | ^^^^^^^^^^^ --------- | |
| 1980 | 1980 | "#]], |
| 1981 | 1981 | ); |
| 1982 | 1982 | } |
src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs+7-12| ... | ... | @@ -14,7 +14,7 @@ mod tests; |
| 14 | 14 | use std::ops::ControlFlow; |
| 15 | 15 | |
| 16 | 16 | use either::Either; |
| 17 | use hir::{DefWithBody, EditionedFileId, InFile, InRealFile, MacroKind, Name, Semantics}; | |
| 17 | use hir::{DefWithBody, EditionedFileId, InFile, InRealFile, MacroKind, Semantics}; | |
| 18 | 18 | use ide_db::{FxHashMap, FxHashSet, MiniCore, Ranker, RootDatabase, SymbolKind}; |
| 19 | 19 | use syntax::{ |
| 20 | 20 | AstNode, AstToken, NodeOrToken, |
| ... | ... | @@ -257,8 +257,7 @@ fn traverse( |
| 257 | 257 | |
| 258 | 258 | // FIXME: accommodate range highlighting |
| 259 | 259 | let mut body_stack: Vec<Option<DefWithBody>> = vec![]; |
| 260 | let mut per_body_cache: FxHashMap<DefWithBody, (FxHashSet<_>, FxHashMap<Name, u32>)> = | |
| 261 | FxHashMap::default(); | |
| 260 | let mut per_body_cache: FxHashMap<DefWithBody, FxHashSet<_>> = FxHashMap::default(); | |
| 262 | 261 | |
| 263 | 262 | // Walk all nodes, keeping track of whether we are inside a macro or not. |
| 264 | 263 | // If in macro, expand it first and highlight the expanded code. |
| ... | ... | @@ -422,14 +421,11 @@ fn traverse( |
| 422 | 421 | } |
| 423 | 422 | |
| 424 | 423 | let edition = descended_element.file_id.edition(sema.db); |
| 425 | let (unsafe_ops, bindings_shadow_count) = match current_body { | |
| 426 | Some(current_body) => { | |
| 427 | let (ops, bindings) = per_body_cache | |
| 428 | .entry(current_body) | |
| 429 | .or_insert_with(|| (sema.get_unsafe_ops(current_body), Default::default())); | |
| 430 | (&*ops, Some(bindings)) | |
| 431 | } | |
| 432 | None => (&empty, None), | |
| 424 | let unsafe_ops = match current_body { | |
| 425 | Some(current_body) => per_body_cache | |
| 426 | .entry(current_body) | |
| 427 | .or_insert_with(|| sema.get_unsafe_ops(current_body)), | |
| 428 | None => &empty, | |
| 433 | 429 | }; |
| 434 | 430 | let is_unsafe_node = |
| 435 | 431 | |node| unsafe_ops.contains(&InFile::new(descended_element.file_id, node)); |
| ... | ... | @@ -438,7 +434,6 @@ fn traverse( |
| 438 | 434 | let hl = highlight::name_like( |
| 439 | 435 | sema, |
| 440 | 436 | krate, |
| 441 | bindings_shadow_count, | |
| 442 | 437 | &is_unsafe_node, |
| 443 | 438 | config.syntactic_name_ref_highlighting, |
| 444 | 439 | name_like, |
src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs+8-32| ... | ... | @@ -5,12 +5,11 @@ use std::ops::ControlFlow; |
| 5 | 5 | use either::Either; |
| 6 | 6 | use hir::{AsAssocItem, HasAttrs, HasVisibility, Semantics}; |
| 7 | 7 | use ide_db::{ |
| 8 | FxHashMap, RootDatabase, SymbolKind, | |
| 8 | RootDatabase, SymbolKind, | |
| 9 | 9 | defs::{Definition, IdentClass, NameClass, NameRefClass}, |
| 10 | 10 | syntax_helpers::node_ext::walk_pat, |
| 11 | 11 | }; |
| 12 | 12 | use span::Edition; |
| 13 | use stdx::hash_once; | |
| 14 | 13 | use syntax::{ |
| 15 | 14 | AstNode, AstPtr, AstToken, NodeOrToken, |
| 16 | 15 | SyntaxKind::{self, *}, |
| ... | ... | @@ -64,7 +63,6 @@ pub(super) fn token( |
| 64 | 63 | pub(super) fn name_like( |
| 65 | 64 | sema: &Semantics<'_, RootDatabase>, |
| 66 | 65 | krate: Option<hir::Crate>, |
| 67 | bindings_shadow_count: Option<&mut FxHashMap<hir::Name, u32>>, | |
| 68 | 66 | is_unsafe_node: &impl Fn(AstPtr<Either<ast::Expr, ast::Pat>>) -> bool, |
| 69 | 67 | syntactic_name_ref_highlighting: bool, |
| 70 | 68 | name_like: ast::NameLike, |
| ... | ... | @@ -75,22 +73,15 @@ pub(super) fn name_like( |
| 75 | 73 | ast::NameLike::NameRef(name_ref) => highlight_name_ref( |
| 76 | 74 | sema, |
| 77 | 75 | krate, |
| 78 | bindings_shadow_count, | |
| 79 | 76 | &mut binding_hash, |
| 80 | 77 | is_unsafe_node, |
| 81 | 78 | syntactic_name_ref_highlighting, |
| 82 | 79 | name_ref, |
| 83 | 80 | edition, |
| 84 | 81 | ), |
| 85 | ast::NameLike::Name(name) => highlight_name( | |
| 86 | sema, | |
| 87 | bindings_shadow_count, | |
| 88 | &mut binding_hash, | |
| 89 | is_unsafe_node, | |
| 90 | krate, | |
| 91 | name, | |
| 92 | edition, | |
| 93 | ), | |
| 82 | ast::NameLike::Name(name) => { | |
| 83 | highlight_name(sema, &mut binding_hash, is_unsafe_node, krate, name, edition) | |
| 84 | } | |
| 94 | 85 | ast::NameLike::Lifetime(lifetime) => match IdentClass::classify_lifetime(sema, &lifetime) { |
| 95 | 86 | Some(IdentClass::NameClass(NameClass::Definition(def))) => { |
| 96 | 87 | highlight_def(sema, krate, def, edition, false) | HlMod::Definition |
| ... | ... | @@ -273,7 +264,6 @@ fn keyword(token: SyntaxToken, kind: SyntaxKind) -> Highlight { |
| 273 | 264 | fn highlight_name_ref( |
| 274 | 265 | sema: &Semantics<'_, RootDatabase>, |
| 275 | 266 | krate: Option<hir::Crate>, |
| 276 | bindings_shadow_count: Option<&mut FxHashMap<hir::Name, u32>>, | |
| 277 | 267 | binding_hash: &mut Option<u64>, |
| 278 | 268 | is_unsafe_node: &impl Fn(AstPtr<Either<ast::Expr, ast::Pat>>) -> bool, |
| 279 | 269 | syntactic_name_ref_highlighting: bool, |
| ... | ... | @@ -306,12 +296,8 @@ fn highlight_name_ref( |
| 306 | 296 | }; |
| 307 | 297 | let mut h = match name_class { |
| 308 | 298 | NameRefClass::Definition(def, _) => { |
| 309 | if let Definition::Local(local) = &def | |
| 310 | && let Some(bindings_shadow_count) = bindings_shadow_count | |
| 311 | { | |
| 312 | let name = local.name(sema.db); | |
| 313 | let shadow_count = bindings_shadow_count.entry(name.clone()).or_default(); | |
| 314 | *binding_hash = Some(calc_binding_hash(&name, *shadow_count)) | |
| 299 | if let Definition::Local(local) = &def { | |
| 300 | *binding_hash = Some(local.as_id() as u64); | |
| 315 | 301 | }; |
| 316 | 302 | |
| 317 | 303 | let mut h = highlight_def(sema, krate, def, edition, true); |
| ... | ... | @@ -432,7 +418,6 @@ fn highlight_name_ref( |
| 432 | 418 | |
| 433 | 419 | fn highlight_name( |
| 434 | 420 | sema: &Semantics<'_, RootDatabase>, |
| 435 | bindings_shadow_count: Option<&mut FxHashMap<hir::Name, u32>>, | |
| 436 | 421 | binding_hash: &mut Option<u64>, |
| 437 | 422 | is_unsafe_node: &impl Fn(AstPtr<Either<ast::Expr, ast::Pat>>) -> bool, |
| 438 | 423 | krate: Option<hir::Crate>, |
| ... | ... | @@ -440,13 +425,8 @@ fn highlight_name( |
| 440 | 425 | edition: Edition, |
| 441 | 426 | ) -> Highlight { |
| 442 | 427 | let name_kind = NameClass::classify(sema, &name); |
| 443 | if let Some(NameClass::Definition(Definition::Local(local))) = &name_kind | |
| 444 | && let Some(bindings_shadow_count) = bindings_shadow_count | |
| 445 | { | |
| 446 | let name = local.name(sema.db); | |
| 447 | let shadow_count = bindings_shadow_count.entry(name.clone()).or_default(); | |
| 448 | *shadow_count += 1; | |
| 449 | *binding_hash = Some(calc_binding_hash(&name, *shadow_count)) | |
| 428 | if let Some(NameClass::Definition(Definition::Local(local))) = &name_kind { | |
| 429 | *binding_hash = Some(local.as_id() as u64); | |
| 450 | 430 | }; |
| 451 | 431 | match name_kind { |
| 452 | 432 | Some(NameClass::Definition(def)) => { |
| ... | ... | @@ -474,10 +454,6 @@ fn highlight_name( |
| 474 | 454 | } |
| 475 | 455 | } |
| 476 | 456 | |
| 477 | fn calc_binding_hash(name: &hir::Name, shadow_count: u32) -> u64 { | |
| 478 | hash_once::<ide_db::FxHasher>((name.as_str(), shadow_count)) | |
| 479 | } | |
| 480 | ||
| 481 | 457 | pub(super) fn highlight_def( |
| 482 | 458 | sema: &Semantics<'_, RootDatabase>, |
| 483 | 459 | krate: Option<hir::Crate>, |
src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html+6-6| ... | ... | @@ -42,14 +42,14 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd |
| 42 | 42 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } |
| 43 | 43 | </style> |
| 44 | 44 | <pre><code><span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
| 45 | <span class="keyword">let</span> <span class="variable declaration reference" data-binding-hash="18084384843626695225" style="color: hsl(154,95%,53%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="semicolon">;</span> | |
| 46 | <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="5697120079570210533" style="color: hsl(268,86%,80%);">x</span> <span class="operator">=</span> <span class="variable reference" data-binding-hash="18084384843626695225" style="color: hsl(154,95%,53%);">hello</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> | |
| 47 | <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="4222724691718692706" style="color: hsl(156,71%,51%);">y</span> <span class="operator">=</span> <span class="variable reference" data-binding-hash="18084384843626695225" style="color: hsl(154,95%,53%);">hello</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> | |
| 45 | <span class="keyword">let</span> <span class="variable declaration reference" data-binding-hash="0" style="color: hsl(74,59%,48%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="semicolon">;</span> | |
| 46 | <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="1" style="color: hsl(152,51%,64%);">x</span> <span class="operator">=</span> <span class="variable reference" data-binding-hash="0" style="color: hsl(74,59%,48%);">hello</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> | |
| 47 | <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="2" style="color: hsl(272,82%,82%);">y</span> <span class="operator">=</span> <span class="variable reference" data-binding-hash="0" style="color: hsl(74,59%,48%);">hello</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> | |
| 48 | 48 | |
| 49 | <span class="keyword">let</span> <span class="variable declaration reference" data-binding-hash="17855021198829413584" style="color: hsl(230,76%,79%);">x</span> <span class="operator">=</span> <span class="string_literal">"other color please!"</span><span class="semicolon">;</span> | |
| 50 | <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="16380625810977895757" style="color: hsl(262,75%,75%);">y</span> <span class="operator">=</span> <span class="variable reference" data-binding-hash="17855021198829413584" style="color: hsl(230,76%,79%);">x</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> | |
| 49 | <span class="keyword">let</span> <span class="variable declaration reference" data-binding-hash="3" style="color: hsl(107,98%,81%);">x</span> <span class="operator">=</span> <span class="string_literal">"other color please!"</span><span class="semicolon">;</span> | |
| 50 | <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="4" style="color: hsl(241,93%,64%);">y</span> <span class="operator">=</span> <span class="variable reference" data-binding-hash="3" style="color: hsl(107,98%,81%);">x</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> | |
| 51 | 51 | <span class="brace">}</span> |
| 52 | 52 | |
| 53 | 53 | <span class="keyword">fn</span> <span class="function declaration">bar</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> |
| 54 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable reference" data-binding-hash="18084384843626695225" style="color: hsl(154,95%,53%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="semicolon">;</span> | |
| 54 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable reference" data-binding-hash="0" style="color: hsl(74,59%,48%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="semicolon">;</span> | |
| 55 | 55 | <span class="brace">}</span></code></pre> |
| \ No newline at end of file |
src/tools/rust-analyzer/crates/ide/src/typing.rs+11-7| ... | ... | @@ -17,7 +17,10 @@ mod on_enter; |
| 17 | 17 | |
| 18 | 18 | use either::Either; |
| 19 | 19 | use hir::EditionedFileId; |
| 20 | use ide_db::{FilePosition, RootDatabase, base_db::RootQueryDb}; | |
| 20 | use ide_db::{ | |
| 21 | FilePosition, RootDatabase, | |
| 22 | base_db::{RootQueryDb, SourceDatabase}, | |
| 23 | }; | |
| 21 | 24 | use span::Edition; |
| 22 | 25 | use std::iter; |
| 23 | 26 | |
| ... | ... | @@ -70,11 +73,12 @@ pub(crate) fn on_char_typed( |
| 70 | 73 | if !TRIGGER_CHARS.contains(&char_typed) { |
| 71 | 74 | return None; |
| 72 | 75 | } |
| 73 | // FIXME: We need to figure out the edition of the file here, but that means hitting the | |
| 74 | // database for more than just parsing the file which is bad. | |
| 76 | let edition = db | |
| 77 | .source_root_crates(db.file_source_root(position.file_id).source_root_id(db)) | |
| 78 | .first() | |
| 79 | .map_or(Edition::CURRENT, |crates| crates.data(db).edition); | |
| 75 | 80 | // FIXME: We are hitting the database here, if we are unlucky this call might block momentarily |
| 76 | // causing the editor to feel sluggish! | |
| 77 | let edition = Edition::CURRENT_FIXME; | |
| 81 | // causing the editor to feel sluggish! We need to make this bail if it would block too long? | |
| 78 | 82 | let editioned_file_id_wrapper = EditionedFileId::from_span_guess_origin( |
| 79 | 83 | db, |
| 80 | 84 | span::EditionedFileId::new(position.file_id, edition), |
| ... | ... | @@ -457,8 +461,8 @@ mod tests { |
| 457 | 461 | let (offset, mut before) = extract_offset(before); |
| 458 | 462 | let edit = TextEdit::insert(offset, char_typed.to_string()); |
| 459 | 463 | edit.apply(&mut before); |
| 460 | let parse = SourceFile::parse(&before, span::Edition::CURRENT_FIXME); | |
| 461 | on_char_typed_(&parse, offset, char_typed, span::Edition::CURRENT_FIXME).map(|it| { | |
| 464 | let parse = SourceFile::parse(&before, span::Edition::CURRENT); | |
| 465 | on_char_typed_(&parse, offset, char_typed, span::Edition::CURRENT).map(|it| { | |
| 462 | 466 | it.apply(&mut before); |
| 463 | 467 | before.to_string() |
| 464 | 468 | }) |
src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs+2| ... | ... | @@ -110,6 +110,7 @@ define_symbols! { |
| 110 | 110 | win64_dash_unwind = "win64-unwind", |
| 111 | 111 | x86_dash_interrupt = "x86-interrupt", |
| 112 | 112 | rust_dash_preserve_dash_none = "preserve-none", |
| 113 | _0_u8 = "0_u8", | |
| 113 | 114 | |
| 114 | 115 | @PLAIN: |
| 115 | 116 | __ra_fixup, |
| ... | ... | @@ -285,6 +286,7 @@ define_symbols! { |
| 285 | 286 | Into, |
| 286 | 287 | into_future, |
| 287 | 288 | into_iter, |
| 289 | into_try_type, | |
| 288 | 290 | IntoFuture, |
| 289 | 291 | IntoIter, |
| 290 | 292 | IntoIterator, |
src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs+6| ... | ... | @@ -976,11 +976,17 @@ fn break_expr(p: &mut Parser<'_>, r: Restrictions) -> CompletedMarker { |
| 976 | 976 | // test try_block_expr |
| 977 | 977 | // fn foo() { |
| 978 | 978 | // let _ = try {}; |
| 979 | // let _ = try bikeshed T<U> {}; | |
| 979 | 980 | // } |
| 980 | 981 | fn try_block_expr(p: &mut Parser<'_>, m: Option<Marker>) -> CompletedMarker { |
| 981 | 982 | assert!(p.at(T![try])); |
| 982 | 983 | let m = m.unwrap_or_else(|| p.start()); |
| 984 | let try_modifier = p.start(); | |
| 983 | 985 | p.bump(T![try]); |
| 986 | if p.eat_contextual_kw(T![bikeshed]) { | |
| 987 | type_(p); | |
| 988 | } | |
| 989 | try_modifier.complete(p, TRY_BLOCK_MODIFIER); | |
| 984 | 990 | if p.at(T!['{']) { |
| 985 | 991 | stmt_list(p); |
| 986 | 992 | } else { |
src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs+8| ... | ... | @@ -114,6 +114,7 @@ pub enum SyntaxKind { |
| 114 | 114 | ATT_SYNTAX_KW, |
| 115 | 115 | AUTO_KW, |
| 116 | 116 | AWAIT_KW, |
| 117 | BIKESHED_KW, | |
| 117 | 118 | BUILTIN_KW, |
| 118 | 119 | CLOBBER_ABI_KW, |
| 119 | 120 | DEFAULT_KW, |
| ... | ... | @@ -285,6 +286,7 @@ pub enum SyntaxKind { |
| 285 | 286 | STRUCT, |
| 286 | 287 | TOKEN_TREE, |
| 287 | 288 | TRAIT, |
| 289 | TRY_BLOCK_MODIFIER, | |
| 288 | 290 | TRY_EXPR, |
| 289 | 291 | TUPLE_EXPR, |
| 290 | 292 | TUPLE_FIELD, |
| ... | ... | @@ -458,6 +460,7 @@ impl SyntaxKind { |
| 458 | 460 | | STRUCT |
| 459 | 461 | | TOKEN_TREE |
| 460 | 462 | | TRAIT |
| 463 | | TRY_BLOCK_MODIFIER | |
| 461 | 464 | | TRY_EXPR |
| 462 | 465 | | TUPLE_EXPR |
| 463 | 466 | | TUPLE_FIELD |
| ... | ... | @@ -596,6 +599,7 @@ impl SyntaxKind { |
| 596 | 599 | ASM_KW => "asm", |
| 597 | 600 | ATT_SYNTAX_KW => "att_syntax", |
| 598 | 601 | AUTO_KW => "auto", |
| 602 | BIKESHED_KW => "bikeshed", | |
| 599 | 603 | BUILTIN_KW => "builtin", |
| 600 | 604 | CLOBBER_ABI_KW => "clobber_abi", |
| 601 | 605 | DEFAULT_KW => "default", |
| ... | ... | @@ -698,6 +702,7 @@ impl SyntaxKind { |
| 698 | 702 | ASM_KW => true, |
| 699 | 703 | ATT_SYNTAX_KW => true, |
| 700 | 704 | AUTO_KW => true, |
| 705 | BIKESHED_KW => true, | |
| 701 | 706 | BUILTIN_KW => true, |
| 702 | 707 | CLOBBER_ABI_KW => true, |
| 703 | 708 | DEFAULT_KW => true, |
| ... | ... | @@ -788,6 +793,7 @@ impl SyntaxKind { |
| 788 | 793 | ASM_KW => true, |
| 789 | 794 | ATT_SYNTAX_KW => true, |
| 790 | 795 | AUTO_KW => true, |
| 796 | BIKESHED_KW => true, | |
| 791 | 797 | BUILTIN_KW => true, |
| 792 | 798 | CLOBBER_ABI_KW => true, |
| 793 | 799 | DEFAULT_KW => true, |
| ... | ... | @@ -941,6 +947,7 @@ impl SyntaxKind { |
| 941 | 947 | "asm" => ASM_KW, |
| 942 | 948 | "att_syntax" => ATT_SYNTAX_KW, |
| 943 | 949 | "auto" => AUTO_KW, |
| 950 | "bikeshed" => BIKESHED_KW, | |
| 944 | 951 | "builtin" => BUILTIN_KW, |
| 945 | 952 | "clobber_abi" => CLOBBER_ABI_KW, |
| 946 | 953 | "default" => DEFAULT_KW, |
| ... | ... | @@ -1112,6 +1119,7 @@ macro_rules ! T_ { |
| 1112 | 1119 | [asm] => { $ crate :: SyntaxKind :: ASM_KW }; |
| 1113 | 1120 | [att_syntax] => { $ crate :: SyntaxKind :: ATT_SYNTAX_KW }; |
| 1114 | 1121 | [auto] => { $ crate :: SyntaxKind :: AUTO_KW }; |
| 1122 | [bikeshed] => { $ crate :: SyntaxKind :: BIKESHED_KW }; | |
| 1115 | 1123 | [builtin] => { $ crate :: SyntaxKind :: BUILTIN_KW }; |
| 1116 | 1124 | [clobber_abi] => { $ crate :: SyntaxKind :: CLOBBER_ABI_KW }; |
| 1117 | 1125 | [default] => { $ crate :: SyntaxKind :: DEFAULT_KW }; |
src/tools/rust-analyzer/crates/parser/test_data/parser/err/0042_weird_blocks.rast+2-1| ... | ... | @@ -45,7 +45,8 @@ SOURCE_FILE |
| 45 | 45 | WHITESPACE " " |
| 46 | 46 | EXPR_STMT |
| 47 | 47 | BLOCK_EXPR |
| 48 | TRY_KW "try" | |
| 48 | TRY_BLOCK_MODIFIER | |
| 49 | TRY_KW "try" | |
| 49 | 50 | WHITESPACE " " |
| 50 | 51 | LITERAL |
| 51 | 52 | INT_NUMBER "92" |
src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/try_block_expr.rast+36-1| ... | ... | @@ -21,7 +21,42 @@ SOURCE_FILE |
| 21 | 21 | EQ "=" |
| 22 | 22 | WHITESPACE " " |
| 23 | 23 | BLOCK_EXPR |
| 24 | TRY_KW "try" | |
| 24 | TRY_BLOCK_MODIFIER | |
| 25 | TRY_KW "try" | |
| 26 | WHITESPACE " " | |
| 27 | STMT_LIST | |
| 28 | L_CURLY "{" | |
| 29 | R_CURLY "}" | |
| 30 | SEMICOLON ";" | |
| 31 | WHITESPACE "\n " | |
| 32 | LET_STMT | |
| 33 | LET_KW "let" | |
| 34 | WHITESPACE " " | |
| 35 | WILDCARD_PAT | |
| 36 | UNDERSCORE "_" | |
| 37 | WHITESPACE " " | |
| 38 | EQ "=" | |
| 39 | WHITESPACE " " | |
| 40 | BLOCK_EXPR | |
| 41 | TRY_BLOCK_MODIFIER | |
| 42 | TRY_KW "try" | |
| 43 | WHITESPACE " " | |
| 44 | BIKESHED_KW "bikeshed" | |
| 45 | WHITESPACE " " | |
| 46 | PATH_TYPE | |
| 47 | PATH | |
| 48 | PATH_SEGMENT | |
| 49 | NAME_REF | |
| 50 | IDENT "T" | |
| 51 | GENERIC_ARG_LIST | |
| 52 | L_ANGLE "<" | |
| 53 | TYPE_ARG | |
| 54 | PATH_TYPE | |
| 55 | PATH | |
| 56 | PATH_SEGMENT | |
| 57 | NAME_REF | |
| 58 | IDENT "U" | |
| 59 | R_ANGLE ">" | |
| 25 | 60 | WHITESPACE " " |
| 26 | 61 | STMT_LIST |
| 27 | 62 | L_CURLY "{" |
src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/try_block_expr.rs+1| ... | ... | @@ -1,3 +1,4 @@ |
| 1 | 1 | fn foo() { |
| 2 | 2 | let _ = try {}; |
| 3 | let _ = try bikeshed T<U> {}; | |
| 3 | 4 | } |
src/tools/rust-analyzer/crates/project-model/src/sysroot.rs+5-1| ... | ... | @@ -275,7 +275,10 @@ impl Sysroot { |
| 275 | 275 | } |
| 276 | 276 | tracing::debug!("Stitching sysroot library: {src_root}"); |
| 277 | 277 | |
| 278 | let mut stitched = stitched::Stitched { crates: Default::default() }; | |
| 278 | let mut stitched = stitched::Stitched { | |
| 279 | crates: Default::default(), | |
| 280 | edition: span::Edition::Edition2024, | |
| 281 | }; | |
| 279 | 282 | |
| 280 | 283 | for path in stitched::SYSROOT_CRATES.trim().lines() { |
| 281 | 284 | let name = path.split('/').next_back().unwrap(); |
| ... | ... | @@ -511,6 +514,7 @@ pub(crate) mod stitched { |
| 511 | 514 | #[derive(Debug, Clone, Eq, PartialEq)] |
| 512 | 515 | pub struct Stitched { |
| 513 | 516 | pub(super) crates: Arena<RustLibSrcCrateData>, |
| 517 | pub(crate) edition: span::Edition, | |
| 514 | 518 | } |
| 515 | 519 | |
| 516 | 520 | impl ops::Index<RustLibSrcCrate> for Stitched { |
src/tools/rust-analyzer/crates/project-model/src/workspace.rs+1-1| ... | ... | @@ -1831,7 +1831,7 @@ fn sysroot_to_crate_graph( |
| 1831 | 1831 | let display_name = CrateDisplayName::from_canonical_name(&stitched[krate].name); |
| 1832 | 1832 | let crate_id = crate_graph.add_crate_root( |
| 1833 | 1833 | file_id, |
| 1834 | Edition::CURRENT_FIXME, | |
| 1834 | stitched.edition, | |
| 1835 | 1835 | Some(display_name), |
| 1836 | 1836 | None, |
| 1837 | 1837 | cfg_options.clone(), |
src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs+145-143| ... | ... | @@ -22,7 +22,6 @@ use serde_derive::Deserialize; |
| 22 | 22 | pub(crate) use cargo_metadata::diagnostic::{ |
| 23 | 23 | Applicability, Diagnostic, DiagnosticCode, DiagnosticLevel, DiagnosticSpan, |
| 24 | 24 | }; |
| 25 | use toolchain::DISPLAY_COMMAND_IGNORE_ENVS; | |
| 26 | 25 | use toolchain::Tool; |
| 27 | 26 | use triomphe::Arc; |
| 28 | 27 | |
| ... | ... | @@ -144,6 +143,7 @@ impl FlycheckConfig { |
| 144 | 143 | } |
| 145 | 144 | |
| 146 | 145 | impl fmt::Display for FlycheckConfig { |
| 146 | /// Show a shortened version of the check command. | |
| 147 | 147 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 148 | 148 | match self { |
| 149 | 149 | FlycheckConfig::Automatic { cargo_options, .. } => { |
| ... | ... | @@ -153,12 +153,23 @@ impl fmt::Display for FlycheckConfig { |
| 153 | 153 | // Don't show `my_custom_check --foo $saved_file` literally to the user, as it |
| 154 | 154 | // looks like we've forgotten to substitute $saved_file. |
| 155 | 155 | // |
| 156 | // `my_custom_check --foo /home/user/project/src/dir/foo.rs` is too verbose. | |
| 157 | // | |
| 156 | 158 | // Instead, show `my_custom_check --foo ...`. The |
| 157 | 159 | // actual path is often too long to be worth showing |
| 158 | 160 | // in the IDE (e.g. in the VS Code status bar). |
| 159 | 161 | let display_args = args |
| 160 | 162 | .iter() |
| 161 | .map(|arg| if arg == SAVED_FILE_PLACEHOLDER_DOLLAR { "..." } else { arg }) | |
| 163 | .map(|arg| { | |
| 164 | if (arg == SAVED_FILE_PLACEHOLDER_DOLLAR) | |
| 165 | || (arg == SAVED_FILE_INLINE) | |
| 166 | || arg.ends_with(".rs") | |
| 167 | { | |
| 168 | "..." | |
| 169 | } else { | |
| 170 | arg | |
| 171 | } | |
| 172 | }) | |
| 162 | 173 | .collect::<Vec<_>>(); |
| 163 | 174 | |
| 164 | 175 | write!(f, "{command} {}", display_args.join(" ")) |
| ... | ... | @@ -403,24 +414,30 @@ struct FlycheckActor { |
| 403 | 414 | /// doesn't provide a way to read sub-process output without blocking, so we |
| 404 | 415 | /// have to wrap sub-processes output handling in a thread and pass messages |
| 405 | 416 | /// back over a channel. |
| 406 | command_handle: Option<CommandHandle<CargoCheckMessage>>, | |
| 417 | command_handle: Option<CommandHandle<CheckMessage>>, | |
| 407 | 418 | /// The receiver side of the channel mentioned above. |
| 408 | command_receiver: Option<Receiver<CargoCheckMessage>>, | |
| 419 | command_receiver: Option<Receiver<CheckMessage>>, | |
| 409 | 420 | diagnostics_cleared_for: FxHashSet<PackageSpecifier>, |
| 410 | 421 | diagnostics_received: DiagnosticsReceived, |
| 411 | 422 | } |
| 412 | 423 | |
| 413 | #[derive(PartialEq)] | |
| 424 | #[derive(PartialEq, Debug)] | |
| 414 | 425 | enum DiagnosticsReceived { |
| 415 | Yes, | |
| 416 | No, | |
| 417 | YesAndClearedForAll, | |
| 426 | /// We started a flycheck, but we haven't seen any diagnostics yet. | |
| 427 | NotYet, | |
| 428 | /// We received a non-zero number of diagnostics from rustc or clippy (via | |
| 429 | /// cargo or custom check command). This means there were errors or | |
| 430 | /// warnings. | |
| 431 | AtLeastOne, | |
| 432 | /// We received a non-zero number of diagnostics, and the scope is | |
| 433 | /// workspace, so we've discarded the previous workspace diagnostics. | |
| 434 | AtLeastOneAndClearedWorkspace, | |
| 418 | 435 | } |
| 419 | 436 | |
| 420 | 437 | #[allow(clippy::large_enum_variant)] |
| 421 | 438 | enum Event { |
| 422 | 439 | RequestStateChange(StateChange), |
| 423 | CheckEvent(Option<CargoCheckMessage>), | |
| 440 | CheckEvent(Option<CheckMessage>), | |
| 424 | 441 | } |
| 425 | 442 | |
| 426 | 443 | /// This is stable behaviour. Don't change. |
| ... | ... | @@ -511,7 +528,7 @@ impl FlycheckActor { |
| 511 | 528 | command_handle: None, |
| 512 | 529 | command_receiver: None, |
| 513 | 530 | diagnostics_cleared_for: Default::default(), |
| 514 | diagnostics_received: DiagnosticsReceived::No, | |
| 531 | diagnostics_received: DiagnosticsReceived::NotYet, | |
| 515 | 532 | } |
| 516 | 533 | } |
| 517 | 534 | |
| ... | ... | @@ -563,23 +580,13 @@ impl FlycheckActor { |
| 563 | 580 | }; |
| 564 | 581 | |
| 565 | 582 | let debug_command = format!("{command:?}"); |
| 566 | let user_facing_command = match origin { | |
| 567 | // Don't show all the --format=json-with-blah-blah args, just the simple | |
| 568 | // version | |
| 569 | FlycheckCommandOrigin::Cargo => self.config.to_string(), | |
| 570 | // show them the full command but pretty printed. advanced user | |
| 571 | FlycheckCommandOrigin::ProjectJsonRunnable | |
| 572 | | FlycheckCommandOrigin::CheckOverrideCommand => display_command( | |
| 573 | &command, | |
| 574 | Some(std::path::Path::new(self.root.as_path())), | |
| 575 | ), | |
| 576 | }; | |
| 583 | let user_facing_command = self.config.to_string(); | |
| 577 | 584 | |
| 578 | 585 | tracing::debug!(?origin, ?command, "will restart flycheck"); |
| 579 | 586 | let (sender, receiver) = unbounded(); |
| 580 | 587 | match CommandHandle::spawn( |
| 581 | 588 | command, |
| 582 | CargoCheckParser, | |
| 589 | CheckParser, | |
| 583 | 590 | sender, |
| 584 | 591 | match &self.config { |
| 585 | 592 | FlycheckConfig::Automatic { cargo_options, .. } => { |
| ... | ... | @@ -640,7 +647,7 @@ impl FlycheckActor { |
| 640 | 647 | error |
| 641 | 648 | ); |
| 642 | 649 | } |
| 643 | if self.diagnostics_received == DiagnosticsReceived::No { | |
| 650 | if self.diagnostics_received == DiagnosticsReceived::NotYet { | |
| 644 | 651 | tracing::trace!(flycheck_id = self.id, "clearing diagnostics"); |
| 645 | 652 | // We finished without receiving any diagnostics. |
| 646 | 653 | // Clear everything for good measure |
| ... | ... | @@ -699,7 +706,7 @@ impl FlycheckActor { |
| 699 | 706 | self.report_progress(Progress::DidFinish(res)); |
| 700 | 707 | } |
| 701 | 708 | Event::CheckEvent(Some(message)) => match message { |
| 702 | CargoCheckMessage::CompilerArtifact(msg) => { | |
| 709 | CheckMessage::CompilerArtifact(msg) => { | |
| 703 | 710 | tracing::trace!( |
| 704 | 711 | flycheck_id = self.id, |
| 705 | 712 | artifact = msg.target.name, |
| ... | ... | @@ -729,46 +736,75 @@ impl FlycheckActor { |
| 729 | 736 | }); |
| 730 | 737 | } |
| 731 | 738 | } |
| 732 | CargoCheckMessage::Diagnostic { diagnostic, package_id } => { | |
| 739 | CheckMessage::Diagnostic { diagnostic, package_id } => { | |
| 733 | 740 | tracing::trace!( |
| 734 | 741 | flycheck_id = self.id, |
| 735 | 742 | message = diagnostic.message, |
| 736 | 743 | package_id = package_id.as_ref().map(|it| it.as_str()), |
| 744 | scope = ?self.scope, | |
| 737 | 745 | "diagnostic received" |
| 738 | 746 | ); |
| 739 | if self.diagnostics_received == DiagnosticsReceived::No { | |
| 740 | self.diagnostics_received = DiagnosticsReceived::Yes; | |
| 741 | } | |
| 742 | if let Some(package_id) = &package_id { | |
| 743 | if self.diagnostics_cleared_for.insert(package_id.clone()) { | |
| 744 | tracing::trace!( | |
| 745 | flycheck_id = self.id, | |
| 746 | package_id = package_id.as_str(), | |
| 747 | "clearing diagnostics" | |
| 748 | ); | |
| 749 | self.send(FlycheckMessage::ClearDiagnostics { | |
| 747 | ||
| 748 | match &self.scope { | |
| 749 | FlycheckScope::Workspace => { | |
| 750 | if self.diagnostics_received == DiagnosticsReceived::NotYet { | |
| 751 | self.send(FlycheckMessage::ClearDiagnostics { | |
| 752 | id: self.id, | |
| 753 | kind: ClearDiagnosticsKind::All(ClearScope::Workspace), | |
| 754 | }); | |
| 755 | ||
| 756 | self.diagnostics_received = | |
| 757 | DiagnosticsReceived::AtLeastOneAndClearedWorkspace; | |
| 758 | } | |
| 759 | ||
| 760 | if let Some(package_id) = package_id { | |
| 761 | tracing::warn!( | |
| 762 | "Ignoring package label {:?} and applying diagnostics to the whole workspace", | |
| 763 | package_id | |
| 764 | ); | |
| 765 | } | |
| 766 | ||
| 767 | self.send(FlycheckMessage::AddDiagnostic { | |
| 750 | 768 | id: self.id, |
| 751 | kind: ClearDiagnosticsKind::All(ClearScope::Package( | |
| 752 | package_id.clone(), | |
| 753 | )), | |
| 769 | generation: self.generation, | |
| 770 | package_id: None, | |
| 771 | workspace_root: self.root.clone(), | |
| 772 | diagnostic, | |
| 773 | }); | |
| 774 | } | |
| 775 | FlycheckScope::Package { package: flycheck_package, .. } => { | |
| 776 | if self.diagnostics_received == DiagnosticsReceived::NotYet { | |
| 777 | self.diagnostics_received = DiagnosticsReceived::AtLeastOne; | |
| 778 | } | |
| 779 | ||
| 780 | // If the package has been set in the diagnostic JSON, respect that. Otherwise, use the | |
| 781 | // package that the current flycheck is scoped to. This is useful when a project is | |
| 782 | // directly using rustc for its checks (e.g. custom check commands in rust-project.json). | |
| 783 | let package_id = package_id.unwrap_or(flycheck_package.clone()); | |
| 784 | ||
| 785 | if self.diagnostics_cleared_for.insert(package_id.clone()) { | |
| 786 | tracing::trace!( | |
| 787 | flycheck_id = self.id, | |
| 788 | package_id = package_id.as_str(), | |
| 789 | "clearing diagnostics" | |
| 790 | ); | |
| 791 | self.send(FlycheckMessage::ClearDiagnostics { | |
| 792 | id: self.id, | |
| 793 | kind: ClearDiagnosticsKind::All(ClearScope::Package( | |
| 794 | package_id.clone(), | |
| 795 | )), | |
| 796 | }); | |
| 797 | } | |
| 798 | ||
| 799 | self.send(FlycheckMessage::AddDiagnostic { | |
| 800 | id: self.id, | |
| 801 | generation: self.generation, | |
| 802 | package_id: Some(package_id), | |
| 803 | workspace_root: self.root.clone(), | |
| 804 | diagnostic, | |
| 754 | 805 | }); |
| 755 | 806 | } |
| 756 | } else if self.diagnostics_received | |
| 757 | != DiagnosticsReceived::YesAndClearedForAll | |
| 758 | { | |
| 759 | self.diagnostics_received = DiagnosticsReceived::YesAndClearedForAll; | |
| 760 | self.send(FlycheckMessage::ClearDiagnostics { | |
| 761 | id: self.id, | |
| 762 | kind: ClearDiagnosticsKind::All(ClearScope::Workspace), | |
| 763 | }); | |
| 764 | 807 | } |
| 765 | self.send(FlycheckMessage::AddDiagnostic { | |
| 766 | id: self.id, | |
| 767 | generation: self.generation, | |
| 768 | package_id, | |
| 769 | workspace_root: self.root.clone(), | |
| 770 | diagnostic, | |
| 771 | }); | |
| 772 | 808 | } |
| 773 | 809 | }, |
| 774 | 810 | } |
| ... | ... | @@ -792,7 +828,7 @@ impl FlycheckActor { |
| 792 | 828 | |
| 793 | 829 | fn clear_diagnostics_state(&mut self) { |
| 794 | 830 | self.diagnostics_cleared_for.clear(); |
| 795 | self.diagnostics_received = DiagnosticsReceived::No; | |
| 831 | self.diagnostics_received = DiagnosticsReceived::NotYet; | |
| 796 | 832 | } |
| 797 | 833 | |
| 798 | 834 | fn explicit_check_command( |
| ... | ... | @@ -942,15 +978,18 @@ impl FlycheckActor { |
| 942 | 978 | } |
| 943 | 979 | |
| 944 | 980 | #[allow(clippy::large_enum_variant)] |
| 945 | enum CargoCheckMessage { | |
| 981 | enum CheckMessage { | |
| 982 | /// A message from `cargo check`, including details like the path | |
| 983 | /// to the relevant `Cargo.toml`. | |
| 946 | 984 | CompilerArtifact(cargo_metadata::Artifact), |
| 985 | /// A diagnostic message from rustc itself. | |
| 947 | 986 | Diagnostic { diagnostic: Diagnostic, package_id: Option<PackageSpecifier> }, |
| 948 | 987 | } |
| 949 | 988 | |
| 950 | struct CargoCheckParser; | |
| 989 | struct CheckParser; | |
| 951 | 990 | |
| 952 | impl JsonLinesParser<CargoCheckMessage> for CargoCheckParser { | |
| 953 | fn from_line(&self, line: &str, error: &mut String) -> Option<CargoCheckMessage> { | |
| 991 | impl JsonLinesParser<CheckMessage> for CheckParser { | |
| 992 | fn from_line(&self, line: &str, error: &mut String) -> Option<CheckMessage> { | |
| 954 | 993 | let mut deserializer = serde_json::Deserializer::from_str(line); |
| 955 | 994 | deserializer.disable_recursion_limit(); |
| 956 | 995 | if let Ok(message) = JsonMessage::deserialize(&mut deserializer) { |
| ... | ... | @@ -958,10 +997,10 @@ impl JsonLinesParser<CargoCheckMessage> for CargoCheckParser { |
| 958 | 997 | // Skip certain kinds of messages to only spend time on what's useful |
| 959 | 998 | JsonMessage::Cargo(message) => match message { |
| 960 | 999 | cargo_metadata::Message::CompilerArtifact(artifact) if !artifact.fresh => { |
| 961 | Some(CargoCheckMessage::CompilerArtifact(artifact)) | |
| 1000 | Some(CheckMessage::CompilerArtifact(artifact)) | |
| 962 | 1001 | } |
| 963 | 1002 | cargo_metadata::Message::CompilerMessage(msg) => { |
| 964 | Some(CargoCheckMessage::Diagnostic { | |
| 1003 | Some(CheckMessage::Diagnostic { | |
| 965 | 1004 | diagnostic: msg.message, |
| 966 | 1005 | package_id: Some(PackageSpecifier::Cargo { |
| 967 | 1006 | package_id: Arc::new(msg.package_id), |
| ... | ... | @@ -971,7 +1010,7 @@ impl JsonLinesParser<CargoCheckMessage> for CargoCheckParser { |
| 971 | 1010 | _ => None, |
| 972 | 1011 | }, |
| 973 | 1012 | JsonMessage::Rustc(message) => { |
| 974 | Some(CargoCheckMessage::Diagnostic { diagnostic: message, package_id: None }) | |
| 1013 | Some(CheckMessage::Diagnostic { diagnostic: message, package_id: None }) | |
| 975 | 1014 | } |
| 976 | 1015 | }; |
| 977 | 1016 | } |
| ... | ... | @@ -981,7 +1020,7 @@ impl JsonLinesParser<CargoCheckMessage> for CargoCheckParser { |
| 981 | 1020 | None |
| 982 | 1021 | } |
| 983 | 1022 | |
| 984 | fn from_eof(&self) -> Option<CargoCheckMessage> { | |
| 1023 | fn from_eof(&self) -> Option<CheckMessage> { | |
| 985 | 1024 | None |
| 986 | 1025 | } |
| 987 | 1026 | } |
| ... | ... | @@ -993,64 +1032,14 @@ enum JsonMessage { |
| 993 | 1032 | Rustc(Diagnostic), |
| 994 | 1033 | } |
| 995 | 1034 | |
| 996 | /// Not good enough to execute in a shell, but good enough to show the user without all the noisy | |
| 997 | /// quotes | |
| 998 | /// | |
| 999 | /// Pass implicit_cwd if there is one regarded as the obvious by the user, so we can skip showing it. | |
| 1000 | /// Compactness is the aim of the game, the output typically gets truncated quite a lot. | |
| 1001 | fn display_command(c: &Command, implicit_cwd: Option<&std::path::Path>) -> String { | |
| 1002 | let mut o = String::new(); | |
| 1003 | use std::fmt::Write; | |
| 1004 | let lossy = std::ffi::OsStr::to_string_lossy; | |
| 1005 | if let Some(dir) = c.get_current_dir() { | |
| 1006 | if Some(dir) == implicit_cwd.map(std::path::Path::new) { | |
| 1007 | // pass | |
| 1008 | } else if dir.to_string_lossy().contains(" ") { | |
| 1009 | write!(o, "cd {:?} && ", dir).unwrap(); | |
| 1010 | } else { | |
| 1011 | write!(o, "cd {} && ", dir.display()).unwrap(); | |
| 1012 | } | |
| 1013 | } | |
| 1014 | for (env, val) in c.get_envs() { | |
| 1015 | let (env, val) = (lossy(env), val.map(lossy).unwrap_or(std::borrow::Cow::Borrowed(""))); | |
| 1016 | if DISPLAY_COMMAND_IGNORE_ENVS.contains(&env.as_ref()) { | |
| 1017 | continue; | |
| 1018 | } | |
| 1019 | if env.contains(" ") { | |
| 1020 | write!(o, "\"{}={}\" ", env, val).unwrap(); | |
| 1021 | } else if val.contains(" ") { | |
| 1022 | write!(o, "{}=\"{}\" ", env, val).unwrap(); | |
| 1023 | } else { | |
| 1024 | write!(o, "{}={} ", env, val).unwrap(); | |
| 1025 | } | |
| 1026 | } | |
| 1027 | let prog = lossy(c.get_program()); | |
| 1028 | if prog.contains(" ") { | |
| 1029 | write!(o, "{:?}", prog).unwrap(); | |
| 1030 | } else { | |
| 1031 | write!(o, "{}", prog).unwrap(); | |
| 1032 | } | |
| 1033 | for arg in c.get_args() { | |
| 1034 | let arg = lossy(arg); | |
| 1035 | if arg.contains(" ") { | |
| 1036 | write!(o, " \"{}\"", arg).unwrap(); | |
| 1037 | } else { | |
| 1038 | write!(o, " {}", arg).unwrap(); | |
| 1039 | } | |
| 1040 | } | |
| 1041 | o | |
| 1042 | } | |
| 1043 | ||
| 1044 | 1035 | #[cfg(test)] |
| 1045 | 1036 | mod tests { |
| 1037 | use super::*; | |
| 1046 | 1038 | use ide_db::FxHashMap; |
| 1047 | 1039 | use itertools::Itertools; |
| 1048 | 1040 | use paths::Utf8Path; |
| 1049 | 1041 | use project_model::project_json; |
| 1050 | 1042 | |
| 1051 | use crate::flycheck::Substitutions; | |
| 1052 | use crate::flycheck::display_command; | |
| 1053 | ||
| 1054 | 1043 | #[test] |
| 1055 | 1044 | fn test_substitutions() { |
| 1056 | 1045 | let label = ":label"; |
| ... | ... | @@ -1139,34 +1128,47 @@ mod tests { |
| 1139 | 1128 | } |
| 1140 | 1129 | |
| 1141 | 1130 | #[test] |
| 1142 | fn test_display_command() { | |
| 1143 | use std::path::Path; | |
| 1144 | let workdir = Path::new("workdir"); | |
| 1145 | let mut cmd = toolchain::command("command", workdir, &FxHashMap::default()); | |
| 1146 | assert_eq!(display_command(cmd.arg("--arg"), Some(workdir)), "command --arg"); | |
| 1147 | assert_eq!( | |
| 1148 | display_command(cmd.arg("spaced arg"), Some(workdir)), | |
| 1149 | "command --arg \"spaced arg\"" | |
| 1150 | ); | |
| 1151 | assert_eq!( | |
| 1152 | display_command(cmd.env("ENVIRON", "yeah"), Some(workdir)), | |
| 1153 | "ENVIRON=yeah command --arg \"spaced arg\"" | |
| 1154 | ); | |
| 1155 | assert_eq!( | |
| 1156 | display_command(cmd.env("OTHER", "spaced env"), Some(workdir)), | |
| 1157 | "ENVIRON=yeah OTHER=\"spaced env\" command --arg \"spaced arg\"" | |
| 1158 | ); | |
| 1159 | assert_eq!( | |
| 1160 | display_command(cmd.current_dir("/tmp"), Some(workdir)), | |
| 1161 | "cd /tmp && ENVIRON=yeah OTHER=\"spaced env\" command --arg \"spaced arg\"" | |
| 1162 | ); | |
| 1163 | assert_eq!( | |
| 1164 | display_command(cmd.current_dir("/tmp and/thing"), Some(workdir)), | |
| 1165 | "cd \"/tmp and/thing\" && ENVIRON=yeah OTHER=\"spaced env\" command --arg \"spaced arg\"" | |
| 1166 | ); | |
| 1167 | assert_eq!( | |
| 1168 | display_command(cmd.current_dir("/tmp and/thing"), Some(Path::new("/tmp and/thing"))), | |
| 1169 | "ENVIRON=yeah OTHER=\"spaced env\" command --arg \"spaced arg\"" | |
| 1170 | ); | |
| 1131 | fn test_flycheck_config_display() { | |
| 1132 | let clippy = FlycheckConfig::Automatic { | |
| 1133 | cargo_options: CargoOptions { | |
| 1134 | subcommand: "clippy".to_owned(), | |
| 1135 | target_tuples: vec![], | |
| 1136 | all_targets: false, | |
| 1137 | set_test: false, | |
| 1138 | no_default_features: false, | |
| 1139 | all_features: false, | |
| 1140 | features: vec![], | |
| 1141 | extra_args: vec![], | |
| 1142 | extra_test_bin_args: vec![], | |
| 1143 | extra_env: FxHashMap::default(), | |
| 1144 | target_dir_config: TargetDirectoryConfig::default(), | |
| 1145 | }, | |
| 1146 | ansi_color_output: true, | |
| 1147 | }; | |
| 1148 | assert_eq!(clippy.to_string(), "cargo clippy"); | |
| 1149 | ||
| 1150 | let custom_dollar = FlycheckConfig::CustomCommand { | |
| 1151 | command: "check".to_owned(), | |
| 1152 | args: vec!["--input".to_owned(), "$saved_file".to_owned()], | |
| 1153 | extra_env: FxHashMap::default(), | |
| 1154 | invocation_strategy: InvocationStrategy::Once, | |
| 1155 | }; | |
| 1156 | assert_eq!(custom_dollar.to_string(), "check --input ..."); | |
| 1157 | ||
| 1158 | let custom_inline = FlycheckConfig::CustomCommand { | |
| 1159 | command: "check".to_owned(), | |
| 1160 | args: vec!["--input".to_owned(), "{saved_file}".to_owned()], | |
| 1161 | extra_env: FxHashMap::default(), | |
| 1162 | invocation_strategy: InvocationStrategy::Once, | |
| 1163 | }; | |
| 1164 | assert_eq!(custom_inline.to_string(), "check --input ..."); | |
| 1165 | ||
| 1166 | let custom_rs = FlycheckConfig::CustomCommand { | |
| 1167 | command: "check".to_owned(), | |
| 1168 | args: vec!["--input".to_owned(), "/path/to/file.rs".to_owned()], | |
| 1169 | extra_env: FxHashMap::default(), | |
| 1170 | invocation_strategy: InvocationStrategy::Once, | |
| 1171 | }; | |
| 1172 | assert_eq!(custom_rs.to_string(), "check --input ..."); | |
| 1171 | 1173 | } |
| 1172 | 1174 | } |
src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs+7-1| ... | ... | @@ -14,7 +14,7 @@ use hir::ChangeWithProcMacros; |
| 14 | 14 | use ide::{Analysis, AnalysisHost, Cancellable, FileId, SourceRootId}; |
| 15 | 15 | use ide_db::{ |
| 16 | 16 | MiniCore, |
| 17 | base_db::{Crate, ProcMacroPaths, SourceDatabase, salsa::Revision}, | |
| 17 | base_db::{Crate, ProcMacroPaths, SourceDatabase, salsa::CancellationToken, salsa::Revision}, | |
| 18 | 18 | }; |
| 19 | 19 | use itertools::Itertools; |
| 20 | 20 | use load_cargo::SourceRootConfig; |
| ... | ... | @@ -88,6 +88,7 @@ pub(crate) struct GlobalState { |
| 88 | 88 | pub(crate) task_pool: Handle<TaskPool<Task>, Receiver<Task>>, |
| 89 | 89 | pub(crate) fmt_pool: Handle<TaskPool<Task>, Receiver<Task>>, |
| 90 | 90 | pub(crate) cancellation_pool: thread::Pool, |
| 91 | pub(crate) cancellation_tokens: FxHashMap<lsp_server::RequestId, CancellationToken>, | |
| 91 | 92 | |
| 92 | 93 | pub(crate) config: Arc<Config>, |
| 93 | 94 | pub(crate) config_errors: Option<ConfigErrors>, |
| ... | ... | @@ -265,6 +266,7 @@ impl GlobalState { |
| 265 | 266 | task_pool, |
| 266 | 267 | fmt_pool, |
| 267 | 268 | cancellation_pool, |
| 269 | cancellation_tokens: Default::default(), | |
| 268 | 270 | loader, |
| 269 | 271 | config: Arc::new(config.clone()), |
| 270 | 272 | analysis_host, |
| ... | ... | @@ -617,6 +619,7 @@ impl GlobalState { |
| 617 | 619 | } |
| 618 | 620 | |
| 619 | 621 | pub(crate) fn respond(&mut self, response: lsp_server::Response) { |
| 622 | self.cancellation_tokens.remove(&response.id); | |
| 620 | 623 | if let Some((method, start)) = self.req_queue.incoming.complete(&response.id) { |
| 621 | 624 | if let Some(err) = &response.error |
| 622 | 625 | && err.message.starts_with("server panicked") |
| ... | ... | @@ -631,6 +634,9 @@ impl GlobalState { |
| 631 | 634 | } |
| 632 | 635 | |
| 633 | 636 | pub(crate) fn cancel(&mut self, request_id: lsp_server::RequestId) { |
| 637 | if let Some(token) = self.cancellation_tokens.remove(&request_id) { | |
| 638 | token.cancel(); | |
| 639 | } | |
| 634 | 640 | if let Some(response) = self.req_queue.incoming.cancel(request_id) { |
| 635 | 641 | self.send(response.into()); |
| 636 | 642 | } |
src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs+16-1| ... | ... | @@ -253,6 +253,9 @@ impl RequestDispatcher<'_> { |
| 253 | 253 | tracing::debug!(?params); |
| 254 | 254 | |
| 255 | 255 | let world = self.global_state.snapshot(); |
| 256 | self.global_state | |
| 257 | .cancellation_tokens | |
| 258 | .insert(req.id.clone(), world.analysis.cancellation_token()); | |
| 256 | 259 | if RUSTFMT { |
| 257 | 260 | &mut self.global_state.fmt_pool.handle |
| 258 | 261 | } else { |
| ... | ... | @@ -265,7 +268,19 @@ impl RequestDispatcher<'_> { |
| 265 | 268 | }); |
| 266 | 269 | match thread_result_to_response::<R>(req.id.clone(), result) { |
| 267 | 270 | Ok(response) => Task::Response(response), |
| 268 | Err(_cancelled) if ALLOW_RETRYING => Task::Retry(req), | |
| 271 | Err(HandlerCancelledError::Inner( | |
| 272 | Cancelled::PendingWrite | Cancelled::PropagatedPanic, | |
| 273 | )) if ALLOW_RETRYING => Task::Retry(req), | |
| 274 | // Note: Technically the return value here does not matter as we have already responded to the client with this error. | |
| 275 | Err(HandlerCancelledError::Inner(Cancelled::Local)) => Task::Response(Response { | |
| 276 | id: req.id, | |
| 277 | result: None, | |
| 278 | error: Some(ResponseError { | |
| 279 | code: lsp_server::ErrorCode::RequestCanceled as i32, | |
| 280 | message: "canceled by client".to_owned(), | |
| 281 | data: None, | |
| 282 | }), | |
| 283 | }), | |
| 269 | 284 | Err(_cancelled) => { |
| 270 | 285 | let error = on_cancelled(); |
| 271 | 286 | Task::Response(Response { id: req.id, result: None, error: Some(error) }) |
src/tools/rust-analyzer/crates/span/src/hygiene.rs+25-26| ... | ... | @@ -81,25 +81,24 @@ const _: () = { |
| 81 | 81 | #[derive(Hash)] |
| 82 | 82 | struct StructKey<'db, T0, T1, T2, T3>(T0, T1, T2, T3, std::marker::PhantomData<&'db ()>); |
| 83 | 83 | |
| 84 | impl<'db, T0, T1, T2, T3> zalsa_::interned::HashEqLike<StructKey<'db, T0, T1, T2, T3>> | |
| 85 | for SyntaxContextData | |
| 84 | impl<'db, T0, T1, T2, T3> zalsa_::HashEqLike<StructKey<'db, T0, T1, T2, T3>> for SyntaxContextData | |
| 86 | 85 | where |
| 87 | Option<MacroCallId>: zalsa_::interned::HashEqLike<T0>, | |
| 88 | Transparency: zalsa_::interned::HashEqLike<T1>, | |
| 89 | Edition: zalsa_::interned::HashEqLike<T2>, | |
| 90 | SyntaxContext: zalsa_::interned::HashEqLike<T3>, | |
| 86 | Option<MacroCallId>: zalsa_::HashEqLike<T0>, | |
| 87 | Transparency: zalsa_::HashEqLike<T1>, | |
| 88 | Edition: zalsa_::HashEqLike<T2>, | |
| 89 | SyntaxContext: zalsa_::HashEqLike<T3>, | |
| 91 | 90 | { |
| 92 | 91 | fn hash<H: std::hash::Hasher>(&self, h: &mut H) { |
| 93 | zalsa_::interned::HashEqLike::<T0>::hash(&self.outer_expn, &mut *h); | |
| 94 | zalsa_::interned::HashEqLike::<T1>::hash(&self.outer_transparency, &mut *h); | |
| 95 | zalsa_::interned::HashEqLike::<T2>::hash(&self.edition, &mut *h); | |
| 96 | zalsa_::interned::HashEqLike::<T3>::hash(&self.parent, &mut *h); | |
| 92 | zalsa_::HashEqLike::<T0>::hash(&self.outer_expn, &mut *h); | |
| 93 | zalsa_::HashEqLike::<T1>::hash(&self.outer_transparency, &mut *h); | |
| 94 | zalsa_::HashEqLike::<T2>::hash(&self.edition, &mut *h); | |
| 95 | zalsa_::HashEqLike::<T3>::hash(&self.parent, &mut *h); | |
| 97 | 96 | } |
| 98 | 97 | fn eq(&self, data: &StructKey<'db, T0, T1, T2, T3>) -> bool { |
| 99 | zalsa_::interned::HashEqLike::<T0>::eq(&self.outer_expn, &data.0) | |
| 100 | && zalsa_::interned::HashEqLike::<T1>::eq(&self.outer_transparency, &data.1) | |
| 101 | && zalsa_::interned::HashEqLike::<T2>::eq(&self.edition, &data.2) | |
| 102 | && zalsa_::interned::HashEqLike::<T3>::eq(&self.parent, &data.3) | |
| 98 | zalsa_::HashEqLike::<T0>::eq(&self.outer_expn, &data.0) | |
| 99 | && zalsa_::HashEqLike::<T1>::eq(&self.outer_transparency, &data.1) | |
| 100 | && zalsa_::HashEqLike::<T2>::eq(&self.edition, &data.2) | |
| 101 | && zalsa_::HashEqLike::<T3>::eq(&self.parent, &data.3) | |
| 103 | 102 | } |
| 104 | 103 | } |
| 105 | 104 | impl zalsa_struct_::Configuration for SyntaxContext { |
| ... | ... | @@ -203,10 +202,10 @@ const _: () = { |
| 203 | 202 | impl<'db> SyntaxContext { |
| 204 | 203 | pub fn new< |
| 205 | 204 | Db, |
| 206 | T0: zalsa_::interned::Lookup<Option<MacroCallId>> + std::hash::Hash, | |
| 207 | T1: zalsa_::interned::Lookup<Transparency> + std::hash::Hash, | |
| 208 | T2: zalsa_::interned::Lookup<Edition> + std::hash::Hash, | |
| 209 | T3: zalsa_::interned::Lookup<SyntaxContext> + std::hash::Hash, | |
| 205 | T0: zalsa_::Lookup<Option<MacroCallId>> + std::hash::Hash, | |
| 206 | T1: zalsa_::Lookup<Transparency> + std::hash::Hash, | |
| 207 | T2: zalsa_::Lookup<Edition> + std::hash::Hash, | |
| 208 | T3: zalsa_::Lookup<SyntaxContext> + std::hash::Hash, | |
| 210 | 209 | >( |
| 211 | 210 | db: &'db Db, |
| 212 | 211 | outer_expn: T0, |
| ... | ... | @@ -218,10 +217,10 @@ const _: () = { |
| 218 | 217 | ) -> Self |
| 219 | 218 | where |
| 220 | 219 | Db: ?Sized + salsa::Database, |
| 221 | Option<MacroCallId>: zalsa_::interned::HashEqLike<T0>, | |
| 222 | Transparency: zalsa_::interned::HashEqLike<T1>, | |
| 223 | Edition: zalsa_::interned::HashEqLike<T2>, | |
| 224 | SyntaxContext: zalsa_::interned::HashEqLike<T3>, | |
| 220 | Option<MacroCallId>: zalsa_::HashEqLike<T0>, | |
| 221 | Transparency: zalsa_::HashEqLike<T1>, | |
| 222 | Edition: zalsa_::HashEqLike<T2>, | |
| 223 | SyntaxContext: zalsa_::HashEqLike<T3>, | |
| 225 | 224 | { |
| 226 | 225 | let (zalsa, zalsa_local) = db.zalsas(); |
| 227 | 226 | |
| ... | ... | @@ -236,10 +235,10 @@ const _: () = { |
| 236 | 235 | std::marker::PhantomData, |
| 237 | 236 | ), |
| 238 | 237 | |id, data| SyntaxContextData { |
| 239 | outer_expn: zalsa_::interned::Lookup::into_owned(data.0), | |
| 240 | outer_transparency: zalsa_::interned::Lookup::into_owned(data.1), | |
| 241 | edition: zalsa_::interned::Lookup::into_owned(data.2), | |
| 242 | parent: zalsa_::interned::Lookup::into_owned(data.3), | |
| 238 | outer_expn: zalsa_::Lookup::into_owned(data.0), | |
| 239 | outer_transparency: zalsa_::Lookup::into_owned(data.1), | |
| 240 | edition: zalsa_::Lookup::into_owned(data.2), | |
| 241 | parent: zalsa_::Lookup::into_owned(data.3), | |
| 243 | 242 | opaque: opaque(zalsa_::FromId::from_id(id)), |
| 244 | 243 | opaque_and_semiopaque: opaque_and_semiopaque(zalsa_::FromId::from_id(id)), |
| 245 | 244 | }, |
src/tools/rust-analyzer/crates/syntax/rust.ungram+4-1| ... | ... | @@ -472,8 +472,11 @@ RefExpr = |
| 472 | 472 | TryExpr = |
| 473 | 473 | Attr* Expr '?' |
| 474 | 474 | |
| 475 | TryBlockModifier = | |
| 476 | 'try' ('bikeshed' Type)? | |
| 477 | ||
| 475 | 478 | BlockExpr = |
| 476 | Attr* Label? ('try' | 'unsafe' | ('async' 'move'?) | ('gen' 'move'?) | 'const') StmtList | |
| 479 | Attr* Label? (TryBlockModifier | 'unsafe' | ('async' 'move'?) | ('gen' 'move'?) | 'const') StmtList | |
| 477 | 480 | |
| 478 | 481 | PrefixExpr = |
| 479 | 482 | Attr* op:('-' | '!' | '*') Expr |
src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs+12-2| ... | ... | @@ -375,7 +375,11 @@ impl ast::Literal { |
| 375 | 375 | pub enum BlockModifier { |
| 376 | 376 | Async(SyntaxToken), |
| 377 | 377 | Unsafe(SyntaxToken), |
| 378 | Try(SyntaxToken), | |
| 378 | Try { | |
| 379 | try_token: SyntaxToken, | |
| 380 | bikeshed_token: Option<SyntaxToken>, | |
| 381 | result_type: Option<ast::Type>, | |
| 382 | }, | |
| 379 | 383 | Const(SyntaxToken), |
| 380 | 384 | AsyncGen(SyntaxToken), |
| 381 | 385 | Gen(SyntaxToken), |
| ... | ... | @@ -394,7 +398,13 @@ impl ast::BlockExpr { |
| 394 | 398 | }) |
| 395 | 399 | .or_else(|| self.async_token().map(BlockModifier::Async)) |
| 396 | 400 | .or_else(|| self.unsafe_token().map(BlockModifier::Unsafe)) |
| 397 | .or_else(|| self.try_token().map(BlockModifier::Try)) | |
| 401 | .or_else(|| { | |
| 402 | let modifier = self.try_block_modifier()?; | |
| 403 | let try_token = modifier.try_token()?; | |
| 404 | let bikeshed_token = modifier.bikeshed_token(); | |
| 405 | let result_type = modifier.ty(); | |
| 406 | Some(BlockModifier::Try { try_token, bikeshed_token, result_type }) | |
| 407 | }) | |
| 398 | 408 | .or_else(|| self.const_token().map(BlockModifier::Const)) |
| 399 | 409 | .or_else(|| self.label().map(BlockModifier::Label)) |
| 400 | 410 | } |
src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs+52-2| ... | ... | @@ -323,6 +323,8 @@ impl BlockExpr { |
| 323 | 323 | #[inline] |
| 324 | 324 | pub fn stmt_list(&self) -> Option<StmtList> { support::child(&self.syntax) } |
| 325 | 325 | #[inline] |
| 326 | pub fn try_block_modifier(&self) -> Option<TryBlockModifier> { support::child(&self.syntax) } | |
| 327 | #[inline] | |
| 326 | 328 | pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) } |
| 327 | 329 | #[inline] |
| 328 | 330 | pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) } |
| ... | ... | @@ -331,8 +333,6 @@ impl BlockExpr { |
| 331 | 333 | #[inline] |
| 332 | 334 | pub fn move_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![move]) } |
| 333 | 335 | #[inline] |
| 334 | pub fn try_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![try]) } | |
| 335 | #[inline] | |
| 336 | 336 | pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) } |
| 337 | 337 | } |
| 338 | 338 | pub struct BoxPat { |
| ... | ... | @@ -1630,6 +1630,19 @@ impl Trait { |
| 1630 | 1630 | #[inline] |
| 1631 | 1631 | pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) } |
| 1632 | 1632 | } |
| 1633 | pub struct TryBlockModifier { | |
| 1634 | pub(crate) syntax: SyntaxNode, | |
| 1635 | } | |
| 1636 | impl TryBlockModifier { | |
| 1637 | #[inline] | |
| 1638 | pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } | |
| 1639 | #[inline] | |
| 1640 | pub fn bikeshed_token(&self) -> Option<SyntaxToken> { | |
| 1641 | support::token(&self.syntax, T![bikeshed]) | |
| 1642 | } | |
| 1643 | #[inline] | |
| 1644 | pub fn try_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![try]) } | |
| 1645 | } | |
| 1633 | 1646 | pub struct TryExpr { |
| 1634 | 1647 | pub(crate) syntax: SyntaxNode, |
| 1635 | 1648 | } |
| ... | ... | @@ -6320,6 +6333,38 @@ impl fmt::Debug for Trait { |
| 6320 | 6333 | f.debug_struct("Trait").field("syntax", &self.syntax).finish() |
| 6321 | 6334 | } |
| 6322 | 6335 | } |
| 6336 | impl AstNode for TryBlockModifier { | |
| 6337 | #[inline] | |
| 6338 | fn kind() -> SyntaxKind | |
| 6339 | where | |
| 6340 | Self: Sized, | |
| 6341 | { | |
| 6342 | TRY_BLOCK_MODIFIER | |
| 6343 | } | |
| 6344 | #[inline] | |
| 6345 | fn can_cast(kind: SyntaxKind) -> bool { kind == TRY_BLOCK_MODIFIER } | |
| 6346 | #[inline] | |
| 6347 | fn cast(syntax: SyntaxNode) -> Option<Self> { | |
| 6348 | if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None } | |
| 6349 | } | |
| 6350 | #[inline] | |
| 6351 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | |
| 6352 | } | |
| 6353 | impl hash::Hash for TryBlockModifier { | |
| 6354 | fn hash<H: hash::Hasher>(&self, state: &mut H) { self.syntax.hash(state); } | |
| 6355 | } | |
| 6356 | impl Eq for TryBlockModifier {} | |
| 6357 | impl PartialEq for TryBlockModifier { | |
| 6358 | fn eq(&self, other: &Self) -> bool { self.syntax == other.syntax } | |
| 6359 | } | |
| 6360 | impl Clone for TryBlockModifier { | |
| 6361 | fn clone(&self) -> Self { Self { syntax: self.syntax.clone() } } | |
| 6362 | } | |
| 6363 | impl fmt::Debug for TryBlockModifier { | |
| 6364 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| 6365 | f.debug_struct("TryBlockModifier").field("syntax", &self.syntax).finish() | |
| 6366 | } | |
| 6367 | } | |
| 6323 | 6368 | impl AstNode for TryExpr { |
| 6324 | 6369 | #[inline] |
| 6325 | 6370 | fn kind() -> SyntaxKind |
| ... | ... | @@ -9979,6 +10024,11 @@ impl std::fmt::Display for Trait { |
| 9979 | 10024 | std::fmt::Display::fmt(self.syntax(), f) |
| 9980 | 10025 | } |
| 9981 | 10026 | } |
| 10027 | impl std::fmt::Display for TryBlockModifier { | |
| 10028 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | |
| 10029 | std::fmt::Display::fmt(self.syntax(), f) | |
| 10030 | } | |
| 10031 | } | |
| 9982 | 10032 | impl std::fmt::Display for TryExpr { |
| 9983 | 10033 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| 9984 | 10034 | std::fmt::Display::fmt(self.syntax(), f) |
src/tools/rust-analyzer/crates/syntax/src/syntax_error.rs-10| ... | ... | @@ -9,16 +9,6 @@ use crate::{TextRange, TextSize}; |
| 9 | 9 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
| 10 | 10 | pub struct SyntaxError(String, TextRange); |
| 11 | 11 | |
| 12 | // FIXME: there was an unused SyntaxErrorKind previously (before this enum was removed) | |
| 13 | // It was introduced in this PR: https://github.com/rust-lang/rust-analyzer/pull/846/files#diff-827da9b03b8f9faa1bade5cdd44d5dafR95 | |
| 14 | // but it was not removed by a mistake. | |
| 15 | // | |
| 16 | // So, we need to find a place where to stick validation for attributes in match clauses. | |
| 17 | // Code before refactor: | |
| 18 | // InvalidMatchInnerAttr => { | |
| 19 | // write!(f, "Inner attributes are only allowed directly after the opening brace of the match expression") | |
| 20 | // } | |
| 21 | ||
| 22 | 12 | impl SyntaxError { |
| 23 | 13 | pub fn new(message: impl Into<String>, range: TextRange) -> Self { |
| 24 | 14 | Self(message.into(), range) |
src/tools/rust-analyzer/crates/test-utils/src/minicore.rs+31-1| ... | ... | @@ -43,6 +43,7 @@ |
| 43 | 43 | //! dispatch_from_dyn: unsize, pin |
| 44 | 44 | //! hash: sized |
| 45 | 45 | //! include: |
| 46 | //! include_bytes: | |
| 46 | 47 | //! index: sized |
| 47 | 48 | //! infallible: |
| 48 | 49 | //! int_impl: size_of, transmute |
| ... | ... | @@ -953,6 +954,9 @@ pub mod ops { |
| 953 | 954 | #[lang = "from_residual"] |
| 954 | 955 | fn from_residual(residual: R) -> Self; |
| 955 | 956 | } |
| 957 | pub const trait Residual<O>: Sized { | |
| 958 | type TryType: [const] Try<Output = O, Residual = Self>; | |
| 959 | } | |
| 956 | 960 | #[lang = "Try"] |
| 957 | 961 | pub trait Try: FromResidual<Self::Residual> { |
| 958 | 962 | type Output; |
| ... | ... | @@ -962,6 +966,12 @@ pub mod ops { |
| 962 | 966 | #[lang = "branch"] |
| 963 | 967 | fn branch(self) -> ControlFlow<Self::Residual, Self::Output>; |
| 964 | 968 | } |
| 969 | #[lang = "into_try_type"] | |
| 970 | pub const fn residual_into_try_type<R: [const] Residual<O>, O>( | |
| 971 | r: R, | |
| 972 | ) -> <R as Residual<O>>::TryType { | |
| 973 | FromResidual::from_residual(r) | |
| 974 | } | |
| 965 | 975 | |
| 966 | 976 | impl<B, C> Try for ControlFlow<B, C> { |
| 967 | 977 | type Output = C; |
| ... | ... | @@ -985,6 +995,10 @@ pub mod ops { |
| 985 | 995 | } |
| 986 | 996 | } |
| 987 | 997 | } |
| 998 | ||
| 999 | impl<B, C> Residual<C> for ControlFlow<B, Infallible> { | |
| 1000 | type TryType = ControlFlow<B, C>; | |
| 1001 | } | |
| 988 | 1002 | // region:option |
| 989 | 1003 | impl<T> Try for Option<T> { |
| 990 | 1004 | type Output = T; |
| ... | ... | @@ -1008,6 +1022,10 @@ pub mod ops { |
| 1008 | 1022 | } |
| 1009 | 1023 | } |
| 1010 | 1024 | } |
| 1025 | ||
| 1026 | impl<T> const Residual<T> for Option<Infallible> { | |
| 1027 | type TryType = Option<T>; | |
| 1028 | } | |
| 1011 | 1029 | // endregion:option |
| 1012 | 1030 | // region:result |
| 1013 | 1031 | // region:from |
| ... | ... | @@ -1037,10 +1055,14 @@ pub mod ops { |
| 1037 | 1055 | } |
| 1038 | 1056 | } |
| 1039 | 1057 | } |
| 1058 | ||
| 1059 | impl<T, E> const Residual<T> for Result<Infallible, E> { | |
| 1060 | type TryType = Result<T, E>; | |
| 1061 | } | |
| 1040 | 1062 | // endregion:from |
| 1041 | 1063 | // endregion:result |
| 1042 | 1064 | } |
| 1043 | pub use self::try_::{ControlFlow, FromResidual, Try}; | |
| 1065 | pub use self::try_::{ControlFlow, FromResidual, Residual, Try}; | |
| 1044 | 1066 | // endregion:try |
| 1045 | 1067 | |
| 1046 | 1068 | // region:add |
| ... | ... | @@ -2040,6 +2062,14 @@ mod macros { |
| 2040 | 2062 | } |
| 2041 | 2063 | // endregion:include |
| 2042 | 2064 | |
| 2065 | // region:include_bytes | |
| 2066 | #[rustc_builtin_macro] | |
| 2067 | #[macro_export] | |
| 2068 | macro_rules! include_bytes { | |
| 2069 | ($file:expr $(,)?) => {{ /* compiler built-in */ }}; | |
| 2070 | } | |
| 2071 | // endregion:include_bytes | |
| 2072 | ||
| 2043 | 2073 | // region:concat |
| 2044 | 2074 | #[rustc_builtin_macro] |
| 2045 | 2075 | #[macro_export] |
src/tools/rust-analyzer/crates/toolchain/src/lib.rs-3| ... | ... | @@ -74,9 +74,6 @@ impl Tool { |
| 74 | 74 | // Prevent rustup from automatically installing toolchains, see https://github.com/rust-lang/rust-analyzer/issues/20719. |
| 75 | 75 | pub const NO_RUSTUP_AUTO_INSTALL_ENV: (&str, &str) = ("RUSTUP_AUTO_INSTALL", "0"); |
| 76 | 76 | |
| 77 | // These get ignored when displaying what command is running in LSP status messages. | |
| 78 | pub const DISPLAY_COMMAND_IGNORE_ENVS: &[&str] = &[NO_RUSTUP_AUTO_INSTALL_ENV.0]; | |
| 79 | ||
| 80 | 77 | #[allow(clippy::disallowed_types)] /* generic parameter allows for FxHashMap */ |
| 81 | 78 | pub fn command<H>( |
| 82 | 79 | cmd: impl AsRef<OsStr>, |
src/tools/rust-analyzer/docs/book/README.md+1-1| ... | ... | @@ -6,7 +6,7 @@ The rust analyzer manual uses [mdbook](https://rust-lang.github.io/mdBook/). |
| 6 | 6 | |
| 7 | 7 | To run the documentation site locally: |
| 8 | 8 | |
| 9 | ```shell | |
| 9 | ```bash | |
| 10 | 10 | cargo install mdbook |
| 11 | 11 | cargo xtask codegen |
| 12 | 12 | cd docs/book |
src/tools/rust-analyzer/docs/book/src/contributing/README.md+6-5| ... | ... | @@ -4,7 +4,7 @@ rust-analyzer is an ordinary Rust project, which is organized as a Cargo workspa |
| 4 | 4 | So, just |
| 5 | 5 | |
| 6 | 6 | ```bash |
| 7 | $ cargo test | |
| 7 | cargo test | |
| 8 | 8 | ``` |
| 9 | 9 | |
| 10 | 10 | should be enough to get you started! |
| ... | ... | @@ -203,14 +203,14 @@ It is enabled by `RA_COUNT=1`. |
| 203 | 203 | To measure time for from-scratch analysis, use something like this: |
| 204 | 204 | |
| 205 | 205 | ```bash |
| 206 | $ cargo run --release -p rust-analyzer -- analysis-stats ../chalk/ | |
| 206 | cargo run --release -p rust-analyzer -- analysis-stats ../chalk/ | |
| 207 | 207 | ``` |
| 208 | 208 | |
| 209 | 209 | For measuring time of incremental analysis, use either of these: |
| 210 | 210 | |
| 211 | 211 | ```bash |
| 212 | $ cargo run --release -p rust-analyzer -- analysis-bench ../chalk/ --highlight ../chalk/chalk-engine/src/logic.rs | |
| 213 | $ cargo run --release -p rust-analyzer -- analysis-bench ../chalk/ --complete ../chalk/chalk-engine/src/logic.rs:94:0 | |
| 212 | cargo run --release -p rust-analyzer -- analysis-bench ../chalk/ --highlight ../chalk/chalk-engine/src/logic.rs | |
| 213 | cargo run --release -p rust-analyzer -- analysis-bench ../chalk/ --complete ../chalk/chalk-engine/src/logic.rs:94:0 | |
| 214 | 214 | ``` |
| 215 | 215 | |
| 216 | 216 | Look for `fn benchmark_xxx` tests for a quick way to reproduce performance problems. |
| ... | ... | @@ -283,7 +283,8 @@ repository. We use the [rustc-josh-sync](https://github.com/rust-lang/josh-sync) |
| 283 | 283 | repositories. You can find documentation of the tool [here](https://github.com/rust-lang/josh-sync). |
| 284 | 284 | |
| 285 | 285 | You can install the synchronization tool using the following commands: |
| 286 | ``` | |
| 286 | ||
| 287 | ```bash | |
| 287 | 288 | cargo install --locked --git https://github.com/rust-lang/josh-sync |
| 288 | 289 | ``` |
| 289 | 290 |
src/tools/rust-analyzer/docs/book/src/contributing/debugging.md+1-1| ... | ... | @@ -68,7 +68,7 @@ while d == 4 { // set a breakpoint here and change the value |
| 68 | 68 | |
| 69 | 69 | However for this to work, you will need to enable debug_assertions in your build |
| 70 | 70 | |
| 71 | ```rust | |
| 71 | ```bash | |
| 72 | 72 | RUSTFLAGS='--cfg debug_assertions' cargo build --release |
| 73 | 73 | ``` |
| 74 | 74 |
src/tools/rust-analyzer/docs/book/src/installation.md+3-1| ... | ... | @@ -13,7 +13,9 @@ editor](./other_editors.html). |
| 13 | 13 | rust-analyzer will attempt to install the standard library source code |
| 14 | 14 | automatically. You can also install it manually with `rustup`. |
| 15 | 15 | |
| 16 | $ rustup component add rust-src | |
| 16 | ```bash | |
| 17 | rustup component add rust-src | |
| 18 | ``` | |
| 17 | 19 | |
| 18 | 20 | Only the latest stable standard library source is officially supported |
| 19 | 21 | for use with rust-analyzer. If you are using an older toolchain or have |
src/tools/rust-analyzer/docs/book/src/rust_analyzer_binary.md+18-8| ... | ... | @@ -11,9 +11,11 @@ your `$PATH`. |
| 11 | 11 | On Linux to install the `rust-analyzer` binary into `~/.local/bin`, |
| 12 | 12 | these commands should work: |
| 13 | 13 | |
| 14 | $ mkdir -p ~/.local/bin | |
| 15 | $ curl -L https://github.com/rust-lang/rust-analyzer/releases/latest/download/rust-analyzer-x86_64-unknown-linux-gnu.gz | gunzip -c - > ~/.local/bin/rust-analyzer | |
| 16 | $ chmod +x ~/.local/bin/rust-analyzer | |
| 14 | ```bash | |
| 15 | mkdir -p ~/.local/bin | |
| 16 | curl -L https://github.com/rust-lang/rust-analyzer/releases/latest/download/rust-analyzer-x86_64-unknown-linux-gnu.gz | gunzip -c - > ~/.local/bin/rust-analyzer | |
| 17 | chmod +x ~/.local/bin/rust-analyzer | |
| 18 | ``` | |
| 17 | 19 | |
| 18 | 20 | Make sure that `~/.local/bin` is listed in the `$PATH` variable and use |
| 19 | 21 | the appropriate URL if you’re not on a `x86-64` system. |
| ... | ... | @@ -24,8 +26,10 @@ or `/usr/local/bin` will work just as well. |
| 24 | 26 | Alternatively, you can install it from source using the command below. |
| 25 | 27 | You’ll need the latest stable version of the Rust toolchain. |
| 26 | 28 | |
| 27 | $ git clone https://github.com/rust-lang/rust-analyzer.git && cd rust-analyzer | |
| 28 | $ cargo xtask install --server | |
| 29 | ```bash | |
| 30 | git clone https://github.com/rust-lang/rust-analyzer.git && cd rust-analyzer | |
| 31 | cargo xtask install --server | |
| 32 | ``` | |
| 29 | 33 | |
| 30 | 34 | If your editor can’t find the binary even though the binary is on your |
| 31 | 35 | `$PATH`, the likely explanation is that it doesn’t see the same `$PATH` |
| ... | ... | @@ -38,7 +42,9 @@ the environment should help. |
| 38 | 42 | |
| 39 | 43 | `rust-analyzer` is available in `rustup`: |
| 40 | 44 | |
| 41 | $ rustup component add rust-analyzer | |
| 45 | ```bash | |
| 46 | rustup component add rust-analyzer | |
| 47 | ``` | |
| 42 | 48 | |
| 43 | 49 | ### Arch Linux |
| 44 | 50 | |
| ... | ... | @@ -53,7 +59,9 @@ User Repository): |
| 53 | 59 | |
| 54 | 60 | Install it with pacman, for example: |
| 55 | 61 | |
| 56 | $ pacman -S rust-analyzer | |
| 62 | ```bash | |
| 63 | pacman -S rust-analyzer | |
| 64 | ``` | |
| 57 | 65 | |
| 58 | 66 | ### Gentoo Linux |
| 59 | 67 | |
| ... | ... | @@ -64,7 +72,9 @@ Install it with pacman, for example: |
| 64 | 72 | The `rust-analyzer` binary can be installed via |
| 65 | 73 | [Homebrew](https://brew.sh/). |
| 66 | 74 | |
| 67 | $ brew install rust-analyzer | |
| 75 | ```bash | |
| 76 | brew install rust-analyzer | |
| 77 | ``` | |
| 68 | 78 | |
| 69 | 79 | ### Windows |
| 70 | 80 |
src/tools/rust-analyzer/docs/book/src/troubleshooting.md+5-5| ... | ... | @@ -37,13 +37,13 @@ bypassing LSP machinery. |
| 37 | 37 | When filing issues, it is useful (but not necessary) to try to minimize |
| 38 | 38 | examples. An ideal bug reproduction looks like this: |
| 39 | 39 | |
| 40 | ```shell | |
| 41 | $ git clone https://github.com/username/repo.git && cd repo && git switch --detach commit-hash | |
| 42 | $ rust-analyzer --version | |
| 40 | ```bash | |
| 41 | git clone https://github.com/username/repo.git && cd repo && git switch --detach commit-hash | |
| 42 | rust-analyzer --version | |
| 43 | 43 | rust-analyzer dd12184e4 2021-05-08 dev |
| 44 | $ rust-analyzer analysis-stats . | |
| 45 | 💀 💀 💀 | |
| 44 | rust-analyzer analysis-stats . | |
| 46 | 45 | ``` |
| 46 | 💀 💀 💀 | |
| 47 | 47 | |
| 48 | 48 | It is especially useful when the `repo` doesn’t use external crates or |
| 49 | 49 | the standard library. |
src/tools/rust-analyzer/docs/book/src/vs_code.md+10-5| ... | ... | @@ -49,7 +49,9 @@ Alternatively, download a VSIX corresponding to your platform from the |
| 49 | 49 | Install the extension with the `Extensions: Install from VSIX` command |
| 50 | 50 | within VS Code, or from the command line via: |
| 51 | 51 | |
| 52 | $ code --install-extension /path/to/rust-analyzer.vsix | |
| 52 | ```bash | |
| 53 | code --install-extension /path/to/rust-analyzer.vsix | |
| 54 | ``` | |
| 53 | 55 | |
| 54 | 56 | If you are running an unsupported platform, you can install |
| 55 | 57 | `rust-analyzer-no-server.vsix` and compile or obtain a server binary. |
| ... | ... | @@ -64,8 +66,10 @@ example: |
| 64 | 66 | |
| 65 | 67 | Both the server and the Code plugin can be installed from source: |
| 66 | 68 | |
| 67 | $ git clone https://github.com/rust-lang/rust-analyzer.git && cd rust-analyzer | |
| 68 | $ cargo xtask install | |
| 69 | ```bash | |
| 70 | git clone https://github.com/rust-lang/rust-analyzer.git && cd rust-analyzer | |
| 71 | cargo xtask install | |
| 72 | ``` | |
| 69 | 73 | |
| 70 | 74 | You’ll need Cargo, nodejs (matching a supported version of VS Code) and |
| 71 | 75 | npm for this. |
| ... | ... | @@ -76,7 +80,9 @@ Remote, instead you’ll need to install the `.vsix` manually. |
| 76 | 80 | If you’re not using Code, you can compile and install only the LSP |
| 77 | 81 | server: |
| 78 | 82 | |
| 79 | $ cargo xtask install --server | |
| 83 | ```bash | |
| 84 | cargo xtask install --server | |
| 85 | ``` | |
| 80 | 86 | |
| 81 | 87 | Make sure that `.cargo/bin` is in `$PATH` and precedes paths where |
| 82 | 88 | `rust-analyzer` may also be installed. Specifically, `rustup` includes a |
| ... | ... | @@ -118,4 +124,3 @@ steps might help: |
| 118 | 124 | |
| 119 | 125 | A C compiler should already be available via `org.freedesktop.Sdk`. Any |
| 120 | 126 | other tools or libraries you will need to acquire from Flatpak. |
| 121 |
src/tools/rust-analyzer/xtask/src/codegen/grammar/ast_src.rs+1-1| ... | ... | @@ -112,7 +112,7 @@ const RESERVED: &[&str] = &[ |
| 112 | 112 | // keywords that are keywords only in specific parse contexts |
| 113 | 113 | #[doc(alias = "WEAK_KEYWORDS")] |
| 114 | 114 | const CONTEXTUAL_KEYWORDS: &[&str] = |
| 115 | &["macro_rules", "union", "default", "raw", "dyn", "auto", "yeet", "safe"]; | |
| 115 | &["macro_rules", "union", "default", "raw", "dyn", "auto", "yeet", "safe", "bikeshed"]; | |
| 116 | 116 | // keywords we use for special macro expansions |
| 117 | 117 | const CONTEXTUAL_BUILTIN_KEYWORDS: &[&str] = &[ |
| 118 | 118 | "asm", |
tests/crashes/135470.rs deleted-41| ... | ... | @@ -1,41 +0,0 @@ |
| 1 | //@ known-bug: #135470 | |
| 2 | //@ compile-flags: -Copt-level=0 | |
| 3 | //@ edition: 2021 | |
| 4 | ||
| 5 | use std::future::Future; | |
| 6 | trait Access { | |
| 7 | type Lister; | |
| 8 | ||
| 9 | fn list() -> impl Future<Output = Self::Lister> { | |
| 10 | async { todo!() } | |
| 11 | } | |
| 12 | } | |
| 13 | ||
| 14 | trait Foo {} | |
| 15 | impl Access for dyn Foo { | |
| 16 | type Lister = (); | |
| 17 | } | |
| 18 | ||
| 19 | fn main() { | |
| 20 | let svc = async { | |
| 21 | async { <dyn Foo>::list() }.await; | |
| 22 | }; | |
| 23 | &svc as &dyn Service; | |
| 24 | } | |
| 25 | ||
| 26 | trait UnaryService { | |
| 27 | fn call2() {} | |
| 28 | } | |
| 29 | trait Unimplemented {} | |
| 30 | impl<T: Unimplemented> UnaryService for T {} | |
| 31 | struct Wrap<T>(T); | |
| 32 | impl<T: Send> UnaryService for Wrap<T> {} | |
| 33 | ||
| 34 | trait Service { | |
| 35 | fn call(&self); | |
| 36 | } | |
| 37 | impl<T: Send> Service for T { | |
| 38 | fn call(&self) { | |
| 39 | Wrap::<T>::call2(); | |
| 40 | } | |
| 41 | } |
tests/crashes/137190-2.rs deleted-18| ... | ... | @@ -1,18 +0,0 @@ |
| 1 | //@ known-bug: #137190 | |
| 2 | trait Supertrait<T> { | |
| 3 | fn method(&self) {} | |
| 4 | } | |
| 5 | ||
| 6 | trait Trait<P>: Supertrait<()> {} | |
| 7 | ||
| 8 | impl<P> Trait<P> for () {} | |
| 9 | ||
| 10 | const fn upcast<P>(x: &dyn Trait<P>) -> &dyn Supertrait<()> { | |
| 11 | x | |
| 12 | } | |
| 13 | ||
| 14 | const fn foo() -> &'static dyn Supertrait<()> { | |
| 15 | upcast::<()>(&()) | |
| 16 | } | |
| 17 | ||
| 18 | const _: &'static dyn Supertrait<()> = foo(); |
tests/crashes/137190-3.rs deleted-10| ... | ... | @@ -1,10 +0,0 @@ |
| 1 | //@ known-bug: #137190 | |
| 2 | trait Supertrait { | |
| 3 | fn method(&self) {} | |
| 4 | } | |
| 5 | ||
| 6 | trait Trait: Supertrait {} | |
| 7 | ||
| 8 | impl Trait for () {} | |
| 9 | ||
| 10 | const _: &dyn Supertrait = &() as &dyn Trait as &dyn Supertrait; |
tests/crashes/137916.rs deleted-13| ... | ... | @@ -1,13 +0,0 @@ |
| 1 | //@ known-bug: #137916 | |
| 2 | //@ edition: 2021 | |
| 3 | use std::ptr::null; | |
| 4 | ||
| 5 | async fn a() -> Box<dyn Send> { | |
| 6 | Box::new(async { | |
| 7 | let non_send = null::<()>(); | |
| 8 | &non_send; | |
| 9 | async {}.await | |
| 10 | }) | |
| 11 | } | |
| 12 | ||
| 13 | fn main() {} |
tests/crashes/138274.rs deleted-18| ... | ... | @@ -1,18 +0,0 @@ |
| 1 | //@ known-bug: #138274 | |
| 2 | //@ edition: 2021 | |
| 3 | //@ compile-flags: --crate-type=lib | |
| 4 | trait Trait {} | |
| 5 | ||
| 6 | fn foo() -> Box<dyn Trait> { | |
| 7 | todo!() | |
| 8 | } | |
| 9 | ||
| 10 | fn fetch() { | |
| 11 | async { | |
| 12 | let fut = async { | |
| 13 | let _x = foo(); | |
| 14 | async {}.await; | |
| 15 | }; | |
| 16 | let _: Box<dyn Send> = Box::new(fut); | |
| 17 | }; | |
| 18 | } |
tests/run-make/wasm-emscripten-cdylib/foo.rs created+4| ... | ... | @@ -0,0 +1,4 @@ |
| 1 | #[no_mangle] | |
| 2 | pub extern "C" fn foo() -> i32 { | |
| 3 | 42 | |
| 4 | } |
tests/run-make/wasm-emscripten-cdylib/rmake.rs created+25| ... | ... | @@ -0,0 +1,25 @@ |
| 1 | //! Check that cdylib crate type is supported for the wasm32-unknown-emscripten | |
| 2 | //! target and produces a valid Emscripten dynamic library. | |
| 3 | ||
| 4 | //@ only-wasm32-unknown-emscripten | |
| 5 | ||
| 6 | use run_make_support::{bare_rustc, rfs, wasmparser}; | |
| 7 | ||
| 8 | fn main() { | |
| 9 | bare_rustc().input("foo.rs").target("wasm32-unknown-emscripten").crate_type("cdylib").run(); | |
| 10 | ||
| 11 | // Verify the output is a valid wasm file with a dylink.0 section | |
| 12 | let file = rfs::read("foo.wasm"); | |
| 13 | let mut has_dylink = false; | |
| 14 | ||
| 15 | for payload in wasmparser::Parser::new(0).parse_all(&file) { | |
| 16 | let payload = payload.unwrap(); | |
| 17 | if let wasmparser::Payload::CustomSection(s) = payload { | |
| 18 | if s.name() == "dylink.0" { | |
| 19 | has_dylink = true; | |
| 20 | } | |
| 21 | } | |
| 22 | } | |
| 23 | ||
| 24 | assert!(has_dylink, "expected dylink.0 section in emscripten cdylib output"); | |
| 25 | } |
tests/ui/async-await/issue-70818.rs+1-2| ... | ... | @@ -2,9 +2,8 @@ |
| 2 | 2 | |
| 3 | 3 | use std::future::Future; |
| 4 | 4 | fn foo<T: Send, U>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send { |
| 5 | //~^ ERROR future cannot be sent between threads safely | |
| 5 | //~^ ERROR: future cannot be sent between threads safely | |
| 6 | 6 | async { (ty, ty1) } |
| 7 | //~^ ERROR future cannot be sent between threads safely | |
| 8 | 7 | } |
| 9 | 8 | |
| 10 | 9 | fn main() {} |
tests/ui/async-await/issue-70818.stderr+1-22| ... | ... | @@ -1,24 +1,3 @@ |
| 1 | error: future cannot be sent between threads safely | |
| 2 | --> $DIR/issue-70818.rs:6:5 | |
| 3 | | | |
| 4 | LL | async { (ty, ty1) } | |
| 5 | | ^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` | |
| 6 | | | |
| 7 | note: captured value is not `Send` | |
| 8 | --> $DIR/issue-70818.rs:6:18 | |
| 9 | | | |
| 10 | LL | async { (ty, ty1) } | |
| 11 | | ^^^ has type `U` which is not `Send` | |
| 12 | note: required by a bound in an opaque type | |
| 13 | --> $DIR/issue-70818.rs:4:69 | |
| 14 | | | |
| 15 | LL | fn foo<T: Send, U>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send { | |
| 16 | | ^^^^ | |
| 17 | help: consider restricting type parameter `U` with trait `Send` | |
| 18 | | | |
| 19 | LL | fn foo<T: Send, U: std::marker::Send>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send { | |
| 20 | | +++++++++++++++++++ | |
| 21 | ||
| 22 | 1 | error: future cannot be sent between threads safely |
| 23 | 2 | --> $DIR/issue-70818.rs:4:38 |
| 24 | 3 | | |
| ... | ... | @@ -35,5 +14,5 @@ help: consider restricting type parameter `U` with trait `Send` |
| 35 | 14 | LL | fn foo<T: Send, U: std::marker::Send>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send { |
| 36 | 15 | | +++++++++++++++++++ |
| 37 | 16 | |
| 38 | error: aborting due to 2 previous errors | |
| 17 | error: aborting due to 1 previous error | |
| 39 | 18 |
tests/ui/async-await/issue-70935-complex-spans.rs-1| ... | ... | @@ -15,7 +15,6 @@ async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> { |
| 15 | 15 | fn foo(x: NotSync) -> impl Future + Send { |
| 16 | 16 | //~^ ERROR `*mut ()` cannot be shared between threads safely |
| 17 | 17 | async move { |
| 18 | //~^ ERROR `*mut ()` cannot be shared between threads safely | |
| 19 | 18 | baz(|| async { |
| 20 | 19 | foo(x.clone()); |
| 21 | 20 | }).await; |
tests/ui/async-await/issue-70935-complex-spans.stderr+2-45| ... | ... | @@ -1,46 +1,3 @@ |
| 1 | error[E0277]: `*mut ()` cannot be shared between threads safely | |
| 2 | --> $DIR/issue-70935-complex-spans.rs:17:5 | |
| 3 | | | |
| 4 | LL | / async move { | |
| 5 | LL | | | |
| 6 | LL | | baz(|| async { | |
| 7 | LL | | foo(x.clone()); | |
| 8 | LL | | }).await; | |
| 9 | LL | | } | |
| 10 | | |_____^ `*mut ()` cannot be shared between threads safely | |
| 11 | | | |
| 12 | = help: within `NotSync`, the trait `Sync` is not implemented for `*mut ()` | |
| 13 | note: required because it appears within the type `PhantomData<*mut ()>` | |
| 14 | --> $SRC_DIR/core/src/marker.rs:LL:COL | |
| 15 | note: required because it appears within the type `NotSync` | |
| 16 | --> $DIR/issue-70935-complex-spans.rs:9:8 | |
| 17 | | | |
| 18 | LL | struct NotSync(PhantomData<*mut ()>); | |
| 19 | | ^^^^^^^ | |
| 20 | = note: required for `&NotSync` to implement `Send` | |
| 21 | note: required because it's used within this closure | |
| 22 | --> $DIR/issue-70935-complex-spans.rs:19:13 | |
| 23 | | | |
| 24 | LL | baz(|| async { | |
| 25 | | ^^ | |
| 26 | note: required because it's used within this `async` fn body | |
| 27 | --> $DIR/issue-70935-complex-spans.rs:12:67 | |
| 28 | | | |
| 29 | LL | async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> { | |
| 30 | | ___________________________________________________________________^ | |
| 31 | LL | | } | |
| 32 | | |_^ | |
| 33 | note: required because it's used within this `async` block | |
| 34 | --> $DIR/issue-70935-complex-spans.rs:17:5 | |
| 35 | | | |
| 36 | LL | async move { | |
| 37 | | ^^^^^^^^^^ | |
| 38 | note: required by a bound in an opaque type | |
| 39 | --> $DIR/issue-70935-complex-spans.rs:15:37 | |
| 40 | | | |
| 41 | LL | fn foo(x: NotSync) -> impl Future + Send { | |
| 42 | | ^^^^ | |
| 43 | ||
| 44 | 1 | error[E0277]: `*mut ()` cannot be shared between threads safely |
| 45 | 2 | --> $DIR/issue-70935-complex-spans.rs:15:23 |
| 46 | 3 | | |
| ... | ... | @@ -57,7 +14,7 @@ LL | struct NotSync(PhantomData<*mut ()>); |
| 57 | 14 | | ^^^^^^^ |
| 58 | 15 | = note: required for `&NotSync` to implement `Send` |
| 59 | 16 | note: required because it's used within this closure |
| 60 | --> $DIR/issue-70935-complex-spans.rs:19:13 | |
| 17 | --> $DIR/issue-70935-complex-spans.rs:18:13 | |
| 61 | 18 | | |
| 62 | 19 | LL | baz(|| async { |
| 63 | 20 | | ^^ |
| ... | ... | @@ -74,6 +31,6 @@ note: required because it's used within this `async` block |
| 74 | 31 | LL | async move { |
| 75 | 32 | | ^^^^^^^^^^ |
| 76 | 33 | |
| 77 | error: aborting due to 2 previous errors | |
| 34 | error: aborting due to 1 previous error | |
| 78 | 35 | |
| 79 | 36 | For more information about this error, try `rustc --explain E0277`. |
tests/ui/coercion/vtable-impossible-predicates-async.rs created+45| ... | ... | @@ -0,0 +1,45 @@ |
| 1 | // Regression test for #135470. | |
| 2 | // Verify that we don't ICE when building vtable entries | |
| 3 | // for a blanket impl involving async and impossible predicates. | |
| 4 | ||
| 5 | //@ check-pass | |
| 6 | //@ compile-flags: -Copt-level=0 | |
| 7 | //@ edition: 2021 | |
| 8 | ||
| 9 | use std::future::Future; | |
| 10 | trait Access { | |
| 11 | type Lister; | |
| 12 | ||
| 13 | fn list() -> impl Future<Output = Self::Lister> { | |
| 14 | async { todo!() } | |
| 15 | } | |
| 16 | } | |
| 17 | ||
| 18 | trait Foo {} | |
| 19 | impl Access for dyn Foo { | |
| 20 | type Lister = (); | |
| 21 | } | |
| 22 | ||
| 23 | fn main() { | |
| 24 | let svc = async { | |
| 25 | async { <dyn Foo>::list() }.await; | |
| 26 | }; | |
| 27 | &svc as &dyn Service; | |
| 28 | } | |
| 29 | ||
| 30 | trait UnaryService { | |
| 31 | fn call2() {} | |
| 32 | } | |
| 33 | trait Unimplemented {} | |
| 34 | impl<T: Unimplemented> UnaryService for T {} | |
| 35 | struct Wrap<T>(T); | |
| 36 | impl<T: Send> UnaryService for Wrap<T> {} | |
| 37 | ||
| 38 | trait Service { | |
| 39 | fn call(&self); | |
| 40 | } | |
| 41 | impl<T: Send> Service for T { | |
| 42 | fn call(&self) { | |
| 43 | Wrap::<T>::call2(); | |
| 44 | } | |
| 45 | } |
tests/ui/coercion/vtable-unsatisfied-supertrait-generics.rs created+25| ... | ... | @@ -0,0 +1,25 @@ |
| 1 | // Regression test for #137190. | |
| 2 | // Variant of vtable-unsatisfied-supertrait.rs with generic traits. | |
| 3 | // Verify that we don't ICE when building vtable entries | |
| 4 | // for a generic trait whose supertrait is not implemented. | |
| 5 | ||
| 6 | //@ compile-flags: --crate-type lib | |
| 7 | ||
| 8 | trait Supertrait<T> { | |
| 9 | fn method(&self) {} | |
| 10 | } | |
| 11 | ||
| 12 | trait Trait<P>: Supertrait<()> {} | |
| 13 | ||
| 14 | impl<P> Trait<P> for () {} | |
| 15 | //~^ ERROR the trait bound `(): Supertrait<()>` is not satisfied | |
| 16 | ||
| 17 | const fn upcast<P>(x: &dyn Trait<P>) -> &dyn Supertrait<()> { | |
| 18 | x | |
| 19 | } | |
| 20 | ||
| 21 | const fn foo() -> &'static dyn Supertrait<()> { | |
| 22 | upcast::<()>(&()) | |
| 23 | } | |
| 24 | ||
| 25 | const _: &'static dyn Supertrait<()> = foo(); |
tests/ui/coercion/vtable-unsatisfied-supertrait-generics.stderr created+20| ... | ... | @@ -0,0 +1,20 @@ |
| 1 | error[E0277]: the trait bound `(): Supertrait<()>` is not satisfied | |
| 2 | --> $DIR/vtable-unsatisfied-supertrait-generics.rs:14:22 | |
| 3 | | | |
| 4 | LL | impl<P> Trait<P> for () {} | |
| 5 | | ^^ the trait `Supertrait<()>` is not implemented for `()` | |
| 6 | | | |
| 7 | help: this trait has no implementations, consider adding one | |
| 8 | --> $DIR/vtable-unsatisfied-supertrait-generics.rs:8:1 | |
| 9 | | | |
| 10 | LL | trait Supertrait<T> { | |
| 11 | | ^^^^^^^^^^^^^^^^^^^ | |
| 12 | note: required by a bound in `Trait` | |
| 13 | --> $DIR/vtable-unsatisfied-supertrait-generics.rs:12:17 | |
| 14 | | | |
| 15 | LL | trait Trait<P>: Supertrait<()> {} | |
| 16 | | ^^^^^^^^^^^^^^ required by this bound in `Trait` | |
| 17 | ||
| 18 | error: aborting due to 1 previous error | |
| 19 | ||
| 20 | For more information about this error, try `rustc --explain E0277`. |
tests/ui/coercion/vtable-unsatisfied-supertrait.rs created+16| ... | ... | @@ -0,0 +1,16 @@ |
| 1 | // Regression test for #137190. | |
| 2 | // Verify that we don't ICE when building vtable entries | |
| 3 | // for a trait whose supertrait is not implemented. | |
| 4 | ||
| 5 | //@ compile-flags: --crate-type lib | |
| 6 | ||
| 7 | trait Supertrait { | |
| 8 | fn method(&self) {} | |
| 9 | } | |
| 10 | ||
| 11 | trait Trait: Supertrait {} | |
| 12 | ||
| 13 | impl Trait for () {} | |
| 14 | //~^ ERROR the trait bound `(): Supertrait` is not satisfied | |
| 15 | ||
| 16 | const _: &dyn Supertrait = &() as &dyn Trait as &dyn Supertrait; |
tests/ui/coercion/vtable-unsatisfied-supertrait.stderr created+20| ... | ... | @@ -0,0 +1,20 @@ |
| 1 | error[E0277]: the trait bound `(): Supertrait` is not satisfied | |
| 2 | --> $DIR/vtable-unsatisfied-supertrait.rs:13:16 | |
| 3 | | | |
| 4 | LL | impl Trait for () {} | |
| 5 | | ^^ the trait `Supertrait` is not implemented for `()` | |
| 6 | | | |
| 7 | help: this trait has no implementations, consider adding one | |
| 8 | --> $DIR/vtable-unsatisfied-supertrait.rs:7:1 | |
| 9 | | | |
| 10 | LL | trait Supertrait { | |
| 11 | | ^^^^^^^^^^^^^^^^ | |
| 12 | note: required by a bound in `Trait` | |
| 13 | --> $DIR/vtable-unsatisfied-supertrait.rs:11:14 | |
| 14 | | | |
| 15 | LL | trait Trait: Supertrait {} | |
| 16 | | ^^^^^^^^^^ required by this bound in `Trait` | |
| 17 | ||
| 18 | error: aborting due to 1 previous error | |
| 19 | ||
| 20 | For more information about this error, try `rustc --explain E0277`. |
tests/ui/coroutine/issue-105084.rs-1| ... | ... | @@ -36,7 +36,6 @@ fn main() { |
| 36 | 36 | // one inside `g` and one inside `h`. |
| 37 | 37 | // Proceed and drop `t` in `g`. |
| 38 | 38 | Pin::new(&mut g).resume(()); |
| 39 | //~^ ERROR borrow of moved value: `g` | |
| 40 | 39 | |
| 41 | 40 | // Proceed and drop `t` in `h` -> double free! |
| 42 | 41 | Pin::new(&mut h).resume(()); |
tests/ui/coroutine/issue-105084.stderr+2-27| ... | ... | @@ -1,27 +1,3 @@ |
| 1 | error[E0382]: borrow of moved value: `g` | |
| 2 | --> $DIR/issue-105084.rs:38:14 | |
| 3 | | | |
| 4 | LL | let mut g = #[coroutine] | |
| 5 | | ----- move occurs because `g` has type `{coroutine@$DIR/issue-105084.rs:16:5: 16:7}`, which does not implement the `Copy` trait | |
| 6 | ... | |
| 7 | LL | let mut h = copy(g); | |
| 8 | | - value moved here | |
| 9 | ... | |
| 10 | LL | Pin::new(&mut g).resume(()); | |
| 11 | | ^^^^^^ value borrowed here after move | |
| 12 | | | |
| 13 | note: consider changing this parameter type in function `copy` to borrow instead if owning the value isn't necessary | |
| 14 | --> $DIR/issue-105084.rs:10:21 | |
| 15 | | | |
| 16 | LL | fn copy<T: Copy>(x: T) -> T { | |
| 17 | | ---- ^ this parameter takes ownership of the value | |
| 18 | | | | |
| 19 | | in this function | |
| 20 | help: consider cloning the value if the performance cost is acceptable | |
| 21 | | | |
| 22 | LL | let mut h = copy(g.clone()); | |
| 23 | | ++++++++ | |
| 24 | ||
| 25 | 1 | error[E0277]: the trait bound `Box<(i32, ())>: Copy` is not satisfied in `{coroutine@$DIR/issue-105084.rs:16:5: 16:7}` |
| 26 | 2 | --> $DIR/issue-105084.rs:32:17 |
| 27 | 3 | | |
| ... | ... | @@ -45,7 +21,6 @@ note: required by a bound in `copy` |
| 45 | 21 | LL | fn copy<T: Copy>(x: T) -> T { |
| 46 | 22 | | ^^^^ required by this bound in `copy` |
| 47 | 23 | |
| 48 | error: aborting due to 2 previous errors | |
| 24 | error: aborting due to 1 previous error | |
| 49 | 25 | |
| 50 | Some errors have detailed explanations: E0277, E0382. | |
| 51 | For more information about an error, try `rustc --explain E0277`. | |
| 26 | For more information about this error, try `rustc --explain E0277`. |
tests/ui/coroutine/stalled-coroutine-obligations.rs created+32| ... | ... | @@ -0,0 +1,32 @@ |
| 1 | //@ edition: 2021 | |
| 2 | ||
| 3 | // Regression tests for #137916 and #138274 | |
| 4 | // We now check stalled coroutine obligations eagerly at the start of `mir_borrowck`. | |
| 5 | // So these unsatisfied bounds are caught before causing ICEs. | |
| 6 | use std::ptr::null; | |
| 7 | ||
| 8 | async fn a() -> Box<dyn Send> { | |
| 9 | Box::new(async { | |
| 10 | //~^ ERROR: future cannot be sent between threads safely | |
| 11 | let non_send = null::<()>(); | |
| 12 | &non_send; | |
| 13 | async {}.await | |
| 14 | }) | |
| 15 | } | |
| 16 | ||
| 17 | ||
| 18 | trait Trait {} | |
| 19 | fn foo() -> Box<dyn Trait> { todo!() } | |
| 20 | ||
| 21 | fn fetch() { | |
| 22 | async { | |
| 23 | let fut = async { | |
| 24 | let _x = foo(); | |
| 25 | async {}.await; | |
| 26 | }; | |
| 27 | let _: Box<dyn Send> = Box::new(fut); | |
| 28 | //~^ ERROR: future cannot be sent between threads safely | |
| 29 | }; | |
| 30 | } | |
| 31 | ||
| 32 | fn main() {} |
tests/ui/coroutine/stalled-coroutine-obligations.stderr created+40| ... | ... | @@ -0,0 +1,40 @@ |
| 1 | error: future cannot be sent between threads safely | |
| 2 | --> $DIR/stalled-coroutine-obligations.rs:9:5 | |
| 3 | | | |
| 4 | LL | / Box::new(async { | |
| 5 | LL | | | |
| 6 | LL | | let non_send = null::<()>(); | |
| 7 | LL | | &non_send; | |
| 8 | LL | | async {}.await | |
| 9 | LL | | }) | |
| 10 | | |______^ future created by async block is not `Send` | |
| 11 | | | |
| 12 | = help: within `{async block@$DIR/stalled-coroutine-obligations.rs:9:14: 9:19}`, the trait `Send` is not implemented for `*const ()` | |
| 13 | note: future is not `Send` as this value is used across an await | |
| 14 | --> $DIR/stalled-coroutine-obligations.rs:13:18 | |
| 15 | | | |
| 16 | LL | let non_send = null::<()>(); | |
| 17 | | -------- has type `*const ()` which is not `Send` | |
| 18 | LL | &non_send; | |
| 19 | LL | async {}.await | |
| 20 | | ^^^^^ await occurs here, with `non_send` maybe used later | |
| 21 | = note: required for the cast from `Box<{async block@$DIR/stalled-coroutine-obligations.rs:9:14: 9:19}>` to `Box<dyn Send>` | |
| 22 | ||
| 23 | error: future cannot be sent between threads safely | |
| 24 | --> $DIR/stalled-coroutine-obligations.rs:27:32 | |
| 25 | | | |
| 26 | LL | let _: Box<dyn Send> = Box::new(fut); | |
| 27 | | ^^^^^^^^^^^^^ future created by async block is not `Send` | |
| 28 | | | |
| 29 | = help: the trait `Send` is not implemented for `dyn Trait` | |
| 30 | note: future is not `Send` as this value is used across an await | |
| 31 | --> $DIR/stalled-coroutine-obligations.rs:25:22 | |
| 32 | | | |
| 33 | LL | let _x = foo(); | |
| 34 | | -- has type `Box<dyn Trait>` which is not `Send` | |
| 35 | LL | async {}.await; | |
| 36 | | ^^^^^ await occurs here, with `_x` maybe used later | |
| 37 | = note: required for the cast from `Box<{async block@$DIR/stalled-coroutine-obligations.rs:23:19: 23:24}>` to `Box<dyn Send>` | |
| 38 | ||
| 39 | error: aborting due to 2 previous errors | |
| 40 |
tests/ui/suggestions/issue-71394-no-from-impl.stderr+1-1| ... | ... | @@ -13,7 +13,7 @@ LL | let _: &[i8] = data.into(); |
| 13 | 13 | `[T; 6]` implements `From<(T, T, T, T, T, T)>` |
| 14 | 14 | `[T; 7]` implements `From<(T, T, T, T, T, T, T)>` |
| 15 | 15 | `[T; 8]` implements `From<(T, T, T, T, T, T, T, T)>` |
| 16 | and 6 others | |
| 16 | and 7 others | |
| 17 | 17 | = note: required for `&[u8]` to implement `Into<&[i8]>` |
| 18 | 18 | |
| 19 | 19 | error: aborting due to 1 previous error |
tests/ui/traits/next-solver/stalled-coroutine-obligations.rs created+50| ... | ... | @@ -0,0 +1,50 @@ |
| 1 | //@ edition: 2024 | |
| 2 | //@ compile-flags: -Znext-solver --diagnostic-width=300 | |
| 3 | ||
| 4 | // Previously we check stalled coroutine obligations after borrowck pass. | |
| 5 | // And we wrongly assume that these obligations hold in borrowck which leads to | |
| 6 | // silent normalization failures. | |
| 7 | // In the next solver, we register opaques types via `NormalizesTo` goals. | |
| 8 | // So these failures also cause those opaques types not registered in storage. | |
| 9 | // | |
| 10 | // Regression test for #151322 and #151323. | |
| 11 | ||
| 12 | #![feature(type_alias_impl_trait)] | |
| 13 | #![feature(negative_impls)] | |
| 14 | #![feature(auto_traits)] | |
| 15 | ||
| 16 | fn stalled_copy_clone() { | |
| 17 | type T = impl Copy; | |
| 18 | let foo: T = async {}; | |
| 19 | //~^ ERROR: the trait bound | |
| 20 | ||
| 21 | type U = impl Clone; | |
| 22 | let bar: U = async {}; | |
| 23 | //~^ ERROR: the trait bound | |
| 24 | } | |
| 25 | ||
| 26 | auto trait Valid {} | |
| 27 | struct False; | |
| 28 | impl !Valid for False {} | |
| 29 | ||
| 30 | fn stalled_auto_traits() { | |
| 31 | type T = impl Valid; | |
| 32 | let a = False; | |
| 33 | let foo: T = async { a }; | |
| 34 | //~^ ERROR: the trait bound `False: Valid` is not satisfied | |
| 35 | } | |
| 36 | ||
| 37 | ||
| 38 | trait Trait { | |
| 39 | fn stalled_send(&self, b: *mut ()) -> impl Future + Send { | |
| 40 | //~^ ERROR: type mismatch resolving | |
| 41 | //~| ERROR: type mismatch resolving | |
| 42 | async move { | |
| 43 | //~^ ERROR: type mismatch resolving | |
| 44 | b | |
| 45 | } | |
| 46 | } | |
| 47 | } | |
| 48 | ||
| 49 | ||
| 50 | fn main() {} |
tests/ui/traits/next-solver/stalled-coroutine-obligations.stderr created+62| ... | ... | @@ -0,0 +1,62 @@ |
| 1 | error[E0277]: the trait bound `{async block@$DIR/stalled-coroutine-obligations.rs:18:18: 18:23}: Copy` is not satisfied | |
| 2 | --> $DIR/stalled-coroutine-obligations.rs:18:14 | |
| 3 | | | |
| 4 | LL | let foo: T = async {}; | |
| 5 | | ^ the trait `Copy` is not implemented for `{async block@$DIR/stalled-coroutine-obligations.rs:18:18: 18:23}` | |
| 6 | ||
| 7 | error[E0277]: the trait bound `{async block@$DIR/stalled-coroutine-obligations.rs:22:18: 22:23}: Clone` is not satisfied | |
| 8 | --> $DIR/stalled-coroutine-obligations.rs:22:14 | |
| 9 | | | |
| 10 | LL | let bar: U = async {}; | |
| 11 | | ^ the trait `Clone` is not implemented for `{async block@$DIR/stalled-coroutine-obligations.rs:22:18: 22:23}` | |
| 12 | ||
| 13 | error[E0277]: the trait bound `False: Valid` is not satisfied in `{async block@$DIR/stalled-coroutine-obligations.rs:33:18: 33:23}` | |
| 14 | --> $DIR/stalled-coroutine-obligations.rs:33:14 | |
| 15 | | | |
| 16 | LL | let foo: T = async { a }; | |
| 17 | | ^ ----- within this `{async block@$DIR/stalled-coroutine-obligations.rs:33:18: 33:23}` | |
| 18 | | | | |
| 19 | | unsatisfied trait bound | |
| 20 | | | |
| 21 | help: within `{async block@$DIR/stalled-coroutine-obligations.rs:33:18: 33:23}`, the trait `Valid` is not implemented for `False` | |
| 22 | --> $DIR/stalled-coroutine-obligations.rs:27:1 | |
| 23 | | | |
| 24 | LL | struct False; | |
| 25 | | ^^^^^^^^^^^^ | |
| 26 | note: captured value does not implement `Valid` | |
| 27 | --> $DIR/stalled-coroutine-obligations.rs:33:26 | |
| 28 | | | |
| 29 | LL | let foo: T = async { a }; | |
| 30 | | ^ has type `False` which does not implement `Valid` | |
| 31 | ||
| 32 | error[E0271]: type mismatch resolving `impl Future + Send == {async block@$DIR/stalled-coroutine-obligations.rs:42:9: 42:19}` | |
| 33 | --> $DIR/stalled-coroutine-obligations.rs:39:5 | |
| 34 | | | |
| 35 | LL | fn stalled_send(&self, b: *mut ()) -> impl Future + Send { | |
| 36 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ | |
| 37 | ||
| 38 | error[E0271]: type mismatch resolving `impl Future + Send == {async block@$DIR/stalled-coroutine-obligations.rs:42:9: 42:19}` | |
| 39 | --> $DIR/stalled-coroutine-obligations.rs:42:9 | |
| 40 | | | |
| 41 | LL | / async move { | |
| 42 | LL | | | |
| 43 | LL | | b | |
| 44 | LL | | } | |
| 45 | | |_________^ types differ | |
| 46 | ||
| 47 | error[E0271]: type mismatch resolving `{async block@$DIR/stalled-coroutine-obligations.rs:42:9: 42:19} <: impl Future + Send` | |
| 48 | --> $DIR/stalled-coroutine-obligations.rs:39:62 | |
| 49 | | | |
| 50 | LL | fn stalled_send(&self, b: *mut ()) -> impl Future + Send { | |
| 51 | | ______________________________________________________________^ | |
| 52 | LL | | | |
| 53 | LL | | | |
| 54 | LL | | async move { | |
| 55 | ... | | |
| 56 | LL | | } | |
| 57 | | |_____^ types differ | |
| 58 | ||
| 59 | error: aborting due to 6 previous errors | |
| 60 | ||
| 61 | Some errors have detailed explanations: E0271, E0277. | |
| 62 | For more information about an error, try `rustc --explain E0271`. |